chore: loose parser improvements (#14733)

* handle invalid expression inside each key

* handle invalid expression inside each expression

* handle invalid expression inside await block

* handle "in the middle of typing" components with starting lowercase and dot at the end

* changeset
pull/14735/head
Simon H 1 week ago committed by GitHub
parent 36d73cad55
commit 3146e93bbb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
chore: more loose parser improvements

@ -7,9 +7,10 @@ import { find_matching_bracket } from '../utils/bracket.js';
/** /**
* @param {Parser} parser * @param {Parser} parser
* @param {string} [opening_token]
* @returns {Expression} * @returns {Expression}
*/ */
export default function read_expression(parser) { export default function read_expression(parser, opening_token) {
try { try {
const node = parse_expression_at(parser.template, parser.ts, parser.index); const node = parse_expression_at(parser.template, parser.ts, parser.index);
@ -42,7 +43,7 @@ export default function read_expression(parser) {
} catch (err) { } catch (err) {
if (parser.loose) { if (parser.loose) {
// Find the next } and treat it as the end of the expression // Find the next } and treat it as the end of the expression
const end = find_matching_bracket(parser.template, parser.index, '{'); const end = find_matching_bracket(parser.template, parser.index, opening_token ?? '{');
if (end) { if (end) {
const start = parser.index; const start = parser.index;
parser.index = end; parser.index = end;

@ -123,9 +123,12 @@ export default function element(parser) {
} }
if (!regex_valid_element_name.test(name) && !regex_valid_component_name.test(name)) { if (!regex_valid_element_name.test(name) && !regex_valid_component_name.test(name)) {
// <div. -> in the middle of typing -> allow in loose mode
if (!parser.loose || !name.endsWith('.')) {
const bounds = { start: start + 1, end: start + 1 + name.length }; const bounds = { start: start + 1, end: start + 1 + name.length };
e.tag_invalid_name(bounds); e.tag_invalid_name(bounds);
} }
}
if (root_only_meta_tags.has(name)) { if (root_only_meta_tags.has(name)) {
if (name in parser.meta_tags) { if (name in parser.meta_tags) {
@ -141,7 +144,7 @@ export default function element(parser) {
const type = meta_tags.has(name) const type = meta_tags.has(name)
? meta_tags.get(name) ? meta_tags.get(name)
: regex_valid_component_name.test(name) : regex_valid_component_name.test(name) || (parser.loose && name.endsWith('.'))
? 'Component' ? 'Component'
: name === 'title' && parent_is_head(parser.stack) : name === 'title' && parent_is_head(parser.stack)
? 'TitleElement' ? 'TitleElement'

@ -174,13 +174,30 @@ function open(parser) {
if (parser.eat('(')) { if (parser.eat('(')) {
parser.allow_whitespace(); parser.allow_whitespace();
key = read_expression(parser); key = read_expression(parser, '(');
parser.allow_whitespace(); parser.allow_whitespace();
parser.eat(')', true); parser.eat(')', true);
parser.allow_whitespace(); parser.allow_whitespace();
} }
const matches = parser.eat('}', true, false);
if (!matches) {
// Parser may have read the `as` as part of the expression (e.g. in `{#each foo. as x}`)
if (parser.template.slice(parser.index - 4, parser.index) === ' as ') {
const prev_index = parser.index;
context = read_pattern(parser);
parser.eat('}', true); parser.eat('}', true);
expression = {
type: 'Identifier',
name: '',
start: expression.start,
end: prev_index - 4
};
} else {
parser.eat('}', true); // rerun to produce the parser error
}
}
/** @type {AST.EachBlock} */ /** @type {AST.EachBlock} */
const block = parser.append({ const block = parser.append({
@ -246,7 +263,39 @@ function open(parser) {
parser.fragments.push(block.pending); parser.fragments.push(block.pending);
} }
const matches = parser.eat('}', true, false);
// Parser may have read the `then/catch` as part of the expression (e.g. in `{#await foo. then x}`)
if (!matches) {
if (parser.template.slice(parser.index - 6, parser.index) === ' then ') {
const prev_index = parser.index;
block.value = read_pattern(parser);
parser.eat('}', true); parser.eat('}', true);
block.expression = {
type: 'Identifier',
name: '',
start: expression.start,
end: prev_index - 6
};
block.then = block.pending;
block.pending = null;
} else if (parser.template.slice(parser.index - 7, parser.index) === ' catch ') {
const prev_index = parser.index;
block.error = read_pattern(parser);
parser.eat('}', true);
block.expression = {
type: 'Identifier',
name: '',
start: expression.start,
end: prev_index - 7
};
block.catch = block.pending;
block.pending = null;
} else {
parser.eat('}', true); // rerun to produce the parser error
}
}
parser.stack.push(block); parser.stack.push(block);
return; return;

@ -4,6 +4,8 @@ const SQUARE_BRACKET_OPEN = '['.charCodeAt(0);
const SQUARE_BRACKET_CLOSE = ']'.charCodeAt(0); const SQUARE_BRACKET_CLOSE = ']'.charCodeAt(0);
const CURLY_BRACKET_OPEN = '{'.charCodeAt(0); const CURLY_BRACKET_OPEN = '{'.charCodeAt(0);
const CURLY_BRACKET_CLOSE = '}'.charCodeAt(0); const CURLY_BRACKET_CLOSE = '}'.charCodeAt(0);
const PARENTHESES_OPEN = '('.charCodeAt(0);
const PARENTHESES_CLOSE = ')'.charCodeAt(0);
/** @param {number} code */ /** @param {number} code */
export function is_bracket_open(code) { export function is_bracket_open(code) {
@ -34,6 +36,9 @@ export function get_bracket_close(open) {
if (open === CURLY_BRACKET_OPEN) { if (open === CURLY_BRACKET_OPEN) {
return CURLY_BRACKET_CLOSE; return CURLY_BRACKET_CLOSE;
} }
if (open === PARENTHESES_OPEN) {
return PARENTHESES_CLOSE;
}
} }
/** /**

@ -9,3 +9,15 @@
asd{a.}asd asd{a.}asd
{foo[bar.]} {foo[bar.]}
{#if x.}{/if}
{#each array as item (item.)}{/each}
{#each obj. as item}{/each}
{#await x.}{/await}
{#await x. then y}{/await}
{#await x. catch y}{/await}

@ -2,7 +2,7 @@
"html": { "html": {
"type": "Fragment", "type": "Fragment",
"start": 0, "start": 0,
"end": 164, "end": 324,
"children": [ "children": [
{ {
"type": "Element", "type": "Element",
@ -236,6 +236,272 @@
"end": 163, "end": 163,
"name": "" "name": ""
} }
},
{
"type": "Text",
"start": 164,
"end": 166,
"raw": "\n\n",
"data": "\n\n"
},
{
"type": "IfBlock",
"start": 166,
"end": 179,
"expression": {
"type": "Identifier",
"start": 171,
"end": 173,
"name": ""
},
"children": []
},
{
"type": "Text",
"start": 179,
"end": 181,
"raw": "\n\n",
"data": "\n\n"
},
{
"type": "EachBlock",
"start": 181,
"end": 217,
"children": [],
"context": {
"type": "Identifier",
"name": "item",
"start": 197,
"loc": {
"start": {
"line": 15,
"column": 16,
"character": 197
},
"end": {
"line": 15,
"column": 20,
"character": 201
}
},
"end": 201
},
"expression": {
"type": "Identifier",
"start": 188,
"end": 193,
"loc": {
"start": {
"line": 15,
"column": 7
},
"end": {
"line": 15,
"column": 12
}
},
"name": "array"
},
"key": {
"type": "Identifier",
"start": 203,
"end": 208,
"name": ""
}
},
{
"type": "Text",
"start": 217,
"end": 219,
"raw": "\n\n",
"data": "\n\n"
},
{
"type": "EachBlock",
"start": 219,
"end": 246,
"children": [],
"context": {
"type": "Identifier",
"name": "item",
"start": 234,
"loc": {
"start": {
"line": 17,
"column": 15,
"character": 234
},
"end": {
"line": 17,
"column": 19,
"character": 238
}
},
"end": 238
},
"expression": {
"type": "Identifier",
"name": "",
"start": 226,
"end": 230
}
},
{
"type": "Text",
"start": 246,
"end": 248,
"raw": "\n\n",
"data": "\n\n"
},
{
"type": "AwaitBlock",
"start": 248,
"end": 267,
"expression": {
"type": "Identifier",
"start": 256,
"end": 258,
"name": ""
},
"value": null,
"error": null,
"pending": {
"type": "PendingBlock",
"start": 259,
"end": 259,
"children": [],
"skip": false
},
"then": {
"type": "ThenBlock",
"start": null,
"end": null,
"children": [],
"skip": true
},
"catch": {
"type": "CatchBlock",
"start": null,
"end": null,
"children": [],
"skip": true
}
},
{
"type": "Text",
"start": 267,
"end": 269,
"raw": "\n\n",
"data": "\n\n"
},
{
"type": "AwaitBlock",
"start": 269,
"end": 295,
"expression": {
"type": "Identifier",
"name": "",
"start": 277,
"end": 279
},
"value": {
"type": "Identifier",
"name": "y",
"start": 285,
"loc": {
"start": {
"line": 21,
"column": 16,
"character": 285
},
"end": {
"line": 21,
"column": 17,
"character": 286
}
},
"end": 286
},
"error": null,
"pending": {
"type": "PendingBlock",
"start": null,
"end": null,
"children": [],
"skip": true
},
"then": {
"type": "ThenBlock",
"start": 287,
"end": 267,
"children": [],
"skip": false
},
"catch": {
"type": "CatchBlock",
"start": null,
"end": null,
"children": [],
"skip": true
}
},
{
"type": "Text",
"start": 295,
"end": 297,
"raw": "\n\n",
"data": "\n\n"
},
{
"type": "AwaitBlock",
"start": 297,
"end": 324,
"expression": {
"type": "Identifier",
"name": "",
"start": 305,
"end": 307
},
"value": null,
"error": {
"type": "Identifier",
"name": "y",
"start": 314,
"loc": {
"start": {
"line": 23,
"column": 17,
"character": 314
},
"end": {
"line": 23,
"column": 18,
"character": 315
}
},
"end": 315
},
"pending": {
"type": "PendingBlock",
"start": null,
"end": null,
"children": [],
"skip": true
},
"then": {
"type": "ThenBlock",
"start": null,
"end": null,
"children": [],
"skip": true
},
"catch": {
"type": "CatchBlock",
"start": 316,
"end": 295,
"children": [],
"skip": false
}
} }
] ]
} }

@ -10,6 +10,14 @@
<span <span
</div> </div>
<div>
<Comp.
</div>
<div>
<comp.
</div>
{#if foo} {#if foo}
<div> <div>
{/if} {/if}

@ -2,7 +2,7 @@
"html": { "html": {
"type": "Fragment", "type": "Fragment",
"start": 0, "start": 0,
"end": 160, "end": 204,
"children": [ "children": [
{ {
"type": "Element", "type": "Element",
@ -136,20 +136,82 @@
"data": "\n\n" "data": "\n\n"
}, },
{ {
"type": "IfBlock", "type": "Element",
"start": 74, "start": 74,
"end": 94,
"name": "div",
"attributes": [],
"children": [
{
"type": "Text",
"start": 79,
"end": 81,
"raw": "\n\t",
"data": "\n\t"
},
{
"type": "InlineComponent",
"start": 81,
"end": 88,
"name": "Comp.",
"attributes": [],
"children": []
}
]
},
{
"type": "Text",
"start": 94,
"end": 96, "end": 96,
"raw": "\n\n",
"data": "\n\n"
},
{
"type": "Element",
"start": 96,
"end": 116,
"name": "div",
"attributes": [],
"children": [
{
"type": "Text",
"start": 101,
"end": 103,
"raw": "\n\t",
"data": "\n\t"
},
{
"type": "InlineComponent",
"start": 103,
"end": 110,
"name": "comp.",
"attributes": [],
"children": []
}
]
},
{
"type": "Text",
"start": 116,
"end": 118,
"raw": "\n\n",
"data": "\n\n"
},
{
"type": "IfBlock",
"start": 118,
"end": 140,
"expression": { "expression": {
"type": "Identifier", "type": "Identifier",
"start": 79, "start": 123,
"end": 82, "end": 126,
"loc": { "loc": {
"start": { "start": {
"line": 13, "line": 21,
"column": 5 "column": 5
}, },
"end": { "end": {
"line": 13, "line": 21,
"column": 8 "column": 8
} }
}, },
@ -158,15 +220,15 @@
"children": [ "children": [
{ {
"type": "Element", "type": "Element",
"start": 85, "start": 129,
"end": 91, "end": 135,
"name": "div", "name": "div",
"attributes": [], "attributes": [],
"children": [ "children": [
{ {
"type": "Text", "type": "Text",
"start": 90, "start": 134,
"end": 91, "end": 135,
"raw": "\n", "raw": "\n",
"data": "\n" "data": "\n"
} }
@ -176,26 +238,26 @@
}, },
{ {
"type": "Text", "type": "Text",
"start": 96, "start": 140,
"end": 98, "end": 142,
"raw": "\n\n", "raw": "\n\n",
"data": "\n\n" "data": "\n\n"
}, },
{ {
"type": "IfBlock", "type": "IfBlock",
"start": 98, "start": 142,
"end": 130, "end": 174,
"expression": { "expression": {
"type": "Identifier", "type": "Identifier",
"start": 103, "start": 147,
"end": 106, "end": 150,
"loc": { "loc": {
"start": { "start": {
"line": 17, "line": 25,
"column": 5 "column": 5
}, },
"end": { "end": {
"line": 17, "line": 25,
"column": 8 "column": 8
} }
}, },
@ -204,31 +266,31 @@
"children": [ "children": [
{ {
"type": "InlineComponent", "type": "InlineComponent",
"start": 109, "start": 153,
"end": 125, "end": 169,
"name": "Comp", "name": "Comp",
"attributes": [ "attributes": [
{ {
"type": "Attribute", "type": "Attribute",
"start": 115, "start": 159,
"end": 124, "end": 168,
"name": "foo", "name": "foo",
"value": [ "value": [
{ {
"type": "MustacheTag", "type": "MustacheTag",
"start": 119, "start": 163,
"end": 124, "end": 168,
"expression": { "expression": {
"type": "Identifier", "type": "Identifier",
"start": 120, "start": 164,
"end": 123, "end": 167,
"loc": { "loc": {
"start": { "start": {
"line": 18, "line": 26,
"column": 12 "column": 12
}, },
"end": { "end": {
"line": 18, "line": 26,
"column": 15 "column": 15
} }
}, },
@ -244,36 +306,36 @@
}, },
{ {
"type": "Text", "type": "Text",
"start": 130, "start": 174,
"end": 132, "end": 176,
"raw": "\n\n", "raw": "\n\n",
"data": "\n\n" "data": "\n\n"
}, },
{ {
"type": "Element", "type": "Element",
"start": 132, "start": 176,
"end": 160, "end": 204,
"name": "div", "name": "div",
"attributes": [], "attributes": [],
"children": [ "children": [
{ {
"type": "Text", "type": "Text",
"start": 137, "start": 181,
"end": 138, "end": 182,
"raw": "\n", "raw": "\n",
"data": "\n" "data": "\n"
}, },
{ {
"type": "Element", "type": "Element",
"start": 138, "start": 182,
"end": 147, "end": 191,
"name": "p", "name": "p",
"attributes": [], "attributes": [],
"children": [ "children": [
{ {
"type": "Text", "type": "Text",
"start": 141, "start": 185,
"end": 143, "end": 187,
"raw": "hi", "raw": "hi",
"data": "hi" "data": "hi"
} }
@ -281,15 +343,15 @@
}, },
{ {
"type": "Text", "type": "Text",
"start": 147, "start": 191,
"end": 149, "end": 193,
"raw": "\n\n", "raw": "\n\n",
"data": "\n\n" "data": "\n\n"
}, },
{ {
"type": "Element", "type": "Element",
"start": 149, "start": 193,
"end": 160, "end": 204,
"name": "open-ended", "name": "open-ended",
"attributes": [], "attributes": [],
"children": [] "children": []

@ -9,3 +9,15 @@
asd{a.}asd asd{a.}asd
{foo[bar.]} {foo[bar.]}
{#if x.}{/if}
{#each array as item (item.)}{/each}
{#each obj. as item}{/each}
{#await x.}{/await}
{#await x. then y}{/await}
{#await x. catch y}{/await}

@ -2,7 +2,7 @@
"css": null, "css": null,
"js": [], "js": [],
"start": 0, "start": 0,
"end": 164, "end": 324,
"type": "Root", "type": "Root",
"fragment": { "fragment": {
"type": "Fragment", "type": "Fragment",
@ -247,6 +247,238 @@
"end": 163, "end": 163,
"name": "" "name": ""
} }
},
{
"type": "Text",
"start": 164,
"end": 166,
"raw": "\n\n",
"data": "\n\n"
},
{
"type": "IfBlock",
"elseif": false,
"start": 166,
"end": 179,
"test": {
"type": "Identifier",
"start": 171,
"end": 173,
"name": ""
},
"consequent": {
"type": "Fragment",
"nodes": []
},
"alternate": null
},
{
"type": "Text",
"start": 179,
"end": 181,
"raw": "\n\n",
"data": "\n\n"
},
{
"type": "EachBlock",
"start": 181,
"end": 217,
"expression": {
"type": "Identifier",
"start": 188,
"end": 193,
"loc": {
"start": {
"line": 15,
"column": 7
},
"end": {
"line": 15,
"column": 12
}
},
"name": "array"
},
"body": {
"type": "Fragment",
"nodes": []
},
"context": {
"type": "Identifier",
"name": "item",
"start": 197,
"loc": {
"start": {
"line": 15,
"column": 16,
"character": 197
},
"end": {
"line": 15,
"column": 20,
"character": 201
}
},
"end": 201
},
"key": {
"type": "Identifier",
"start": 203,
"end": 208,
"name": ""
}
},
{
"type": "Text",
"start": 217,
"end": 219,
"raw": "\n\n",
"data": "\n\n"
},
{
"type": "EachBlock",
"start": 219,
"end": 246,
"expression": {
"type": "Identifier",
"name": "",
"start": 226,
"end": 230
},
"body": {
"type": "Fragment",
"nodes": []
},
"context": {
"type": "Identifier",
"name": "item",
"start": 234,
"loc": {
"start": {
"line": 17,
"column": 15,
"character": 234
},
"end": {
"line": 17,
"column": 19,
"character": 238
}
},
"end": 238
}
},
{
"type": "Text",
"start": 246,
"end": 248,
"raw": "\n\n",
"data": "\n\n"
},
{
"type": "AwaitBlock",
"start": 248,
"end": 267,
"expression": {
"type": "Identifier",
"start": 256,
"end": 258,
"name": ""
},
"value": null,
"error": null,
"pending": {
"type": "Fragment",
"nodes": []
},
"then": null,
"catch": null
},
{
"type": "Text",
"start": 267,
"end": 269,
"raw": "\n\n",
"data": "\n\n"
},
{
"type": "AwaitBlock",
"start": 269,
"end": 295,
"expression": {
"type": "Identifier",
"name": "",
"start": 277,
"end": 279
},
"value": {
"type": "Identifier",
"name": "y",
"start": 285,
"loc": {
"start": {
"line": 21,
"column": 16,
"character": 285
},
"end": {
"line": 21,
"column": 17,
"character": 286
}
},
"end": 286
},
"error": null,
"pending": null,
"then": {
"type": "Fragment",
"nodes": []
},
"catch": null
},
{
"type": "Text",
"start": 295,
"end": 297,
"raw": "\n\n",
"data": "\n\n"
},
{
"type": "AwaitBlock",
"start": 297,
"end": 324,
"expression": {
"type": "Identifier",
"name": "",
"start": 305,
"end": 307
},
"value": null,
"error": {
"type": "Identifier",
"name": "y",
"start": 314,
"loc": {
"start": {
"line": 23,
"column": 17,
"character": 314
},
"end": {
"line": 23,
"column": 18,
"character": 315
}
},
"end": 315
},
"pending": null,
"then": null,
"catch": {
"type": "Fragment",
"nodes": []
}
} }
] ]
}, },

@ -10,6 +10,14 @@
<span <span
</div> </div>
<div>
<Comp.
</div>
<div>
<comp.
</div>
{#if foo} {#if foo}
<div> <div>
{/if} {/if}

@ -2,7 +2,7 @@
"css": null, "css": null,
"js": [], "js": [],
"start": 0, "start": 0,
"end": 160, "end": 204,
"type": "Root", "type": "Root",
"fragment": { "fragment": {
"type": "Fragment", "type": "Fragment",
@ -155,21 +155,95 @@
"data": "\n\n" "data": "\n\n"
}, },
{ {
"type": "IfBlock", "type": "RegularElement",
"elseif": false,
"start": 74, "start": 74,
"end": 94,
"name": "div",
"attributes": [],
"fragment": {
"type": "Fragment",
"nodes": [
{
"type": "Text",
"start": 79,
"end": 81,
"raw": "\n\t",
"data": "\n\t"
},
{
"type": "Component",
"start": 81,
"end": 88,
"name": "Comp.",
"attributes": [],
"fragment": {
"type": "Fragment",
"nodes": []
}
}
]
}
},
{
"type": "Text",
"start": 94,
"end": 96, "end": 96,
"raw": "\n\n",
"data": "\n\n"
},
{
"type": "RegularElement",
"start": 96,
"end": 116,
"name": "div",
"attributes": [],
"fragment": {
"type": "Fragment",
"nodes": [
{
"type": "Text",
"start": 101,
"end": 103,
"raw": "\n\t",
"data": "\n\t"
},
{
"type": "Component",
"start": 103,
"end": 110,
"name": "comp.",
"attributes": [],
"fragment": {
"type": "Fragment",
"nodes": []
}
}
]
}
},
{
"type": "Text",
"start": 116,
"end": 118,
"raw": "\n\n",
"data": "\n\n"
},
{
"type": "IfBlock",
"elseif": false,
"start": 118,
"end": 140,
"test": { "test": {
"type": "Identifier", "type": "Identifier",
"start": 79, "start": 123,
"end": 82, "end": 126,
"loc": { "loc": {
"start": { "start": {
"line": 13, "line": 21,
"column": 5 "column": 5
}, },
"end": { "end": {
"line": 13, "line": 21,
"column": 8 "column": 8
} }
}, },
@ -180,15 +254,15 @@
"nodes": [ "nodes": [
{ {
"type": "Text", "type": "Text",
"start": 83, "start": 127,
"end": 85, "end": 129,
"raw": "\n\t", "raw": "\n\t",
"data": "\n\t" "data": "\n\t"
}, },
{ {
"type": "RegularElement", "type": "RegularElement",
"start": 85, "start": 129,
"end": 91, "end": 135,
"name": "div", "name": "div",
"attributes": [], "attributes": [],
"fragment": { "fragment": {
@ -196,8 +270,8 @@
"nodes": [ "nodes": [
{ {
"type": "Text", "type": "Text",
"start": 90, "start": 134,
"end": 91, "end": 135,
"raw": "\n", "raw": "\n",
"data": "\n" "data": "\n"
} }
@ -210,27 +284,27 @@
}, },
{ {
"type": "Text", "type": "Text",
"start": 96, "start": 140,
"end": 98, "end": 142,
"raw": "\n\n", "raw": "\n\n",
"data": "\n\n" "data": "\n\n"
}, },
{ {
"type": "IfBlock", "type": "IfBlock",
"elseif": false, "elseif": false,
"start": 98, "start": 142,
"end": 130, "end": 174,
"test": { "test": {
"type": "Identifier", "type": "Identifier",
"start": 103, "start": 147,
"end": 106, "end": 150,
"loc": { "loc": {
"start": { "start": {
"line": 17, "line": 25,
"column": 5 "column": 5
}, },
"end": { "end": {
"line": 17, "line": 25,
"column": 8 "column": 8
} }
}, },
@ -241,37 +315,37 @@
"nodes": [ "nodes": [
{ {
"type": "Text", "type": "Text",
"start": 107, "start": 151,
"end": 109, "end": 153,
"raw": "\n\t", "raw": "\n\t",
"data": "\n\t" "data": "\n\t"
}, },
{ {
"type": "Component", "type": "Component",
"start": 109, "start": 153,
"end": 125, "end": 169,
"name": "Comp", "name": "Comp",
"attributes": [ "attributes": [
{ {
"type": "Attribute", "type": "Attribute",
"start": 115, "start": 159,
"end": 124, "end": 168,
"name": "foo", "name": "foo",
"value": { "value": {
"type": "ExpressionTag", "type": "ExpressionTag",
"start": 119, "start": 163,
"end": 124, "end": 168,
"expression": { "expression": {
"type": "Identifier", "type": "Identifier",
"start": 120, "start": 164,
"end": 123, "end": 167,
"loc": { "loc": {
"start": { "start": {
"line": 18, "line": 26,
"column": 12 "column": 12
}, },
"end": { "end": {
"line": 18, "line": 26,
"column": 15 "column": 15
} }
}, },
@ -291,15 +365,15 @@
}, },
{ {
"type": "Text", "type": "Text",
"start": 130, "start": 174,
"end": 132, "end": 176,
"raw": "\n\n", "raw": "\n\n",
"data": "\n\n" "data": "\n\n"
}, },
{ {
"type": "RegularElement", "type": "RegularElement",
"start": 132, "start": 176,
"end": 160, "end": 204,
"name": "div", "name": "div",
"attributes": [], "attributes": [],
"fragment": { "fragment": {
@ -307,15 +381,15 @@
"nodes": [ "nodes": [
{ {
"type": "Text", "type": "Text",
"start": 137, "start": 181,
"end": 138, "end": 182,
"raw": "\n", "raw": "\n",
"data": "\n" "data": "\n"
}, },
{ {
"type": "RegularElement", "type": "RegularElement",
"start": 138, "start": 182,
"end": 147, "end": 191,
"name": "p", "name": "p",
"attributes": [], "attributes": [],
"fragment": { "fragment": {
@ -323,8 +397,8 @@
"nodes": [ "nodes": [
{ {
"type": "Text", "type": "Text",
"start": 141, "start": 185,
"end": 143, "end": 187,
"raw": "hi", "raw": "hi",
"data": "hi" "data": "hi"
} }
@ -333,15 +407,15 @@
}, },
{ {
"type": "Text", "type": "Text",
"start": 147, "start": 191,
"end": 149, "end": 193,
"raw": "\n\n", "raw": "\n\n",
"data": "\n\n" "data": "\n\n"
}, },
{ {
"type": "RegularElement", "type": "RegularElement",
"start": 149, "start": 193,
"end": 160, "end": 204,
"name": "open-ended", "name": "open-ended",
"attributes": [], "attributes": [],
"fragment": { "fragment": {

Loading…
Cancel
Save