eslint-plugin-no-jquery 3.0.1 → 3.0.2
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/package.json +1 -1
- package/src/rules/no-append-html.js +12 -3
- package/src/rules/no-parse-html-literal.js +3 -26
- package/src/rules/no-sizzle.js +1 -14
- package/src/utils.js +33 -1
package/package.json
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const utils = require( '../utils.js' );
|
|
4
|
-
|
|
4
|
+
// htmlStrings or jQuery collections
|
|
5
|
+
const htmlOrCollectionMethods = [ 'append', 'prepend', 'before', 'after', 'replaceWith' ];
|
|
6
|
+
// htmlStrings, selectors or jQuery collections
|
|
7
|
+
const htmlOrSelectorOrCollectionMethods = [ 'add', 'appendTo', 'prependTo', 'insertBefore', 'insertAfter' ];
|
|
8
|
+
const allMethods = htmlOrCollectionMethods.concat( htmlOrSelectorOrCollectionMethods );
|
|
5
9
|
|
|
6
10
|
function alljQueryOrEmpty( context, node ) {
|
|
7
11
|
if ( node.type === 'ConditionalExpression' ) {
|
|
@@ -22,7 +26,7 @@ module.exports = {
|
|
|
22
26
|
meta: {
|
|
23
27
|
type: 'suggestion',
|
|
24
28
|
docs: {
|
|
25
|
-
description: 'Disallows using ' +
|
|
29
|
+
description: 'Disallows using ' + allMethods.map( utils.jQueryCollectionLink ).join( '/' ) +
|
|
26
30
|
' to inject HTML, in order to prevent possible XSS bugs.'
|
|
27
31
|
},
|
|
28
32
|
schema: []
|
|
@@ -32,13 +36,18 @@ module.exports = {
|
|
|
32
36
|
'CallExpression:exit': ( node ) => {
|
|
33
37
|
if ( !(
|
|
34
38
|
node.callee.type === 'MemberExpression' &&
|
|
35
|
-
|
|
39
|
+
allMethods.includes( node.callee.property.name )
|
|
36
40
|
) ) {
|
|
37
41
|
return;
|
|
38
42
|
}
|
|
39
43
|
if ( node.arguments.every( ( arg ) => alljQueryOrEmpty( context, arg ) ) ) {
|
|
40
44
|
return;
|
|
41
45
|
}
|
|
46
|
+
if ( htmlOrSelectorOrCollectionMethods.includes( node.callee.property.name ) ) {
|
|
47
|
+
if ( node.arguments.every( ( arg ) => !utils.isHtmlString( arg ) ) ) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
42
51
|
|
|
43
52
|
if ( utils.isjQuery( context, node.callee ) ) {
|
|
44
53
|
context.report( {
|
|
@@ -2,33 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
const utils = require( '../utils.js' );
|
|
4
4
|
|
|
5
|
-
// HTML regex (modified from jQuery)
|
|
6
|
-
const rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*)$/;
|
|
7
5
|
// Single tag regex (from jQuery)
|
|
8
6
|
const rsingleTag = /^<([a-z][^/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;
|
|
9
7
|
const rsingleTagMinimal = /^<([a-z][^/\0>:\x20\t\r\n\f]*)>$/i;
|
|
10
8
|
const rsingleTagSelfClosing = /^<([a-z][^/\0>:\x20\t\r\n\f]*)\/>$/i;
|
|
11
9
|
|
|
12
|
-
function allLiteral( node ) {
|
|
13
|
-
if ( node.type === 'BinaryExpression' ) {
|
|
14
|
-
return allLiteral( node.left ) && allLiteral( node.right );
|
|
15
|
-
} else {
|
|
16
|
-
return node.type === 'Literal';
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function joinLiterals( node ) {
|
|
21
|
-
if ( node.type === 'BinaryExpression' ) {
|
|
22
|
-
return joinLiterals( node.left ) + joinLiterals( node.right );
|
|
23
|
-
}
|
|
24
|
-
/* istanbul ignore else */
|
|
25
|
-
if ( node.type === 'Literal' ) {
|
|
26
|
-
return node.value;
|
|
27
|
-
}
|
|
28
|
-
/* istanbul ignore next */
|
|
29
|
-
throw new Error( 'Non-literal node passed to joinLiteral' );
|
|
30
|
-
}
|
|
31
|
-
|
|
32
10
|
module.exports = {
|
|
33
11
|
meta: {
|
|
34
12
|
type: 'suggestion',
|
|
@@ -94,11 +72,10 @@ module.exports = {
|
|
|
94
72
|
let expectedTag;
|
|
95
73
|
const arg = node.arguments[ 0 ];
|
|
96
74
|
if ( allowSingle ) {
|
|
97
|
-
|
|
98
|
-
if ( !( typeof value === 'string' && value ) || !rquickExpr.exec( value ) ) {
|
|
99
|
-
// Empty or non-string, or non-HTML
|
|
75
|
+
if ( !utils.isHtmlString( arg ) ) {
|
|
100
76
|
return;
|
|
101
77
|
}
|
|
78
|
+
const value = utils.joinLiterals( arg );
|
|
102
79
|
let match;
|
|
103
80
|
if ( ( match = rsingleTag.exec( value ) ) ) {
|
|
104
81
|
// Single tag
|
|
@@ -122,7 +99,7 @@ module.exports = {
|
|
|
122
99
|
return;
|
|
123
100
|
}
|
|
124
101
|
}
|
|
125
|
-
} else if ( !( arg && allLiteral( arg ) ) ) {
|
|
102
|
+
} else if ( !( arg && utils.allLiteral( arg ) ) ) {
|
|
126
103
|
// Non literals passed to $.parseHTML
|
|
127
104
|
return;
|
|
128
105
|
}
|
package/src/rules/no-sizzle.js
CHANGED
|
@@ -2,19 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const utils = require( '../utils.js' );
|
|
4
4
|
|
|
5
|
-
function collectLiterals( node ) {
|
|
6
|
-
if ( node.type === 'BinaryExpression' ) {
|
|
7
|
-
return collectLiterals( node.left ) + collectLiterals( node.right );
|
|
8
|
-
} else if ( node.type === 'Literal' ) {
|
|
9
|
-
return node.value;
|
|
10
|
-
} else if ( node.type === 'Identifier' ) {
|
|
11
|
-
// Dummy value for regex matching
|
|
12
|
-
return 'A0';
|
|
13
|
-
} else {
|
|
14
|
-
return '';
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
5
|
module.exports = {
|
|
19
6
|
meta: {
|
|
20
7
|
type: 'suggestion',
|
|
@@ -79,7 +66,7 @@ module.exports = {
|
|
|
79
66
|
context.options[ 0 ].allowPositional;
|
|
80
67
|
const allowOther = context.options[ 0 ] &&
|
|
81
68
|
context.options[ 0 ].allowOther;
|
|
82
|
-
const value =
|
|
69
|
+
const value = utils.joinLiterals( node.arguments[ 0 ] );
|
|
83
70
|
|
|
84
71
|
if ( !allowPositional && forbiddenPositional.test( value ) ) {
|
|
85
72
|
context.report( {
|
package/src/utils.js
CHANGED
|
@@ -541,6 +541,35 @@ function eventShorthandFixer( node, context, fixer ) {
|
|
|
541
541
|
}
|
|
542
542
|
}
|
|
543
543
|
|
|
544
|
+
function allLiteral( node ) {
|
|
545
|
+
if ( node.type === 'BinaryExpression' ) {
|
|
546
|
+
return allLiteral( node.left ) && allLiteral( node.right );
|
|
547
|
+
} else {
|
|
548
|
+
return node.type === 'Literal';
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
function joinLiterals( node ) {
|
|
553
|
+
if ( node.type === 'BinaryExpression' ) {
|
|
554
|
+
return joinLiterals( node.left ) + joinLiterals( node.right );
|
|
555
|
+
} else if ( node.type === 'Literal' ) {
|
|
556
|
+
return node.value;
|
|
557
|
+
} else if ( node.type === 'Identifier' ) {
|
|
558
|
+
// Dummy value for regex matching
|
|
559
|
+
return 'A0';
|
|
560
|
+
} else {
|
|
561
|
+
return '';
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// HTML regex (modified from jQuery)
|
|
566
|
+
const rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*)$/;
|
|
567
|
+
|
|
568
|
+
function isHtmlString( arg ) {
|
|
569
|
+
const value = arg && allLiteral( arg ) && joinLiterals( arg );
|
|
570
|
+
return typeof value === 'string' && value && rquickExpr.exec( value );
|
|
571
|
+
}
|
|
572
|
+
|
|
544
573
|
module.exports = {
|
|
545
574
|
isjQuery,
|
|
546
575
|
isjQueryConstructor,
|
|
@@ -552,5 +581,8 @@ module.exports = {
|
|
|
552
581
|
createCollectionOrUtilMethodRule,
|
|
553
582
|
eventShorthandFixer,
|
|
554
583
|
jQueryCollectionLink,
|
|
555
|
-
jQueryGlobalLink
|
|
584
|
+
jQueryGlobalLink,
|
|
585
|
+
allLiteral,
|
|
586
|
+
joinLiterals,
|
|
587
|
+
isHtmlString
|
|
556
588
|
};
|