Skip to content

Commit 918f303

Browse files
committed
Handle local jquery vars in no-jquery-methods
1 parent 294c350 commit 918f303

File tree

3 files changed

+99
-16
lines changed

3 files changed

+99
-16
lines changed

lib/rules/no-jquery-methods.js

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44
'use strict';
55

6-
const { get } = require('../utils/get');
6+
const { get, getParent } = require('../utils/get');
77
const { isJQueryCallee, isVariableAssigmentJquery } = require('../utils/jquery');
88

99
function getMessage(blackListName) {
@@ -28,26 +28,35 @@ module.exports = {
2828
},
2929
create(context) {
3030
const BLACKLIST = context.options[0] || [];
31-
let jQueryLocalName = null;
31+
let funcScopeJqueryVariables = [];
32+
let moduleScopeJqueryVariables = [];
3233

3334
return {
3435

3536
ImportDeclaration(node) {
3637
let localName = getLocalImportName(node, 'jquery');
3738
if (localName.length > 0) {
38-
jQueryLocalName = localName[0];
39+
moduleScopeJqueryVariables.push(localName[0]);
3940
}
4041
},
4142

4243
VariableDeclarator(node) {
43-
const varName = get(node, 'id.name');
44-
jQueryLocalName = isVariableAssigmentJquery(node) ? varName : null;
44+
if (isVariableAssigmentJquery(node)) {
45+
const varName = get(node, 'id.name');
46+
const isFuncScope = !!getParent(node, (parent) => parent.type === 'FunctionDeclaration'); // Determine if variable is in function scope or global scope.
47+
48+
if (isFuncScope) {
49+
funcScopeJqueryVariables.push(varName);
50+
} else {
51+
moduleScopeJqueryVariables.push(varName);
52+
}
53+
}
4554
},
4655

4756
CallExpression(node) {
4857
const calleeName = get(node, 'callee.property.name');
4958
const parentCalleeName = get(node, 'callee.object.property.name');
50-
if (BLACKLIST.includes(calleeName) && (parentCalleeName === '$' || isJQueryCallee(node, jQueryLocalName))) {
59+
if (BLACKLIST.includes(calleeName) && (parentCalleeName === '$' || isJQueryCallee(node, moduleScopeJqueryVariables, funcScopeJqueryVariables))) {
5160
context.report({ node: node.callee.property, message: getMessage(`${parentCalleeName}.${calleeName}()`) });
5261
}
5362
},
@@ -61,9 +70,14 @@ module.exports = {
6170
let blackListName = BLACKLIST.includes(propertyName) ? propertyName : false;
6271
let isThisExpression = get(node, 'object.type').includes('ThisExpression');
6372

64-
if (!isThisExpression && blackListName && isJQueryCallee(node, jQueryLocalName)) {
73+
if (!isThisExpression && blackListName && isJQueryCallee(node, moduleScopeJqueryVariables, funcScopeJqueryVariables)) {
6574
context.report({ node: node.property, message: getMessage(blackListName) });
6675
}
76+
},
77+
78+
FunctionDeclaration() {
79+
// Reset the function scope variables for each function declaration.
80+
funcScopeJqueryVariables.length = 0;
6781
}
6882
};
6983
}

lib/utils/jquery.js

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,24 @@ const { get } = require('../utils/get');
22

33
const JQUERY_ALIASES = ['$', 'jQuery'];
44

5-
function isJQueryCallee(node, name = null) {
6-
const calleePropertyNameisJquery = JQUERY_ALIASES.includes(get(node, 'object.callee.property.name'));
7-
const calleeNameIsJquery = JQUERY_ALIASES.includes(get(node, 'object.callee.name'));
8-
const calleeNameIsLocalJquery = get(node, 'object.callee.name') === name;
9-
const objectNameisLocalJquery = get(node, 'object.name') === name;
5+
/**
6+
* Determines whether a given node's callee is jQuery.
7+
* @param {ASTNode} node
8+
* @param {...Array} localJqueryVars Array(s) of local variables that have jQuery assigned to them.
9+
* @return {Boolean}
10+
*/
11+
function isJQueryCallee(node, ...localJqueryVars) {
12+
const allJqueryAliases = localJqueryVars.reduce((accumulator, newArray) => {
13+
return accumulator.concat(newArray);
14+
}, JQUERY_ALIASES);
15+
16+
const calleePropertyNameisJquery = allJqueryAliases.includes(get(node, 'object.callee.property.name'));
17+
const calleeNameIsJquery = allJqueryAliases.includes(get(node, 'object.callee.name'));
18+
const objectNameisJquery = allJqueryAliases.includes(get(node, 'object.name'));
1019

1120
return calleePropertyNameisJquery
1221
|| calleeNameIsJquery
13-
|| calleeNameIsLocalJquery
14-
|| objectNameisLocalJquery;
22+
|| objectNameisJquery;
1523
}
1624

1725
/**
@@ -21,7 +29,7 @@ function isJQueryCallee(node, name = null) {
2129
*/
2230
function getVarAssignmentName(node) {
2331
// Get the name of what was assigned to the variable.
24-
return get(node, 'init.callee.property.name') || get(node, 'init.name');
32+
return get(node, 'init.callee.property.name') || get(node, 'init.name') || get(node, 'init.property.name');
2533
}
2634

2735
/**
@@ -31,7 +39,7 @@ function getVarAssignmentName(node) {
3139
*/
3240
function isVarAssignmentCalleeEmber(node) {
3341
// A variable's callee object's name tells us whether this is a usage of Ember.$ or global $.
34-
const isVarCalleeObjNameEmber = get(node, 'init.callee.object.name') === 'Ember';
42+
const isVarCalleeObjNameEmber = get(node, 'init.callee.object.name') === 'Ember' || get(node, 'init.object.name') === 'Ember';
3543
// Whether or not the callee oject is `this.$`.
3644
const isVarCalleeObjThis = get(node, 'init.callee.object.type') === 'ThisExpression';
3745

tests/lib/rules/no-jquery-methods.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,67 @@ ruleTester.run('no-jquery-methods', rule, {
218218
errors: [{
219219
message: getMessage(`$.${BLACKLISTMETHOD}()`)
220220
}]
221+
},
222+
{
223+
code: `
224+
import jQ from 'jquery';
225+
const jayQuery = Ember.$;
226+
227+
jayQuery('.class').add();
228+
jQ('.class2').add();`,
229+
options: [BLACKLISTMETHOD],
230+
errors: [
231+
{ message: getMessage(BLACKLISTMETHOD) },
232+
{ message: getMessage(BLACKLISTMETHOD) }
233+
]
234+
},
235+
{
236+
code: `
237+
function func1() {
238+
const jayQuery = Bar.foo;
239+
jayQuery().add();
240+
}
241+
242+
function func2() {
243+
const jayQuery = Ember.$;
244+
jayQuery().add();
245+
}
246+
247+
function func3() {
248+
const jayQuery = Obj.method;
249+
jayQuery().add();
250+
}
251+
252+
function func4() {
253+
const jayQuery = $;
254+
jayQuery().add();
255+
}
256+
257+
function func5() {
258+
const jayQuery = Foo.bar;
259+
jayQuery().add();
260+
}`,
261+
options: [BLACKLISTMETHOD],
262+
errors: [
263+
{ message: getMessage(BLACKLISTMETHOD) },
264+
{ message: getMessage(BLACKLISTMETHOD) }
265+
]
266+
},
267+
{
268+
code: `
269+
import jQ from 'jquery';
270+
function func1() {
271+
const jayQuery = Ember.$;
272+
jayQuery().add();
273+
}
274+
275+
jQ().add();
276+
`,
277+
options: [BLACKLISTMETHOD],
278+
errors: [
279+
{ message: getMessage(BLACKLISTMETHOD) },
280+
{ message: getMessage(BLACKLISTMETHOD) }
281+
]
221282
}
222283
]
223284
});

0 commit comments

Comments
 (0)