From afefafe0aa16f4b471571a19efd0db7cabb53e76 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Thu, 31 Jul 2025 16:25:10 -0700 Subject: [PATCH 1/5] fix: emit `snippet_invalid_export` instead of `undefined_export` for exported snippets --- .changeset/thick-snakes-look.md | 5 +++++ packages/svelte/src/compiler/phases/2-analyze/index.js | 9 ++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 .changeset/thick-snakes-look.md diff --git a/.changeset/thick-snakes-look.md b/.changeset/thick-snakes-look.md new file mode 100644 index 000000000000..f5f22e8a6ca4 --- /dev/null +++ b/.changeset/thick-snakes-look.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: emit `snippet_invalid_export` instead of `undefined_export` for exported snippets diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index cd44fd998aed..88b181d9daf9 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -789,7 +789,14 @@ export function analyze_component(root, source, options) { if (specifier.local.type !== 'Identifier') continue; const binding = analysis.module.scope.get(specifier.local.name); - if (!binding) e.export_undefined(specifier, specifier.local.name); + if (!binding) { + const instance_binding = analysis.instance.scope.get(specifier.local.name); + if (instance_binding?.kind === 'snippet') { + e.snippet_invalid_export(specifier); + } else { + e.export_undefined(specifier, specifier.local.name); + } + } } } } From e2b569fd55d5105188f4808b45c70afe4271d169 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Thu, 31 Jul 2025 16:28:38 -0700 Subject: [PATCH 2/5] try this --- packages/svelte/src/compiler/phases/2-analyze/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index 88b181d9daf9..374e03a43c10 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -790,8 +790,8 @@ export function analyze_component(root, source, options) { const binding = analysis.module.scope.get(specifier.local.name); if (!binding) { - const instance_binding = analysis.instance.scope.get(specifier.local.name); - if (instance_binding?.kind === 'snippet') { + const template_binding = analysis.template.scope.get(specifier.local.name); + if (template_binding?.kind === 'snippet') { e.snippet_invalid_export(specifier); } else { e.export_undefined(specifier, specifier.local.name); From 0917ce78f0c6abed42ab1f9d354d4ddaed803011 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Thu, 31 Jul 2025 16:37:29 -0700 Subject: [PATCH 3/5] this should work --- packages/svelte/src/compiler/phases/2-analyze/index.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index 374e03a43c10..fc66736b36dc 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -787,14 +787,13 @@ export function analyze_component(root, source, options) { if (node.type === 'ExportNamedDeclaration' && node.specifiers !== null && node.source == null) { for (const specifier of node.specifiers) { if (specifier.local.type !== 'Identifier') continue; - - const binding = analysis.module.scope.get(specifier.local.name); + const name = specifier.local.name; + const binding = analysis.module.scope.get(name); if (!binding) { - const template_binding = analysis.template.scope.get(specifier.local.name); - if (template_binding?.kind === 'snippet') { + if ([...analysis.snippets].find((snippet) => snippet.expression.name === name)) { e.snippet_invalid_export(specifier); } else { - e.export_undefined(specifier, specifier.local.name); + e.export_undefined(specifier, name); } } } From 2cf74a0c3c659d6da16164d833cbb6455b50240c Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 5 Aug 2025 20:42:22 -0400 Subject: [PATCH 4/5] remove some junk (this never did anything) --- packages/svelte/src/compiler/phases/2-analyze/index.js | 1 - .../src/compiler/phases/2-analyze/visitors/SnippetBlock.js | 5 ----- packages/svelte/src/compiler/phases/types.d.ts | 1 - 3 files changed, 7 deletions(-) diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index fc66736b36dc..ecc843d2f42a 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -526,7 +526,6 @@ export function analyze_component(root, source, options) { has_global: false }, source, - undefined_exports: new Map(), snippet_renderers: new Map(), snippets: new Set(), async_deriveds: new Set() diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/SnippetBlock.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/SnippetBlock.js index 2f6bbd785a71..7930c2b1a7b8 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/SnippetBlock.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/SnippetBlock.js @@ -35,11 +35,6 @@ export function SnippetBlock(node, context) { if (can_hoist) { const binding = /** @type {Binding} */ (context.state.scope.get(name)); context.state.analysis.module.scope.declarations.set(name, binding); - } else { - const undefined_export = context.state.analysis.undefined_exports.get(name); - if (undefined_export) { - e.snippet_invalid_export(undefined_export); - } } node.metadata.can_hoist = can_hoist; diff --git a/packages/svelte/src/compiler/phases/types.d.ts b/packages/svelte/src/compiler/phases/types.d.ts index 4cbbc362c7cc..4da78f1482f7 100644 --- a/packages/svelte/src/compiler/phases/types.d.ts +++ b/packages/svelte/src/compiler/phases/types.d.ts @@ -95,7 +95,6 @@ export interface ComponentAnalysis extends Analysis { }; /** @deprecated use `source` from `state.js` instead */ source: string; - undefined_exports: Map; /** * Every render tag/component, and whether it could be definitively resolved or not */ From 970dcaa8b6e12ceaeed5375be732e136c058582f Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 5 Aug 2025 20:42:27 -0400 Subject: [PATCH 5/5] add test --- .../samples/snippet-invalid-export/_config.js | 10 ++++++++++ .../samples/snippet-invalid-export/main.svelte | 11 +++++++++++ 2 files changed, 21 insertions(+) create mode 100644 packages/svelte/tests/compiler-errors/samples/snippet-invalid-export/_config.js create mode 100644 packages/svelte/tests/compiler-errors/samples/snippet-invalid-export/main.svelte diff --git a/packages/svelte/tests/compiler-errors/samples/snippet-invalid-export/_config.js b/packages/svelte/tests/compiler-errors/samples/snippet-invalid-export/_config.js new file mode 100644 index 000000000000..cc0dd388f4bf --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/snippet-invalid-export/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + error: { + code: 'snippet_invalid_export', + message: + 'An exported snippet can only reference things declared in a ` + + + +{#snippet foo()} + {x} +{/snippet}