@@ -93,6 +93,21 @@ const escapeRegExp = string => {
9393 return result ;
9494} ;
9595
96+ // Combine every discouraged name into a single regular expression so each identifier is scanned in one pass.
97+ // Without this, the rule would compile and run one regular expression per replacement for every identifier in the file.
98+ const boundary = String . raw `(?=$|[\d_$]|\p{Uppercase_Letter})` ;
99+ const buildReplacementRegExp = replacements => {
100+ // The lowercase-first form only matches at the start of the name; the uppercase-first form matches a compound segment anywhere.
101+ const lowerFirstForms = [ ] ;
102+ const upperFirstForms = [ ] ;
103+ for ( const discouragedName of replacements . keys ( ) ) {
104+ lowerFirstForms . push ( escapeRegExp ( discouragedName ) ) ;
105+ upperFirstForms . push ( escapeRegExp ( upperFirst ( discouragedName ) ) ) ;
106+ }
107+
108+ return new RegExp ( `(?:^(?:${ lowerFirstForms . join ( '|' ) } )|(?:${ upperFirstForms . join ( '|' ) } ))${ boundary } ` , 'gv' ) ;
109+ } ;
110+
96111const prepareOptions = ( {
97112 checkProperties = false ,
98113 checkVariables = true ,
@@ -110,6 +125,8 @@ const prepareOptions = ({
110125 ? { ...defaultReplacements , ...replacements }
111126 : replacements ;
112127
128+ const replacementsMap = new Map ( Object . entries ( mergedReplacements ) . filter ( ( [ , replacement ] ) => replacement !== false ) ) ;
129+
113130 return {
114131 checkProperties,
115132 checkVariables,
@@ -118,7 +135,8 @@ const prepareOptions = ({
118135 checkShorthandImports,
119136 checkShorthandProperties,
120137
121- replacements : new Map ( Object . entries ( mergedReplacements ) . filter ( ( [ , replacement ] ) => replacement !== false ) ) ,
138+ replacements : replacementsMap ,
139+ replacementRegExp : replacementsMap . size > 0 ? buildReplacementRegExp ( replacementsMap ) : undefined ,
122140 allowList : new Set ( Object . keys ( allowList ) ) ,
123141 } ;
124142} ;
@@ -132,18 +150,12 @@ const getReplacementForPart = (part, replacements) => {
132150 return isUpperFirst ( part ) ? upperFirst ( replacement ) : lowerFirst ( replacement ) ;
133151} ;
134152
135- const getNameReplacement = ( name , { replacements, allowList} ) => {
136- if ( isUpperCase ( name ) || allowList . has ( name ) ) {
153+ const getNameReplacement = ( name , { replacementRegExp , replacements, allowList} ) => {
154+ if ( ! replacementRegExp || isUpperCase ( name ) || allowList . has ( name ) ) {
137155 return ;
138156 }
139157
140- const boundary = String . raw `(?=$|[\d_$]|\p{Uppercase_Letter})` ;
141- let replacement = name ;
142- for ( const discouragedName of replacements . keys ( ) ) {
143- const pattern = new RegExp ( `^${ escapeRegExp ( discouragedName ) } ${ boundary } |${ escapeRegExp ( upperFirst ( discouragedName ) ) } ${ boundary } ` , 'gv' ) ;
144- replacement = replacement . replaceAll ( pattern , part => getReplacementForPart ( part , replacements ) ) ;
145- }
146-
158+ const replacement = name . replaceAll ( replacementRegExp , part => getReplacementForPart ( part , replacements ) ) ;
147159 if ( replacement === name ) {
148160 return ;
149161 }
0 commit comments