Skip to content

Commit fc4e29a

Browse files
authored
consistent-compound-words: Improve performance (#3185)
1 parent 0763b75 commit fc4e29a

1 file changed

Lines changed: 22 additions & 10 deletions

File tree

rules/consistent-compound-words.js

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
96111
const 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

Comments
 (0)