Skip to content

Commit a0c39eb

Browse files
fix: avoid all escaped characters replaced
1 parent 1f42f0e commit a0c39eb

File tree

4 files changed

+158
-8
lines changed

4 files changed

+158
-8
lines changed

src/utils.js

+47-4
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,7 @@ function getLocalIdent(loaderContext, localIdentName, localName, options) {
8888
options
8989
);
9090

91-
return hash
92-
.replace(/\\@/g, '@')
93-
.replace(new RegExp('[^a-zA-Z0-9@\\-_\u00A0-\uFFFF]', 'g'), '-')
94-
.replace(/^((-?[0-9])|--)/, '_$1');
91+
return normalizeIdentifier(hash);
9592
}
9693

9794
function getFilter(filter, resourcePath, defaultFilter = null) {
@@ -108,6 +105,52 @@ function getFilter(filter, resourcePath, defaultFilter = null) {
108105
};
109106
}
110107

108+
function normalizeIdentifier(value) {
109+
const escapedSymbols = [
110+
'~',
111+
'!',
112+
'@',
113+
'#',
114+
'$',
115+
'%',
116+
'&',
117+
'^',
118+
'*',
119+
'(',
120+
')',
121+
'{',
122+
'}',
123+
'[',
124+
']',
125+
'`',
126+
'/',
127+
'=',
128+
'?',
129+
'+',
130+
'\\',
131+
'|',
132+
'-',
133+
'_',
134+
':',
135+
';',
136+
"'",
137+
'"',
138+
',',
139+
'<',
140+
'.',
141+
'>',
142+
];
143+
144+
const identifiersRegExp = new RegExp(
145+
`[^a-zA-Z0-9${escapedSymbols.join('\\')}\\-_\u00A0-\uFFFF]`,
146+
'g'
147+
);
148+
149+
return value
150+
.replace(identifiersRegExp, '-')
151+
.replace(/^((-?[0-9])|--)/, '_$1');
152+
}
153+
111154
export {
112155
getImportPrefix,
113156
getLocalIdent,

test/__snapshots__/localIdentName-option.test.js.snap

+105-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ Array [
3939
:local(.m_x_\\\\@) {
4040
margin-left: auto !important;
4141
margin-right: auto !important;
42+
}
43+
44+
:local(.B\\\\&W\\\\?) {
45+
margin-left: auto !important;
46+
margin-right: auto !important;
4247
}",
4348
"",
4449
],
@@ -86,6 +91,11 @@ Array [
8691
:local(.m_x_\\\\@) {
8792
margin-left: auto !important;
8893
margin-right: auto !important;
94+
}
95+
96+
:local(.B\\\\&W\\\\?) {
97+
margin-left: auto !important;
98+
margin-right: auto !important;
8999
}",
90100
"",
91101
],
@@ -133,6 +143,11 @@ Array [
133143
:local(.m_x_\\\\@) {
134144
margin-left: auto !important;
135145
margin-right: auto !important;
146+
}
147+
148+
:local(.B\\\\&W\\\\?) {
149+
margin-left: auto !important;
150+
margin-right: auto !important;
136151
}",
137152
"",
138153
],
@@ -180,6 +195,11 @@ Array [
180195
:local(.m_x_\\\\@) {
181196
margin-left: auto !important;
182197
margin-right: auto !important;
198+
}
199+
200+
:local(.B\\\\&W\\\\?) {
201+
margin-left: auto !important;
202+
margin-right: auto !important;
183203
}",
184204
"",
185205
],
@@ -227,6 +247,11 @@ Array [
227247
:local(.m_x_\\\\@) {
228248
margin-left: auto !important;
229249
margin-right: auto !important;
250+
}
251+
252+
:local(.B\\\\&W\\\\?) {
253+
margin-left: auto !important;
254+
margin-right: auto !important;
230255
}",
231256
"",
232257
],
@@ -274,6 +299,11 @@ Array [
274299
:local(.m_x_\\\\@) {
275300
margin-left: auto !important;
276301
margin-right: auto !important;
302+
}
303+
304+
:local(.B\\\\&W\\\\?) {
305+
margin-left: auto !important;
306+
margin-right: auto !important;
277307
}",
278308
"",
279309
],
@@ -321,6 +351,11 @@ Array [
321351
:local(.m_x_\\\\@) {
322352
margin-left: auto !important;
323353
margin-right: auto !important;
354+
}
355+
356+
:local(.B\\\\&W\\\\?) {
357+
margin-left: auto !important;
358+
margin-right: auto !important;
324359
}",
325360
"",
326361
],
@@ -329,11 +364,75 @@ Array [
329364

330365
exports[`localIdentName option should use hash prefix: warnings 1`] = `Array []`;
331366

367+
exports[`localIdentName option should сorrectly replace escaped symbols in selector: errors 1`] = `Array []`;
368+
369+
exports[`localIdentName option should сorrectly replace escaped symbols in selector: locals 1`] = `
370+
Object {
371+
"-a0-34a___f": "-a0-34a___f--2nJ5",
372+
"B&W?": "B&W?--1s8i",
373+
"_test": "_test--23te",
374+
"className": "className--1E8H",
375+
"m_x_@": "m_x_@--2G3b",
376+
"someId": "someId--3w7J",
377+
"subClass": "subClass--3lo0",
378+
"test": "test--NW9Y",
379+
}
380+
`;
381+
382+
exports[`localIdentName option should сorrectly replace escaped symbols in selector: module (evaluated) 1`] = `
383+
Array [
384+
Array [
385+
1,
386+
".test--NW9Y {
387+
background: red;
388+
}
389+
390+
._test--23te {
391+
background: blue;
392+
}
393+
394+
.className--1E8H {
395+
background: red;
396+
}
397+
398+
#someId--3w7J {
399+
background: green;
400+
}
401+
402+
.className--1E8H .subClass--3lo0 {
403+
color: green;
404+
}
405+
406+
#someId--3w7J .subClass--3lo0 {
407+
color: blue;
408+
}
409+
410+
.-a0-34a___f--2nJ5 {
411+
color: red;
412+
}
413+
414+
.m_x_\\\\@--2G3b {
415+
margin-left: auto !important;
416+
margin-right: auto !important;
417+
}
418+
419+
.B\\\\&W\\\\?--1s8i {
420+
margin-left: auto !important;
421+
margin-right: auto !important;
422+
}",
423+
"",
424+
],
425+
]
426+
`;
427+
428+
exports[`localIdentName option should сorrectly replace escaped symbols in selector: warnings 1`] = `Array []`;
429+
332430
exports[`localIdentName option should сorrectly replace symbol @ in selector: errors 1`] = `Array []`;
333431

334432
exports[`localIdentName option should сorrectly replace symbol @ in selector: locals 1`] = `
335433
Object {
336434
"-a0-34a___f": "-a0-34a___f--2nJ5",
435+
"B&W?": "B&W?--1s8i",
337436
"_test": "_test--23te",
338437
"className": "className--1E8H",
339438
"m_x_@": "m_x_@--2G3b",
@@ -375,7 +474,12 @@ Array [
375474
color: red;
376475
}
377476
378-
.m_x_@--2G3b {
477+
.m_x_\\\\@--2G3b {
478+
margin-left: auto !important;
479+
margin-right: auto !important;
480+
}
481+
482+
.B\\\\&W\\\\?--1s8i {
379483
margin-left: auto !important;
380484
margin-right: auto !important;
381485
}",

test/fixtures/modules/localIdentName.css

+5
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,9 @@
2929
:local(.m_x_\@) {
3030
margin-left: auto !important;
3131
margin-right: auto !important;
32+
}
33+
34+
:local(.B\&W\?) {
35+
margin-left: auto !important;
36+
margin-right: auto !important;
3237
}

test/localIdentName-option.test.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ describe('localIdentName option', () => {
118118
expect(stats.compilation.errors).toMatchSnapshot('errors');
119119
});
120120

121-
it('should сorrectly replace symbol @ in selector', async () => {
121+
it('should сorrectly replace escaped symbols in selector', async () => {
122122
const config = {
123123
loader: {
124124
options: {
@@ -134,8 +134,6 @@ describe('localIdentName option', () => {
134134
const module = modules.find((m) => m.id === testId);
135135
const evaluatedModule = evaluated(module.source, modules);
136136

137-
expect(evaluatedModule.locals['m_x_@']).toContain('m_x_@');
138-
139137
expect(evaluatedModule).toMatchSnapshot('module (evaluated)');
140138
expect(evaluatedModule.locals).toMatchSnapshot('locals');
141139
expect(stats.compilation.warnings).toMatchSnapshot('warnings');

0 commit comments

Comments
 (0)