diff --git a/.changeset/gold-pens-sell.md b/.changeset/gold-pens-sell.md new file mode 100644 index 000000000000..945c795890d8 --- /dev/null +++ b/.changeset/gold-pens-sell.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +feat: support migrating `svelte:self` diff --git a/packages/svelte/src/compiler/migrate/index.js b/packages/svelte/src/compiler/migrate/index.js index 393b34f5b2ad..e0d8cd55dff9 100644 --- a/packages/svelte/src/compiler/migrate/index.js +++ b/packages/svelte/src/compiler/migrate/index.js @@ -27,9 +27,10 @@ const style_placeholder = '/*$$__STYLE_CONTENT__$$*/'; * May throw an error if the code is too complex to migrate automatically. * * @param {string} source + * @param {{filename?: string}} [options] * @returns {{ code: string; }} */ -export function migrate(source) { +export function migrate(source, { filename } = {}) { try { // Blank CSS, could contain SCSS or similar that needs a preprocessor. // Since we don't care about CSS in this migration, we'll just ignore it. @@ -41,7 +42,7 @@ export function migrate(source) { }); reset_warning_filter(() => false); - reset(source, { filename: 'migrate.svelte' }); + reset(source, { filename: filename ?? 'migrate.svelte' }); let parsed = parse(source); @@ -68,6 +69,7 @@ export function migrate(source) { let state = { scope: analysis.instance.scope, analysis, + filename, str, indent, props: [], @@ -90,12 +92,14 @@ export function migrate(source) { createBubbler: analysis.root.unique('createBubbler').name, bubble: analysis.root.unique('bubble').name, passive: analysis.root.unique('passive').name, - nonpassive: analysis.root.unique('nonpassive').name + nonpassive: analysis.root.unique('nonpassive').name, + svelte_self: analysis.root.unique('SvelteSelf').name }, legacy_imports: new Set(), script_insertions: new Set(), derived_components: new Map(), - derived_labeled_statements: new Set() + derived_labeled_statements: new Set(), + has_svelte_self: false }; if (parsed.module) { @@ -122,12 +126,21 @@ export function migrate(source) { state.script_insertions.size > 0 || state.props.length > 0 || analysis.uses_rest_props || - analysis.uses_props; + analysis.uses_props || + state.has_svelte_self; if (!parsed.instance && need_script) { str.appendRight(0, ' + +{#if false} + + + + + child + + + child + + + child + + +{/if} \ No newline at end of file diff --git a/packages/svelte/tests/migrate/samples/svelte-self-name-conflict/output.svelte b/packages/svelte/tests/migrate/samples/svelte-self-name-conflict/output.svelte new file mode 100644 index 000000000000..827d06c3a32c --- /dev/null +++ b/packages/svelte/tests/migrate/samples/svelte-self-name-conflict/output.svelte @@ -0,0 +1,22 @@ + + +{#if false} + + + + + child + + + child + + + child + + +{/if} \ No newline at end of file diff --git a/packages/svelte/tests/migrate/samples/svelte-self-skip-filename/_config.js b/packages/svelte/tests/migrate/samples/svelte-self-skip-filename/_config.js new file mode 100644 index 000000000000..9c8f6f9c78f1 --- /dev/null +++ b/packages/svelte/tests/migrate/samples/svelte-self-skip-filename/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + skip_filename: true +}); diff --git a/packages/svelte/tests/migrate/samples/svelte-self-skip-filename/input.svelte b/packages/svelte/tests/migrate/samples/svelte-self-skip-filename/input.svelte new file mode 100644 index 000000000000..340b257fc1be --- /dev/null +++ b/packages/svelte/tests/migrate/samples/svelte-self-skip-filename/input.svelte @@ -0,0 +1,3 @@ +{#if false} + +{/if} \ No newline at end of file diff --git a/packages/svelte/tests/migrate/samples/svelte-self-skip-filename/output.svelte b/packages/svelte/tests/migrate/samples/svelte-self-skip-filename/output.svelte new file mode 100644 index 000000000000..59ae5ff19ca0 --- /dev/null +++ b/packages/svelte/tests/migrate/samples/svelte-self-skip-filename/output.svelte @@ -0,0 +1,4 @@ +{#if false} + + +{/if} \ No newline at end of file diff --git a/packages/svelte/tests/migrate/samples/svelte-self/input.svelte b/packages/svelte/tests/migrate/samples/svelte-self/input.svelte new file mode 100644 index 000000000000..09eb5767be9e --- /dev/null +++ b/packages/svelte/tests/migrate/samples/svelte-self/input.svelte @@ -0,0 +1,15 @@ +{#if false} + + + + + child + + + child + + + child + + +{/if} \ No newline at end of file diff --git a/packages/svelte/tests/migrate/samples/svelte-self/output.svelte b/packages/svelte/tests/migrate/samples/svelte-self/output.svelte new file mode 100644 index 000000000000..7e7ebae21595 --- /dev/null +++ b/packages/svelte/tests/migrate/samples/svelte-self/output.svelte @@ -0,0 +1,21 @@ + + +{#if false} + + + + + child + + + child + + + child + + +{/if} \ No newline at end of file diff --git a/packages/svelte/tests/migrate/test.ts b/packages/svelte/tests/migrate/test.ts index 5aa86a194f0f..e26e8e376bba 100644 --- a/packages/svelte/tests/migrate/test.ts +++ b/packages/svelte/tests/migrate/test.ts @@ -4,7 +4,9 @@ import { migrate } from 'svelte/compiler'; import { try_read_file } from '../helpers.js'; import { suite, type BaseTest } from '../suite.js'; -interface ParserTest extends BaseTest {} +interface ParserTest extends BaseTest { + skip_filename?: boolean; +} const { test, run } = suite(async (config, cwd) => { const input = fs @@ -12,7 +14,9 @@ const { test, run } = suite(async (config, cwd) => { .replace(/\s+$/, '') .replace(/\r/g, ''); - const actual = migrate(input).code; + const actual = migrate(input, { + filename: config.skip_filename ? undefined : `${cwd}/output.svelte` + }).code; // run `UPDATE_SNAPSHOTS=true pnpm test migrate` to update parser tests if (process.env.UPDATE_SNAPSHOTS || !fs.existsSync(`${cwd}/output.svelte`)) { diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index 22b47d35ecbd..e64abef0c5ca 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -1264,7 +1264,9 @@ declare module 'svelte/compiler' { * May throw an error if the code is too complex to migrate automatically. * * */ - export function migrate(source: string): { + export function migrate(source: string, { filename }?: { + filename?: string; + } | undefined): { code: string; }; namespace Css { diff --git a/sites/svelte-5-preview/src/lib/Output/Compiler.js b/sites/svelte-5-preview/src/lib/Output/Compiler.js index ae363682411a..94484ecf3951 100644 --- a/sites/svelte-5-preview/src/lib/Output/Compiler.js +++ b/sites/svelte-5-preview/src/lib/Output/Compiler.js @@ -80,7 +80,8 @@ export default class Compiler { this.worker.postMessage({ id, type: 'migrate', - source: file.source + source: file.source, + filename: `${file.name}.${file.type}` }); }); } diff --git a/sites/svelte-5-preview/src/lib/workers/compiler/index.js b/sites/svelte-5-preview/src/lib/workers/compiler/index.js index 46853c3984b4..9247894dd6e3 100644 --- a/sites/svelte-5-preview/src/lib/workers/compiler/index.js +++ b/sites/svelte-5-preview/src/lib/workers/compiler/index.js @@ -133,9 +133,9 @@ function compile({ id, source, options, return_ast }) { } /** @param {import("../workers").MigrateMessageData} param0 */ -function migrate({ id, source }) { +function migrate({ id, source, filename }) { try { - const result = svelte.migrate(source); + const result = svelte.migrate(source, { filename }); return { id,