11'use strict' ; 
22
3+ const  CallExpression  =  ( fnName )  =>  `CallExpression[callee.name=${ fnName }  ]` ; 
4+ 
35function  checkProperties ( context ,  node )  { 
46  if  ( 
57    node . type  ===  'CallExpression'  && 
@@ -64,8 +66,10 @@ function checkPropertyDescriptor(context, node) {
6466} 
6567
6668function  createUnsafeStringMethodReport ( context ,  name ,  lookedUpProperty )  { 
69+   const  lastDotPosition  =  '$String.prototype.' . length ; 
70+   const  unsafePrimordialName  =  `StringPrototype${ name . charAt ( lastDotPosition ) . toUpperCase ( ) } ${ name . slice ( lastDotPosition  +  1 ,  - 1 ) }  ` ; 
6771  return  { 
68-     [ ` ${ CallExpression } [expression.callee.name= ${ JSON . stringify ( name ) } ]` ] ( node )  { 
72+     [ CallExpression ( unsafePrimordialName ) ] ( node )  { 
6973      context . report ( { 
7074        node, 
7175        message : `${ name }   looks up the ${ lookedUpProperty }   property on the first argument` , 
@@ -74,31 +78,46 @@ function createUnsafeStringMethodReport(context, name, lookedUpProperty) {
7478  } ; 
7579} 
7680
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+ 
7899module . exports  =  { 
79100  meta : {  hasSuggestions : true  } , 
80101  create ( context )  { 
81102    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 )  { 
86105          case  'ObjectDefineProperties' :
87-             checkProperties ( context ,  node . expression . arguments [ 1 ] ) ; 
106+             checkProperties ( context ,  node . arguments [ 1 ] ) ; 
88107            break ; 
89108          case  'ReflectDefineProperty' :
90109          case  'ObjectDefineProperty' :
91-             checkPropertyDescriptor ( context ,  node . expression . arguments [ 2 ] ) ; 
110+             checkPropertyDescriptor ( context ,  node . arguments [ 2 ] ) ; 
92111            break ; 
93112          default :
94113            throw  new  Error ( 'Unreachable' ) ; 
95114        } 
96115      } , 
97116
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 ] ) ; 
100119      } , 
101-       [ ` ${ CallExpression } [expression.callee.name=" RegExpPrototypeTest"]` ] ( node )  { 
120+       [ CallExpression ( ' RegExpPrototypeTest' ) ] ( node )  { 
102121        context . report ( { 
103122          node, 
104123          message : '%RegExp.prototype.test% looks up the "exec" property of `this` value' , 
@@ -116,18 +135,18 @@ module.exports = {
116135          } ] , 
117136        } ) ; 
118137      } , 
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 )  { 
120139        context . report ( { 
121140          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' , 
123142        } ) ; 
124143      } , 
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' ) , 
131150
132151      'NewExpression[callee.name="Proxy"][arguments.1.type="ObjectExpression"]' ( node )  { 
133152        for  ( const  {  key,  value }  of  node . arguments [ 1 ] . properties )  { 
@@ -146,15 +165,15 @@ module.exports = {
146165        } ) ; 
147166      } , 
148167
149-       [ ` ${ CallExpression } [expression.callee.name= PromisePrototypeCatch]` ] ( node )  { 
168+       [ CallExpression ( ' PromisePrototypeCatch' ) ] ( node )  { 
150169        context . report ( { 
151170          node, 
152171          message : '%Promise.prototype.catch% look up the `then` property of '  + 
153172                   'the `this` argument, use PromisePrototypeThen instead' , 
154173        } ) ; 
155174      } , 
156175
157-       [ ` ${ CallExpression } [expression.callee.name= PromisePrototypeFinally]` ] ( node )  { 
176+       [ CallExpression ( ' PromisePrototypeFinally' ) ] ( node )  { 
158177        context . report ( { 
159178          node, 
160179          message : '%Promise.prototype.finally% look up the `then` property of '  + 
@@ -163,10 +182,10 @@ module.exports = {
163182        } ) ; 
164183      } , 
165184
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 )  { 
167186        context . report ( { 
168187          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 }  ` , 
170189        } ) ; 
171190      } , 
172191    } ; 
0 commit comments