Skip to content

Commit 81625e5

Browse files
nkovacssindresorhus
authored andcommitted
Handle backslashes correctly in no-hex-escape and escape-case (#110)
1 parent e198d50 commit 81625e5

File tree

4 files changed

+133
-10
lines changed

4 files changed

+133
-10
lines changed

rules/escape-case.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
'use strict';
2-
const escapeWithLowercase = /\\(x[a-f\d]{2}|u[a-f\d]{4}|u\{([a-f\d]{1,})\}|c[a-z])/;
2+
const escapeWithLowercase = /((?:^|[^\\])(?:\\\\)*)\\(x[a-f\d]{2}|u[a-f\d]{4}|u\{(?:[a-f\d]{1,})\}|c[a-z])/;
33
const hasLowercaseCharacter = /[a-z]+/;
44
const message = 'Use uppercase characters for the value of the escape sequence.';
55

66
const fix = value => {
77
const results = escapeWithLowercase.exec(value);
88

99
if (results) {
10-
const fixedEscape = results[0].slice(0, 2) + results[0].slice(2).toUpperCase();
11-
return value.slice(0, results.index) + fixedEscape + value.slice(results.index + results[0].length);
10+
const prefix = results[1].length + 1;
11+
const fixedEscape = results[2].slice(0, 1) + results[2].slice(1).toUpperCase();
12+
return value.slice(0, results.index + prefix) + fixedEscape + value.slice(results.index + results[0].length);
1213
}
1314

1415
return value;
@@ -23,7 +24,7 @@ const create = context => {
2324

2425
const matches = node.raw.match(escapeWithLowercase);
2526

26-
if (matches && matches[0].slice(2).match(hasLowercaseCharacter)) {
27+
if (matches && matches[2].slice(1).match(hasLowercaseCharacter)) {
2728
context.report({
2829
node,
2930
message,
@@ -38,7 +39,7 @@ const create = context => {
3839

3940
const matches = node.value.raw.match(escapeWithLowercase);
4041

41-
if (matches && matches[0].slice(2).match(hasLowercaseCharacter)) {
42+
if (matches && matches[2].slice(1).match(hasLowercaseCharacter)) {
4243
context.report({
4344
node,
4445
message,

rules/no-hex-escape.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
'use strict';
33

44
function checkEscape(context, node, value) {
5-
const fixedValue = typeof value === 'string' ? value.replace(/\\x/g, '\\u00') : value;
5+
const fixedValue = typeof value === 'string' ? value.replace(/((?:^|[^\\])(?:\\\\)*)\\x/g, '$1\\u00') : value;
66

77
if (value !== fixedValue) {
88
context.report({

test/escape-case.js

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,18 @@ ruleTester.run('escape-case', rule, {
3131
'const foo = "\\uD834foo";',
3232
'const foo = "foo\\uD834";',
3333
'const foo = "foo \\uD834";',
34-
'const foo = "\\u2500";',
35-
'const foo = "\\x46";',
3634
'const foo = "foo \\u2500";',
3735
'const foo = "foo \\x46";',
3836
'const foo = `foo \\u2500`;',
39-
'const foo = `foo \\x46`;'
37+
'const foo = `foo \\x46`;',
38+
'const foo = "foo\\\\xbar";',
39+
'const foo = "foo\\\\ubarbaz";',
40+
'const foo = "foo\\\\\\\\xbar";',
41+
'const foo = "foo\\\\\\\\ubarbaz";',
42+
'const foo = `foo\\\\xbar`;',
43+
'const foo = `foo\\\\ubarbaz`;',
44+
'const foo = `foo\\\\\\\\xbar`;',
45+
'const foo = `foo\\\\\\\\ubarbaz`;'
4046
],
4147
invalid: [
4248
{
@@ -113,6 +119,36 @@ ruleTester.run('escape-case', rule, {
113119
code: 'const foo = "foo \\ud834";',
114120
errors,
115121
output: 'const foo = "foo \\uD834";'
122+
},
123+
{
124+
code: 'const foo = "\\\\\\ud834foo";',
125+
errors,
126+
output: 'const foo = "\\\\\\uD834foo";'
127+
},
128+
{
129+
code: 'const foo = "foo\\\\\\ud834";',
130+
errors,
131+
output: 'const foo = "foo\\\\\\uD834";'
132+
},
133+
{
134+
code: 'const foo = "foo \\\\\\ud834";',
135+
errors,
136+
output: 'const foo = "foo \\\\\\uD834";'
137+
},
138+
{
139+
code: 'const foo = `\\\\\\ud834foo`;',
140+
errors,
141+
output: 'const foo = `\\\\\\uD834foo`;'
142+
},
143+
{
144+
code: 'const foo = `foo\\\\\\ud834`;',
145+
errors,
146+
output: 'const foo = `foo\\\\\\uD834`;'
147+
},
148+
{
149+
code: 'const foo = `foo \\\\\\ud834`;',
150+
errors,
151+
output: 'const foo = `foo \\\\\\uD834`;'
116152
}
117153
]
118154
});

test/no-hex-escape.js

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,26 +22,62 @@ ruleTester.run('no-hex-escape', rule, {
2222
`const foo = 'foo\\u00b1'`,
2323
`const foo = 'foo\\u00b1foo'`,
2424
`const foo = '\\u00b1foo'`,
25+
`const foo = '\\\\xb1'`,
26+
`const foo = '\\\\\\\\xb1'`,
27+
`const foo = 'foo\\\\xb1'`,
28+
`const foo = 'foo\\\\\\\\xb1'`,
29+
`const foo = '\\\\xd8\\\\x3d\\\\xdc\\\\xa9'`,
30+
`const foo = 'foo\\\\x12foo\\\\x34'`,
31+
`const foo = '\\\\\\\\xd8\\\\\\\\x3d\\\\\\\\xdc\\\\\\\\xa9'`,
32+
`const foo = 'foo\\\\\\\\x12foo\\\\\\\\x34'`,
2533
'const foo = 42',
2634
'const foo = `foo`',
2735
'const foo = `\\u00b1`',
2836
'const foo = `\\u00b1\\u00b1`',
2937
'const foo = `foo\\u00b1`',
3038
'const foo = `foo\\u00b1foo`',
3139
'const foo = `\\u00b1foo`',
32-
'const foo = `42`'
40+
'const foo = `42`',
41+
'const foo = `\\\\xb1`',
42+
'const foo = `\\\\\\\\xb1`',
43+
'const foo = `foo\\\\xb1`',
44+
'const foo = `foo\\\\\\\\xb1`',
45+
'const foo = `\\\\xd8\\\\x3d\\\\xdc\\\\xa9`',
46+
'const foo = `foo\\\\x12foo\\\\x34`',
47+
'const foo = `\\\\\\\\xd8\\\\\\\\x3d\\\\\\\\xdc\\\\\\\\xa9`',
48+
'const foo = `foo\\\\\\\\x12foo\\\\\\\\x34`'
3349
],
3450
invalid: [
3551
{
3652
code: `const foo = '\\xb1'`,
3753
errors: [error],
3854
output: `const foo = '\\u00b1'`
3955
},
56+
{
57+
code: `const foo = '\\\\\\xb1'`,
58+
errors: [error],
59+
output: `const foo = '\\\\\\u00b1'`
60+
},
4061
{
4162
code: `const foo = '\\xb1\\xb1'`,
4263
errors: [error],
4364
output: `const foo = '\\u00b1\\u00b1'`
4465
},
66+
{
67+
code: `const foo = '\\\\\\xb1\\\\\\xb1'`,
68+
errors: [error],
69+
output: `const foo = '\\\\\\u00b1\\\\\\u00b1'`
70+
},
71+
{
72+
code: `const foo = '\\\\\\xb1\\\\\\\\xb1'`,
73+
errors: [error],
74+
output: `const foo = '\\\\\\u00b1\\\\\\\\xb1'`
75+
},
76+
{
77+
code: `const foo = '\\\\\\\\\\xb1\\\\\\xb1'`,
78+
errors: [error],
79+
output: `const foo = '\\\\\\\\\\u00b1\\\\\\u00b1'`
80+
},
4581
{
4682
code: `const foo = '\\xb1foo'`,
4783
errors: [error],
@@ -57,6 +93,16 @@ ruleTester.run('no-hex-escape', rule, {
5793
errors: [error],
5894
output: `const foo = 'foo\\u00b1'`
5995
},
96+
{
97+
code: `const foo = 'foo\\\\\\xb1'`,
98+
errors: [error],
99+
output: `const foo = 'foo\\\\\\u00b1'`
100+
},
101+
{
102+
code: `const foo = 'foo\\\\\\\\\\xb1'`,
103+
errors: [error],
104+
output: `const foo = 'foo\\\\\\\\\\u00b1'`
105+
},
60106
{
61107
code: `const foo = 'foo\\x12foo\\x34'`,
62108
errors: [error],
@@ -67,17 +113,42 @@ ruleTester.run('no-hex-escape', rule, {
67113
errors: [error],
68114
output: `const foo = '42\\u001242\\u0034'`
69115
},
116+
{
117+
code: `const foo = '42\\\\\\x1242\\\\\\x34'`,
118+
errors: [error],
119+
output: `const foo = '42\\\\\\u001242\\\\\\u0034'`
120+
},
70121
// Test template literals
71122
{
72123
code: 'const foo = `\\xb1`',
73124
errors: [error],
74125
output: 'const foo = `\\u00b1`'
75126
},
127+
{
128+
code: 'const foo = `\\\\\\xb1`',
129+
errors: [error],
130+
output: 'const foo = `\\\\\\u00b1`'
131+
},
76132
{
77133
code: 'const foo = `\\xb1\\xb1`',
78134
errors: [error],
79135
output: 'const foo = `\\u00b1\\u00b1`'
80136
},
137+
{
138+
code: 'const foo = `\\\\\\xb1\\\\\\xb1`',
139+
errors: [error],
140+
output: 'const foo = `\\\\\\u00b1\\\\\\u00b1`'
141+
},
142+
{
143+
code: 'const foo = `\\\\\\\\\\xb1\\\\\\xb1`',
144+
errors: [error],
145+
output: 'const foo = `\\\\\\\\\\u00b1\\\\\\u00b1`'
146+
},
147+
{
148+
code: 'const foo = `\\\\\\\\\\xb1\\\\\\\\xb1`',
149+
errors: [error],
150+
output: 'const foo = `\\\\\\\\\\u00b1\\\\\\\\xb1`'
151+
},
81152
{
82153
code: 'const foo = `\\xb1foo`',
83154
errors: [error],
@@ -93,6 +164,16 @@ ruleTester.run('no-hex-escape', rule, {
93164
errors: [error],
94165
output: 'const foo = `foo\\u00b1`'
95166
},
167+
{
168+
code: 'const foo = `foo\\\\\\xb1`',
169+
errors: [error],
170+
output: 'const foo = `foo\\\\\\u00b1`'
171+
},
172+
{
173+
code: 'const foo = `foo\\\\\\\\\\xb1`',
174+
errors: [error],
175+
output: 'const foo = `foo\\\\\\\\\\u00b1`'
176+
},
96177
{
97178
code: 'const foo = `foo\\x12foo\\x34`',
98179
errors: [error],
@@ -102,6 +183,11 @@ ruleTester.run('no-hex-escape', rule, {
102183
code: 'const foo = `42\\x1242\\x34`',
103184
errors: [error],
104185
output: 'const foo = `42\\u001242\\u0034`'
186+
},
187+
{
188+
code: 'const foo = `42\\\\\\x1242\\\\\\x34`',
189+
errors: [error],
190+
output: 'const foo = `42\\\\\\u001242\\\\\\u0034`'
105191
}
106192
]
107193
});

0 commit comments

Comments
 (0)