Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5a347a5

Browse files
authored
fix(eslint-plugin): [prefer-includes] escape special characters (typescript-eslint#7161)
fix: escape special characters typescript-eslint#7145
1 parent 6edaa04 commit 5a347a5

File tree

2 files changed

+54
-6
lines changed

2 files changed

+54
-6
lines changed

packages/eslint-plugin/src/rules/prefer-includes.ts

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,27 @@ export default createRule({
124124
);
125125
}
126126

127+
function escapeString(str: string): string {
128+
const EscapeMap = {
129+
'\0': '\\0',
130+
"'": "\\'",
131+
'\\': '\\\\',
132+
'\n': '\\n',
133+
'\r': '\\r',
134+
'\v': '\\v',
135+
'\t': '\\t',
136+
'\f': '\\f',
137+
// "\b" cause unexpected replacements
138+
// '\b': '\\b',
139+
};
140+
const replaceRegex = new RegExp(Object.values(EscapeMap).join('|'), 'g');
141+
142+
return str.replace(
143+
replaceRegex,
144+
char => EscapeMap[char as keyof typeof EscapeMap],
145+
);
146+
}
147+
127148
function checkArrayIndexOf(
128149
node: TSESTree.MemberExpression,
129150
allowFixing: boolean,
@@ -202,12 +223,11 @@ export default createRule({
202223
},
203224

204225
// /bar/.test(foo)
205-
'CallExpression > MemberExpression.callee[property.name="test"][computed=false]'(
206-
node: TSESTree.MemberExpression,
226+
'CallExpression[arguments.length=1] > MemberExpression.callee[property.name="test"][computed=false]'(
227+
node: TSESTree.MemberExpression & { parent: TSESTree.CallExpression },
207228
): void {
208-
const callNode = node.parent as TSESTree.CallExpression;
209-
const text =
210-
callNode.arguments.length === 1 ? parseRegExp(node.object) : null;
229+
const callNode = node.parent;
230+
const text = parseRegExp(node.object);
211231
if (text == null) {
212232
return;
213233
}
@@ -237,13 +257,14 @@ export default createRule({
237257
argNode.type !== AST_NODE_TYPES.CallExpression;
238258

239259
yield fixer.removeRange([callNode.range[0], argNode.range[0]]);
260+
yield fixer.removeRange([argNode.range[1], callNode.range[1]]);
240261
if (needsParen) {
241262
yield fixer.insertTextBefore(argNode, '(');
242263
yield fixer.insertTextAfter(argNode, ')');
243264
}
244265
yield fixer.insertTextAfter(
245266
argNode,
246-
`${node.optional ? '?.' : '.'}includes('${text}'`,
267+
`${node.optional ? '?.' : '.'}includes('${escapeString(text)}')`,
247268
);
248269
},
249270
});

packages/eslint-plugin/tests/rules/prefer-includes.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,33 @@ ruleTester.run('prefer-includes', rule, {
234234
`,
235235
errors: [{ messageId: 'preferStringIncludes' }],
236236
},
237+
// test SequenceExpression
238+
{
239+
code: `
240+
function f(a: string): void {
241+
/bar/.test((1 + 1, a));
242+
}
243+
`,
244+
output: `
245+
function f(a: string): void {
246+
(1 + 1, a).includes('bar');
247+
}
248+
`,
249+
errors: [{ messageId: 'preferStringIncludes' }],
250+
},
251+
{
252+
code: `
253+
function f(a: string): void {
254+
/\\0'\\\\\\n\\r\\v\\t\\f/.test(a);
255+
}
256+
`,
257+
output: `
258+
function f(a: string): void {
259+
a.includes('\\0\\'\\\\\\n\\r\\v\\t\\f');
260+
}
261+
`,
262+
errors: [{ messageId: 'preferStringIncludes' }],
263+
},
237264
{
238265
code: `
239266
const pattern = new RegExp('bar');

0 commit comments

Comments
 (0)