From 5b512ac9a2e453b909d92efe543013a09878dd26 Mon Sep 17 00:00:00 2001 From: Nat Burns Date: Mon, 29 Jun 2015 20:39:27 +0000 Subject: [PATCH] Only check references inside class definitions (fixes #1). --- lib/rules/ext-deps.js | 101 +++++++++++++++++++------------------ test/lib/rules/ext-deps.js | 14 +++++ 2 files changed, 67 insertions(+), 48 deletions(-) diff --git a/lib/rules/ext-deps.js b/lib/rules/ext-deps.js index 4d27351..c5105af 100644 --- a/lib/rules/ext-deps.js +++ b/lib/rules/ext-deps.js @@ -10,33 +10,33 @@ var classdata = require("../classdata"); //------------------------------------------------------------------------------ module.exports = function(context) { - + "use strict"; - + var classes = classdata.loadDefaults(); var calls = []; - + var getPropertyKey = function(property) { var key = property.key; - + if (key.type === "Identifier") { return key.name; } else if (key.type === "Literal") { return "" + key.value; } - + return null; }; - + var addDependency = function(typeName) { calls[calls.length - 1].dependencies[classes.alternates[typeName] || typeName] = true; }; - + var addReference = function(typeName) { calls[calls.length - 1].references[classes.alternates[typeName] || typeName] = true; }; - + var handleTypes = function(node, key, callback, options) { if (options.string && node.type === "Literal" && typeof node.value === "string") { callback(node.value); @@ -49,7 +49,7 @@ module.exports = function(context) { else if (options.objectkey && node.type === "ObjectExpression") { node.properties.forEach(function(prop) { var subkey = getPropertyKey(prop); - + if (subkey === options.objectkey) { handleTypes(prop.value, key, callback, options); } @@ -66,7 +66,7 @@ module.exports = function(context) { ); } }; - + var parseReference = function(node) { if (node.type === "Identifier") { return node.name; @@ -74,68 +74,73 @@ module.exports = function(context) { else if (node.type === "MemberExpression") { var obj = parseReference(node.object); var prop = parseReference(node.property); - + if (obj && prop) { return obj + "." + prop; } } - + return null; }; - - + + return { - + "Program": function() { classes.loadScope(context.getScope()); }, - + "MemberExpression": function(node) { + if (calls.length < 1) { + // Don't include top-level references without a wrapping class. + return; + } + var ancestors = context.getAncestors(); var parent = ancestors[ancestors.length - 1]; - + if (parent.type !== "MemberExpression") { var member = parseReference(node); - + if (member) { var cls = classes.getClassName(member); - + if (cls) { addReference(cls); } } } }, - + "Property": function(node) { var key = getPropertyKey(node); - + switch (key) { case "xtype": case "items": key = "widget"; break; - + case "defaultReaderType": key = "reader"; break; - + case "defaultWriterType": key = "writer"; break; } - + var aliases = classes.aliases[key]; - + if (aliases) { var addAliasReference = function(type) { var cls = aliases[type]; - + if (cls) { addReference(cls); } }; - + handleTypes( node.value, key, @@ -153,52 +158,52 @@ module.exports = function(context) { ); } }, - + "CallExpression": function(node) { var info = { node: node, references: {} }; - + calls.push(info); - + var callee = node.callee; var method = callee.property ? callee.property.name : null; - + var args = node.arguments; var arg; - + if (callee.type === "MemberExpression" && callee.object.name === "Ext") { if (method === "create" && args.length > 0) { arg = node.arguments[0]; - + if (arg.type === "Literal" && typeof arg.value === "string") { addReference(arg.value); } } else if (method === "define" && args.length > 1) { arg = node.arguments[0]; - + if (arg.type === "Literal" && typeof arg.value === "string") { info.name = arg.value; } - + arg = node.arguments[1]; - + if (arg.type === "ObjectExpression") { info.dependencies = {}; - + arg.properties.forEach(function(prop) { var key = getPropertyKey(prop); - + var handler; var options; - + if (key === "requires" || key === "uses") { handler = addDependency; - + options = { string: true, array: true @@ -209,10 +214,10 @@ module.exports = function(context) { addDependency(type); addReference(type); }; - + options = { string: true }; } - + if (handler) { options.strict = true; handleTypes(prop.value, key, handler, options); @@ -222,13 +227,13 @@ module.exports = function(context) { } } }, - + "CallExpression:exit": function() { var call = calls.pop(); - + var deps = call.dependencies; var refs = call.references; - + if (deps) { Object.keys(refs).forEach(function(name) { if (refs[name] && !deps[name] && !classes.foundation[name]) { @@ -242,7 +247,7 @@ module.exports = function(context) { ); } }); - + Object.keys(deps).forEach(function(name) { if (deps[name] && !refs[name]) { context.report( @@ -258,12 +263,12 @@ module.exports = function(context) { } else if (calls.length > 0) { var parent = calls[calls.length - 1].references; - + Object.keys(refs).forEach(function(name) { parent[name] = parent[name] || refs[name]; }); } } }; - + }; \ No newline at end of file diff --git a/test/lib/rules/ext-deps.js b/test/lib/rules/ext-deps.js index 706cc6d..86c3ca7 100644 --- a/test/lib/rules/ext-deps.js +++ b/test/lib/rules/ext-deps.js @@ -17,6 +17,20 @@ var eslintTester = new ESLintTester(linter); eslintTester.addRuleTest("lib/rules/ext-deps", { valid: [ + { + code: "Ext.require('App.Class');", + global: { + Ext: true, + App: true + } + }, + { + code: "Ext.util.History.back();", + global: { + Ext: true, + App: true + } + }, { code: "Ext.define('App.Class', { requires: ['Ext.panel.Panel'], constructor: function() { this.panel = new Ext.panel.Panel(); } });", global: {