Skip to content

Commit a5d694b

Browse files
committed
fix: properly transform $props.id when $props is assigned to props
1 parent a24d819 commit a5d694b

File tree

9 files changed

+114
-4
lines changed

9 files changed

+114
-4
lines changed

packages/svelte2tsx/src/svelte2tsx/processInstanceScriptContent.ts

+38-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import MagicString from 'magic-string';
22
import { Node } from 'estree-walker';
3-
import ts from 'typescript';
3+
import ts, { VariableDeclaration } from 'typescript';
44
import { getBinaryAssignmentExpr, isNotPropertyNameOfImport, moveNode } from './utils/tsAst';
55
import { ExportedNames, is$$PropsDeclaration } from './nodes/ExportedNames';
66
import { ImplicitTopLevelNames } from './nodes/ImplicitTopLevelNames';
@@ -32,6 +32,7 @@ interface PendingStoreResolution {
3232
node: ts.Identifier;
3333
parent: ts.Node;
3434
scope: Scope;
35+
isPropsId: boolean;
3536
}
3637

3738
export function processInstanceScriptContent(
@@ -82,13 +83,18 @@ export function processInstanceScriptContent(
8283
//track if we are in a declaration scope
8384
let isDeclaration = false;
8485

86+
//track the variable declaration node
87+
let variableDeclarationNode: VariableDeclaration | null = null;
88+
8589
//track $store variables since we are only supposed to give top level scopes special treatment, and users can declare $blah variables at higher scopes
8690
//which prevents us just changing all instances of Identity that start with $
87-
const pendingStoreResolutions: PendingStoreResolution[] = [];
91+
let pendingStoreResolutions: PendingStoreResolution[] = [];
8892

8993
let scope = new Scope();
9094
const rootScope = scope;
9195

96+
let isPropsDeclarationRune = false;
97+
9298
const pushScope = () => (scope = new Scope(scope));
9399
const popScope = () => (scope = scope.parent);
94100

@@ -124,6 +130,16 @@ export function processInstanceScriptContent(
124130
return;
125131
}
126132

133+
if (
134+
ident.text === 'props' &&
135+
variableDeclarationNode &&
136+
variableDeclarationNode.initializer &&
137+
ts.isCallExpression(variableDeclarationNode.initializer) &&
138+
variableDeclarationNode.initializer.getText() === '$props()'
139+
) {
140+
isPropsDeclarationRune = true;
141+
}
142+
127143
if (isDeclaration || ts.isParameter(parent)) {
128144
if (
129145
isNotPropertyNameOfImport(ident) &&
@@ -148,14 +164,25 @@ export function processInstanceScriptContent(
148164
!ts.isTypeAliasDeclaration(parent) &&
149165
!ts.isInterfaceDeclaration(parent)
150166
) {
167+
let isPropsId = false;
168+
if (
169+
text === '$props' &&
170+
ts.isPropertyAccessExpression(parent) &&
171+
parent.parent &&
172+
ts.isCallExpression(parent.parent) &&
173+
parent.parent.arguments.length === 0
174+
) {
175+
const text = parent.getText();
176+
isPropsId = text === '$props.id';
177+
}
151178
// Handle the const { ...props } = $props() case
152179
const is_rune =
153180
(text === '$props' || text === '$derived' || text === '$state') &&
154181
ts.isCallExpression(parent) &&
155182
ts.isVariableDeclaration(parent.parent) &&
156183
parent.parent.name.getText().includes(text.slice(1));
157184
if (!is_rune) {
158-
pendingStoreResolutions.push({ node: ident, parent, scope });
185+
pendingStoreResolutions.push({ node: ident, parent, scope, isPropsId });
159186
}
160187
}
161188
}
@@ -234,7 +261,11 @@ export function processInstanceScriptContent(
234261

235262
if (ts.isVariableDeclaration(parent) && parent.name == node) {
236263
isDeclaration = true;
237-
onLeaveCallbacks.push(() => (isDeclaration = false));
264+
variableDeclarationNode = parent;
265+
onLeaveCallbacks.push(() => {
266+
isDeclaration = false;
267+
variableDeclarationNode = null;
268+
});
238269
}
239270

240271
if (ts.isBindingElement(parent) && parent.name == node) {
@@ -295,6 +326,9 @@ export function processInstanceScriptContent(
295326
tsAst.forEachChild((n) => walk(n, tsAst));
296327

297328
//resolve stores
329+
if (isPropsDeclarationRune) {
330+
pendingStoreResolutions = pendingStoreResolutions.filter(({ isPropsId }) => !isPropsId);
331+
}
298332
pendingStoreResolutions.map(resolveStore);
299333

300334
// declare implicit reactive variables we found in the script
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
///<reference types="svelte" />
2+
;function $$render() {
3+
4+
let/** @typedef {{ props: any }} $$ComponentProps *//** @type {$$ComponentProps} */ { props } = $props();
5+
let id = $props.id();
6+
;
7+
async () => {
8+
9+
id; props;};
10+
return { props: /** @type {$$ComponentProps} */({}), exports: {}, bindings: __sveltets_$$bindings(''), slots: {}, events: {} }}
11+
const Input__SvelteComponent_ = __sveltets_2_fn_component($$render());
12+
type Input__SvelteComponent_ = ReturnType<typeof Input__SvelteComponent_>;
13+
export default Input__SvelteComponent_;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<script>
2+
let { props } = $props();
3+
let id = $props.id();
4+
</script>
5+
6+
{id} {props}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
///<reference types="svelte" />
2+
;function $$render() {
3+
4+
let props = {}/*Ωignore_startΩ*/;let $props = __sveltets_2_store_get(props);/*Ωignore_endΩ*/;
5+
let id = $props.id();
6+
;
7+
async () => {
8+
9+
id; props;};
10+
return { props: /** @type {Record<string, never>} */ ({}), exports: {}, bindings: "", slots: {}, events: {} }}
11+
const Input__SvelteComponent_ = __sveltets_2_isomorphic_component(__sveltets_2_partial(__sveltets_2_with_any_event($$render())));
12+
/*Ωignore_startΩ*/type Input__SvelteComponent_ = InstanceType<typeof Input__SvelteComponent_>;
13+
/*Ωignore_endΩ*/export default Input__SvelteComponent_;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<script>
2+
let props = {};
3+
let id = $props.id();
4+
</script>
5+
6+
{id} {props}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
///<reference types="svelte" />
2+
;function $$render() {
3+
4+
let/** @typedef {Record<string, any>} $$ComponentProps *//** @type {$$ComponentProps} */ {...props} = $props();
5+
let id = $props.id();
6+
;
7+
async () => {
8+
9+
id; props;};
10+
return { props: /** @type {$$ComponentProps} */({}), exports: {}, bindings: __sveltets_$$bindings(''), slots: {}, events: {} }}
11+
const Input__SvelteComponent_ = __sveltets_2_fn_component($$render());
12+
type Input__SvelteComponent_ = ReturnType<typeof Input__SvelteComponent_>;
13+
export default Input__SvelteComponent_;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<script>
2+
let {...props} = $props();
3+
let id = $props.id();
4+
</script>
5+
6+
{id} {props}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
///<reference types="svelte" />
2+
;function $$render() {
3+
4+
let props = $props();
5+
let id = $props.id();
6+
;
7+
async () => {
8+
9+
id; props;};
10+
return { props: /** @type {$$ComponentProps} */({}), exports: {}, bindings: __sveltets_$$bindings(''), slots: {}, events: {} }}
11+
const Input__SvelteComponent_ = __sveltets_2_fn_component($$render());
12+
type Input__SvelteComponent_ = ReturnType<typeof Input__SvelteComponent_>;
13+
export default Input__SvelteComponent_;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<script>
2+
let props = $props();
3+
let id = $props.id();
4+
</script>
5+
6+
{id} {props}

0 commit comments

Comments
 (0)