Skip to content

Commit

Permalink
fix: bail-out event handler referencing each index (#10063)
Browse files Browse the repository at this point in the history
* fix: bail-out event handler referencing each index

* lint

* ts

* types
  • Loading branch information
trueadm committed Jan 2, 2024
1 parent 15d6308 commit 5f3fcaf
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 7 deletions.
5 changes: 5 additions & 0 deletions .changeset/tall-garlics-try.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

fix: bail-out event handler referencing each index
4 changes: 4 additions & 0 deletions packages/svelte/src/compiler/phases/2-analyze/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 &&
Expand Down
6 changes: 3 additions & 3 deletions packages/svelte/src/compiler/phases/scope.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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 });

Expand Down Expand Up @@ -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}
*/
Expand Down
10 changes: 8 additions & 2 deletions packages/svelte/src/compiler/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
initial:
| null
| Expression
| FunctionDeclaration
| ClassDeclaration
| ImportDeclaration
| EachBlock;
is_called: boolean;
references: { node: Identifier; path: SvelteNode[] }[];
mutated: boolean;
Expand Down
10 changes: 8 additions & 2 deletions packages/svelte/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
initial:
| null
| Expression
| FunctionDeclaration
| ClassDeclaration
| ImportDeclaration
| EachBlock;
is_called: boolean;
references: { node: Identifier; path: SvelteNode[] }[];
mutated: boolean;
Expand Down Expand Up @@ -1021,7 +1027,7 @@ declare module 'svelte/compiler' {
*/
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;
Expand Down

1 comment on commit 5f3fcaf

@vercel
Copy link

@vercel vercel bot commented on 5f3fcaf Jan 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

svelte-5-preview – ./sites/svelte-5-preview

svelte-5-preview-svelte.vercel.app
svelte-5-preview-git-main-svelte.vercel.app
svelte-octane.vercel.app
svelte-5-preview.vercel.app

Please sign in to comment.