diff --git a/packages/svelte/src/compiler/phases/1-parse/state/tag.js b/packages/svelte/src/compiler/phases/1-parse/state/tag.js index f9df97a3c1..0cfce31d6d 100644 --- a/packages/svelte/src/compiler/phases/1-parse/state/tag.js +++ b/packages/svelte/src/compiler/phases/1-parse/state/tag.js @@ -573,14 +573,7 @@ function special(parser) { type: 'ConstTag', start, end: parser.index, - expression: { - type: 'AssignmentExpression', - start: (declaration.start ?? 0) + CONST_LENGTH, - end: declaration.end ?? 0, - operator: '=', - left: declaration.declarations[0].id, - right: declaration.declarations[0].init - } + declaration }) ); } diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js index 207bc6faf0..442c196384 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js @@ -1611,19 +1611,20 @@ export const template_visitors = { ); }, ConstTag(node, { state, visit }) { + const declaration = node.declaration.declarations[0]; // TODO we can almost certainly share some code with $derived(...) - if (node.expression.left.type === 'Identifier') { + if (declaration.id.type === 'Identifier') { state.init.push( b.const( - node.expression.left, + declaration.id, b.call( '$.derived', - b.thunk(/** @type {import('estree').Expression} */ (visit(node.expression.right))) + b.thunk(/** @type {import('estree').Expression} */ (visit(declaration.init))) ) ) ); } else { - const identifiers = extract_identifiers(node.expression.left); + const identifiers = extract_identifiers(declaration.id); const tmp = b.id(state.scope.generate('computed_const')); // Make all identifiers that are declared within the following computed regular @@ -1639,8 +1640,8 @@ export const template_visitors = { [], b.block([ b.const( - /** @type {import('estree').Pattern} */ (visit(node.expression.left)), - /** @type {import('estree').Expression} */ (visit(node.expression.right)) + /** @type {import('estree').Pattern} */ (visit(declaration.id)), + /** @type {import('estree').Expression} */ (visit(declaration.init)) ), b.return(b.object(identifiers.map((node) => b.prop('init', node, node)))) ]) diff --git a/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js b/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js index 78356d8f5f..aff250ad5b 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js @@ -1049,8 +1049,9 @@ const template_visitors = { state.template.push(t_expression(id)); }, ConstTag(node, { state, visit }) { - const pattern = /** @type {import('estree').Pattern} */ (visit(node.expression.left)); - const init = /** @type {import('estree').Expression} */ (visit(node.expression.right)); + const declaration = node.declaration.declarations[0]; + const pattern = /** @type {import('estree').Pattern} */ (visit(declaration.id)); + const init = /** @type {import('estree').Expression} */ (visit(declaration.init)); state.init.push(b.declaration('const', pattern, init)); }, DebugTag(node, { state, visit }) { diff --git a/packages/svelte/src/compiler/phases/scope.js b/packages/svelte/src/compiler/phases/scope.js index 95c192d4d4..c4299b015e 100644 --- a/packages/svelte/src/compiler/phases/scope.js +++ b/packages/svelte/src/compiler/phases/scope.js @@ -437,7 +437,8 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) { next(); }, - VariableDeclaration(node, { state, next }) { + VariableDeclaration(node, { state, path, next }) { + const is_parent_const_tag = path.at(-1)?.type === 'ConstTag'; for (const declarator of node.declarations) { /** @type {import('#compiler').Binding[]} */ const bindings = []; @@ -445,7 +446,12 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) { state.scope.declarators.set(declarator, bindings); for (const id of extract_identifiers(declarator.id)) { - const binding = state.scope.declare(id, 'normal', node.kind, declarator.init); + const binding = state.scope.declare( + id, + is_parent_const_tag ? 'derived' : 'normal', + node.kind, + declarator.init + ); bindings.push(binding); } } @@ -594,7 +600,8 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) { }, ConstTag(node, { state, next }) { - for (const identifier of extract_identifiers(node.expression.left)) { + const declaration = node.declaration.declarations[0]; + for (const identifier of extract_identifiers(declaration.id)) { state.scope.declare( /** @type {import('estree').Identifier} */ (identifier), 'derived', diff --git a/packages/svelte/src/compiler/types/template.d.ts b/packages/svelte/src/compiler/types/template.d.ts index 98c51b6ad0..f5e55f4829 100644 --- a/packages/svelte/src/compiler/types/template.d.ts +++ b/packages/svelte/src/compiler/types/template.d.ts @@ -2,7 +2,8 @@ import type { Binding } from '#compiler'; import type { ArrayExpression, ArrowFunctionExpression, - AssignmentExpression, + VariableDeclaration, + VariableDeclarator, Expression, FunctionDeclaration, FunctionExpression, @@ -11,8 +12,7 @@ import type { Node, ObjectExpression, Pattern, - Program, - VariableDeclaration + Program } from 'estree'; export interface BaseNode { @@ -131,7 +131,9 @@ export interface Comment extends BaseNode { /** A `{@const ...}` tag */ export interface ConstTag extends BaseNode { type: 'ConstTag'; - expression: AssignmentExpression; + declaration: VariableDeclaration & { + declarations: [VariableDeclarator & { id: Identifier, init: Expression } ] + }; } /** A `{@debug ...}` tag */