Skip to content

Commit 611c43f

Browse files
rogeriolaanavoriteRich-Harris
authored andcommitted
fix: parser error when using semicolon inside quotes in style (#10221)
* fix error when using semicolon inside quotes in style * refactor to include { like in the original code * simplified version of regex Co-authored-by: navorite <[email protected]> * add changeset * add changeset * add test * Update .changeset/seven-hornets-smile.md Co-authored-by: navorite <[email protected]> * undo demo.css change * fix support-font-face test not passing * add double quotes * beef up test * robustify parsing * Update .changeset/seven-hornets-smile.md --------- Co-authored-by: navorite <[email protected]> Co-authored-by: Rogerio Luiz Aques de Amorim <Rogerio Amorim> Co-authored-by: Rich Harris <[email protected]> Co-authored-by: Rich Harris <[email protected]>
1 parent 49a2d87 commit 611c43f

File tree

4 files changed

+126
-5
lines changed

4 files changed

+126
-5
lines changed

.changeset/seven-hornets-smile.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte": patch
3+
---
4+
5+
fix: correctly parse at-rules containing special characters in strings

packages/svelte/src/compiler/phases/1-parse/read/style.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ const REGEX_PERCENTAGE = /^\d+(\.\d+)?%/;
99
const REGEX_NTH_OF =
1010
/^(even|odd|\+?(\d+|\d*n(\s*[+-]\s*\d+)?)|-\d*n(\s*\+\s*\d+))((?=\s*[,)])|\s+of\s+)/;
1111
const REGEX_WHITESPACE_OR_COLON = /[\s:]/;
12-
const REGEX_BRACE_OR_SEMICOLON = /[{;]/;
1312
const REGEX_LEADING_HYPHEN_OR_DIGIT = /-?\d/;
1413
const REGEX_VALID_IDENTIFIER_CHAR = /[a-zA-Z0-9_-]/;
1514
const REGEX_COMMENT_CLOSE = /\*\//;
@@ -79,7 +78,7 @@ function read_at_rule(parser) {
7978

8079
const name = read_identifier(parser);
8180

82-
const prelude = parser.read_until(REGEX_BRACE_OR_SEMICOLON).trim();
81+
const prelude = read_value(parser);
8382

8483
/** @type {import('#compiler').Css.Block | null} */
8584
let block = null;
@@ -398,7 +397,7 @@ function read_declaration(parser) {
398397
parser.eat(':');
399398
parser.allow_whitespace();
400399

401-
const value = read_declaration_value(parser);
400+
const value = read_value(parser);
402401

403402
const end = parser.index;
404403

@@ -419,7 +418,7 @@ function read_declaration(parser) {
419418
* @param {import('../index.js').Parser} parser
420419
* @returns {string}
421420
*/
422-
function read_declaration_value(parser) {
421+
function read_value(parser) {
423422
let value = '';
424423
let escaped = false;
425424
let in_url = false;
@@ -443,7 +442,7 @@ function read_declaration_value(parser) {
443442
quote_mark = char;
444443
} else if (char === '(' && value.slice(-3) === 'url') {
445444
in_url = true;
446-
} else if ((char === ';' || char === '}') && !in_url && !quote_mark) {
445+
} else if ((char === ';' || char === '{' || char === '}') && !in_url && !quote_mark) {
447446
return value.trim();
448447
}
449448

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<h1>
2+
Semicolon inside quotes
3+
</h1>
4+
<style>
5+
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap");
6+
h1 {
7+
font-weight: bold;
8+
background: url("whatever");
9+
}
10+
</style>
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
{
2+
"css": {
3+
"type": "Style",
4+
"start": 36,
5+
"end": 205,
6+
"attributes": [],
7+
"children": [
8+
{
9+
"type": "Atrule",
10+
"start": 45,
11+
"end": 135,
12+
"name": "import",
13+
"prelude": "url(\"https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap\")",
14+
"block": null
15+
},
16+
{
17+
"type": "Rule",
18+
"prelude": {
19+
"type": "SelectorList",
20+
"start": 137,
21+
"end": 139,
22+
"children": [
23+
{
24+
"type": "Selector",
25+
"start": 137,
26+
"end": 139,
27+
"children": [
28+
{
29+
"type": "TypeSelector",
30+
"name": "h1",
31+
"start": 137,
32+
"end": 139
33+
}
34+
]
35+
}
36+
]
37+
},
38+
"block": {
39+
"type": "Block",
40+
"start": 140,
41+
"end": 196,
42+
"children": [
43+
{
44+
"type": "Declaration",
45+
"start": 144,
46+
"end": 161,
47+
"property": "font-weight",
48+
"value": "bold"
49+
},
50+
{
51+
"type": "Declaration",
52+
"start": 165,
53+
"end": 192,
54+
"property": "background",
55+
"value": "url(\"whatever\")"
56+
}
57+
]
58+
},
59+
"start": 137,
60+
"end": 196
61+
}
62+
],
63+
"content": {
64+
"start": 43,
65+
"end": 197,
66+
"styles": "\n\t@import url(\"https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap\");\n\th1 {\n\t\tfont-weight: bold;\n\t\tbackground: url(\"whatever\");\n\t}\n"
67+
}
68+
},
69+
"js": [],
70+
"start": 0,
71+
"end": 35,
72+
"type": "Root",
73+
"fragment": {
74+
"type": "Fragment",
75+
"nodes": [
76+
{
77+
"type": "RegularElement",
78+
"start": 0,
79+
"end": 35,
80+
"name": "h1",
81+
"attributes": [],
82+
"fragment": {
83+
"type": "Fragment",
84+
"nodes": [
85+
{
86+
"type": "Text",
87+
"start": 4,
88+
"end": 30,
89+
"raw": "\n\tSemicolon inside quotes\n",
90+
"data": "\n\tSemicolon inside quotes\n"
91+
}
92+
],
93+
"transparent": true
94+
}
95+
},
96+
{
97+
"type": "Text",
98+
"start": 35,
99+
"end": 36,
100+
"raw": "\n",
101+
"data": "\n"
102+
}
103+
],
104+
"transparent": false
105+
},
106+
"options": null
107+
}

0 commit comments

Comments
 (0)