From 531e75d314075506748fb01457b396bf7765d3b0 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 19 Dec 2024 23:41:33 -0500 Subject: [PATCH] parse attachments --- .../compiler/phases/1-parse/state/element.js | 20 ++- .../svelte/src/compiler/types/template.d.ts | 8 +- .../samples/attachments/input.svelte | 1 + .../samples/attachments/output.json | 141 ++++++++++++++++++ 4 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 packages/svelte/tests/parser-modern/samples/attachments/input.svelte create mode 100644 packages/svelte/tests/parser-modern/samples/attachments/output.json 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 66946a8f8d..a79ff5f206 100644 --- a/packages/svelte/src/compiler/phases/1-parse/state/element.js +++ b/packages/svelte/src/compiler/phases/1-parse/state/element.js @@ -480,7 +480,7 @@ function read_static_attribute(parser) { /** * @param {Parser} parser - * @returns {AST.Attribute | AST.SpreadAttribute | AST.Directive | null} + * @returns {AST.Attribute | AST.SpreadAttribute | AST.Directive | AST.UseTag | null} */ function read_attribute(parser) { const start = parser.index; @@ -488,6 +488,24 @@ function read_attribute(parser) { if (parser.eat('{')) { parser.allow_whitespace(); + if (parser.eat('@use')) { + parser.require_whitespace(); + + const expression = read_expression(parser); + parser.allow_whitespace(); + parser.eat('}', true); + + /** @type {AST.UseTag} */ + const use = { + type: 'UseTag', + start, + end: parser.index, + expression + }; + + return use; + } + if (parser.eat('...')) { const expression = read_expression(parser); diff --git a/packages/svelte/src/compiler/types/template.d.ts b/packages/svelte/src/compiler/types/template.d.ts index 97a25df4a7..6b4c7d6d52 100644 --- a/packages/svelte/src/compiler/types/template.d.ts +++ b/packages/svelte/src/compiler/types/template.d.ts @@ -174,6 +174,12 @@ export namespace AST { }; } + /** A `{@use foo(...)} tag */ + export interface UseTag extends BaseNode { + type: 'UseTag'; + expression: Expression; + } + /** An `animate:` directive */ export interface AnimateDirective extends BaseNode { type: 'AnimateDirective'; @@ -273,7 +279,7 @@ export namespace AST { interface BaseElement extends BaseNode { name: string; - attributes: Array; + attributes: Array; fragment: Fragment; } diff --git a/packages/svelte/tests/parser-modern/samples/attachments/input.svelte b/packages/svelte/tests/parser-modern/samples/attachments/input.svelte new file mode 100644 index 0000000000..042bcbb98b --- /dev/null +++ b/packages/svelte/tests/parser-modern/samples/attachments/input.svelte @@ -0,0 +1 @@ +
{}} {@use (node) => {}}>
diff --git a/packages/svelte/tests/parser-modern/samples/attachments/output.json b/packages/svelte/tests/parser-modern/samples/attachments/output.json new file mode 100644 index 0000000000..68ee771072 --- /dev/null +++ b/packages/svelte/tests/parser-modern/samples/attachments/output.json @@ -0,0 +1,141 @@ +{ + "css": null, + "js": [], + "start": 0, + "end": 51, + "type": "Root", + "fragment": { + "type": "Fragment", + "nodes": [ + { + "type": "RegularElement", + "start": 0, + "end": 51, + "name": "div", + "attributes": [ + { + "type": "UseTag", + "start": 5, + "end": 24, + "expression": { + "type": "ArrowFunctionExpression", + "start": 11, + "end": 23, + "loc": { + "start": { + "line": 1, + "column": 11 + }, + "end": { + "line": 1, + "column": 23 + } + }, + "id": null, + "expression": false, + "generator": false, + "async": false, + "params": [ + { + "type": "Identifier", + "start": 12, + "end": 16, + "loc": { + "start": { + "line": 1, + "column": 12 + }, + "end": { + "line": 1, + "column": 16 + } + }, + "name": "node" + } + ], + "body": { + "type": "BlockStatement", + "start": 21, + "end": 23, + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 1, + "column": 23 + } + }, + "body": [] + } + } + }, + { + "type": "UseTag", + "start": 25, + "end": 44, + "expression": { + "type": "ArrowFunctionExpression", + "start": 31, + "end": 43, + "loc": { + "start": { + "line": 1, + "column": 31 + }, + "end": { + "line": 1, + "column": 43 + } + }, + "id": null, + "expression": false, + "generator": false, + "async": false, + "params": [ + { + "type": "Identifier", + "start": 32, + "end": 36, + "loc": { + "start": { + "line": 1, + "column": 32 + }, + "end": { + "line": 1, + "column": 36 + } + }, + "name": "node" + } + ], + "body": { + "type": "BlockStatement", + "start": 41, + "end": 43, + "loc": { + "start": { + "line": 1, + "column": 41 + }, + "end": { + "line": 1, + "column": 43 + } + }, + "body": [] + } + } + } + ], + "fragment": { + "type": "Fragment", + "nodes": [] + } + } + ] + }, + "options": null +} \ No newline at end of file