1
1
'use strict' ;
2
2
3
+ const CallExpression = ( fnName ) => `CallExpression[callee.name=${ fnName } ]` ;
4
+
3
5
function checkProperties ( context , node ) {
4
6
if (
5
7
node . type === 'CallExpression' &&
@@ -64,8 +66,10 @@ function checkPropertyDescriptor(context, node) {
64
66
}
65
67
66
68
function createUnsafeStringMethodReport ( context , name , lookedUpProperty ) {
69
+ const lastDotPosition = '$String.prototype.' . length ;
70
+ const unsafePrimordialName = `StringPrototype${ name . charAt ( lastDotPosition ) . toUpperCase ( ) } ${ name . slice ( lastDotPosition + 1 , - 1 ) } ` ;
67
71
return {
68
- [ ` ${ CallExpression } [expression.callee.name= ${ JSON . stringify ( name ) } ]` ] ( node ) {
72
+ [ CallExpression ( unsafePrimordialName ) ] ( node ) {
69
73
context . report ( {
70
74
node,
71
75
message : `${ name } looks up the ${ lookedUpProperty } property on the first argument` ,
@@ -74,31 +78,46 @@ function createUnsafeStringMethodReport(context, name, lookedUpProperty) {
74
78
} ;
75
79
}
76
80
77
- const CallExpression = 'ExpressionStatement[expression.type="CallExpression"]' ;
81
+ function createUnsafeStringMethodOnRegexReport ( context , name , lookedUpProperty ) {
82
+ const dotPosition = 'Symbol.' . length ;
83
+ const safePrimordialName = `RegExpPrototypeSymbol${ lookedUpProperty . charAt ( dotPosition ) . toUpperCase ( ) } ${ lookedUpProperty . slice ( dotPosition + 1 ) } ` ;
84
+ const lastDotPosition = '$String.prototype.' . length ;
85
+ const unsafePrimordialName = `StringPrototype${ name . charAt ( lastDotPosition ) . toUpperCase ( ) } ${ name . slice ( lastDotPosition + 1 , - 1 ) } ` ;
86
+ return {
87
+ [ [
88
+ `${ CallExpression ( unsafePrimordialName ) } [arguments.1.type=Literal][arguments.1.regex]` ,
89
+ `${ CallExpression ( unsafePrimordialName ) } [arguments.1.type=NewExpression][arguments.1.callee.name=RegExp]` ,
90
+ ] . join ( ',' ) ] ( node ) {
91
+ context . report ( {
92
+ node,
93
+ message : `${ name } looks up the ${ lookedUpProperty } property of the passed regex, use ${ safePrimordialName } directly` ,
94
+ } ) ;
95
+ }
96
+ } ;
97
+ }
98
+
78
99
module . exports = {
79
100
meta : { hasSuggestions : true } ,
80
101
create ( context ) {
81
102
return {
82
- [ `${ CallExpression } [expression.callee.name=${ / ^ ( O b j e c t | R e f l e c t ) D e f i n e P r o p e r t ( i e s | y ) $ / } ]` ] (
83
- node
84
- ) {
85
- switch ( node . expression . callee . name ) {
103
+ [ CallExpression ( / ^ ( O b j e c t | R e f l e c t ) D e f i n e P r o p e r t ( i e s | y ) $ / ) ] ( node ) {
104
+ switch ( node . callee . name ) {
86
105
case 'ObjectDefineProperties' :
87
- checkProperties ( context , node . expression . arguments [ 1 ] ) ;
106
+ checkProperties ( context , node . arguments [ 1 ] ) ;
88
107
break ;
89
108
case 'ReflectDefineProperty' :
90
109
case 'ObjectDefineProperty' :
91
- checkPropertyDescriptor ( context , node . expression . arguments [ 2 ] ) ;
110
+ checkPropertyDescriptor ( context , node . arguments [ 2 ] ) ;
92
111
break ;
93
112
default :
94
113
throw new Error ( 'Unreachable' ) ;
95
114
}
96
115
} ,
97
116
98
- [ `${ CallExpression } [expression.callee.name="ObjectCreate"][expression. arguments.length=2]` ] ( node ) {
99
- checkProperties ( context , node . expression . arguments [ 1 ] ) ;
117
+ [ `${ CallExpression ( 'ObjectCreate' ) } [ arguments.length=2]` ] ( node ) {
118
+ checkProperties ( context , node . arguments [ 1 ] ) ;
100
119
} ,
101
- [ ` ${ CallExpression } [expression.callee.name=" RegExpPrototypeTest"]` ] ( node ) {
120
+ [ CallExpression ( ' RegExpPrototypeTest' ) ] ( node ) {
102
121
context . report ( {
103
122
node,
104
123
message : '%RegExp.prototype.test% looks up the "exec" property of `this` value' ,
@@ -116,18 +135,18 @@ module.exports = {
116
135
} ] ,
117
136
} ) ;
118
137
} ,
119
- [ ` ${ CallExpression } [expression.callee.name= ${ / ^ R e g E x p P r o t o t y p e S y m b o l ( M a t c h | M a t c h A l l | S e a r c h ) $ / } ]` ] ( node ) {
138
+ [ CallExpression ( / ^ R e g E x p P r o t o t y p e S y m b o l ( M a t c h | M a t c h A l l | S e a r c h ) $ / ) ] ( node ) {
120
139
context . report ( {
121
140
node,
122
- message : node . expression . callee . name + ' looks up the "exec" property of `this` value' ,
141
+ message : node . callee . name + ' looks up the "exec" property of `this` value' ,
123
142
} ) ;
124
143
} ,
125
- ...createUnsafeStringMethodReport ( context , 'StringPrototypeMatch ' , 'Symbol.match' ) ,
126
- ...createUnsafeStringMethodReport ( context , 'StringPrototypeMatchAll ' , 'Symbol.matchAll' ) ,
127
- ...createUnsafeStringMethodReport ( context , 'StringPrototypeReplace ' , 'Symbol.replace' ) ,
128
- ...createUnsafeStringMethodReport ( context , 'StringPrototypeReplaceAll ' , 'Symbol.replace' ) ,
129
- ...createUnsafeStringMethodReport ( context , 'StringPrototypeSearch ' , 'Symbol.search' ) ,
130
- ...createUnsafeStringMethodReport ( context , 'StringPrototypeSplit ' , 'Symbol.split' ) ,
144
+ ...createUnsafeStringMethodReport ( context , '%String.prototype.match% ' , 'Symbol.match' ) ,
145
+ ...createUnsafeStringMethodReport ( context , '%String.prototype.matchAll% ' , 'Symbol.matchAll' ) ,
146
+ ...createUnsafeStringMethodOnRegexReport ( context , '%String.prototype.replace% ' , 'Symbol.replace' ) ,
147
+ ...createUnsafeStringMethodOnRegexReport ( context , '%String.prototype.replaceAll% ' , 'Symbol.replace' ) ,
148
+ ...createUnsafeStringMethodReport ( context , '%String.prototype.search% ' , 'Symbol.search' ) ,
149
+ ...createUnsafeStringMethodOnRegexReport ( context , '%String.prototype.split% ' , 'Symbol.split' ) ,
131
150
132
151
'NewExpression[callee.name="Proxy"][arguments.1.type="ObjectExpression"]' ( node ) {
133
152
for ( const { key, value } of node . arguments [ 1 ] . properties ) {
@@ -146,15 +165,15 @@ module.exports = {
146
165
} ) ;
147
166
} ,
148
167
149
- [ ` ${ CallExpression } [expression.callee.name= PromisePrototypeCatch]` ] ( node ) {
168
+ [ CallExpression ( ' PromisePrototypeCatch' ) ] ( node ) {
150
169
context . report ( {
151
170
node,
152
171
message : '%Promise.prototype.catch% look up the `then` property of ' +
153
172
'the `this` argument, use PromisePrototypeThen instead' ,
154
173
} ) ;
155
174
} ,
156
175
157
- [ ` ${ CallExpression } [expression.callee.name= PromisePrototypeFinally]` ] ( node ) {
176
+ [ CallExpression ( ' PromisePrototypeFinally' ) ] ( node ) {
158
177
context . report ( {
159
178
node,
160
179
message : '%Promise.prototype.finally% look up the `then` property of ' +
@@ -163,10 +182,10 @@ module.exports = {
163
182
} ) ;
164
183
} ,
165
184
166
- [ ` ${ CallExpression } [expression.callee.name= ${ / ^ P r o m i s e ( A l l ( S e t t l e d ) ? | A n y | R a c e ) / } ]` ] ( node ) {
185
+ [ CallExpression ( / ^ P r o m i s e ( A l l ( S e t t l e d ) ? | A n y | R a c e ) / ) ] ( node ) {
167
186
context . report ( {
168
187
node,
169
- message : `Use Safe${ node . expression . callee . name } instead of ${ node . expression . callee . name } ` ,
188
+ message : `Use Safe${ node . callee . name } instead of ${ node . callee . name } ` ,
170
189
} ) ;
171
190
} ,
172
191
} ;
0 commit comments