diff --git a/.changeset/serious-crabs-punch.md b/.changeset/serious-crabs-punch.md
new file mode 100644
index 0000000000..850f0d03a7
--- /dev/null
+++ b/.changeset/serious-crabs-punch.md
@@ -0,0 +1,5 @@
+---
+"svelte": patch
+---
+
+feat: include `script` and `svelte:options` attributes in ast
diff --git a/packages/svelte/src/compiler/legacy.js b/packages/svelte/src/compiler/legacy.js
index d5c51d0d57..49d2f78260 100644
--- a/packages/svelte/src/compiler/legacy.js
+++ b/packages/svelte/src/compiler/legacy.js
@@ -86,11 +86,15 @@ export function convert(source, ast) {
if (instance) {
// @ts-ignore
delete instance.parent;
+ // @ts-ignore
+ delete instance.attributes;
}
if (module) {
// @ts-ignore
delete module.parent;
+ // @ts-ignore
+ delete module.attributes;
}
return {
diff --git a/packages/svelte/src/compiler/phases/1-parse/read/options.js b/packages/svelte/src/compiler/phases/1-parse/read/options.js
index 5d4f58868f..c9262c54a8 100644
--- a/packages/svelte/src/compiler/phases/1-parse/read/options.js
+++ b/packages/svelte/src/compiler/phases/1-parse/read/options.js
@@ -11,7 +11,9 @@ export default function read_options(node) {
/** @type {import('#compiler').SvelteOptions} */
const component_options = {
start: node.start,
- end: node.end
+ end: node.end,
+ // @ts-ignore
+ attributes: node.attributes
};
if (!node) {
diff --git a/packages/svelte/src/compiler/phases/1-parse/read/script.js b/packages/svelte/src/compiler/phases/1-parse/read/script.js
index 4761052e1c..cd9129e8b5 100644
--- a/packages/svelte/src/compiler/phases/1-parse/read/script.js
+++ b/packages/svelte/src/compiler/phases/1-parse/read/script.js
@@ -63,6 +63,8 @@ export function read_script(parser, start, attributes) {
end: parser.index,
context: get_context(attributes),
content: ast,
- parent: null
+ parent: null,
+ // @ts-ignore
+ attributes: attributes
};
}
diff --git a/packages/svelte/src/compiler/types/template.d.ts b/packages/svelte/src/compiler/types/template.d.ts
index e42a34c0aa..4ddee3096f 100644
--- a/packages/svelte/src/compiler/types/template.d.ts
+++ b/packages/svelte/src/compiler/types/template.d.ts
@@ -93,6 +93,7 @@ export interface SvelteOptions {
*/
extend?: ArrowFunctionExpression | Identifier;
};
+ attributes: Attribute[];
}
/** Static text */
@@ -467,6 +468,7 @@ export interface Script extends BaseNode {
type: 'Script';
context: string;
content: Program;
+ attributes: Attribute[];
}
declare module 'estree' {
diff --git a/packages/svelte/tests/parser-modern/samples/comment-before-script/output.json b/packages/svelte/tests/parser-modern/samples/comment-before-script/output.json
index 794e80f66f..e7e5dfe244 100644
--- a/packages/svelte/tests/parser-modern/samples/comment-before-script/output.json
+++ b/packages/svelte/tests/parser-modern/samples/comment-before-script/output.json
@@ -133,6 +133,23 @@
"value": "should not error out"
}
]
- }
+ },
+ "attributes": [
+ {
+ "type": "Attribute",
+ "start": 36,
+ "end": 45,
+ "name": "lang",
+ "value": [
+ {
+ "start": 42,
+ "end": 44,
+ "type": "Text",
+ "raw": "ts",
+ "data": "ts"
+ }
+ ]
+ }
+ ]
}
}
diff --git a/packages/svelte/tests/parser-modern/samples/options/input.svelte b/packages/svelte/tests/parser-modern/samples/options/input.svelte
new file mode 100644
index 0000000000..9e8253c50c
--- /dev/null
+++ b/packages/svelte/tests/parser-modern/samples/options/input.svelte
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/packages/svelte/tests/parser-modern/samples/options/output.json b/packages/svelte/tests/parser-modern/samples/options/output.json
new file mode 100644
index 0000000000..398c178cb4
--- /dev/null
+++ b/packages/svelte/tests/parser-modern/samples/options/output.json
@@ -0,0 +1,208 @@
+{
+ "css": null,
+ "js": [],
+ "start": 0,
+ "end": 112,
+ "type": "Root",
+ "fragment": {
+ "type": "Fragment",
+ "nodes": [
+ {
+ "type": "Text",
+ "start": 65,
+ "end": 67,
+ "raw": "\n\n",
+ "data": "\n\n"
+ },
+ {
+ "type": "Text",
+ "start": 112,
+ "end": 114,
+ "raw": "\n\n",
+ "data": "\n\n"
+ }
+ ],
+ "transparent": false
+ },
+ "options": {
+ "start": 0,
+ "end": 65,
+ "attributes": [
+ {
+ "type": "Attribute",
+ "start": 16,
+ "end": 49,
+ "name": "customElement",
+ "value": [
+ {
+ "start": 31,
+ "end": 48,
+ "type": "Text",
+ "raw": "my-custom-element",
+ "data": "my-custom-element",
+ "parent": null
+ }
+ ],
+ "parent": null,
+ "metadata": {
+ "dynamic": false,
+ "delegated": null
+ }
+ },
+ {
+ "type": "Attribute",
+ "start": 50,
+ "end": 62,
+ "name": "runes",
+ "value": [
+ {
+ "type": "ExpressionTag",
+ "start": 56,
+ "end": 62,
+ "expression": {
+ "type": "Literal",
+ "start": 57,
+ "end": 61,
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 57
+ },
+ "end": {
+ "line": 1,
+ "column": 61
+ }
+ },
+ "value": true,
+ "raw": "true"
+ },
+ "parent": null,
+ "metadata": {
+ "contains_call_expression": false,
+ "dynamic": false
+ }
+ }
+ ],
+ "parent": null,
+ "metadata": {
+ "dynamic": false,
+ "delegated": null
+ }
+ }
+ ],
+ "customElement": {
+ "tag": "my-custom-element"
+ },
+ "runes": true
+ },
+ "module": {
+ "type": "Script",
+ "start": 67,
+ "end": 112,
+ "context": "module",
+ "content": {
+ "type": "Program",
+ "start": 102,
+ "end": 103,
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 0
+ },
+ "end": {
+ "line": 4,
+ "column": 0
+ }
+ },
+ "body": [],
+ "sourceType": "module"
+ },
+ "attributes": [
+ {
+ "type": "Attribute",
+ "start": 75,
+ "end": 91,
+ "name": "context",
+ "value": [
+ {
+ "start": 84,
+ "end": 90,
+ "type": "Text",
+ "raw": "module",
+ "data": "module"
+ }
+ ]
+ },
+ {
+ "type": "Attribute",
+ "start": 92,
+ "end": 101,
+ "name": "lang",
+ "value": [
+ {
+ "start": 98,
+ "end": 100,
+ "type": "Text",
+ "raw": "ts",
+ "data": "ts"
+ }
+ ]
+ }
+ ]
+ },
+ "instance": {
+ "type": "Script",
+ "start": 114,
+ "end": 179,
+ "context": "default",
+ "content": {
+ "type": "Program",
+ "start": 169,
+ "end": 170,
+ "loc": {
+ "start": {
+ "line": 1,
+ "column": 0
+ },
+ "end": {
+ "line": 7,
+ "column": 0
+ }
+ },
+ "body": [],
+ "sourceType": "module"
+ },
+ "attributes": [
+ {
+ "type": "Attribute",
+ "start": 122,
+ "end": 131,
+ "name": "lang",
+ "value": [
+ {
+ "start": 128,
+ "end": 130,
+ "type": "Text",
+ "raw": "ts",
+ "data": "ts"
+ }
+ ]
+ },
+ {
+ "type": "Attribute",
+ "start": 132,
+ "end": 168,
+ "name": "generics",
+ "value": [
+ {
+ "start": 142,
+ "end": 167,
+ "type": "Text",
+ "raw": "T extends { foo: number }",
+ "data": "T extends { foo: number }"
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/packages/svelte/tests/parser-modern/samples/snippets/output.json b/packages/svelte/tests/parser-modern/samples/snippets/output.json
index a1b96c588c..ac9aa58067 100644
--- a/packages/svelte/tests/parser-modern/samples/snippets/output.json
+++ b/packages/svelte/tests/parser-modern/samples/snippets/output.json
@@ -206,6 +206,23 @@
},
"body": [],
"sourceType": "module"
- }
+ },
+ "attributes": [
+ {
+ "type": "Attribute",
+ "start": 8,
+ "end": 17,
+ "name": "lang",
+ "value": [
+ {
+ "start": 14,
+ "end": 16,
+ "type": "Text",
+ "raw": "ts",
+ "data": "ts"
+ }
+ ]
+ }
+ ]
}
}
diff --git a/packages/svelte/tests/parser-modern/samples/typescript-in-event-handler/output.json b/packages/svelte/tests/parser-modern/samples/typescript-in-event-handler/output.json
index a23219770b..6f219c7311 100644
--- a/packages/svelte/tests/parser-modern/samples/typescript-in-event-handler/output.json
+++ b/packages/svelte/tests/parser-modern/samples/typescript-in-event-handler/output.json
@@ -477,6 +477,23 @@
}
],
"sourceType": "module"
- }
+ },
+ "attributes": [
+ {
+ "type": "Attribute",
+ "start": 8,
+ "end": 17,
+ "name": "lang",
+ "value": [
+ {
+ "start": 14,
+ "end": 16,
+ "type": "Text",
+ "raw": "ts",
+ "data": "ts"
+ }
+ ]
+ }
+ ]
}
}
diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts
index d03a7b553d..900bee5a76 100644
--- a/packages/svelte/types/index.d.ts
+++ b/packages/svelte/types/index.d.ts
@@ -1316,6 +1316,7 @@ declare module 'svelte/compiler' {
*/
extend?: ArrowFunctionExpression | Identifier;
};
+ attributes: Attribute[];
}
/** Static text */
@@ -1690,6 +1691,7 @@ declare module 'svelte/compiler' {
type: 'Script';
context: string;
content: Program;
+ attributes: Attribute[];
}
/**
* The result of a preprocessor run. If the preprocessor does not return a result, it is assumed that the code is unchanged.