diff --git a/packages/svelte2tsx/src/svelte2tsx/nodes/Generics.ts b/packages/svelte2tsx/src/svelte2tsx/nodes/Generics.ts index 79d1918a4..982626652 100644 --- a/packages/svelte2tsx/src/svelte2tsx/nodes/Generics.ts +++ b/packages/svelte2tsx/src/svelte2tsx/nodes/Generics.ts @@ -5,8 +5,10 @@ import { surroundWithIgnoreComments } from '../../utils/ignore'; import { throwError } from '../utils/error'; export class Generics { + /** The whole `T extends boolean` */ private definitions: string[] = []; private typeReferences: string[] = []; + /** The `T` in `T extends boolean` */ private references: string[] = []; genericsAttr: Node | undefined; @@ -93,6 +95,10 @@ export class Generics { return this.typeReferences; } + getReferences() { + return this.references; + } + toDefinitionString(addIgnore = false) { const surround = addIgnore ? surroundWithIgnoreComments : (str: string) => str; return this.definitions.length ? surround(`<${this.definitions.join(',')}>`) : ''; diff --git a/packages/svelte2tsx/src/svelte2tsx/nodes/HoistableInterfaces.ts b/packages/svelte2tsx/src/svelte2tsx/nodes/HoistableInterfaces.ts index 4337c3503..0ad8d535b 100644 --- a/packages/svelte2tsx/src/svelte2tsx/nodes/HoistableInterfaces.ts +++ b/packages/svelte2tsx/src/svelte2tsx/nodes/HoistableInterfaces.ts @@ -167,11 +167,16 @@ export class HoistableInterfaces { } }); - this.interface_map.set(interface_name, { - type_deps: type_dependencies, - value_deps: value_dependencies, - node - }); + if (this.import_type_set.has(interface_name)) { + // shadowed; delete because we can't hoist + this.import_type_set.delete(interface_name); + } else { + this.interface_map.set(interface_name, { + type_deps: type_dependencies, + value_deps: value_dependencies, + node + }); + } } // Handle Type Alias Declarations @@ -188,12 +193,46 @@ export class HoistableInterfaces { generics ); - this.interface_map.set(alias_name, { - type_deps: type_dependencies, - value_deps: value_dependencies, - node + if (this.import_type_set.has(alias_name)) { + // shadowed; delete because we can't hoist + this.import_type_set.delete(alias_name); + } else { + this.interface_map.set(alias_name, { + type_deps: type_dependencies, + value_deps: value_dependencies, + node + }); + } + } + + // Handle top-level declarations: They could shadow module declarations; delete them from the set of allowed import values + if (ts.isVariableStatement(node)) { + node.declarationList.declarations.forEach((declaration) => { + if (ts.isIdentifier(declaration.name)) { + this.import_value_set.delete(declaration.name.text); + } }); } + + if (ts.isFunctionDeclaration(node) && node.name) { + this.import_value_set.delete(node.name.text); + } + + if (ts.isClassDeclaration(node) && node.name) { + this.import_value_set.delete(node.name.text); + } + + if (ts.isEnumDeclaration(node)) { + this.import_value_set.delete(node.name.text); + } + + if (ts.isTypeAliasDeclaration(node)) { + this.import_type_set.delete(node.name.text); + } + + if (ts.isInterfaceDeclaration(node)) { + this.import_type_set.delete(node.name.text); + } } analyze$propsRune( @@ -280,9 +319,18 @@ export class HoistableInterfaces { /** * Moves all interfaces that can be hoisted to the top of the script, if the $props rune's type is hoistable. */ - moveHoistableInterfaces(str: MagicString, astOffset: number, scriptStart: number) { + moveHoistableInterfaces( + str: MagicString, + astOffset: number, + scriptStart: number, + generics: string[] + ) { if (!this.props_interface.name) return; + for (const generic of generics) { + this.import_type_set.delete(generic); + } + const hoistable = this.determineHoistableInterfaces(); if (hoistable.has(this.props_interface.name)) { for (const [, node] of hoistable) { diff --git a/packages/svelte2tsx/src/svelte2tsx/processInstanceScriptContent.ts b/packages/svelte2tsx/src/svelte2tsx/processInstanceScriptContent.ts index e7d66870c..5b504ec6a 100644 --- a/packages/svelte2tsx/src/svelte2tsx/processInstanceScriptContent.ts +++ b/packages/svelte2tsx/src/svelte2tsx/processInstanceScriptContent.ts @@ -318,7 +318,12 @@ export function processInstanceScriptContent( transformInterfacesToTypes(tsAst, str, astOffset, nodesToMove); } - exportedNames.hoistableInterfaces.moveHoistableInterfaces(str, astOffset, script.start); + exportedNames.hoistableInterfaces.moveHoistableInterfaces( + str, + astOffset, + script.start, + generics.getReferences() + ); return { exportedNames, diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-hoistable-props-false-3.v5/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-hoistable-props-false-3.v5/expectedv2.ts new file mode 100644 index 000000000..bec5d85d2 --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-hoistable-props-false-3.v5/expectedv2.ts @@ -0,0 +1,34 @@ +/// +; + type SomeType = T; + type T = unknown; +;;function render() { +;type $$ComponentProps = { someProp: SomeType; }; + let { someProp }:/*Ωignore_startΩ*/$$ComponentProps/*Ωignore_endΩ*/ = $props(); +; +async () => { + +}; +return { props: {} as any as $$ComponentProps, exports: {}, bindings: __sveltets_$$bindings(''), slots: {}, events: {} }} +class __sveltets_Render { + props() { + return render().props; + } + events() { + return render().events; + } + slots() { + return render().slots; + } + bindings() { return __sveltets_$$bindings(''); } + 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: ReturnType<__sveltets_Render['props']> & {}): 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/ts-runes-hoistable-props-false-3.v5/input.svelte b/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-hoistable-props-false-3.v5/input.svelte new file mode 100644 index 000000000..af13570b3 --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-hoistable-props-false-3.v5/input.svelte @@ -0,0 +1,8 @@ + + + diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-hoistable-props-false-4.v5/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-hoistable-props-false-4.v5/expectedv2.ts new file mode 100644 index 000000000..d7fe39298 --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-hoistable-props-false-4.v5/expectedv2.ts @@ -0,0 +1,15 @@ +/// +; + let a = ''; +;;function render() { + + let a = true;;type $$ComponentProps = { someProp: typeof a }; + let { someProp }:/*Ωignore_startΩ*/$$ComponentProps/*Ωignore_endΩ*/ = $props(); +; +async () => { + +}; +return { props: {} as any as $$ComponentProps, exports: {}, bindings: __sveltets_$$bindings(''), slots: {}, events: {} }} +const Input__SvelteComponent_ = __sveltets_2_fn_component(render()); +type Input__SvelteComponent_ = ReturnType; +export default Input__SvelteComponent_; \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-hoistable-props-false-4.v5/input.svelte b/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-hoistable-props-false-4.v5/input.svelte new file mode 100644 index 000000000..a892a8c9f --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-hoistable-props-false-4.v5/input.svelte @@ -0,0 +1,8 @@ + + + diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-hoistable-props-false-5.v5/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-hoistable-props-false-5.v5/expectedv2.ts new file mode 100644 index 000000000..9455873cb --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-hoistable-props-false-5.v5/expectedv2.ts @@ -0,0 +1,15 @@ +/// +; + type Shadowed = string; +;;function render() { + + type Shadowed = boolean;;type $$ComponentProps = { someProp: Shadowed }; + let { someProp }:/*Ωignore_startΩ*/$$ComponentProps/*Ωignore_endΩ*/ = $props(); +; +async () => { + +}; +return { props: {} as any as $$ComponentProps, exports: {}, bindings: __sveltets_$$bindings(''), slots: {}, events: {} }} +const Input__SvelteComponent_ = __sveltets_2_fn_component(render()); +type Input__SvelteComponent_ = ReturnType; +export default Input__SvelteComponent_; \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-hoistable-props-false-5.v5/input.svelte b/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-hoistable-props-false-5.v5/input.svelte new file mode 100644 index 000000000..3b2b98957 --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/ts-runes-hoistable-props-false-5.v5/input.svelte @@ -0,0 +1,8 @@ + + + pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy