diff --git a/packages/svelte/src/compiler/phases/1-parse/state/element.js b/packages/svelte/src/compiler/phases/1-parse/state/element.js index 9082b76c4972..f59f2566e387 100644 --- a/packages/svelte/src/compiler/phases/1-parse/state/element.js +++ b/packages/svelte/src/compiler/phases/1-parse/state/element.js @@ -14,7 +14,8 @@ import { get_attribute_expression, is_expression_attribute } from '../../../util import { closing_tag_omitted } from '../../../../html-tree-validation.js'; import { list } from '../../../utils/string.js'; -const regex_invalid_unquoted_attribute_value = /^(\/>|[\s"'=<>`])/; +const regex_invalid_unquoted_attribute_value_or_self_closing_tag = /^(\/>|[\s"'=<>`])/; +const regex_invalid_unquoted_attribute_value = /^[\s"'=<>`]/; const regex_closing_textarea_tag = /^<\/textarea(\s[^>]*)?>/i; const regex_closing_comment = /-->/; const regex_whitespace_or_slash_or_closing_tag = /(\s|\/|>)/; @@ -634,9 +635,15 @@ function read_attribute_value(parser) { try { value = read_sequence( parser, - () => { + /** @param {number} chunk_length */ + (chunk_length) => { // handle common case of quote marks existing outside of regex for performance reasons - if (quote_mark) return parser.match(quote_mark); + if (quote_mark) return !!parser.match(quote_mark); + + // if chunk is not empty, handle possibility of self-closing tag + if (chunk_length > 0) { + return !!parser.match_regex(regex_invalid_unquoted_attribute_value_or_self_closing_tag); + } return !!parser.match_regex(regex_invalid_unquoted_attribute_value); }, 'in attribute value' @@ -670,7 +677,7 @@ function read_attribute_value(parser) { /** * @param {Parser} parser - * @param {() => boolean} done + * @param {(value: number) => boolean} done * @param {string} location * @returns {any[]} */ @@ -700,7 +707,7 @@ function read_sequence(parser, done, location) { while (parser.index < parser.template.length) { const index = parser.index; - if (done()) { + if (done(current_chunk.raw.length)) { flush(parser.index); return chunks; } else if (parser.eat('{')) { diff --git a/packages/svelte/tests/parser-legacy/samples/attribute-unquoted/input.svelte b/packages/svelte/tests/parser-legacy/samples/attribute-unquoted/input.svelte index 4bab0df72f3e..959042384e69 100644 --- a/packages/svelte/tests/parser-legacy/samples/attribute-unquoted/input.svelte +++ b/packages/svelte/tests/parser-legacy/samples/attribute-unquoted/input.svelte @@ -1 +1,2 @@ -
\ No newline at end of file + +home \ No newline at end of file diff --git a/packages/svelte/tests/parser-legacy/samples/attribute-unquoted/output.json b/packages/svelte/tests/parser-legacy/samples/attribute-unquoted/output.json index 5df4d66ab668..554da4827775 100644 --- a/packages/svelte/tests/parser-legacy/samples/attribute-unquoted/output.json +++ b/packages/svelte/tests/parser-legacy/samples/attribute-unquoted/output.json @@ -2,12 +2,12 @@ "html": { "type": "Fragment", "start": 0, - "end": 21, + "end": 40, "children": [ { "type": "Element", "start": 0, - "end": 21, + "end": 40, "name": "div", "attributes": [ { @@ -27,7 +27,46 @@ } ], "children": [] + }, + { + "type": "Text", + "start": 21, + "end": 22, + "raw": "\n", + "data": "\n" + }, + { + "type": "Element", + "start": 22, + "end": 40, + "name": "a", + "attributes": [ + { + "type": "Attribute", + "start": 25, + "end": 31, + "name": "href", + "value": [ + { + "start": 30, + "end": 31, + "type": "Text", + "raw": "/", + "data": "/" + } + ] + } + ], + "children": [ + { + "type": "Text", + "start": 32, + "end": 36, + "raw": "home", + "data": "home" + } + ] } ] } -} +} \ No newline at end of file