Skip to content

Commit d986427

Browse files
authored
escape-case: Fix missing characters (#678)
1 parent 352e90c commit d986427

File tree

2 files changed

+88
-48
lines changed

2 files changed

+88
-48
lines changed

rules/escape-case.js

Lines changed: 28 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,67 +2,47 @@
22
const getDocumentationUrl = require('./utils/get-documentation-url');
33
const replaceTemplateElement = require('./utils/replace-template-element');
44

5-
const escapeWithLowercase = /(?<=(?:^|[^\\])(?:\\\\)*\\)(?<data>x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|u{[\dA-Fa-f]+})/;
6-
const escapePatternWithLowercase = /(?<=(?:^|[^\\])(?:\\\\)*\\)(?<data>x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|u{[\dA-Fa-f]+}|c[a-z])/;
5+
const escapeWithLowercase = /(?<=(?:^|[^\\])(?:\\\\)*\\)(?<data>x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|u{[\dA-Fa-f]+})/g;
6+
const escapePatternWithLowercase = /(?<=(?:^|[^\\])(?:\\\\)*\\)(?<data>x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|u{[\dA-Fa-f]+}|c[a-z])/g;
77
const message = 'Use uppercase characters for the value of the escape sequence.';
88

9-
const fix = (value, regexp) => {
10-
const results = regexp.exec(value);
11-
12-
if (results) {
13-
const {data} = results.groups;
14-
const fixedEscape = data.slice(0, 1) + data.slice(1).toUpperCase();
15-
return (
16-
value.slice(0, results.index) +
17-
fixedEscape +
18-
value.slice(results.index + data.length)
19-
);
20-
}
21-
22-
return value;
23-
};
24-
259
const create = context => {
10+
const check = ({node, original, regex = escapeWithLowercase, fix}) => {
11+
const fixed = original.replace(regex, data => data.slice(0, 1) + data.slice(1).toUpperCase());
12+
13+
if (fixed !== original) {
14+
context.report({
15+
node,
16+
message,
17+
fix: fixer => fix ? fix(fixer, fixed) : fixer.replaceText(node, fixed)
18+
});
19+
}
20+
};
21+
2622
return {
2723
Literal(node) {
2824
if (typeof node.value !== 'string') {
2925
return;
3026
}
3127

32-
const original = node.raw;
33-
const fixed = fix(original, escapeWithLowercase);
34-
35-
if (fixed !== original) {
36-
context.report({
37-
node,
38-
message,
39-
fix: fixer => fixer.replaceText(node, fixed)
40-
});
41-
}
28+
check({
29+
node,
30+
original: node.raw
31+
});
4232
},
4333
'Literal[regex]'(node) {
44-
const original = node.raw;
45-
const fixed = fix(original, escapePatternWithLowercase);
46-
47-
if (fixed !== original) {
48-
context.report({
49-
node,
50-
message,
51-
fix: fixer => fixer.replaceText(node, fixed)
52-
});
53-
}
34+
check({
35+
node,
36+
original: node.raw,
37+
regex: escapePatternWithLowercase
38+
});
5439
},
5540
TemplateElement(node) {
56-
const original = node.value.raw;
57-
const fixed = fix(original, escapePatternWithLowercase);
58-
59-
if (fixed !== original) {
60-
context.report({
61-
node,
62-
message,
63-
fix: fixer => replaceTemplateElement(fixer, node, fixed)
64-
});
65-
}
41+
check({
42+
node,
43+
original: node.value.raw,
44+
fix: (fixer, fixed) => replaceTemplateElement(fixer, node, fixed)
45+
});
6646
}
6747
};
6848
};

test/escape-case.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ ruleTester.run('escape-case', rule, {
3131
'const foo = "foo\\\\ubarbaz";',
3232
'const foo = "foo\\\\\\\\xbar";',
3333
'const foo = "foo\\\\\\\\ubarbaz";',
34+
'const foo = "\\ca";',
3435

3536
// TemplateLiteral
3637
'const foo = `\\xA9`;',
@@ -46,6 +47,7 @@ ruleTester.run('escape-case', rule, {
4647
'const foo = `foo\\\\ubarbaz`;',
4748
'const foo = `foo\\\\\\\\xbar`;',
4849
'const foo = `foo\\\\\\\\ubarbaz`;',
50+
'const foo = `\\ca`;',
4951

5052
// Literal regex
5153
'const foo = /foo\\xA9/',
@@ -63,6 +65,7 @@ ruleTester.run('escape-case', rule, {
6365
'const foo = new RegExp("/\\xA9")',
6466
'const foo = new RegExp("/\\uD834/")',
6567
'const foo = new RegExp("/\\u{1D306}/", "u")',
68+
'const foo = new RegExp("/\\ca/")',
6669
'const foo = new RegExp("/\\cA/")'
6770
],
6871
invalid: [
@@ -72,6 +75,7 @@ ruleTester.run('escape-case', rule, {
7275
errors,
7376
output: 'const foo = "\\xA9";'
7477
},
78+
7579
// Mixed cases
7680
{
7781
code: 'const foo = "\\xAa";',
@@ -88,6 +92,14 @@ ruleTester.run('escape-case', rule, {
8892
errors,
8993
output: 'const foo = "\\u{AAAA}";'
9094
},
95+
96+
// Many
97+
{
98+
code: 'const foo = "\\xAab\\xaab\\xAAb\\uAaAab\\uaaaab\\uAAAAb\\u{AaAa}b\\u{aaaa}b\\u{AAAA}";',
99+
errors,
100+
output: 'const foo = "\\xAAb\\xAAb\\xAAb\\uAAAAb\\uAAAAb\\uAAAAb\\u{AAAA}b\\u{AAAA}b\\u{AAAA}";'
101+
},
102+
91103
{
92104
code: 'const foo = "\\ud834";',
93105
errors,
@@ -186,6 +198,30 @@ ruleTester.run('escape-case', rule, {
186198
output: 'const foo = `foo \\\\\\uD834`;'
187199
},
188200

201+
// Mixed cases
202+
{
203+
code: 'const foo = `\\xAa`;',
204+
errors,
205+
output: 'const foo = `\\xAA`;'
206+
},
207+
{
208+
code: 'const foo = `\\uAaAa`;',
209+
errors,
210+
output: 'const foo = `\\uAAAA`;'
211+
},
212+
{
213+
code: 'const foo = `\\u{AaAa}`;',
214+
errors,
215+
output: 'const foo = `\\u{AAAA}`;'
216+
},
217+
218+
// Many
219+
{
220+
code: 'const foo = `\\xAab\\xaab\\xAA${foo}\\uAaAab\\uaaaab\\uAAAAb\\u{AaAa}${foo}\\u{aaaa}b\\u{AAAA}`;',
221+
errors: Array.from({length: 3}, () => errors[0]),
222+
output: 'const foo = `\\xAAb\\xAAb\\xAA${foo}\\uAAAAb\\uAAAAb\\uAAAAb\\u{AAAA}${foo}\\u{AAAA}b\\u{AAAA}`;'
223+
},
224+
189225
// Literal regex
190226
{
191227
code: 'const foo = /\\xa9/;',
@@ -218,6 +254,30 @@ ruleTester.run('escape-case', rule, {
218254
output: 'const foo = /foo\\\\\\\\\\xA9/;'
219255
},
220256

257+
// Mixed cases
258+
{
259+
code: 'const foo = /\\xAa/;',
260+
errors,
261+
output: 'const foo = /\\xAA/;'
262+
},
263+
{
264+
code: 'const foo = /\\uAaAa/;',
265+
errors,
266+
output: 'const foo = /\\uAAAA/;'
267+
},
268+
{
269+
code: 'const foo = /\\u{AaAa}/;',
270+
errors,
271+
output: 'const foo = /\\u{AAAA}/;'
272+
},
273+
274+
// Many
275+
{
276+
code: 'const foo = /\\xAab\\xaab\\xAAb\\uAaAab\\uaaaab\\uAAAAb\\u{AaAa}b\\u{aaaa}b\\u{AAAA}b\\ca/;',
277+
errors,
278+
output: 'const foo = /\\xAAb\\xAAb\\xAAb\\uAAAAb\\uAAAAb\\uAAAAb\\u{AAAA}b\\u{AAAA}b\\u{AAAA}b\\cA/;'
279+
},
280+
221281
// RegExp
222282
{
223283
code: 'const foo = new RegExp("/\\xa9")',

0 commit comments

Comments
 (0)