From dc4858af92a8bcfd421caf8eb9737bea5cf6bda8 Mon Sep 17 00:00:00 2001 From: Ilya Volodin Date: Thu, 24 Mar 2016 23:11:29 -0400 Subject: [PATCH] Update for version 2.0 --- .eslintrc | 2 +- README.md | 19 ++++ index.js | 50 ++++++---- lib/rules/collection-model.js | 65 +++++++------ lib/rules/defaults-on-top.js | 78 +++++++++------- lib/rules/event-scope.js | 71 +++++++------- lib/rules/events-on-top.js | 78 +++++++++------- lib/rules/initialize-on-top.js | 120 ++++++++++++------------ lib/rules/model-defaults.js | 64 +++++++------ lib/rules/no-changed-set.js | 62 +++++++------ lib/rules/no-collection-models.js | 56 +++++++----- lib/rules/no-constructor.js | 36 +++++--- lib/rules/no-el-assign.js | 58 +++++++----- lib/rules/no-model-attributes.js | 56 +++++++----- lib/rules/no-native-jquery.js | 80 ++++++++-------- lib/rules/no-silent.js | 62 +++++++------ lib/rules/no-view-collection-models.js | 60 ++++++------ lib/rules/no-view-model-attributes.js | 60 ++++++------ lib/rules/no-view-onoff-binding.js | 64 +++++++------ lib/rules/no-view-qualified-jquery.js | 122 +++++++++++++------------ lib/rules/render-return.js | 64 +++++++------ package.json | 6 +- 22 files changed, 754 insertions(+), 579 deletions(-) diff --git a/.eslintrc b/.eslintrc index 1da2289..a08bd49 100644 --- a/.eslintrc +++ b/.eslintrc @@ -13,7 +13,7 @@ "no-nested-ternary": 2, "no-undefined": 2, "radix": 2, - "space-after-keywords": [2, "always"], + "keyword-spacing": 2, "no-multi-spaces": 2, "valid-jsdoc": [2, { "prefer": { diff --git a/README.md b/README.md index bc2df50..4f0ec42 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,10 @@ npm install eslint-plugin-backbone --save-dev ## Default configuration +** Deprecated in v2 ** + +**node:** ESLint v2 removed support for default configurations. Please see config below for details. + If you are using ESLint >0.9.0 then this plugin will provide default configuration. If you are fine with defaults, you do not need to update your .eslintrc file. Defaults are currently set to the following: @@ -56,9 +60,24 @@ Defaults are currently set to the following: "no-view-collection-models": 2, "no-view-model-attributes": 2, "no-view-onoff-binding": 2, + "no-view-qualified-jquery": 0, "render-return": 2 ``` +## Configuration + +In version 2.0.0 removed support for default configurations for plugins and replaced it with ability for plugins to bundle configs. This plugin include `recommended` +configuration that you can extend from to enable recommended setup of the rules (see "Default configuration" for the list of enabled rules). + +To enable bundled config modify your .eslintrc file to include the following line: + +```json +{ + "extends": "plugin:backbone/recommended" +} + +This will enable all of the rules listed above, as well as add two global variables - `Backbone` and `_`. + ## Modify .eslintrc for your project Add `plugins` section and specify eslint-plugin-backbone as a plugin diff --git a/index.js b/index.js index 9279f3a..0af3823 100644 --- a/index.js +++ b/index.js @@ -21,24 +21,36 @@ module.exports = { "no-view-qualified-jquery": require("./lib/rules/no-view-qualified-jquery"), "render-return": require("./lib/rules/render-return") }, - rulesConfig: { - "collection-model": 2, - "defaults-on-top": 1, - "event-scope": 1, - "events-on-top": [1, ["tagName", "className"]], - "initialize-on-top": [1, { View: ["tagName", "className", "events"], Model: ["defaults", "url", "urlRoot"], Collection: ["model", "url"] }], - "model-defaults": 2, - "no-changed-set": 2, - "no-collection-models": 2, - "no-constructor": 1, - "no-el-assign": 2, - "no-model-attributes": 2, - "no-native-jquery": [1, "selector"], - "no-silent": 1, - "no-view-collection-models": 2, - "no-view-model-attributes": 2, - "no-view-onoff-binding": 2, - "no-view-qualified-jquery": 0, - "render-return": 2 + configs: { + recommended: { + env: ["browser"], + globals: { + "Backbone": false, + "_": false + }, + plugins: [ + "backbone" + ], + rules: { + "backbone/collection-model": 2, + "backbone/defaults-on-top": 1, + "backbone/event-scope": 1, + "backbone/events-on-top": [1, ["tagName", "className"]], + "backbone/initialize-on-top": [1, { View: ["tagName", "className", "events"], Model: ["defaults", "url", "urlRoot"], Collection: ["model", "url"] }], + "backbone/model-defaults": 2, + "backbone/no-changed-set": 2, + "backbone/no-collection-models": 2, + "backbone/no-constructor": 1, + "backbone/no-el-assign": 2, + "backbone/no-model-attributes": 2, + "backbone/no-native-jquery": [1, "selector"], + "backbone/no-silent": 1, + "backbone/no-view-collection-models": 2, + "backbone/no-view-model-attributes": 2, + "backbone/no-view-onoff-binding": 2, + "backbone/no-view-qualified-jquery": 0, + "backbone/render-return": 2 + } + } } }; diff --git a/lib/rules/collection-model.js b/lib/rules/collection-model.js index 996d4ea..deeaf1f 100644 --- a/lib/rules/collection-model.js +++ b/lib/rules/collection-model.js @@ -10,38 +10,45 @@ var helper = require("../backbone-helper.js"); -module.exports = function(context) { - - var settings = context.settings || /* istanbul ignore next */ {}; - var backboneCollection = []; +module.exports = { + meta: { + docs: { + description: "Require all collections to declare model", + category: "Best Practices", + recommended: true + }, + schema: [] + }, + create: function(context) { + var settings = context.settings || /* istanbul ignore next */ {}; + var backboneCollection = []; - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- - return { - "CallExpression": function(node) { - if (helper.isBackboneCollection(node, settings.backbone)) { - backboneCollection.push({ node: node, found: false }); - } - }, - "CallExpression:exit": function(node) { - var lastCollection = backboneCollection[backboneCollection.length - 1]; - if (backboneCollection.length > 0 && lastCollection.node === node) { - if (!lastCollection.found) { - context.report(node, "All collections should have model declared"); + return { + "CallExpression": function(node) { + if (helper.isBackboneCollection(node, settings.backbone)) { + backboneCollection.push({ node: node, found: false }); } - backboneCollection.pop(); - } - }, - "Identifier": function(node) { - if (backboneCollection.length > 0 && node.name === "model") { - if (helper.checkIfPropertyInBackboneCollection(node, settings.backbone)) { - backboneCollection[backboneCollection.length - 1].found = true; + }, + "CallExpression:exit": function(node) { + var lastCollection = backboneCollection[backboneCollection.length - 1]; + if (backboneCollection.length > 0 && lastCollection.node === node) { + if (!lastCollection.found) { + context.report(node, "All collections should have model declared"); + } + backboneCollection.pop(); + } + }, + "Identifier": function(node) { + if (backboneCollection.length > 0 && node.name === "model") { + if (helper.checkIfPropertyInBackboneCollection(node, settings.backbone)) { + backboneCollection[backboneCollection.length - 1].found = true; + } } } - } - }; + }; + } }; - -module.exports.schema = []; diff --git a/lib/rules/defaults-on-top.js b/lib/rules/defaults-on-top.js index c9b7590..de673cd 100644 --- a/lib/rules/defaults-on-top.js +++ b/lib/rules/defaults-on-top.js @@ -10,47 +10,55 @@ var helper = require("../backbone-helper.js"); -module.exports = function(context) { +module.exports = { + meta: { + docs: { + description: "Require defaults to be on top of the model", + category: "Stylistic", + recommended: false + }, + schema: [ + { + "type": "array", + "items": { + "type": "string", + "uniqueItems": true + }, + "additionalProperties": false + } + ] + }, + create: function(context) { - var settings = context.settings || /* istanbul ignore next */ {}; + var settings = context.settings || /* istanbul ignore next */ {}; - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- - return { - "Identifier": function(node) { - if (node.name === "defaults") { - var parent = node.parent, grandparent = parent.parent; - if (helper.checkIfPropertyInBackboneModel(node, settings.backbone) && grandparent.type === "ObjectExpression" && grandparent.properties[0] !== parent) { - if (context.options && context.options.length > 0) { - //we have exceptions passed into the rule, verify that any property that goes before events is in the options list - for (var i = 0, l = grandparent.properties.length; i < l; i++) { - if (grandparent.properties[i] === parent) { - break; - } - if ((grandparent.properties[i].key.type === "Identifier" && context.options[0].indexOf(grandparent.properties[i].key.name) === -1) || - (grandparent.properties[i].key.type === "Literal" && context.options[0].indexOf(grandparent.properties[i].key.value) === -1)) { - context.report(node, "defaults should be declared at the top of the model."); - break; + return { + "Identifier": function(node) { + if (node.name === "defaults") { + var parent = node.parent, grandparent = parent.parent; + if (helper.checkIfPropertyInBackboneModel(node, settings.backbone) && grandparent.type === "ObjectExpression" && grandparent.properties[0] !== parent) { + if (context.options && context.options.length > 0) { + //we have exceptions passed into the rule, verify that any property that goes before events is in the options list + for (var i = 0, l = grandparent.properties.length; i < l; i++) { + if (grandparent.properties[i] === parent) { + break; + } + if ((grandparent.properties[i].key.type === "Identifier" && context.options[0].indexOf(grandparent.properties[i].key.name) === -1) || + (grandparent.properties[i].key.type === "Literal" && context.options[0].indexOf(grandparent.properties[i].key.value) === -1)) { + context.report(node, "defaults should be declared at the top of the model."); + break; + } } + } else { + context.report(node, "defaults should be declared at the top of the model."); } - } else { - context.report(node, "defaults should be declared at the top of the model."); } } } - } - }; -}; - -module.exports.schema = [ - { - "type": "array", - "items": { - "type": "string", - "uniqueItems": true - }, - "additionalProperties": false + }; } -]; +}; diff --git a/lib/rules/event-scope.js b/lib/rules/event-scope.js index d530a7f..ac172b0 100644 --- a/lib/rules/event-scope.js +++ b/lib/rules/event-scope.js @@ -10,42 +10,51 @@ var helper = require("../backbone-helper.js"); -module.exports = function(context) { +module.exports = { + meta: { + docs: { + description: "Verify that scope is passed into event handlers", + category: "Best Practices", + recommended: false + }, + schema: [] + }, + create: function(context) { - var settings = context.settings || /* istanbul ignore next */ {}; - var backbone = []; + var settings = context.settings || /* istanbul ignore next */ {}; + var backbone = []; - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- - return { - "CallExpression": function(node) { - backbone.push(backbone[backbone.length - 1] || helper.isBackboneAny(node, settings.backbone)); - }, - "CallExpression:exit": function(node) { - if (helper.isBackboneAny(node, settings.backbone)) { - backbone.pop(); - } - }, - "Identifier": function(node) { - var ancestors = context.getAncestors(node); - var parent = ancestors.pop(); - if (backbone[backbone.length - 1] && (node.name === "on" || node.name === "once") && - !((parent.object.type === "CallExpression" && ((parent.object.callee.type === "Identifier" && parent.object.callee.name === "$") || //covers the case of $().on() - (parent.object.callee.type === "MemberExpression" && parent.object.callee.object.type === "ThisExpression" && parent.object.callee.property.name === "$")) || //covers the case of this.$().on() - (parent.object.type === "MemberExpression" && parent.object.property.type === "Identifier" && parent.object.property.name === "$el")))) { //covers the case of this.$el.on() - while (parent.type !== "CallExpression" && !parent.arguments) { - parent = ancestors.pop(); + return { + "CallExpression": function(node) { + backbone.push(backbone[backbone.length - 1] || helper.isBackboneAny(node, settings.backbone)); + }, + "CallExpression:exit": function(node) { + if (helper.isBackboneAny(node, settings.backbone)) { + backbone.pop(); } - if (parent.arguments.length === 1 && parent.arguments[0].type === 'ObjectExpression') { - context.report(node, "Pass scope as second argument."); - } else if (parent.arguments.length < 3 && (parent.arguments[0] || {}).type !== 'ObjectExpression') { - context.report(node, "Pass scope as third argument."); + }, + "Identifier": function(node) { + var ancestors = context.getAncestors(node); + var parent = ancestors.pop(); + if (backbone[backbone.length - 1] && (node.name === "on" || node.name === "once") && + !((parent.object.type === "CallExpression" && ((parent.object.callee.type === "Identifier" && parent.object.callee.name === "$") || //covers the case of $().on() + (parent.object.callee.type === "MemberExpression" && parent.object.callee.object.type === "ThisExpression" && parent.object.callee.property.name === "$")) || //covers the case of this.$().on() + (parent.object.type === "MemberExpression" && parent.object.property.type === "Identifier" && parent.object.property.name === "$el")))) { //covers the case of this.$el.on() + while (parent.type !== "CallExpression" && !parent.arguments) { + parent = ancestors.pop(); + } + if (parent.arguments.length === 1 && parent.arguments[0].type === 'ObjectExpression') { + context.report(node, "Pass scope as second argument."); + } else if (parent.arguments.length < 3 && (parent.arguments[0] || {}).type !== 'ObjectExpression') { + context.report(node, "Pass scope as third argument."); + } } } - } - }; + }; + } }; -module.exports.schema = []; diff --git a/lib/rules/events-on-top.js b/lib/rules/events-on-top.js index d7436a8..00a8d3d 100644 --- a/lib/rules/events-on-top.js +++ b/lib/rules/events-on-top.js @@ -10,47 +10,55 @@ var helper = require("../backbone-helper.js"); -module.exports = function(context) { +module.exports = { + meta: { + docs: { + description: "Events should be the first thing registered in the View", + category: "Stylistic", + recommended: false + }, + schema: [ + { + "type": "array", + "items": { + "type": "string", + "uniqueItems": true + }, + "additionalProperties": false + } + ] + }, + create: function(context) { - var settings = context.settings || /* istanbul ignore next */ {}; + var settings = context.settings || /* istanbul ignore next */ {}; - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- - return { - "Identifier": function(node) { - if (node.name === "events") { - var parent = node.parent, grandparent = parent.parent; - if (helper.checkIfPropertyInBackboneView(node, settings.backbone) && grandparent.type === "ObjectExpression" && grandparent.properties[0] !== parent) { - if (context.options && context.options.length > 0) { - //we have exceptions passed into the rule, verify that any property that goes before events is in the options list - for (var i = 0, l = grandparent.properties.length; i < l; i++) { - if (grandparent.properties[i] === parent) { - break; - } - if ((grandparent.properties[i].key.type === "Identifier" && context.options[0].indexOf(grandparent.properties[i].key.name) === -1) || - (grandparent.properties[i].key.type === "Literal" && context.options[0].indexOf(grandparent.properties[i].key.value) === -1)) { - context.report(node, "events should be declared at the top of the view."); - break; + return { + "Identifier": function(node) { + if (node.name === "events") { + var parent = node.parent, grandparent = parent.parent; + if (helper.checkIfPropertyInBackboneView(node, settings.backbone) && grandparent.type === "ObjectExpression" && grandparent.properties[0] !== parent) { + if (context.options && context.options.length > 0) { + //we have exceptions passed into the rule, verify that any property that goes before events is in the options list + for (var i = 0, l = grandparent.properties.length; i < l; i++) { + if (grandparent.properties[i] === parent) { + break; + } + if ((grandparent.properties[i].key.type === "Identifier" && context.options[0].indexOf(grandparent.properties[i].key.name) === -1) || + (grandparent.properties[i].key.type === "Literal" && context.options[0].indexOf(grandparent.properties[i].key.value) === -1)) { + context.report(node, "events should be declared at the top of the view."); + break; + } } + } else { + context.report(node, "events should be declared at the top of the view."); } - } else { - context.report(node, "events should be declared at the top of the view."); } } } - } - }; -}; - -module.exports.schema = [ - { - "type": "array", - "items": { - "type": "string", - "uniqueItems": true - }, - "additionalProperties": false + }; } -]; +}; diff --git a/lib/rules/initialize-on-top.js b/lib/rules/initialize-on-top.js index 1e38a25..fd9397a 100644 --- a/lib/rules/initialize-on-top.js +++ b/lib/rules/initialize-on-top.js @@ -10,69 +10,77 @@ var helper = require("../backbone-helper.js"); -module.exports = function(context) { - - var settings = context.settings || /* istanbul ignore next */ {}; +module.exports = { + meta: { + docs: { + description: "Requires initialize to be the first property of Backbone Views/Models/Collections", + category: "Stylistic", + recommended: false + }, + schema: [ + { + "type": "object", + "properties": { + "View": { + "type": "array", + "value": "string" + }, + "Model": { + "type": "array", + "value": "string" + }, + "Collection": { + "type": "array", + "value": "string" + } + } + } + ] + }, + create: function(context) { - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- + var settings = context.settings || /* istanbul ignore next */ {}; - return { - "Identifier": function(node) { - if (node.name === "initialize") { - var parent = node.parent, grandparent = parent.parent; - if (helper.checkIfPropertyInBackbone(node, settings.backbone) && grandparent.type === "ObjectExpression" && grandparent.properties[0] !== parent) { - if (context.options && context.options.length > 0) { - var backboneTypeOptions = []; - var backboneType = ""; - if (helper.checkIfPropertyInBackboneView(node, settings.backbone)) { - backboneTypeOptions = context.options[0].View ? context.options[0].View : []; - backboneType = "view"; - } else if (helper.checkIfPropertyInBackboneModel(node, settings.backbone)) { - backboneTypeOptions = context.options[0].Model ? context.options[0].Model : []; - backboneType = "model"; - } else { - backboneTypeOptions = context.options[0].Collection ? context.options[0].Collection : []; - backboneType = "collection"; - } + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- - //we have exceptions passed into the rule, verify that any property that goes before initialize is in the options list - for (var i = 0, l = grandparent.properties.length; i < l; i++) { - if (grandparent.properties[i] === parent) { - break; + return { + "Identifier": function(node) { + if (node.name === "initialize") { + var parent = node.parent, grandparent = parent.parent; + if (helper.checkIfPropertyInBackbone(node, settings.backbone) && grandparent.type === "ObjectExpression" && grandparent.properties[0] !== parent) { + if (context.options && context.options.length > 0) { + var backboneTypeOptions = []; + var backboneType = ""; + if (helper.checkIfPropertyInBackboneView(node, settings.backbone)) { + backboneTypeOptions = context.options[0].View ? context.options[0].View : []; + backboneType = "view"; + } else if (helper.checkIfPropertyInBackboneModel(node, settings.backbone)) { + backboneTypeOptions = context.options[0].Model ? context.options[0].Model : []; + backboneType = "model"; + } else { + backboneTypeOptions = context.options[0].Collection ? context.options[0].Collection : []; + backboneType = "collection"; } - if ((grandparent.properties[i].key.type === "Identifier" && backboneTypeOptions.indexOf(grandparent.properties[i].key.name) === -1) || - (grandparent.properties[i].key.type === "Literal" && backboneTypeOptions.indexOf(grandparent.properties[i].key.value) === -1)) { - context.report(node, "Initialize should be declared at the top of the {{type}}.", { type: backboneType }); - break; + + //we have exceptions passed into the rule, verify that any property that goes before initialize is in the options list + for (var i = 0, l = grandparent.properties.length; i < l; i++) { + if (grandparent.properties[i] === parent) { + break; + } + if ((grandparent.properties[i].key.type === "Identifier" && backboneTypeOptions.indexOf(grandparent.properties[i].key.name) === -1) || + (grandparent.properties[i].key.type === "Literal" && backboneTypeOptions.indexOf(grandparent.properties[i].key.value) === -1)) { + context.report(node, "Initialize should be declared at the top of the {{type}}.", { type: backboneType }); + break; + } } + } else { + context.report(node, "Initialize should be declared at the top."); } - } else { - context.report(node, "Initialize should be declared at the top."); } } } - } - }; -}; - -module.exports.schema = [ - { - "type": "object", - "properties": { - "View": { - "type": "array", - "value": "string" - }, - "Model": { - "type": "array", - "value": "string" - }, - "Collection": { - "type": "array", - "value": "string" - } - } + }; } -]; +}; diff --git a/lib/rules/model-defaults.js b/lib/rules/model-defaults.js index eb351b6..f1b9b59 100644 --- a/lib/rules/model-defaults.js +++ b/lib/rules/model-defaults.js @@ -10,38 +10,46 @@ var helper = require("../backbone-helper.js"); -module.exports = function(context) { +module.exports = { + meta: { + docs: { + description: "Require all models to have defaults section", + category: "Best Practices", + recommended: true + }, + schema: [] + }, + create: function(context) { - var backboneModel = []; - var settings = context.settings || /* istanbul ignore next */ {}; + var backboneModel = []; + var settings = context.settings || /* istanbul ignore next */ {}; - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- - return { - "CallExpression": function(node) { - if (helper.isBackboneModel(node, settings.backbone)) { - backboneModel.push({ node: node, found: false }); - } - }, - "CallExpression:exit": function(node) { - var lastModel = backboneModel[backboneModel.length - 1]; - if (backboneModel.length > 0 && lastModel.node === node) { - if (!lastModel.found) { - context.report(node, "All models should have defaults declared"); + return { + "CallExpression": function(node) { + if (helper.isBackboneModel(node, settings.backbone)) { + backboneModel.push({ node: node, found: false }); } - backboneModel.pop(); - } - }, - "Identifier": function(node) { - if (backboneModel.length > 0 && node.name === "defaults") { - if (helper.checkIfPropertyInBackboneModel(node, settings.backbone)) { - backboneModel[backboneModel.length - 1].found = true; + }, + "CallExpression:exit": function(node) { + var lastModel = backboneModel[backboneModel.length - 1]; + if (backboneModel.length > 0 && lastModel.node === node) { + if (!lastModel.found) { + context.report(node, "All models should have defaults declared"); + } + backboneModel.pop(); + } + }, + "Identifier": function(node) { + if (backboneModel.length > 0 && node.name === "defaults") { + if (helper.checkIfPropertyInBackboneModel(node, settings.backbone)) { + backboneModel[backboneModel.length - 1].found = true; + } } } - } - }; + }; + } }; - -module.exports.schema = []; diff --git a/lib/rules/no-changed-set.js b/lib/rules/no-changed-set.js index 8eb949e..8c529ea 100644 --- a/lib/rules/no-changed-set.js +++ b/lib/rules/no-changed-set.js @@ -10,35 +10,43 @@ var helper = require("../backbone-helper.js"); -module.exports = function(context) { +module.exports = { + meta: { + docs: { + description: "Prevent setting changed attribute of the model in views", + category: "Best Practices", + recommended: true + }, + schema: [] + }, + create: function(context) { - var backboneView = []; - var settings = context.settings || /* istanbul ignore next */ {}; + var backboneView = []; + var settings = context.settings || /* istanbul ignore next */ {}; - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // 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(); + 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."); + } } - }, - "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."); - } - } - }; + }; + } }; - -module.exports.schema = []; diff --git a/lib/rules/no-collection-models.js b/lib/rules/no-collection-models.js index b67e2d5..ae7ebdb 100644 --- a/lib/rules/no-collection-models.js +++ b/lib/rules/no-collection-models.js @@ -10,32 +10,40 @@ var helper = require("../backbone-helper.js"); -module.exports = function(context) { +module.exports = { + meta: { + docs: { + description: "Prevent access to models property of collections", + category: "Best Practices", + recommended: true + }, + schema: [] + }, + create: function(context) { - var backboneCollection = []; - var settings = context.settings || /* istanbul ignore next */ {}; + var backboneCollection = []; + var settings = context.settings || /* istanbul ignore next */ {}; - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // 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"); + 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"); + } + } + }; + } }; - -module.exports.schema = []; diff --git a/lib/rules/no-constructor.js b/lib/rules/no-constructor.js index 88d9928..ced65b0 100644 --- a/lib/rules/no-constructor.js +++ b/lib/rules/no-constructor.js @@ -10,23 +10,31 @@ var helper = require("../backbone-helper.js"); -module.exports = function(context) { +module.exports = { + meta: { + docs: { + description: "Prevent overloading of constructor", + category: "Best Practices", + recommended: false + }, + schema: [] + }, + create: function(context) { - var settings = context.settings || /* istanbul ignore next */ {}; + var settings = context.settings || /* istanbul ignore next */ {}; - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- - return { - "Identifier": function(node) { - if (node.name === "constructor") { - if (helper.checkIfPropertyInBackbone(node, settings.backbone)) { - context.report(node, "Overload initialize instead of constructor"); + return { + "Identifier": function(node) { + if (node.name === "constructor") { + if (helper.checkIfPropertyInBackbone(node, settings.backbone)) { + context.report(node, "Overload initialize instead of constructor"); + } } } - } - }; + }; + } }; - -module.exports.schema = []; diff --git a/lib/rules/no-el-assign.js b/lib/rules/no-el-assign.js index f72ad22..42017ba 100644 --- a/lib/rules/no-el-assign.js +++ b/lib/rules/no-el-assign.js @@ -10,33 +10,41 @@ var helper = require("../backbone-helper.js"); -module.exports = function(context) { +module.exports = { + meta: { + docs: { + description: "Prevent assigning el or $el inside views", + category: "Best Practices", + recommended: true + }, + schema: [] + }, + create: function(context) { - var backboneView = []; - var settings = context.settings || /* istanbul ignore next */ {}; + var backboneView = []; + var settings = context.settings || /* istanbul ignore next */ {}; - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // 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(); + 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 === "ThisExpression" && + (node.left.property.name === "el" || node.left.property.name === "$el")) { + context.report(node, "Do not assign '{{identifier}}' directly. Use setElement() instead", { identifier: node.left.property.name }); + } } - }, - "AssignmentExpression": function(node) { - if (backboneView[backboneView.length - 1] && - node.left.type === "MemberExpression" && - node.left.object.type === "ThisExpression" && - (node.left.property.name === "el" || node.left.property.name === "$el")) { - context.report(node, "Do not assign '{{identifier}}' directly. Use setElement() instead", { identifier: node.left.property.name }); - } - } - }; + }; + } }; - -module.exports.schema = []; diff --git a/lib/rules/no-model-attributes.js b/lib/rules/no-model-attributes.js index 2d82f21..0812539 100644 --- a/lib/rules/no-model-attributes.js +++ b/lib/rules/no-model-attributes.js @@ -10,32 +10,40 @@ var helper = require("../backbone-helper.js"); -module.exports = function(context) { +module.exports = { + meta: { + docs: { + description: "Prevent access to attributes collection inside models", + category: "Best Practices", + recommended: true + }, + schema: [] + }, + create: function(context) { - var backboneModel = []; - var settings = context.settings || /* istanbul ignore next */ {}; + var backboneModel = []; + var settings = context.settings || /* istanbul ignore next */ {}; - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // 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"); + 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"); + } + } + }; + } }; - -module.exports.schema = []; diff --git a/lib/rules/no-native-jquery.js b/lib/rules/no-native-jquery.js index ebba035..d9aba47 100644 --- a/lib/rules/no-native-jquery.js +++ b/lib/rules/no-native-jquery.js @@ -10,52 +10,60 @@ var helper = require("../backbone-helper.js"); -module.exports = function(context) { +module.exports = { + meta: { + docs: { + description: "Prevent usage of $ in the views", + category: "Best Practices", + recommended: false + }, + schema: [ + { + "enum": ["all", "selector"] + } + ] + }, + create: function(context) { - var backboneView = []; - var settings = context.settings || /* istanbul ignore next */ {}; + var backboneView = []; + var settings = context.settings || /* istanbul ignore next */ {}; - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // 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(); - } - }, - "Identifier": function(node) { - if (backboneView[backboneView.length - 1] && node.name === "$") { - var ancestors = context.getAncestors(node), parent = ancestors.pop(); + 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(); + } + }, + "Identifier": function(node) { + if (backboneView[backboneView.length - 1] && node.name === "$") { + var ancestors = context.getAncestors(node), parent = ancestors.pop(); - if (parent.type === "CallExpression") { - if (context.options && context.options.length > 0) { - if (context.options[0] === "selector" && parent.arguments && parent.arguments.length > 0) { - if (parent.arguments[0].type === "Literal") { - if (parent.arguments[0].value.match(/^<.*>$/) || (parent.arguments.length === 2 && parent.arguments[1].type !== 'Literal')) { - return; + if (parent.type === "CallExpression") { + if (context.options && context.options.length > 0) { + if (context.options[0] === "selector" && parent.arguments && parent.arguments.length > 0) { + if (parent.arguments[0].type === "Literal") { + if (parent.arguments[0].value.match(/^<.*>$/) || (parent.arguments.length === 2 && parent.arguments[1].type !== 'Literal')) { + return; + } else { + context.report(node, "Use this.$ instead of $ in views"); + return; + } } else { - context.report(node, "Use this.$ instead of $ in views"); return; } - } else { - return; } } + context.report(node, "Use this.$ instead of $ in views"); } - context.report(node, "Use this.$ instead of $ in views"); } } - } - }; -}; - -module.exports.schema = [ - { - "enum": ["all", "selector"] + }; } -]; +}; diff --git a/lib/rules/no-silent.js b/lib/rules/no-silent.js index 535dd04..be207b9 100644 --- a/lib/rules/no-silent.js +++ b/lib/rules/no-silent.js @@ -11,36 +11,44 @@ var helper = require("../backbone-helper.js"); -module.exports = function(context) { +module.exports = { + meta: { + docs: { + description: "Prevent using silent option in functions that cause events", + category: "Best Practices", + recommended: false + }, + schema: [] + }, + create: function(context) { - var settings = context.settings || /* istanbul ignore next */ {}; - var backbone = []; + var settings = context.settings || /* istanbul ignore next */ {}; + var backbone = []; - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- - return { - "CallExpression": function(node) { - backbone.push(backbone[backbone.length - 1] || helper.isBackboneAny(node, settings.backbone)); - }, - "CallExpression:exit": function(node) { - if (helper.isBackboneAny(node, settings.backbone)) { - backbone.pop(); - } - }, - "Identifier": function(node) { - var functions = ["set", "unset", "reset", "clear", "remove", "add", "push", "unshift", "shift", "sort", "create"]; - var ancestors = context.getAncestors(node); - var parent = ancestors.pop(); - if (backbone[backbone.length - 1] && (node.name === "silent") && parent.type === "Property" && parent.value.type === "Literal" && parent.value.value === true) { - parent = ancestors[ancestors.length - 2]; - if (parent && parent.type === "CallExpression" && parent.callee.type === "MemberExpression" && parent.callee.property.type === "Identifier" && functions.indexOf(parent.callee.property.name) > -1) { - context.report(node, "Do not silence events."); + return { + "CallExpression": function(node) { + backbone.push(backbone[backbone.length - 1] || helper.isBackboneAny(node, settings.backbone)); + }, + "CallExpression:exit": function(node) { + if (helper.isBackboneAny(node, settings.backbone)) { + backbone.pop(); + } + }, + "Identifier": function(node) { + var functions = ["set", "unset", "reset", "clear", "remove", "add", "push", "unshift", "shift", "sort", "create"]; + var ancestors = context.getAncestors(node); + var parent = ancestors.pop(); + if (backbone[backbone.length - 1] && (node.name === "silent") && parent.type === "Property" && parent.value.type === "Literal" && parent.value.value === true) { + parent = ancestors[ancestors.length - 2]; + if (parent && parent.type === "CallExpression" && parent.callee.type === "MemberExpression" && parent.callee.property.type === "Identifier" && functions.indexOf(parent.callee.property.name) > -1) { + context.report(node, "Do not silence events."); + } } } - } - }; + }; + } }; - -module.exports.schema = []; diff --git a/lib/rules/no-view-collection-models.js b/lib/rules/no-view-collection-models.js index 40048d6..d278c29 100644 --- a/lib/rules/no-view-collection-models.js +++ b/lib/rules/no-view-collection-models.js @@ -10,34 +10,42 @@ var helper = require("../backbone-helper.js"); -module.exports = function(context) { +module.exports = { + meta: { + docs: { + description: "Prevent access to collection's models property inside views", + category: "Best Practices", + recommended: true + }, + schema: [] + }, + create: function(context) { - var backboneView = []; - var settings = context.settings || /* istanbul ignore next */ {}; + var backboneView = []; + var settings = context.settings || /* istanbul ignore next */ {}; - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // 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."); + 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."); + } + } + }; + } }; - -module.exports.schema = []; diff --git a/lib/rules/no-view-model-attributes.js b/lib/rules/no-view-model-attributes.js index e5462d5..a405ead 100644 --- a/lib/rules/no-view-model-attributes.js +++ b/lib/rules/no-view-model-attributes.js @@ -10,34 +10,42 @@ var helper = require("../backbone-helper.js"); -module.exports = function(context) { +module.exports = { + meta: { + docs: { + description: "Prevent access to model's attributes collection inside views", + category: "Best Practices", + recommended: true + }, + schema: [] + }, + create: function(context) { - var backboneView = []; - var settings = context.settings || /* istanbul ignore next */ {}; + var backboneView = []; + var settings = context.settings || /* istanbul ignore next */ {}; - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // 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.property.name === "attributes") { - context.report(node, "Do not access attributes directly. Use set() and get() instead"); + 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.property.name === "attributes") { + context.report(node, "Do not access attributes directly. Use set() and get() instead"); + } + } + }; + } }; - -module.exports.schema = []; diff --git a/lib/rules/no-view-onoff-binding.js b/lib/rules/no-view-onoff-binding.js index 2c2ffd8..9f034d7 100644 --- a/lib/rules/no-view-onoff-binding.js +++ b/lib/rules/no-view-onoff-binding.js @@ -11,37 +11,45 @@ var helper = require("../backbone-helper.js"); -module.exports = function(context) { +module.exports = { + meta: { + docs: { + description: "Prevent using on/off bindings inside views", + category: "Best Practices", + recommended: true + }, + schema: [] + }, + create: function(context) { - var backboneView = []; - var settings = context.settings || /* istanbul ignore next */ {}; + var backboneView = []; + var settings = context.settings || /* istanbul ignore next */ {}; - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // 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")) { - if (node.property.name === "on") { - context.report(node, "Use listenTo instead of 'on'."); - } else if (node.property.name === "off") { - context.report(node, "Use stopListening instead of 'off'."); + 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")) { + if (node.property.name === "on") { + context.report(node, "Use listenTo instead of 'on'."); + } else if (node.property.name === "off") { + context.report(node, "Use stopListening instead of 'off'."); + } } } - } - }; + }; + } }; - -module.exports.schema = []; diff --git a/lib/rules/no-view-qualified-jquery.js b/lib/rules/no-view-qualified-jquery.js index 7b44872..e11cd41 100644 --- a/lib/rules/no-view-qualified-jquery.js +++ b/lib/rules/no-view-qualified-jquery.js @@ -12,75 +12,83 @@ var DEFAULT_JQUERY_ALIASES = ["jQuery", "$"], VIEW_ELEMENT_MEMBERS = ["el", "$el"], ERROR_TEMPLATE = "Use {{identifier}}.$ or {{identifier}}.$el.find instead of view-scoped native jQuery"; -module.exports = function(context) { - var options, - sourceCode = context.getSourceCode(); +module.exports = { + meta: { + docs: { + description: "Prevent usage of global $ to reach view elements", + category: "Best Practices", + recommended: false + }, + schema: [ + { + type: "object", + properties: { + identifiers: { + type: "array" + } + }, + additionalProperties: false + } + ] + }, + create: function(context) { + var options, + sourceCode = context.getSourceCode(); - options = context.options[0] || { - identifiers: DEFAULT_JQUERY_ALIASES - }; + options = context.options[0] || { + identifiers: DEFAULT_JQUERY_ALIASES + }; - function isNativeJQuery(node) { - return node.type === "Identifier" && - options.identifiers.indexOf(node.name) !== -1; - } - - function isPotentialViewElement(node) { - return node.type === "MemberExpression" && - node.property && - node.property.type === "Identifier" && - VIEW_ELEMENT_MEMBERS.indexOf(node.property.name) !== -1; - } - - function isJQueryWrappedPotentialViewElement(node) { - return node.type === "CallExpression" && - node.arguments.length && - isNativeJQuery(node.callee) && - isPotentialViewElement(node.arguments[0]); - } + function isNativeJQuery(node) { + return node.type === "Identifier" && + options.identifiers.indexOf(node.name) !== -1; + } - function isArgumentViewQualifier(node) { - return isPotentialViewElement(node) || - isJQueryWrappedPotentialViewElement(node); - } + function isPotentialViewElement(node) { + return node.type === "MemberExpression" && + node.property && + node.property.type === "Identifier" && + VIEW_ELEMENT_MEMBERS.indexOf(node.property.name) !== -1; + } - function getViewIdentifier(node) { - if (isPotentialViewElement(node)) { - return sourceCode.getText(node.object); + function isJQueryWrappedPotentialViewElement(node) { + return node.type === "CallExpression" && + node.arguments.length && + isNativeJQuery(node.callee) && + isPotentialViewElement(node.arguments[0]); } - return sourceCode.getText(node.arguments[0].object); - } + function isArgumentViewQualifier(node) { + return isPotentialViewElement(node) || + isJQueryWrappedPotentialViewElement(node); + } - function checkForViewQualifiedJQuery(node) { - // View qualified jQuery is defined in terms of second argument to - // jQuery call. Argument may be in the form of view.el, view.$el, or - // $(view.el) or $(view.$el). + function getViewIdentifier(node) { + if (isPotentialViewElement(node)) { + return sourceCode.getText(node.object); + } - if (isArgumentViewQualifier(node.arguments[1])) { - context.report(node, ERROR_TEMPLATE, { - identifier: getViewIdentifier(node.arguments[1]) - }); + return sourceCode.getText(node.arguments[0].object); } - } - return { - "CallExpression": function(node) { - if (isNativeJQuery(node.callee) && node.arguments.length > 1) { - checkForViewQualifiedJQuery(node); + function checkForViewQualifiedJQuery(node) { + // View qualified jQuery is defined in terms of second argument to + // jQuery call. Argument may be in the form of view.el, view.$el, or + // $(view.el) or $(view.$el). + + if (isArgumentViewQualifier(node.arguments[1])) { + context.report(node, ERROR_TEMPLATE, { + identifier: getViewIdentifier(node.arguments[1]) + }); } } - }; -}; -module.exports.schema = [ - { - type: "object", - properties: { - identifiers: { - type: "array" + return { + "CallExpression": function(node) { + if (isNativeJQuery(node.callee) && node.arguments.length > 1) { + checkForViewQualifiedJQuery(node); + } } - }, - additionalProperties: false + }; } -]; +}; diff --git a/lib/rules/render-return.js b/lib/rules/render-return.js index 044c5da..03018a2 100644 --- a/lib/rules/render-return.js +++ b/lib/rules/render-return.js @@ -11,38 +11,46 @@ var helper = require("../backbone-helper.js"); -module.exports = function(context) { +module.exports = { + meta: { + docs: { + description: "Enforces render function to always return this", + category: "Best Practices", + recommended: true + }, + schema: [] + }, + create: function(context) { - var inBackboneRender = null; - var returnFound = false; + var inBackboneRender = null; + var returnFound = false; - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- - return { - "FunctionExpression": function(node) { - if (node.parent.type === "Property" && node.parent.key.type === "Identifier" && node.parent.key.name === "render") { - if (helper.checkIfPropertyInBackboneView(node.parent.key)) { - inBackboneRender = node; - returnFound = false; + return { + "FunctionExpression": function(node) { + if (node.parent.type === "Property" && node.parent.key.type === "Identifier" && node.parent.key.name === "render") { + if (helper.checkIfPropertyInBackboneView(node.parent.key)) { + inBackboneRender = node; + returnFound = false; + } } - } - }, - "FunctionExpression:exit": function(node) { - if (inBackboneRender !== null && inBackboneRender === node) { - inBackboneRender = null; - if (!returnFound) { - context.report(node, "render method should always return 'this'"); + }, + "FunctionExpression:exit": function(node) { + if (inBackboneRender !== null && inBackboneRender === node) { + inBackboneRender = null; + if (!returnFound) { + context.report(node, "render method should always return 'this'"); + } + } + }, + "ReturnStatement": function(node) { + if (inBackboneRender) { + returnFound = node.argument && node.argument.type === "ThisExpression"; } } - }, - "ReturnStatement": function(node) { - if (inBackboneRender) { - returnFound = node.argument && node.argument.type === "ThisExpression"; - } - } - }; + }; + } }; - -module.exports.schema = []; diff --git a/package.json b/package.json index edc65a8..f65e783 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-backbone", - "version": "1.2.0", + "version": "2.0.0", "description": "Eslint rules for Backbone.", "main": "index.js", "scripts": { @@ -14,10 +14,10 @@ "devDependencies": { "istanbul": "0.3.0", "mocha": "1.21.4", - "eslint": "^1.10.0" + "eslint": "^2.0.0" }, "peerDependencies": { - "eslint": "^1.10.0" + "eslint": "^2.0.0" }, "repository": { "type": "git",