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 <navorite@gmail.com>

* add changeset

* add changeset

* add test

* Update .changeset/seven-hornets-smile.md

Co-authored-by: navorite <navorite@gmail.com>

* 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 <navorite@gmail.com>
Co-authored-by: Rogerio Luiz Aques de Amorim <Rogerio Amorim>
Co-authored-by: Rich Harris <rich.harris@vercel.com>
Co-authored-by: Rich Harris <hello@rich-harris.dev>
pull/10304/head
Rogério Luiz Aques de Amorim 11 months ago committed by GitHub
parent f7cc8cb263
commit a58d93f8bf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: correctly parse at-rules containing special characters in strings

@ -9,7 +9,6 @@ const REGEX_PERCENTAGE = /^\d+(\.\d+)?%/;
const REGEX_NTH_OF =
/^(even|odd|\+?(\d+|\d*n(\s*[+-]\s*\d+)?)|-\d*n(\s*\+\s*\d+))((?=\s*[,)])|\s+of\s+)/;
const REGEX_WHITESPACE_OR_COLON = /[\s:]/;
const REGEX_BRACE_OR_SEMICOLON = /[{;]/;
const REGEX_LEADING_HYPHEN_OR_DIGIT = /-?\d/;
const REGEX_VALID_IDENTIFIER_CHAR = /[a-zA-Z0-9_-]/;
const REGEX_COMMENT_CLOSE = /\*\//;
@ -79,7 +78,7 @@ function read_at_rule(parser) {
const name = read_identifier(parser);
const prelude = parser.read_until(REGEX_BRACE_OR_SEMICOLON).trim();
const prelude = read_value(parser);
/** @type {import('#compiler').Css.Block | null} */
let block = null;
@ -398,7 +397,7 @@ function read_declaration(parser) {
parser.eat(':');
parser.allow_whitespace();
const value = read_declaration_value(parser);
const value = read_value(parser);
const end = parser.index;
@ -419,7 +418,7 @@ function read_declaration(parser) {
* @param {import('../index.js').Parser} parser
* @returns {string}
*/
function read_declaration_value(parser) {
function read_value(parser) {
let value = '';
let escaped = false;
let in_url = false;
@ -443,7 +442,7 @@ function read_declaration_value(parser) {
quote_mark = char;
} else if (char === '(' && value.slice(-3) === 'url') {
in_url = true;
} else if ((char === ';' || char === '}') && !in_url && !quote_mark) {
} else if ((char === ';' || char === '{' || char === '}') && !in_url && !quote_mark) {
return value.trim();
}

@ -0,0 +1,10 @@
<h1>
Semicolon inside quotes
</h1>
<style>
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap");
h1 {
font-weight: bold;
background: url("whatever");
}
</style>

@ -0,0 +1,107 @@
{
"css": {
"type": "Style",
"start": 36,
"end": 205,
"attributes": [],
"children": [
{
"type": "Atrule",
"start": 45,
"end": 135,
"name": "import",
"prelude": "url(\"https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap\")",
"block": null
},
{
"type": "Rule",
"prelude": {
"type": "SelectorList",
"start": 137,
"end": 139,
"children": [
{
"type": "Selector",
"start": 137,
"end": 139,
"children": [
{
"type": "TypeSelector",
"name": "h1",
"start": 137,
"end": 139
}
]
}
]
},
"block": {
"type": "Block",
"start": 140,
"end": 196,
"children": [
{
"type": "Declaration",
"start": 144,
"end": 161,
"property": "font-weight",
"value": "bold"
},
{
"type": "Declaration",
"start": 165,
"end": 192,
"property": "background",
"value": "url(\"whatever\")"
}
]
},
"start": 137,
"end": 196
}
],
"content": {
"start": 43,
"end": 197,
"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"
}
},
"js": [],
"start": 0,
"end": 35,
"type": "Root",
"fragment": {
"type": "Fragment",
"nodes": [
{
"type": "RegularElement",
"start": 0,
"end": 35,
"name": "h1",
"attributes": [],
"fragment": {
"type": "Fragment",
"nodes": [
{
"type": "Text",
"start": 4,
"end": 30,
"raw": "\n\tSemicolon inside quotes\n",
"data": "\n\tSemicolon inside quotes\n"
}
],
"transparent": true
}
},
{
"type": "Text",
"start": 35,
"end": 36,
"raw": "\n",
"data": "\n"
}
],
"transparent": false
},
"options": null
}
Loading…
Cancel
Save