From 1f771d6bc4025d6e8084ee1bf351a9c15f0739a2 Mon Sep 17 00:00:00 2001 From: paoloricciuti Date: Thu, 16 Jan 2025 23:37:53 +0100 Subject: [PATCH] fix: disambiguate `render` in module script --- .../src/svelte2tsx/addComponentExport.ts | 27 +++++++++------- .../src/svelte2tsx/createRenderFunction.ts | 11 ++++--- packages/svelte2tsx/src/svelte2tsx/index.ts | 19 ++++++++--- .../src/svelte2tsx/nodes/ExportedNames.ts | 8 +++-- .../processInstanceScriptContent.ts | 6 ++-- .../src/svelte2tsx/processModuleScriptTag.ts | 21 +++++++++++- .../expected-svelte5.ts | 9 ++++++ .../render-function-module/input.svelte | 3 ++ .../expected-svelte5.ts | 14 ++++++++ .../render-import-module-exports/input.svelte | 7 ++++ .../expected-svelte5.ts | 32 +++++++++++++++++++ .../input.svelte | 6 ++++ .../render-import-module/expectedv2.ts | 9 ++++++ .../samples/render-import-module/input.svelte | 3 ++ .../expected-svelte5.ts | 9 ++++++ .../render-named-import-module/input.svelte | 3 ++ .../expected-svelte5.ts | 9 ++++++ .../render-variable-module/input.svelte | 3 ++ 18 files changed, 174 insertions(+), 25 deletions(-) create mode 100644 packages/svelte2tsx/test/svelte2tsx/samples/render-function-module/expected-svelte5.ts create mode 100644 packages/svelte2tsx/test/svelte2tsx/samples/render-function-module/input.svelte create mode 100644 packages/svelte2tsx/test/svelte2tsx/samples/render-import-module-exports/expected-svelte5.ts create mode 100644 packages/svelte2tsx/test/svelte2tsx/samples/render-import-module-exports/input.svelte create mode 100644 packages/svelte2tsx/test/svelte2tsx/samples/render-import-module-generics/expected-svelte5.ts create mode 100644 packages/svelte2tsx/test/svelte2tsx/samples/render-import-module-generics/input.svelte create mode 100644 packages/svelte2tsx/test/svelte2tsx/samples/render-import-module/expectedv2.ts create mode 100644 packages/svelte2tsx/test/svelte2tsx/samples/render-import-module/input.svelte create mode 100644 packages/svelte2tsx/test/svelte2tsx/samples/render-named-import-module/expected-svelte5.ts create mode 100644 packages/svelte2tsx/test/svelte2tsx/samples/render-named-import-module/input.svelte create mode 100644 packages/svelte2tsx/test/svelte2tsx/samples/render-variable-module/expected-svelte5.ts create mode 100644 packages/svelte2tsx/test/svelte2tsx/samples/render-variable-module/input.svelte diff --git a/packages/svelte2tsx/src/svelte2tsx/addComponentExport.ts b/packages/svelte2tsx/src/svelte2tsx/addComponentExport.ts index c4f016398..034614f3c 100644 --- a/packages/svelte2tsx/src/svelte2tsx/addComponentExport.ts +++ b/packages/svelte2tsx/src/svelte2tsx/addComponentExport.ts @@ -25,6 +25,7 @@ export interface AddComponentExportPara { usesSlots: boolean; isSvelte5: boolean; noSvelteComponentTyped?: boolean; + renderName: string; } /** @@ -54,7 +55,8 @@ function addGenericsComponentExport({ generics, usesSlots, isSvelte5, - noSvelteComponentTyped + noSvelteComponentTyped, + renderName }: AddComponentExportPara) { const genericsDef = generics.toDefinitionString(); const genericsRef = generics.toReferencesString(); @@ -71,13 +73,13 @@ function addGenericsComponentExport({ let statement = ` class __sveltets_Render${genericsDef} { props() { - return ${props(true, canHaveAnyProp, exportedNames, `render${genericsRef}()`)}.props; + return ${props(true, canHaveAnyProp, exportedNames, `${renderName}${genericsRef}()`)}.props; } events() { - return ${_events(events.hasStrictEvents() || exportedNames.usesRunes(), `render${genericsRef}()`)}.events; + return ${_events(events.hasStrictEvents() || exportedNames.usesRunes(), `${renderName}${genericsRef}()`)}.events; } slots() { - return render${genericsRef}().slots; + return ${renderName}${genericsRef}().slots; } `; @@ -85,15 +87,15 @@ class __sveltets_Render${genericsDef} { if (isSvelte5 && !isTsFile && exportedNames.usesRunes()) { statement = ` class __sveltets_Render${genericsDef} { - props(): ReturnType['props'] { return null as any; } - events(): ReturnType['events'] { return null as any; } - slots(): ReturnType['slots'] { return null as any; } + props(): ReturnType['props'] { return null as any; } + events(): ReturnType['events'] { return null as any; } + slots(): ReturnType['slots'] { return null as any; } `; } statement += isSvelte5 ? ` bindings() { return ${exportedNames.createBindingsStr()}; } - exports() { return ${exportedNames.hasExports() ? `render${genericsRef}().exports` : '{}'}; } + exports() { return ${exportedNames.hasExports() ? `${renderName}${genericsRef}().exports` : '{}'}; } }\n` : '}\n'; @@ -175,13 +177,14 @@ function addSimpleComponentExport({ str, usesSlots, noSvelteComponentTyped, - isSvelte5 + isSvelte5, + renderName }: AddComponentExportPara) { const propDef = props( isTsFile, canHaveAnyProp, exportedNames, - _events(events.hasStrictEvents(), 'render()') + _events(events.hasStrictEvents(), `${renderName}()`) ); const doc = componentDocumentation.getFormatted(); @@ -192,7 +195,7 @@ function addSimpleComponentExport({ if (mode === 'dts') { if (isSvelte5 && exportedNames.usesRunes() && !usesSlots && !events.hasEvents()) { statement = - `\n${doc}const ${componentName} = __sveltets_2_fn_component(render());\n` + + `\n${doc}const ${componentName} = __sveltets_2_fn_component(${renderName}());\n` + `type ${componentName} = ReturnType;\n` + `export default ${componentName};`; } else if (isSvelte5) { @@ -258,7 +261,7 @@ declare function $$__sveltets_2_isomorphic_component< if (isSvelte5) { if (exportedNames.usesRunes() && !usesSlots && !events.hasEvents()) { statement = - `\n${doc}const ${componentName} = __sveltets_2_fn_component(render());\n` + + `\n${doc}const ${componentName} = __sveltets_2_fn_component(${renderName}());\n` + `type ${componentName} = ReturnType;\n` + `export default ${componentName};`; } else { diff --git a/packages/svelte2tsx/src/svelte2tsx/createRenderFunction.ts b/packages/svelte2tsx/src/svelte2tsx/createRenderFunction.ts index 16f65d207..466bec982 100644 --- a/packages/svelte2tsx/src/svelte2tsx/createRenderFunction.ts +++ b/packages/svelte2tsx/src/svelte2tsx/createRenderFunction.ts @@ -18,6 +18,7 @@ export interface CreateRenderFunctionPara extends InstanceScriptProcessResult { svelte5Plus: boolean; isTsFile: boolean; mode?: 'ts' | 'dts'; + renderName: string; } export function createRenderFunction({ @@ -33,7 +34,8 @@ export function createRenderFunction({ uses$$SlotsInterface, generics, isTsFile, - mode + mode, + renderName }: CreateRenderFunctionPara) { const htmlx = str.original; let propsDecl = ''; @@ -75,7 +77,8 @@ export function createRenderFunction({ start++; end--; } - str.overwrite(scriptTag.start + 1, start - 1, `function render`); + + str.overwrite(scriptTag.start + 1, start - 1, `function ${renderName}`); str.overwrite(start - 1, start, isTsFile ? '<' : `<${IGNORE_START_COMMENT}`); // if the generics are unused, only this char is colored opaque str.overwrite( end, @@ -86,7 +89,7 @@ export function createRenderFunction({ str.overwrite( scriptTag.start + 1, scriptTagEnd, - `function render${generics.toDefinitionString(true)}() {${propsDecl}\n` + `function ${renderName}${generics.toDefinitionString(true)}() {${propsDecl}\n` ); } @@ -98,7 +101,7 @@ export function createRenderFunction({ } else { str.prependRight( scriptDestination, - `;function render() {` + `${propsDecl}${slotsDeclaration}\nasync () => {` + `;function ${renderName}() {` + `${propsDecl}${slotsDeclaration}\nasync () => {` ); } diff --git a/packages/svelte2tsx/src/svelte2tsx/index.ts b/packages/svelte2tsx/src/svelte2tsx/index.ts index 207903fa0..e88e8eb54 100644 --- a/packages/svelte2tsx/src/svelte2tsx/index.ts +++ b/packages/svelte2tsx/src/svelte2tsx/index.ts @@ -96,7 +96,15 @@ export function svelte2tsx( : instanceScriptTarget; const implicitStoreValues = new ImplicitStoreValues(resolvedStores, renderFunctionStart); //move the instance script and process the content - let exportedNames = new ExportedNames(str, 0, basename, isTsFile, svelte5Plus, isRunes); + let exportedNames = new ExportedNames( + str, + 0, + basename, + isTsFile, + svelte5Plus, + isRunes, + moduleAst.renderName + ); let generics = new Generics(str, 0, { attributes: [] } as any); let uses$$SlotsInterface = false; if (scriptTag) { @@ -114,7 +122,8 @@ export function svelte2tsx( isTsFile, basename, svelte5Plus, - isRunes + isRunes, + moduleAst.renderName ); uses$$props = uses$$props || res.uses$$props; uses$$restProps = uses$$restProps || res.uses$$restProps; @@ -143,7 +152,8 @@ export function svelte2tsx( generics, svelte5Plus, isTsFile, - mode: options.mode + mode: options.mode, + renderName: moduleAst.renderName }); // we need to process the module script after the instance script has moved otherwise we get warnings about moving edited items @@ -201,7 +211,8 @@ export function svelte2tsx( mode: options.mode, generics, isSvelte5: svelte5Plus, - noSvelteComponentTyped: options.noSvelteComponentTyped + noSvelteComponentTyped: options.noSvelteComponentTyped, + renderName: moduleAst.renderName }); if (options.mode === 'dts') { diff --git a/packages/svelte2tsx/src/svelte2tsx/nodes/ExportedNames.ts b/packages/svelte2tsx/src/svelte2tsx/nodes/ExportedNames.ts index b8851b23c..9741068ef 100644 --- a/packages/svelte2tsx/src/svelte2tsx/nodes/ExportedNames.ts +++ b/packages/svelte2tsx/src/svelte2tsx/nodes/ExportedNames.ts @@ -60,7 +60,8 @@ export class ExportedNames { private basename: string, private isTsFile: boolean, private isSvelte5Plus: boolean, - private isRunes: boolean + private isRunes: boolean, + private renderName: string ) {} handleVariableStatement(node: ts.VariableStatement, parent: ts.Node): void { @@ -506,7 +507,10 @@ export class ExportedNames { if (this.usesRunes()) { // In runes mode, exports are no longer part of props return Array.from(this.getters) - .map((name) => `\n get ${name}() { return render${generics}().exports.${name} }`) + .map( + (name) => + `\n get ${name}() { return ${this.renderName}${generics}().exports.${name} }` + ) .join(''); } else { return Array.from(this.getters) diff --git a/packages/svelte2tsx/src/svelte2tsx/processInstanceScriptContent.ts b/packages/svelte2tsx/src/svelte2tsx/processInstanceScriptContent.ts index 4790739cb..4dd07abc5 100644 --- a/packages/svelte2tsx/src/svelte2tsx/processInstanceScriptContent.ts +++ b/packages/svelte2tsx/src/svelte2tsx/processInstanceScriptContent.ts @@ -44,7 +44,8 @@ export function processInstanceScriptContent( isTSFile: boolean, basename: string, isSvelte5Plus: boolean, - isRunes: boolean + isRunes: boolean, + renderName: string ): InstanceScriptProcessResult { const htmlx = str.original; const scriptContent = htmlx.substring(script.content.start, script.content.end); @@ -62,7 +63,8 @@ export function processInstanceScriptContent( basename, isTSFile, isSvelte5Plus, - isRunes + isRunes, + renderName ); const generics = new Generics(str, astOffset, script); const interfacesAndTypes = new InterfacesAndTypes(); diff --git a/packages/svelte2tsx/src/svelte2tsx/processModuleScriptTag.ts b/packages/svelte2tsx/src/svelte2tsx/processModuleScriptTag.ts index d66d4630b..0eb60df70 100644 --- a/packages/svelte2tsx/src/svelte2tsx/processModuleScriptTag.ts +++ b/packages/svelte2tsx/src/svelte2tsx/processModuleScriptTag.ts @@ -13,6 +13,7 @@ export interface ModuleAst { htmlx: string; tsAst: ts.SourceFile; astOffset: number; + renderName: string; } export function createModuleAst(str: MagicString, script: Node): ModuleAst { @@ -25,9 +26,27 @@ export function createModuleAst(str: MagicString, script: Node): ModuleAst { true, ts.ScriptKind.TS ); + + const identifiers = new Set(); + + const walk = (node: ts.Node) => { + if (ts.isIdentifier(node)) { + identifiers.add(node.getText()); + } + ts.forEachChild(node, (n) => walk(n)); + }; + + walk(tsAst); + + let renderName = 'render'; + let i = 0; + while (identifiers.has(renderName)) { + renderName = `render_${i++}`; + } + const astOffset = script.content.start; - return { htmlx, tsAst, astOffset }; + return { htmlx, tsAst, astOffset, renderName }; } export function processModuleScriptTag( diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/render-function-module/expected-svelte5.ts b/packages/svelte2tsx/test/svelte2tsx/samples/render-function-module/expected-svelte5.ts new file mode 100644 index 000000000..195258c59 --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/render-function-module/expected-svelte5.ts @@ -0,0 +1,9 @@ +/// +; + function render(){} +;;function render_0() { +async () => {}; +return { props: /** @type {Record} */ ({}), exports: {}, bindings: "", slots: {}, events: {} }} +const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_partial(__sveltets_2_with_any_event(render_0()))); +/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType; +/*Ωignore_endΩ*/export default Input__SvelteComponent_; \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/render-function-module/input.svelte b/packages/svelte2tsx/test/svelte2tsx/samples/render-function-module/input.svelte new file mode 100644 index 000000000..7f3edef08 --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/render-function-module/input.svelte @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/render-import-module-exports/expected-svelte5.ts b/packages/svelte2tsx/test/svelte2tsx/samples/render-import-module-exports/expected-svelte5.ts new file mode 100644 index 000000000..81db6c37f --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/render-import-module-exports/expected-svelte5.ts @@ -0,0 +1,14 @@ +/// +; + import { render } from "render"; +;;function render_0() { + + +; +async () => { + +}; +return { props: {render: render}, exports: /** @type {{render: typeof render}} */ ({}), bindings: "", slots: {}, events: {} }} +const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_partial(['render'], __sveltets_2_with_any_event(render_0()))); +/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType; +/*Ωignore_endΩ*/export default Input__SvelteComponent_; \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/render-import-module-exports/input.svelte b/packages/svelte2tsx/test/svelte2tsx/samples/render-import-module-exports/input.svelte new file mode 100644 index 000000000..c976349be --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/render-import-module-exports/input.svelte @@ -0,0 +1,7 @@ + + + \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/render-import-module-generics/expected-svelte5.ts b/packages/svelte2tsx/test/svelte2tsx/samples/render-import-module-generics/expected-svelte5.ts new file mode 100644 index 000000000..9167d2ca2 --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/render-import-module-generics/expected-svelte5.ts @@ -0,0 +1,32 @@ +/// +; + import { render } from "render"; +;;function render_0/*Ωignore_endΩ*/() { + +; +async () => { + +}; +return { props: /** @type {Record} */ ({}), exports: {}, bindings: "", slots: {}, events: {} }} +class __sveltets_Render { + props() { + return render_0().props; + } + events() { + return __sveltets_2_with_any_event(render_0()).events; + } + slots() { + return render_0().slots; + } + bindings() { return ""; } + exports() { return {}; } +} + +interface $$IsomorphicComponent { + new (options: import('svelte').ComponentConstructorOptions['props']>>): import('svelte').SvelteComponent['props']>, ReturnType<__sveltets_Render['events']>, ReturnType<__sveltets_Render['slots']>> & { $$bindings?: ReturnType<__sveltets_Render['bindings']> } & ReturnType<__sveltets_Render['exports']>; + (internal: unknown, props: {$$events?: ReturnType<__sveltets_Render['events']>}): ReturnType<__sveltets_Render['exports']>; + z_$$bindings?: ReturnType<__sveltets_Render['bindings']>; +} +const Input__SvelteComponent_: $$IsomorphicComponent = null as any; +/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType>; +/*Ωignore_endΩ*/export default Input__SvelteComponent_; \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/render-import-module-generics/input.svelte b/packages/svelte2tsx/test/svelte2tsx/samples/render-import-module-generics/input.svelte new file mode 100644 index 000000000..f0642c72b --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/render-import-module-generics/input.svelte @@ -0,0 +1,6 @@ + + + \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/render-import-module/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/render-import-module/expectedv2.ts new file mode 100644 index 000000000..d85855349 --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/render-import-module/expectedv2.ts @@ -0,0 +1,9 @@ +/// +; + import { render } from "render"; +;;function render_0() { +async () => {}; +return { props: /** @type {Record} */ ({}), slots: {}, events: {} }} + +export default class Input__SvelteComponent_ extends __sveltets_2_createSvelte2TsxComponent(__sveltets_2_partial(__sveltets_2_with_any_event(render_0()))) { +} \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/render-import-module/input.svelte b/packages/svelte2tsx/test/svelte2tsx/samples/render-import-module/input.svelte new file mode 100644 index 000000000..f55dfd606 --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/render-import-module/input.svelte @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/render-named-import-module/expected-svelte5.ts b/packages/svelte2tsx/test/svelte2tsx/samples/render-named-import-module/expected-svelte5.ts new file mode 100644 index 000000000..b3fa2902f --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/render-named-import-module/expected-svelte5.ts @@ -0,0 +1,9 @@ +/// +; + import render from "render"; +;;function render_0() { +async () => {}; +return { props: /** @type {Record} */ ({}), exports: {}, bindings: "", slots: {}, events: {} }} +const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_partial(__sveltets_2_with_any_event(render_0()))); +/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType; +/*Ωignore_endΩ*/export default Input__SvelteComponent_; \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/render-named-import-module/input.svelte b/packages/svelte2tsx/test/svelte2tsx/samples/render-named-import-module/input.svelte new file mode 100644 index 000000000..b7d8ea3f2 --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/render-named-import-module/input.svelte @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/render-variable-module/expected-svelte5.ts b/packages/svelte2tsx/test/svelte2tsx/samples/render-variable-module/expected-svelte5.ts new file mode 100644 index 000000000..3efc329c0 --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/render-variable-module/expected-svelte5.ts @@ -0,0 +1,9 @@ +/// +; + const render = 42; +;;function render_0() { +async () => {}; +return { props: /** @type {Record} */ ({}), exports: {}, bindings: "", slots: {}, events: {} }} +const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_partial(__sveltets_2_with_any_event(render_0()))); +/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType; +/*Ωignore_endΩ*/export default Input__SvelteComponent_; \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/render-variable-module/input.svelte b/packages/svelte2tsx/test/svelte2tsx/samples/render-variable-module/input.svelte new file mode 100644 index 000000000..1260b2f34 --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/render-variable-module/input.svelte @@ -0,0 +1,3 @@ + \ No newline at end of file