diff --git a/.changeset/poor-hats-design.md b/.changeset/poor-hats-design.md new file mode 100644 index 0000000000..3bc33931ba --- /dev/null +++ b/.changeset/poor-hats-design.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: return ast from `compile` (like Svelte 4 does) diff --git a/packages/svelte/src/compiler/index.js b/packages/svelte/src/compiler/index.js index 547901ea7b..a35f47adbc 100644 --- a/packages/svelte/src/compiler/index.js +++ b/packages/svelte/src/compiler/index.js @@ -44,6 +44,7 @@ export function compile(source, options) { const analysis = analyze_component(parsed, source, combined_options); const result = transform_component(analysis, source, combined_options); + result.ast = to_public_ast(source, parsed, options.modernAst); return result; } catch (e) { if (e instanceof CompileError) { @@ -121,7 +122,16 @@ export function parse(source, options = {}) { throw e; } - if (options.modern) { + return to_public_ast(source, ast, options.modern); +} + +/** + * @param {string} source + * @param {import('#compiler').Root} ast + * @param {boolean | undefined} modern + */ +function to_public_ast(source, ast, modern) { + if (modern) { // remove things that we don't want to treat as public API return walk(ast, null, { _(node, { next }) { diff --git a/packages/svelte/src/compiler/legacy.js b/packages/svelte/src/compiler/legacy.js index 0593c77acd..d5c51d0d57 100644 --- a/packages/svelte/src/compiler/legacy.js +++ b/packages/svelte/src/compiler/legacy.js @@ -141,29 +141,37 @@ export function convert(source, ast) { }; if (node.pending) { - const first = /** @type {import('#compiler').BaseNode} */ (node.pending.nodes.at(0)); - const last = /** @type {import('#compiler').BaseNode} */ (node.pending.nodes.at(-1)); + const first = node.pending.nodes.at(0); + const last = node.pending.nodes.at(-1); - pendingblock.start = first.start; - pendingblock.end = last.end; + pendingblock.start = first?.start ?? source.indexOf('}', node.expression.end) + 1; + pendingblock.end = last?.end ?? pendingblock.start; pendingblock.skip = false; } if (node.then) { - const first = /** @type {import('#compiler').BaseNode} */ (node.then.nodes.at(0)); - const last = /** @type {import('#compiler').BaseNode} */ (node.then.nodes.at(-1)); + const first = node.then.nodes.at(0); + const last = node.then.nodes.at(-1); - thenblock.start = pendingblock.end ?? first.start; - thenblock.end = last.end; + thenblock.start = + pendingblock.end ?? first?.start ?? source.indexOf('}', node.expression.end) + 1; + thenblock.end = + last?.end ?? source.lastIndexOf('}', pendingblock.end ?? node.expression.end) + 1; thenblock.skip = false; } if (node.catch) { - const first = /** @type {import('#compiler').BaseNode} */ (node.catch.nodes.at(0)); - const last = /** @type {import('#compiler').BaseNode} */ (node.catch.nodes.at(-1)); - - catchblock.start = thenblock.end ?? pendingblock.end ?? first.start; - catchblock.end = last.end; + const first = node.catch.nodes.at(0); + const last = node.catch.nodes.at(-1); + + catchblock.start = + thenblock.end ?? + pendingblock.end ?? + first?.start ?? + source.indexOf('}', node.expression.end) + 1; + catchblock.end = + last?.end ?? + source.lastIndexOf('}', thenblock.end ?? pendingblock.end ?? node.expression.end) + 1; catchblock.skip = false; } diff --git a/packages/svelte/src/compiler/phases/3-transform/index.js b/packages/svelte/src/compiler/phases/3-transform/index.js index 708125f19e..2334b3318d 100644 --- a/packages/svelte/src/compiler/phases/3-transform/index.js +++ b/packages/svelte/src/compiler/phases/3-transform/index.js @@ -20,7 +20,8 @@ export function transform_component(analysis, source, options) { warnings: transform_warnings(source, options.filename, analysis.warnings), metadata: { runes: analysis.runes - } + }, + ast: /** @type {any} */ (null) // set afterwards }; } @@ -62,7 +63,8 @@ export function transform_component(analysis, source, options) { warnings: transform_warnings(source, options.filename, analysis.warnings), // TODO apply preprocessor sourcemap metadata: { runes: analysis.runes - } + }, + ast: /** @type {any} */ (null) // set afterwards }; } @@ -80,7 +82,8 @@ export function transform_module(analysis, source, options) { warnings: transform_warnings(source, analysis.name, analysis.warnings), metadata: { runes: true - } + }, + ast: /** @type {any} */ (null) // set afterwards }; } @@ -105,7 +108,8 @@ export function transform_module(analysis, source, options) { warnings: transform_warnings(source, analysis.name, analysis.warnings), metadata: { runes: true - } + }, + ast: /** @type {any} */ (null) // set afterwards }; } diff --git a/packages/svelte/src/compiler/types/index.d.ts b/packages/svelte/src/compiler/types/index.d.ts index e244520e9c..d94a80a77c 100644 --- a/packages/svelte/src/compiler/types/index.d.ts +++ b/packages/svelte/src/compiler/types/index.d.ts @@ -46,6 +46,8 @@ export interface CompileResult { */ runes: boolean; }; + /** The AST */ + ast: any; } export interface Warning { @@ -184,6 +186,13 @@ export interface CompileOptions extends ModuleCompileOptions { * @default false */ hmr?: boolean; + /** + * If `true`, returns the modern version of the AST. + * Will become `true` by default in Svelte 6, and the option will be removed in Svelte 7. + * + * @default false + */ + modernAst?: boolean; } export interface ModuleCompileOptions { diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index 95c3e6395e..a47745a63a 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -541,6 +541,8 @@ declare module 'svelte/compiler' { */ runes: boolean; }; + /** The AST */ + ast: any; } interface Warning { @@ -675,6 +677,13 @@ declare module 'svelte/compiler' { * @default false */ hmr?: boolean; + /** + * If `true`, returns the modern version of the AST. + * Will become `true` by default in Svelte 6, and the option will be removed in Svelte 7. + * + * @default false + */ + modernAst?: boolean; } interface ModuleCompileOptions { @@ -2476,6 +2485,13 @@ declare module 'svelte/types/compiler/interfaces' { * @default false */ hmr?: boolean; + /** + * If `true`, returns the modern version of the AST. + * Will become `true` by default in Svelte 6, and the option will be removed in Svelte 7. + * + * @default false + */ + modernAst?: boolean; } interface ModuleCompileOptions {