diff --git a/packages/svelte2tsx/src/svelte2tsx/processInstanceScriptContent.ts b/packages/svelte2tsx/src/svelte2tsx/processInstanceScriptContent.ts index 4790739cb..d6f0ebdf6 100644 --- a/packages/svelte2tsx/src/svelte2tsx/processInstanceScriptContent.ts +++ b/packages/svelte2tsx/src/svelte2tsx/processInstanceScriptContent.ts @@ -1,6 +1,6 @@ import MagicString from 'magic-string'; import { Node } from 'estree-walker'; -import ts from 'typescript'; +import ts, { VariableDeclaration } from 'typescript'; import { getBinaryAssignmentExpr, isNotPropertyNameOfImport, moveNode } from './utils/tsAst'; import { ExportedNames, is$$PropsDeclaration } from './nodes/ExportedNames'; import { ImplicitTopLevelNames } from './nodes/ImplicitTopLevelNames'; @@ -32,6 +32,7 @@ interface PendingStoreResolution { node: ts.Identifier; parent: ts.Node; scope: Scope; + isPropsId: boolean; } export function processInstanceScriptContent( @@ -82,13 +83,19 @@ export function processInstanceScriptContent( //track if we are in a declaration scope let isDeclaration = false; + //track the variable declaration node + let variableDeclarationNode: VariableDeclaration | null = null; + //track $store variables since we are only supposed to give top level scopes special treatment, and users can declare $blah variables at higher scopes //which prevents us just changing all instances of Identity that start with $ - const pendingStoreResolutions: PendingStoreResolution[] = []; + let pendingStoreResolutions: PendingStoreResolution[] = []; let scope = new Scope(); const rootScope = scope; + //track is the variable declared as `props` comes from `$props()` + let isPropsDeclarationRune = false; + const pushScope = () => (scope = new Scope(scope)); const popScope = () => (scope = scope.parent); @@ -124,6 +131,17 @@ export function processInstanceScriptContent( return; } + //if we are in a variable declaration and the identifier is `props` we check the initializer + if ( + ident.text === 'props' && + variableDeclarationNode && + variableDeclarationNode.initializer && + ts.isCallExpression(variableDeclarationNode.initializer) && + variableDeclarationNode.initializer.getText() === '$props()' + ) { + isPropsDeclarationRune = true; + } + if (isDeclaration || ts.isParameter(parent)) { if ( isNotPropertyNameOfImport(ident) && @@ -148,6 +166,17 @@ export function processInstanceScriptContent( !ts.isTypeAliasDeclaration(parent) && !ts.isInterfaceDeclaration(parent) ) { + let isPropsId = false; + if ( + text === '$props' && + ts.isPropertyAccessExpression(parent) && + parent.parent && + ts.isCallExpression(parent.parent) && + parent.parent.arguments.length === 0 + ) { + const text = parent.getText(); + isPropsId = text === '$props.id'; + } // Handle the const { ...props } = $props() case const is_rune = (text === '$props' || text === '$derived' || text === '$state') && @@ -155,7 +184,7 @@ export function processInstanceScriptContent( ts.isVariableDeclaration(parent.parent) && parent.parent.name.getText().includes(text.slice(1)); if (!is_rune) { - pendingStoreResolutions.push({ node: ident, parent, scope }); + pendingStoreResolutions.push({ node: ident, parent, scope, isPropsId }); } } } @@ -234,7 +263,11 @@ export function processInstanceScriptContent( if (ts.isVariableDeclaration(parent) && parent.name == node) { isDeclaration = true; - onLeaveCallbacks.push(() => (isDeclaration = false)); + variableDeclarationNode = parent; + onLeaveCallbacks.push(() => { + isDeclaration = false; + variableDeclarationNode = null; + }); } if (ts.isBindingElement(parent) && parent.name == node) { @@ -295,6 +328,10 @@ export function processInstanceScriptContent( tsAst.forEachChild((n) => walk(n, tsAst)); //resolve stores + if (isPropsDeclarationRune) { + //we filter out every pendingStore resolution that `isPropsId` if the variable names `props` comes from `$props()` + pendingStoreResolutions = pendingStoreResolutions.filter(({ isPropsId }) => !isPropsId); + } pendingStoreResolutions.map(resolveStore); // declare implicit reactive variables we found in the script diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/props-variable-and-$props.id-destructured.v5/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/props-variable-and-$props.id-destructured.v5/expectedv2.ts new file mode 100644 index 000000000..2cab6b0ed --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/props-variable-and-$props.id-destructured.v5/expectedv2.ts @@ -0,0 +1,13 @@ +/// +;function $$render() { + + let/** @typedef {{ props: any }} $$ComponentProps *//** @type {$$ComponentProps} */ { props } = $props(); + let id = $props.id(); +; +async () => { + +id; props;}; +return { props: /** @type {$$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/props-variable-and-$props.id-destructured.v5/input.svelte b/packages/svelte2tsx/test/svelte2tsx/samples/props-variable-and-$props.id-destructured.v5/input.svelte new file mode 100644 index 000000000..99067a438 --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/props-variable-and-$props.id-destructured.v5/input.svelte @@ -0,0 +1,6 @@ + + +{id} {props} diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/props-variable-and-$props.id-not-$props-init.v5/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/props-variable-and-$props.id-not-$props-init.v5/expectedv2.ts new file mode 100644 index 000000000..4ca5bbfd3 --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/props-variable-and-$props.id-not-$props-init.v5/expectedv2.ts @@ -0,0 +1,13 @@ +/// +;function $$render() { + + let props = {}/*Ωignore_startΩ*/;let $props = __sveltets_2_store_get(props);/*Ωignore_endΩ*/; + let id = $props.id(); +; +async () => { + +id; props;}; +return { props: /** @type {Record} */ ({}), exports: {}, bindings: "", slots: {}, events: {} }} +const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_partial(__sveltets_2_with_any_event($$render()))); +/*Ω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/props-variable-and-$props.id-not-$props-init.v5/input.svelte b/packages/svelte2tsx/test/svelte2tsx/samples/props-variable-and-$props.id-not-$props-init.v5/input.svelte new file mode 100644 index 000000000..bbda4b80b --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/props-variable-and-$props.id-not-$props-init.v5/input.svelte @@ -0,0 +1,6 @@ + + +{id} {props} diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/props-variable-and-$props.id-spread.v5/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/props-variable-and-$props.id-spread.v5/expectedv2.ts new file mode 100644 index 000000000..7016df35d --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/props-variable-and-$props.id-spread.v5/expectedv2.ts @@ -0,0 +1,13 @@ +/// +;function $$render() { + + let/** @typedef {Record} $$ComponentProps *//** @type {$$ComponentProps} */ {...props} = $props(); + let id = $props.id(); +; +async () => { + +id; props;}; +return { props: /** @type {$$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/props-variable-and-$props.id-spread.v5/input.svelte b/packages/svelte2tsx/test/svelte2tsx/samples/props-variable-and-$props.id-spread.v5/input.svelte new file mode 100644 index 000000000..754e52c42 --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/props-variable-and-$props.id-spread.v5/input.svelte @@ -0,0 +1,6 @@ + + +{id} {props} diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/props-variable-and-$props.id.v5/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/props-variable-and-$props.id.v5/expectedv2.ts new file mode 100644 index 000000000..c897e5063 --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/props-variable-and-$props.id.v5/expectedv2.ts @@ -0,0 +1,13 @@ +/// +;function $$render() { + + let props = $props(); + let id = $props.id(); +; +async () => { + +id; props;}; +return { props: /** @type {$$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/props-variable-and-$props.id.v5/input.svelte b/packages/svelte2tsx/test/svelte2tsx/samples/props-variable-and-$props.id.v5/input.svelte new file mode 100644 index 000000000..8a93516e4 --- /dev/null +++ b/packages/svelte2tsx/test/svelte2tsx/samples/props-variable-and-$props.id.v5/input.svelte @@ -0,0 +1,6 @@ + + +{id} {props}