diff --git a/.changeset/lazy-singers-pretend.md b/.changeset/lazy-singers-pretend.md new file mode 100644 index 000000000000..f0aae8004826 --- /dev/null +++ b/.changeset/lazy-singers-pretend.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: correctly parse escaped unicode characters in css selector diff --git a/packages/svelte/src/compiler/phases/1-parse/read/style.js b/packages/svelte/src/compiler/phases/1-parse/read/style.js index e15a47e6d589..80ab234d925f 100644 --- a/packages/svelte/src/compiler/phases/1-parse/read/style.js +++ b/packages/svelte/src/compiler/phases/1-parse/read/style.js @@ -12,6 +12,7 @@ const REGEX_NTH_OF = const REGEX_WHITESPACE_OR_COLON = /[\s:]/; const REGEX_LEADING_HYPHEN_OR_DIGIT = /-?\d/; const REGEX_VALID_IDENTIFIER_CHAR = /[a-zA-Z0-9_-]/; +const REGEX_UNICODE_SEQUENCE = /^\\[0-9a-fA-F]{1,6}(\r\n|\s)?/; const REGEX_COMMENT_CLOSE = /\*\//; const REGEX_HTML_COMMENT_CLOSE = /-->/; @@ -580,25 +581,26 @@ function read_identifier(parser) { e.css_expected_identifier(start); } - let escaped = false; - while (parser.index < parser.template.length) { const char = parser.template[parser.index]; - if (escaped) { - identifier += '\\' + char; - escaped = false; - } else if (char === '\\') { - escaped = true; + if (char === '\\') { + const sequence = parser.match_regex(REGEX_UNICODE_SEQUENCE); + if (sequence) { + identifier += String.fromCodePoint(parseInt(sequence.slice(1), 16)); + parser.index += sequence.length; + } else { + identifier += '\\' + parser.template[parser.index + 1]; + parser.index += 2; + } } else if ( /** @type {number} */ (char.codePointAt(0)) >= 160 || REGEX_VALID_IDENTIFIER_CHAR.test(char) ) { identifier += char; + parser.index++; } else { break; } - - parser.index++; } if (identifier === '') { diff --git a/packages/svelte/tests/css/samples/unicode-identifier/_config.js b/packages/svelte/tests/css/samples/unicode-identifier/_config.js new file mode 100644 index 000000000000..da4ea75e36b6 --- /dev/null +++ b/packages/svelte/tests/css/samples/unicode-identifier/_config.js @@ -0,0 +1,76 @@ +import { test } from '../../test'; + +export default test({ + warnings: [ + { + code: 'css_unused_selector', + message: 'Unused CSS selector ".\\61 sdf"', + start: { + line: 22, + column: 1, + character: 465 + }, + end: { + line: 22, + column: 10, + character: 474 + } + }, + { + code: 'css_unused_selector', + message: 'Unused CSS selector ".\\61\n\tsdf"', + start: { + line: 23, + column: 1, + character: 492 + }, + end: { + line: 24, + column: 4, + character: 501 + } + }, + { + code: 'css_unused_selector', + message: 'Unused CSS selector ".\\61\n sdf"', + start: { + line: 25, + column: 1, + character: 519 + }, + end: { + line: 26, + column: 4, + character: 528 + } + }, + { + code: 'css_unused_selector', + message: 'Unused CSS selector "#\\31span"', + start: { + line: 28, + column: 1, + character: 547 + }, + end: { + line: 28, + column: 9, + character: 555 + } + }, + { + code: 'css_unused_selector', + message: 'Unused CSS selector "#\\31 span"', + start: { + line: 29, + column: 1, + character: 573 + }, + end: { + line: 29, + column: 10, + character: 582 + } + } + ] +}); diff --git a/packages/svelte/tests/css/samples/unicode-identifier/expected.css b/packages/svelte/tests/css/samples/unicode-identifier/expected.css new file mode 100644 index 000000000000..fb8b936deed2 --- /dev/null +++ b/packages/svelte/tests/css/samples/unicode-identifier/expected.css @@ -0,0 +1,21 @@ + #\31\32\33 .svelte-xyz{ color: green; } + #\31 23.svelte-xyz { color: green; } + #line\a break.svelte-xyz { color: green; } + #line\a +break.svelte-xyz { color: green; } + #line\00000abreak.svelte-xyz { color: green; } + #line\00000a break.svelte-xyz { color: green; } + #line\00000a break.svelte-xyz { color: green; } + .a\1f642 b.svelte-xyz { color: green; } + + .\61sdf.svelte-xyz { color: green; } + + /* (unused) .\61 sdf { color: red; }*/ + /* (unused) .\61 + sdf { color: red; }*/ + /* (unused) .\61 + sdf { color: red; }*/ + + /* (unused) #\31span { color: red; }*/ + /* (unused) #\31 span { color: red; }*/ + #\31 .svelte-xyz span:where(.svelte-xyz) { color: green; } \ No newline at end of file diff --git a/packages/svelte/tests/css/samples/unicode-identifier/expected.html b/packages/svelte/tests/css/samples/unicode-identifier/expected.html new file mode 100644 index 000000000000..9b5f8ede4730 --- /dev/null +++ b/packages/svelte/tests/css/samples/unicode-identifier/expected.html @@ -0,0 +1,7 @@ +
+
+
+
+
+
\ No newline at end of file diff --git a/packages/svelte/tests/css/samples/unicode-identifier/input.svelte b/packages/svelte/tests/css/samples/unicode-identifier/input.svelte new file mode 100644 index 000000000000..04676c4c4db2 --- /dev/null +++ b/packages/svelte/tests/css/samples/unicode-identifier/input.svelte @@ -0,0 +1,31 @@ +
+
+
+
+
+
+ + \ No newline at end of file