eslint-plugin-no-jquery 3.0.2 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -107,6 +107,7 @@ Where rules are included in the configs `recommended`, `slim`, `all` or `depreca
107
107
  * [`no-jquery/no-data`](docs/rules/no-data.md) `all`
108
108
  * [`no-jquery/no-deferred`](docs/rules/no-deferred.md) `all`
109
109
  * [`no-jquery/no-delegate`](docs/rules/no-delegate.md) `3.0`, `all`
110
+ * [`no-jquery/no-done-fail`](docs/rules/no-done-fail.md) `all`
110
111
  * [`no-jquery/no-each`](docs/rules/no-each.md)
111
112
  * [`no-jquery/no-each-collection`](docs/rules/no-each-collection.md) `all`
112
113
  * [`no-jquery/no-each-util`](docs/rules/no-each-util.md) `all`
@@ -120,6 +121,7 @@ Where rules are included in the configs `recommended`, `slim`, `all` or `depreca
120
121
  * [`no-jquery/no-find`](docs/rules/no-find.md)
121
122
  * [`no-jquery/no-find-collection`](docs/rules/no-find-collection.md) `all`
122
123
  * [`no-jquery/no-find-util`](docs/rules/no-find-util.md) `all`
124
+ * [`no-jquery/no-fx`](docs/rules/no-fx.md) `slim`
123
125
  * [`no-jquery/no-fx-interval`](docs/rules/no-fx-interval.md) `3.0`
124
126
  * [`no-jquery/no-global-eval`](docs/rules/no-global-eval.md) `all`
125
127
  * [`no-jquery/no-global-selector`](docs/rules/no-global-selector.md) ⚙️
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-no-jquery",
3
- "version": "3.0.2",
3
+ "version": "3.1.0",
4
4
  "description": "Disallow jQuery functions with native equivalents.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -34,7 +34,7 @@
34
34
  },
35
35
  "devDependencies": {
36
36
  "codecov": "^3.8.3",
37
- "eslint-config-wikimedia": "^0.28.0",
37
+ "eslint-config-wikimedia": "^0.28.2",
38
38
  "eslint-docgen": "^0.7.1",
39
39
  "eslint-plugin-eslint-plugin": "^6.1.0",
40
40
  "eslint-plugin-self": "^1.2.1",
package/src/index.js CHANGED
@@ -25,6 +25,7 @@ module.exports = {
25
25
  'no-deferred': require( './rules/no-deferred' ),
26
26
  'no-delegate': require( './rules/no-delegate' ),
27
27
  'no-die': require( './rules/no-die' ),
28
+ 'no-done-fail': require( './rules/no-done-fail' ),
28
29
  'no-each': require( './rules/no-each' ),
29
30
  'no-each-collection': require( './rules/no-each-collection' ),
30
31
  'no-each-util': require( './rules/no-each-util' ),
@@ -38,6 +39,7 @@ module.exports = {
38
39
  'no-find': require( './rules/no-find' ),
39
40
  'no-find-collection': require( './rules/no-find-collection' ),
40
41
  'no-find-util': require( './rules/no-find-util' ),
42
+ 'no-fx': require( './rules/no-fx' ),
41
43
  'no-fx-interval': require( './rules/no-fx-interval' ),
42
44
  'no-global-eval': require( './rules/no-global-eval' ),
43
45
  'no-global-selector': require( './rules/no-global-selector' ),
@@ -117,6 +119,7 @@ module.exports = {
117
119
  'no-jquery/no-animate-toggle': 'error',
118
120
  'no-jquery/no-fade': 'error',
119
121
  'no-jquery/no-slide': 'error',
122
+ 'no-jquery/no-fx': 'error',
120
123
  // Ajax
121
124
  'no-jquery/no-ajax': 'error',
122
125
  'no-jquery/no-ajax-events': 'error',
@@ -333,8 +336,10 @@ module.exports = {
333
336
  'no-jquery/no-filter': 'warn',
334
337
  'no-jquery/no-prop': 'warn',
335
338
  'no-jquery/no-sub': 'warn',
336
- 'no-jquery/no-text': 'warn'
339
+ 'no-jquery/no-text': 'warn',
337
340
 
341
+ // Other methods
342
+ 'no-jquery/no-done-fail': 'warn'
338
343
  }
339
344
  }
340
345
  }
@@ -2,13 +2,15 @@
2
2
 
3
3
  const utils = require( '../utils.js' );
4
4
 
5
+ const methods = [ 'animate', 'stop', 'finish' ];
6
+
5
7
  module.exports = {
6
8
  meta: {
7
9
  type: 'suggestion',
8
10
  docs: {
9
11
  description:
10
- 'Disallows the ' + utils.jQueryCollectionLink( 'animate' ) +
11
- ' method. Use the `allowScroll` option to allow animations which are just used for scrolling. Prefer CSS transitions.'
12
+ 'Disallows the ' + methods.map( utils.jQueryCollectionLink ).join( '/' ) +
13
+ ' methods. Use the `allowScroll` option to allow animations which are just used for scrolling. Prefer CSS transitions.'
12
14
  },
13
15
  schema: [
14
16
  {
@@ -27,12 +29,12 @@ module.exports = {
27
29
  'CallExpression:exit': ( node ) => {
28
30
  if (
29
31
  node.callee.type !== 'MemberExpression' ||
30
- node.callee.property.name !== 'animate'
32
+ !methods.includes( node.callee.property.name )
31
33
  ) {
32
34
  return;
33
35
  }
34
36
  const allowScroll = context.options[ 0 ] && context.options[ 0 ].allowScroll;
35
- if ( allowScroll ) {
37
+ if ( node.callee.property.name === 'animate' && allowScroll ) {
36
38
  const arg = node.arguments[ 0 ];
37
39
  // Check properties list has more than just scrollTop/scrollLeft
38
40
  if ( arg && arg.type === 'ObjectExpression' ) {
@@ -0,0 +1,11 @@
1
+ 'use strict';
2
+
3
+ const utils = require( '../utils.js' );
4
+
5
+ module.exports = utils.createUniversalMethodRule(
6
+ [ 'done', 'fail' ],
7
+ ( node ) => node === true ?
8
+ 'Prefer `.then`' :
9
+ `Prefer .then to .${ node.callee.property.name }`,
10
+ ( method ) => `[\`.${ method }\`](https://api.jquery.com/deferred.${ method }/)`
11
+ );
@@ -44,8 +44,9 @@ const rule = utils.createCollectionMethodRule(
44
44
  'mousemove',
45
45
  'mouseout',
46
46
  'mouseover',
47
- 'mouseup'
48
- ].concat( ajaxEvents ),
47
+ 'mouseup',
48
+ ...ajaxEvents
49
+ ],
49
50
  ( node ) => node === true ?
50
51
  'Use the `allowAjaxEvents` option to allow `ajax*` methods. Prefer `.on` or `.trigger`' :
51
52
  `Prefer .on or .trigger to .${ node.callee.property.name }`,
@@ -48,7 +48,9 @@ module.exports = {
48
48
  node,
49
49
  message: 'Prefer Object.assign or the spread operator to $.extend',
50
50
  fix: function ( fixer ) {
51
- if ( !isDeep ) {
51
+ // Only auto-fix if we are sure the first argument is an object.
52
+ // If it is undefined or null variable, then Object.assign will throw.
53
+ if ( !isDeep && node.arguments[ 0 ] && node.arguments[ 0 ].type === 'ObjectExpression' ) {
52
54
  return fixer.replaceText( node.callee, 'Object.assign' );
53
55
  }
54
56
  }
@@ -0,0 +1,29 @@
1
+ 'use strict';
2
+
3
+ const utils = require( '../utils.js' );
4
+
5
+ module.exports = {
6
+ meta: {
7
+ type: 'suggestion',
8
+ docs: {
9
+ description: 'Disallows `$.fx`.'
10
+ },
11
+ schema: []
12
+ },
13
+
14
+ create: ( context ) => ( {
15
+ MemberExpression: ( node ) => {
16
+ if (
17
+ !utils.isjQueryConstructor( context, node.object.name ) ||
18
+ node.property.name !== 'fx'
19
+ ) {
20
+ return;
21
+ }
22
+
23
+ context.report( {
24
+ node,
25
+ message: '$.fx is not allowed'
26
+ } );
27
+ }
28
+ } )
29
+ };
package/src/utils.js CHANGED
@@ -173,6 +173,7 @@ function isjQueryConstructor( context, name ) {
173
173
  //
174
174
  // Returns true if the function call node is attached to a jQuery element set.
175
175
  function isjQuery( context, node ) {
176
+ // eslint-disable-next-line security/detect-non-literal-regexp
176
177
  const variablePattern = new RegExp(
177
178
  ( context.settings && context.settings[ 'no-jquery' ] && context.settings[ 'no-jquery' ].variablePattern ) ||
178
179
  '^\\$.'
@@ -311,7 +312,7 @@ function createCollectionMethodRule( methods, message, options ) {
311
312
  methods = Array.isArray( methods ) ? methods : [ methods ];
312
313
 
313
314
  let description = 'Disallows the ' + methods.map( jQueryCollectionLink ).join( '/' ) + ' ' +
314
- ( methods.length > 1 ? 'methods' : 'method' ) + '.';
315
+ ( methods.length > 1 ? 'methods' : 'method' ) + '.';
315
316
 
316
317
  description += messageSuffix( message );
317
318
 
@@ -369,7 +370,7 @@ function createCollectionMethodRule( methods, message, options ) {
369
370
  }
370
371
 
371
372
  /**
372
- * Create a rule for collection property
373
+ * Create a rule for collection properties
373
374
  *
374
375
  * @param {string} property Property name
375
376
  * @param {string|Function} [message] Message to report. See createCollectionMethodRule.
@@ -421,7 +422,7 @@ function createUtilMethodRule( methods, message, options ) {
421
422
  methods = Array.isArray( methods ) ? methods : [ methods ];
422
423
 
423
424
  let description = 'Disallows the ' + methods.map( jQueryGlobalLink ).join( '/' ) + ' ' +
424
- ( methods.length > 1 ? 'utilies' : 'utility' ) + '.';
425
+ ( methods.length > 1 ? 'utilies' : 'utility' ) + '.';
425
426
 
426
427
  description += messageSuffix( message );
427
428
 
@@ -448,7 +449,7 @@ function createUtilMethodRule( methods, message, options ) {
448
449
  }
449
450
 
450
451
  /**
451
- * Create a rule for util methods
452
+ * Create a rule for util properties
452
453
  *
453
454
  * @param {string} property Property name
454
455
  * @param {string|Function} [message] Message to report. See createCollectionMethodRule.
@@ -499,7 +500,7 @@ function createCollectionOrUtilMethodRule( methods, message, options ) {
499
500
  methods = Array.isArray( methods ) ? methods : [ methods ];
500
501
 
501
502
  let description = 'Disallows the ' + methods.map( jQueryCollectionLink ).join( '/' ) + ' ' +
502
- ( methods.length > 1 ? 'methods' : 'method' );
503
+ ( methods.length > 1 ? 'methods' : 'method' );
503
504
 
504
505
  description += ' and ' + methods.map( jQueryGlobalLink ).join( '/' ) + ' ' +
505
506
  ( methods.length > 1 ? 'utilies' : 'utility' ) + '.';
@@ -526,6 +527,47 @@ function createCollectionOrUtilMethodRule( methods, message, options ) {
526
527
  } ), description, options.fixable, options.deprecated );
527
528
  }
528
529
 
530
+ /**
531
+ * Create a rule for a method on any object
532
+ *
533
+ * @param {string|string[]} methods Method or list of method names
534
+ * @param {string|Function} message Message to report. See createCollectionMethodRule.
535
+ * @param {Function} linkGenerator Function to generate a markdown link
536
+ * @param {Object} [options] Options. See createCollectionMethodRule.
537
+ * for a given function name.
538
+ * @return {Object} Rule
539
+ */
540
+ function createUniversalMethodRule( methods, message, linkGenerator, options ) {
541
+ options = options || {};
542
+
543
+ options.mode = 'util';
544
+
545
+ methods = Array.isArray( methods ) ? methods : [ methods ];
546
+
547
+ let description = 'Disallows the ' + methods.map( linkGenerator ).join( '/' ) + ' ' +
548
+ ( methods.length > 1 ? 'methods' : 'method' ) + '.';
549
+
550
+ description += messageSuffix( message );
551
+
552
+ return createRule( ( context ) => ( {
553
+ 'CallExpression:exit': ( node ) => {
554
+ if ( node.callee.type !== 'MemberExpression' ) {
555
+ return;
556
+ }
557
+ const name = node.callee.property.name;
558
+ if ( !methods.includes( name ) ) {
559
+ return;
560
+ }
561
+
562
+ context.report( {
563
+ node,
564
+ message: messageToPlainString( message, node, name, options ),
565
+ fix: options.fix && options.fix.bind( this, node, context )
566
+ } );
567
+ }
568
+ } ), description, options.fixable, options.deprecated );
569
+ }
570
+
529
571
  function eventShorthandFixer( node, context, fixer ) {
530
572
  const name = node.callee.property.name;
531
573
  if ( node.callee.parent.arguments.length ) {
@@ -579,6 +621,7 @@ module.exports = {
579
621
  createUtilMethodRule,
580
622
  createUtilPropertyRule,
581
623
  createCollectionOrUtilMethodRule,
624
+ createUniversalMethodRule,
582
625
  eventShorthandFixer,
583
626
  jQueryCollectionLink,
584
627
  jQueryGlobalLink,