Skip to content

Commit

Permalink
Merge pull request #19 from ilyavolodin/new-rules
Browse files Browse the repository at this point in the history
New rules
  • Loading branch information
ilyavolodin committed Sep 29, 2014
2 parents caa123f + ed4cda5 commit 78e2d59
Show file tree
Hide file tree
Showing 18 changed files with 603 additions and 2 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ If you are using custom models/view/collection bases you also have to specify ea
* [defaults-on-top](docs/rules/defaults-on-top.md)
* [events-on-top](docs/rules/events-on-top.md)
* [model-defaults](docs/rules/model-defaults.md)
* [no-changed-set](/docs/rules/no-changed-set.md)
* [no-collection-models](/docs/rules/no-collection-models.md)
* [no-constructor](docs/rules/no-constructor.md)
* [no-el-assign](docs/rules/no-el-assign.md)
* [no-model-attributes](docs/rules/no-model-attributes.md)
* [no-native-jquery](docs/rules/no-native-jquery.md)
* [no-view-collection-models](docs/rules/no-view-collection-models.md)
* [no-view-model-attributes](docs/rules/no-view-model-attributes.md)
35 changes: 35 additions & 0 deletions docs/rules/no-changed-set.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Prevent setting changed attribute of the model in views (no-changed-set)

Changed attribute is automatically computed by Backbone and modified when any property of the model has been updated. Manually changing it can lead to problems.

## Rule Details

The following patterns are considered warnings:

```js

Backbone.View.extend({
render: function() {
this.model.changed = false;
}
});

```

The following patterns are not warnings:

```js

Backbone.View.extend({
render: function() {
if (this.model.changed) {
...
}
}
});

```

## Further Reading

[BackboneJS Documentation](http://backbonejs.org/#Model-changed)
38 changes: 38 additions & 0 deletions docs/rules/no-collection-models.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Prevent access to models property of collections (no-collection-models)

Instead of accessing `models` collection directly from within views, use `get()`, `at()` or underscore functions. If you are looking for length of the collection, use `this.length` instead. If you want to modify collection use `this.add`, `this.remove`, `this.push` and `this.pop` methods instead.


## Rule Details

The following patterns are considered warnings:

```js

Backbone.Collection.extend({
initialize: function() {
_.first(this.models);
}
});

```

The following patterns are not warnings:

```js

Backbone.Collection.extend({
initialize: function() {
this.at(0);
}
});

```

## Further Reading

[BackboneJS Documentation](http://backbonejs.org/#Collection-models)

## Related Rules

[no-view-collection-models](no-view-collection-models.md)
38 changes: 38 additions & 0 deletions docs/rules/no-model-attributes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Prevent access to attributes collection inside models (no-model-attributes)

Instead of accessing `attributes` collection directly from within models, use `get()` or `set()` function. Backbone setters do more then just assign value, they also keep track of when model has been last modified. If you work with `attributes` collection directly, `changed` and `changedAttributes` will not be updated.


## Rule Details

The following patterns are considered warnings:

```js

Backbone.Model.extend({
initialize: function() {
_.first(this.attributes);
}
});

```

The following patterns are not warnings:

```js

Backbone.Model.extend({
initialize: function() {
this.set('test', true);
}
});

```

## Further Reading

[BackboneJS Documentation](http://backbonejs.org/#Model-get)

## Related Rules

[no-view-model-attributes](no-view-model-attributes.md)
33 changes: 33 additions & 0 deletions docs/rules/no-view-collection-models.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Prevent access to collection's models property inside views (no-view-collection-models)

Instead of accessing `models` collection directly from within views, use `get()`, `at()` or underscore functions.

## Rule Details

The following patterns are considered warnings:

```js

Backbone.View.extend({
render: function() {
alert(this.model.models.length);
}
})

```

The following patterns are not warnings:

```js

Backbone.View.extend({
render: function() {
alert(this.collection.at(0));
}
});

```

## Further Reading

[BackboneJS Documentation](http://backbonejs.org/#Collection-models)
38 changes: 38 additions & 0 deletions docs/rules/no-view-model-attributes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Prevent access to model's attributes collection inside views (no-view-model-attributes)

Instead of accessing `attributes` collection directly from within views, use `get()` or `set()` function. Backbone setters do more then just assign value, they also keep track of when model has been last modified. If you work with `attributes` collection directly, `changed` and `changedAttributes` will not be updated.


## Rule Details

The following patterns are considered warnings:

```js

Backbone.View.extend({
render: function() {
alert(this.model.attributes[0]);
}
});

```

The following patterns are not warnings:

```js

Backbone.View.extend({
render: function() {
alert(this.model.get("test"));
}
});

```

## When Not To Use It

If your models are configured as input to templates and you use them that way, this rule will flag any time you pass attributes collection to the template.

## Further Reading

[BackboneJS Documentation](http://backbonejs.org/#Model-get)
7 changes: 6 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@ module.exports = {
"defaults-on-top": require("./lib/rules/defaults-on-top"),
"events-on-top": require("./lib/rules/events-on-top"),
"model-defaults": require("./lib/rules/model-defaults"),
"no-changed-set": require("./lib/rules/no-changed-set"),
"no-collection-models": require("./lib/rules/no-collection-models"),
"no-constructor": require("./lib/rules/no-constructor"),
"no-el-assign": require("./lib/rules/no-el-assign"),
"no-native-jquery": require("./lib/rules/no-native-jquery")
"no-model-attributes": require("./lib/rules/no-model-attributes"),
"no-native-jquery": require("./lib/rules/no-native-jquery"),
"no-view-collection-models": require("./lib/rules/no-view-collection-models"),
"no-view-model-attributes": require("./lib/rules/no-view-model-attributes")
}
};
42 changes: 42 additions & 0 deletions lib/rules/no-changed-set.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* @fileoverview Prevent setting changed attribute of the model in views
* @author Ilya Volodin
*/
"use strict";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

var helper = require("../../backbone-helper.js");

module.exports = function(context) {

var backboneView = [];
var settings = context.settings || /* istanbul ignore next */ {};

//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------

return {
"CallExpression": function(node) {
backboneView.push(backboneView[backboneView.length - 1] || helper.isBackboneView(node, settings.backbone));
},
"CallExpression:exit": function(node) {
if (helper.isBackboneView(node, settings.backbone)) {
backboneView.pop();
}
},
"AssignmentExpression" : function(node) {
if (backboneView[backboneView.length - 1] &&
node.left.type === "MemberExpression" &&
node.left.object.type === "MemberExpression" &&
node.left.object.object.type === "ThisExpression" &&
node.left.object.property.name === "model" &&
node.left.property.name === "changed") {
context.report(node, "Do not assign changed property of the model directly.");
}
}
};
};
39 changes: 39 additions & 0 deletions lib/rules/no-collection-models.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* @fileoverview Prevent access to models property of collections
* @author Ilya Volodin
*/
"use strict";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

var helper = require("../../backbone-helper.js");

module.exports = function(context) {

var backboneCollection = [];
var settings = context.settings || /* istanbul ignore next */ {};

//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------

return {
"CallExpression": function(node) {
backboneCollection.push(backboneCollection[backboneCollection.length - 1] || helper.isBackboneCollection(node, settings.backbone));
},
"CallExpression:exit": function(node) {
if (helper.isBackboneCollection(node, settings.backbone)) {
backboneCollection.pop();
}
},
"MemberExpression" : function(node) {
if (backboneCollection[backboneCollection.length - 1] &&
node.object.type === "ThisExpression" &&
node.property.name === "models") {
context.report(node, "Do not access models directly. Use get() and at() instead");
}
}
};
};
39 changes: 39 additions & 0 deletions lib/rules/no-model-attributes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* @fileoverview Prevent access to attributes collection inside models
* @author Ilya Volodin
*/
"use strict";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

var helper = require("../../backbone-helper.js");

module.exports = function(context) {

var backboneModel = [];
var settings = context.settings || /* istanbul ignore next */ {};

//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------

return {
"CallExpression": function(node) {
backboneModel.push(backboneModel[backboneModel.length - 1] || helper.isBackboneModel(node, settings.backbone));
},
"CallExpression:exit": function(node) {
if (helper.isBackboneModel(node, settings.backbone)) {
backboneModel.pop();
}
},
"MemberExpression" : function(node) {
if (backboneModel[backboneModel.length - 1] &&
node.object.type === "ThisExpression" &&
node.property.name === "attributes") {
context.report(node, "Do not access attributes directly. Use set() and get() instead");
}
}
};
};
41 changes: 41 additions & 0 deletions lib/rules/no-view-collection-models.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* @fileoverview Prevent access to collection's models property inside views
* @author Ilya Volodin
*/
"use strict";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

var helper = require("../../backbone-helper.js");

module.exports = function(context) {

var backboneView = [];
var settings = context.settings || /* istanbul ignore next */ {};

//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------

return {
"CallExpression": function(node) {
backboneView.push(backboneView[backboneView.length - 1] || helper.isBackboneView(node, settings.backbone));
},
"CallExpression:exit": function(node) {
if (helper.isBackboneView(node, settings.backbone)) {
backboneView.pop();
}
},
"MemberExpression" : function(node) {
if (backboneView[backboneView.length - 1] &&
node.object.type === "MemberExpression" &&
node.object.object.type === "ThisExpression" &&
(node.object.property.name === "model" || node.object.property.name === "collection") &&
node.property.name === "models") {
context.report(node, "Do not access models directly. Use get() and at() methods instead.");
}
}
};
};
Loading

0 comments on commit 78e2d59

Please sign in to comment.