From ad5887424197aaab1dfd9d80fd80757df4bef1a3 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Tue, 2 Jan 2024 22:19:17 +0000 Subject: [PATCH 1/4] fix: bail-out event handler referencing each index --- .changeset/tall-garlics-try.md | 5 +++++ packages/svelte/src/compiler/phases/2-analyze/index.js | 4 ++++ packages/svelte/src/compiler/phases/scope.js | 6 +++--- packages/svelte/src/compiler/types/index.d.ts | 4 ++-- 4 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 .changeset/tall-garlics-try.md diff --git a/.changeset/tall-garlics-try.md b/.changeset/tall-garlics-try.md new file mode 100644 index 000000000000..a7b45bdf69f9 --- /dev/null +++ b/.changeset/tall-garlics-try.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: bail-out event handler referencing each index diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index e7f9e1a727c5..dc98fb31e64b 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -183,6 +183,10 @@ function get_delegated_event(node, context) { ) { return non_hoistable; } + // If we referebnce the index within an each block, then bail-out. + if (binding !== null && binding.initial?.type === 'EachBlock') { + return non_hoistable; + } if ( binding !== null && diff --git a/packages/svelte/src/compiler/phases/scope.js b/packages/svelte/src/compiler/phases/scope.js index ad3e8fdb3443..0530535087f3 100644 --- a/packages/svelte/src/compiler/phases/scope.js +++ b/packages/svelte/src/compiler/phases/scope.js @@ -65,7 +65,7 @@ export class Scope { * @param {import('estree').Identifier} node * @param {import('#compiler').Binding['kind']} kind * @param {import('#compiler').DeclarationKind} declaration_kind - * @param {null | import('estree').Expression | import('estree').FunctionDeclaration | import('estree').ClassDeclaration | import('estree').ImportDeclaration} initial + * @param {null | import('estree').Expression | import('estree').FunctionDeclaration | import('estree').ClassDeclaration | import('estree').ImportDeclaration | import('../types/template.js').EachBlock} initial * @returns {import('#compiler').Binding} */ declare(node, kind, declaration_kind, initial = null) { @@ -523,7 +523,7 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) { const is_keyed = node.key && (node.key.type !== 'Identifier' || !node.index || node.key.name !== node.index); - scope.declare(b.id(node.index), is_keyed ? 'derived' : 'normal', 'const'); + scope.declare(b.id(node.index), is_keyed ? 'derived' : 'normal', 'const', node); } if (node.key) visit(node.key, { scope }); @@ -680,7 +680,7 @@ export function set_scope(scopes) { /** * Returns the name of the rune if the given expression is a `CallExpression` using a rune. - * @param {import('estree').Node | null | undefined} node + * @param {import('estree').Node | import('../types/template.js').EachBlock | null | undefined} node * @param {Scope} scope * @returns {Runes[number] | null} */ diff --git a/packages/svelte/src/compiler/types/index.d.ts b/packages/svelte/src/compiler/types/index.d.ts index fcb960847e88..6a7ab512ae31 100644 --- a/packages/svelte/src/compiler/types/index.d.ts +++ b/packages/svelte/src/compiler/types/index.d.ts @@ -11,7 +11,7 @@ import type { SourceMap } from 'magic-string'; import type { Context } from 'zimmerframe'; import type { Scope } from '../phases/scope.js'; import * as Css from './css.js'; -import type { Namespace, SvelteNode } from './template.js'; +import type { EachBlock, Namespace, SvelteNode } from './template.js'; /** The return value of `compile` from `svelte/compiler` */ export interface CompileResult { @@ -269,7 +269,7 @@ export interface Binding { * What the value was initialized with. * For destructured props such as `let { foo = 'bar' } = $props()` this is `'bar'` and not `$props()` */ - initial: null | Expression | FunctionDeclaration | ClassDeclaration | ImportDeclaration; + initial: null | Expression | FunctionDeclaration | ClassDeclaration | ImportDeclaration | EachBlock; is_called: boolean; references: { node: Identifier; path: SvelteNode[] }[]; mutated: boolean; From df1069aed629b750edc89849d5a081b2b2a463d2 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Tue, 2 Jan 2024 22:46:04 +0000 Subject: [PATCH 2/4] lint --- packages/svelte/src/compiler/types/index.d.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/svelte/src/compiler/types/index.d.ts b/packages/svelte/src/compiler/types/index.d.ts index 6a7ab512ae31..b62b47bf0db8 100644 --- a/packages/svelte/src/compiler/types/index.d.ts +++ b/packages/svelte/src/compiler/types/index.d.ts @@ -269,7 +269,13 @@ export interface Binding { * What the value was initialized with. * For destructured props such as `let { foo = 'bar' } = $props()` this is `'bar'` and not `$props()` */ - initial: null | Expression | FunctionDeclaration | ClassDeclaration | ImportDeclaration | EachBlock; + initial: + | null + | Expression + | FunctionDeclaration + | ClassDeclaration + | ImportDeclaration + | EachBlock; is_called: boolean; references: { node: Identifier; path: SvelteNode[] }[]; mutated: boolean; From 93cce4a2c3274ab8c2e7f0d41ad6b5c2719c133b Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Tue, 2 Jan 2024 23:20:07 +0000 Subject: [PATCH 3/4] ts --- packages/svelte/types/index.d.ts | 34 ++++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index 4db82097064f..17bf2fc951b1 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -746,7 +746,7 @@ declare module 'svelte/compiler' { * What the value was initialized with. * For destructured props such as `let { foo = 'bar' } = $props()` this is `'bar'` and not `$props()` */ - initial: null | Expression | FunctionDeclaration | ClassDeclaration | ImportDeclaration; + initial: null | Expression | FunctionDeclaration | ClassDeclaration | ImportDeclaration | EachBlock; is_called: boolean; references: { node: Identifier; path: SvelteNode[] }[]; mutated: boolean; @@ -975,15 +975,15 @@ declare module 'svelte/compiler' { filename?: string | undefined; } | undefined): Promise; export class CompileError extends Error { - + constructor(code: string, message: string, position: [number, number] | undefined); - + filename: CompileError_1['filename']; - + position: CompileError_1['position']; - + start: CompileError_1['start']; - + end: CompileError_1['end']; code: string; } @@ -994,9 +994,9 @@ declare module 'svelte/compiler' { * */ export const VERSION: string; class Scope { - + constructor(root: ScopeRoot, parent: Scope | null, porous: boolean); - + root: ScopeRoot; /** * A map of every identifier declared by this scope, and all the @@ -1020,25 +1020,25 @@ declare module 'svelte/compiler' { * which is usually an error. Block statements do not increase this value */ function_depth: number; - + declare(node: import('estree').Identifier, kind: Binding['kind'], declaration_kind: DeclarationKind, initial?: null | import('estree').Expression | import('estree').FunctionDeclaration | import('estree').ClassDeclaration | import('estree').ImportDeclaration): Binding; child(porous?: boolean): Scope; - + generate(preferred_name: string): string; - + get(name: string): Binding | null; - + get_bindings(node: import('estree').VariableDeclarator | LetDirective): Binding[]; - + owner(name: string): Scope | null; - + reference(node: import('estree').Identifier, path: SvelteNode[]): void; #private; } class ScopeRoot { - + conflicts: Set; - + unique(preferred_name: string): import("estree").Identifier; } interface BaseNode { @@ -2567,4 +2567,4 @@ declare function $inspect( ...values: T ): { with: (type: 'init' | 'update', ...values: T) => void }; -//# sourceMappingURL=index.d.ts.map \ No newline at end of file +//# sourceMappingURL=index.d.ts.map From 67142a52d14c323ce770826359a162d9e5f6dceb Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Tue, 2 Jan 2024 23:25:46 +0000 Subject: [PATCH 4/4] types --- packages/svelte/types/index.d.ts | 42 ++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index 17bf2fc951b1..7baeab418975 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -746,7 +746,13 @@ declare module 'svelte/compiler' { * What the value was initialized with. * For destructured props such as `let { foo = 'bar' } = $props()` this is `'bar'` and not `$props()` */ - initial: null | Expression | FunctionDeclaration | ClassDeclaration | ImportDeclaration | EachBlock; + initial: + | null + | Expression + | FunctionDeclaration + | ClassDeclaration + | ImportDeclaration + | EachBlock; is_called: boolean; references: { node: Identifier; path: SvelteNode[] }[]; mutated: boolean; @@ -975,15 +981,15 @@ declare module 'svelte/compiler' { filename?: string | undefined; } | undefined): Promise; export class CompileError extends Error { - + constructor(code: string, message: string, position: [number, number] | undefined); - + filename: CompileError_1['filename']; - + position: CompileError_1['position']; - + start: CompileError_1['start']; - + end: CompileError_1['end']; code: string; } @@ -994,9 +1000,9 @@ declare module 'svelte/compiler' { * */ export const VERSION: string; class Scope { - + constructor(root: ScopeRoot, parent: Scope | null, porous: boolean); - + root: ScopeRoot; /** * A map of every identifier declared by this scope, and all the @@ -1020,25 +1026,25 @@ declare module 'svelte/compiler' { * which is usually an error. Block statements do not increase this value */ function_depth: number; - - declare(node: import('estree').Identifier, kind: Binding['kind'], declaration_kind: DeclarationKind, initial?: null | import('estree').Expression | import('estree').FunctionDeclaration | import('estree').ClassDeclaration | import('estree').ImportDeclaration): Binding; + + declare(node: import('estree').Identifier, kind: Binding['kind'], declaration_kind: DeclarationKind, initial?: null | import('estree').Expression | import('estree').FunctionDeclaration | import('estree').ClassDeclaration | import('estree').ImportDeclaration | EachBlock): Binding; child(porous?: boolean): Scope; - + generate(preferred_name: string): string; - + get(name: string): Binding | null; - + get_bindings(node: import('estree').VariableDeclarator | LetDirective): Binding[]; - + owner(name: string): Scope | null; - + reference(node: import('estree').Identifier, path: SvelteNode[]): void; #private; } class ScopeRoot { - + conflicts: Set; - + unique(preferred_name: string): import("estree").Identifier; } interface BaseNode { @@ -2567,4 +2573,4 @@ declare function $inspect( ...values: T ): { with: (type: 'init' | 'update', ...values: T) => void }; -//# sourceMappingURL=index.d.ts.map +//# sourceMappingURL=index.d.ts.map \ No newline at end of file