Skip to content

Commit a343d29

Browse files
lynchbombscalvert
authored andcommitted
Add rule against using specific deprecated jQuery Methods (Blacklisted) (#59)
* Deprecate jQuery N-Method
1 parent 93cee7f commit a343d29

File tree

6 files changed

+363
-50
lines changed

6 files changed

+363
-50
lines changed

config/no-jquery.js

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
const BLACKLIST = [
2+
'add',
3+
'addBack',
4+
'after',
5+
'ajaxComplete',
6+
'ajaxError',
7+
'ajaxSend',
8+
'ajaxStart',
9+
'ajaxStop',
10+
'ajaxSuccess',
11+
'andSelf',
12+
'before',
13+
'bind',
14+
'change',
15+
'clearQueue',
16+
'clone',
17+
'contents',
18+
'contextmenu',
19+
'dblclick',
20+
'delay',
21+
'delegate',
22+
'dequeue',
23+
'detach',
24+
'end',
25+
'error',
26+
'fadeIn',
27+
'fadeTo',
28+
'fadeToggle',
29+
'finish',
30+
'focusin',
31+
'focusout',
32+
'hover',
33+
'insertAfter',
34+
'insertBefore',
35+
'keydown',
36+
'keypress',
37+
'keyup',
38+
'last',
39+
'load',
40+
'mousedown',
41+
'mouseenter',
42+
'mouseleave',
43+
'mousemove',
44+
'mouseout',
45+
'mouseover',
46+
'mouseup',
47+
'next',
48+
'nextAll',
49+
'nextUntil',
50+
'not',
51+
'parentsUntil',
52+
'prepend',
53+
'prependTo',
54+
'prev',
55+
'revUntil',
56+
'promise',
57+
'queue',
58+
'removeData',
59+
'removeProp',
60+
'replaceAll',
61+
'replaceWith',
62+
'resize',
63+
'scroll',
64+
'scrollLeft',
65+
'select',
66+
'serialize',
67+
'show',
68+
'size',
69+
'slice',
70+
'slideDown',
71+
'slideToggle',
72+
'stop',
73+
'submit',
74+
'toArray',
75+
'toggle',
76+
'toggleClass',
77+
'unbind',
78+
'undelegate',
79+
'unload',
80+
'unwrap',
81+
'wrap',
82+
'wrapAll',
83+
'wrapInner'
84+
];
85+
86+
module.exports = {
87+
parserOptions: {
88+
ecmaVersion: 6,
89+
sourceType: 'module'
90+
},
91+
env: {
92+
'browser': true
93+
},
94+
plugins: [
95+
'ember-best-practices'
96+
],
97+
extends: require.resolve('./recommended.js'),
98+
rules: {
99+
// Custom rules
100+
'ember-best-practices/no-jquery-methods': [2, [BLACKLIST]]
101+
}
102+
};

guides/rules/no-jquery-methods.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# No jQuery Methods
2+
3+
**TL;DR** The intent of this rule is to identify any blacklisted jQuery methods as deprecated.
4+
5+
Provides the ability to blacklist a set of jQuery methods for deprecation.
6+
The eventual goal being a complete removal of jQuery.

lib/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ const requireindex = require('requireindex');
22

33
module.exports.rules = requireindex(__dirname + '/rules');
44
module.exports.configs = {
5-
recommended: require('../config/recommended')
5+
recommended: require('../config/recommended'),
6+
nojquery: require('../config/no-jquery')
67
};

lib/rules/no-jquery-methods.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/**
2+
* @fileOverview Disallow the use of specific jQuery methods.
3+
* @author Marc Lynch
4+
*/
5+
'use strict';
6+
7+
const { get } = require('../utils/get');
8+
9+
function getMessage(blackListName) {
10+
return `The use of ${blackListName} method has been deprecated.`;
11+
}
12+
13+
function isJQueryCaller(node, name = null) {
14+
let oName = get(node, 'object.callee.object.name') === 'Ember';
15+
let pName = get(node, 'object.callee.property.name') === '$';
16+
let cName = get(node, 'object.callee.name') === '$';
17+
let lName = get(node, 'object.name') === name;
18+
19+
return oName || pName || cName || lName;
20+
}
21+
22+
function getLocalImportName(node, sourceName) {
23+
if (get(node, 'source.value').includes(sourceName)) {
24+
return get(node, 'specifiers').map((specifier) => specifier.local.name);
25+
}
26+
27+
return [];
28+
}
29+
30+
module.exports = {
31+
docs: {
32+
category: 'Best Practices',
33+
recommended: true
34+
},
35+
meta: {
36+
message: getMessage
37+
},
38+
create(context) {
39+
const BLACKLIST = context.options[0] || [];
40+
let jQueryLocalName = null;
41+
let varDecIDName = null;
42+
43+
return {
44+
45+
ImportDeclaration(node) {
46+
let localName = getLocalImportName(node, 'jquery');
47+
if (localName.length > 0) {
48+
jQueryLocalName = localName[0];
49+
}
50+
},
51+
52+
VariableDeclarator(node) {
53+
varDecIDName = get(node, 'id.name');
54+
jQueryLocalName = jQueryLocalName === get(node, 'init.name') ? varDecIDName : null;
55+
},
56+
57+
MemberExpression(node) {
58+
let propertyName = get(node, 'property.name');
59+
let blackListName = BLACKLIST.includes(propertyName) ? propertyName : false;
60+
let isThisExpression = get(node, 'object.type').includes('ThisExpression');
61+
62+
jQueryLocalName = isThisExpression && propertyName.includes('$') ? varDecIDName : jQueryLocalName;
63+
64+
if (!isThisExpression && blackListName && isJQueryCaller(node, jQueryLocalName)) {
65+
context.report({ node: node.property, message: getMessage(blackListName) });
66+
}
67+
}
68+
};
69+
}
70+
};

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

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
const rule = require('../../../lib/rules/no-jquery-methods');
2+
const RuleTester = require('eslint').RuleTester;
3+
const getMessage = rule.meta.message;
4+
const BLACKLISTMETHOD = 'add';
5+
const ruleTester = new RuleTester({
6+
parserOptions: {
7+
ecmaVersion: 6,
8+
sourceType: 'module'
9+
}
10+
});
11+
12+
ruleTester.run('no-jquery-methods', rule, {
13+
valid: [
14+
{
15+
code: `
16+
export default Ember.Component({
17+
init() {
18+
Ember.$().notBlacklistedMethod();
19+
}
20+
});`,
21+
options: [BLACKLISTMETHOD]
22+
},
23+
{
24+
code: `
25+
export default Ember.Component({
26+
init() {
27+
this.$().notBlacklistedMethod();
28+
}
29+
});`,
30+
options: [BLACKLISTMETHOD]
31+
},
32+
{
33+
code: `
34+
export default Ember.Component({
35+
init() {
36+
const myObj = {};
37+
myObj[${BLACKLISTMETHOD}]();
38+
}
39+
});`,
40+
options: [BLACKLISTMETHOD]
41+
}
42+
],
43+
invalid: [
44+
{
45+
code: `
46+
export default Ember.Component({
47+
init() {
48+
Ember.$()[${BLACKLISTMETHOD}]();
49+
}
50+
});`,
51+
options: [BLACKLISTMETHOD],
52+
errors: [{
53+
message: getMessage(BLACKLISTMETHOD)
54+
}]
55+
},
56+
{
57+
code: `
58+
export default Ember.Component({
59+
init() {
60+
this.$()[${BLACKLISTMETHOD}]();
61+
}
62+
});`,
63+
options: [BLACKLISTMETHOD],
64+
errors: [{
65+
message: getMessage(BLACKLISTMETHOD)
66+
}]
67+
},
68+
{
69+
code: `
70+
export default Ember.Component({
71+
init() {
72+
$()[${BLACKLISTMETHOD}]();
73+
}
74+
});`,
75+
options: [BLACKLISTMETHOD],
76+
errors: [{
77+
message: getMessage(BLACKLISTMETHOD)
78+
}]
79+
},
80+
{
81+
code: `
82+
import jQuery from 'jquery';
83+
export default Ember.Component({
84+
init() {
85+
jQuery[${BLACKLISTMETHOD}]();
86+
}
87+
});`,
88+
options: [BLACKLISTMETHOD],
89+
errors: [{
90+
message: getMessage(BLACKLISTMETHOD)
91+
}]
92+
},
93+
{
94+
code: `
95+
import jQuery from 'jquery';
96+
export default Ember.Component({
97+
init() {
98+
const _$ = jQuery;
99+
_$[${BLACKLISTMETHOD}]();
100+
}
101+
});`,
102+
options: [BLACKLISTMETHOD],
103+
errors: [{
104+
message: getMessage(BLACKLISTMETHOD)
105+
}]
106+
},
107+
{
108+
code: `
109+
export default Ember.Component({
110+
init() {
111+
const myJQueryObj = this.$();
112+
myJQueryObj[${BLACKLISTMETHOD}]();
113+
}
114+
});`,
115+
options: [BLACKLISTMETHOD],
116+
errors: [{
117+
message: getMessage(BLACKLISTMETHOD)
118+
}]
119+
},
120+
{
121+
code: `
122+
import jQuery from 'jquery';
123+
import fOO from 'foo';
124+
export default Ember.Component({
125+
init() {
126+
jQuery[${BLACKLISTMETHOD}]();
127+
}
128+
});`,
129+
options: [BLACKLISTMETHOD],
130+
errors: [{
131+
message: getMessage(BLACKLISTMETHOD)
132+
}]
133+
}
134+
]
135+
});

0 commit comments

Comments
 (0)