Skip to content

Commit c942382

Browse files
fix: properly transform $props.id when $props is assigned to props (#2694)
* fix: properly transform `$props.id` when `$props` is assigned to `props` * chore: add comments
1 parent 8af8141 commit c942382

File tree

9 files changed

+117
-4
lines changed

9 files changed

+117
-4
lines changed

packages/svelte2tsx/src/svelte2tsx/processInstanceScriptContent.ts

Lines changed: 41 additions & 4 deletions
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,19 @@ 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+
//track is the variable declared as `props` comes from `$props()`
97+
let isPropsDeclarationRune = false;
98+
9299
const pushScope = () => (scope = new Scope(scope));
93100
const popScope = () => (scope = scope.parent);
94101

@@ -124,6 +131,17 @@ export function processInstanceScriptContent(
124131
return;
125132
}
126133

134+
//if we are in a variable declaration and the identifier is `props` we check the initializer
135+
if (
136+
ident.text === 'props' &&
137+
variableDeclarationNode &&
138+
variableDeclarationNode.initializer &&
139+
ts.isCallExpression(variableDeclarationNode.initializer) &&
140+
variableDeclarationNode.initializer.getText() === '$props()'
141+
) {
142+
isPropsDeclarationRune = true;
143+
}
144+
127145
if (isDeclaration || ts.isParameter(parent)) {
128146
if (
129147
isNotPropertyNameOfImport(ident) &&
@@ -148,14 +166,25 @@ export function processInstanceScriptContent(
148166
!ts.isTypeAliasDeclaration(parent) &&
149167
!ts.isInterfaceDeclaration(parent)
150168
) {
169+
let isPropsId = false;
170+
if (
171+
text === '$props' &&
172+
ts.isPropertyAccessExpression(parent) &&
173+
parent.parent &&
174+
ts.isCallExpression(parent.parent) &&
175+
parent.parent.arguments.length === 0
176+
) {
177+
const text = parent.getText();
178+
isPropsId = text === '$props.id';
179+
}
151180
// Handle the const { ...props } = $props() case
152181
const is_rune =
153182
(text === '$props' || text === '$derived' || text === '$state') &&
154183
ts.isCallExpression(parent) &&
155184
ts.isVariableDeclaration(parent.parent) &&
156185
parent.parent.name.getText().includes(text.slice(1));
157186
if (!is_rune) {
158-
pendingStoreResolutions.push({ node: ident, parent, scope });
187+
pendingStoreResolutions.push({ node: ident, parent, scope, isPropsId });
159188
}
160189
}
161190
}
@@ -234,7 +263,11 @@ export function processInstanceScriptContent(
234263

235264
if (ts.isVariableDeclaration(parent) && parent.name == node) {
236265
isDeclaration = true;
237-
onLeaveCallbacks.push(() => (isDeclaration = false));
266+
variableDeclarationNode = parent;
267+
onLeaveCallbacks.push(() => {
268+
isDeclaration = false;
269+
variableDeclarationNode = null;
270+
});
238271
}
239272

240273
if (ts.isBindingElement(parent) && parent.name == node) {
@@ -295,6 +328,10 @@ export function processInstanceScriptContent(
295328
tsAst.forEachChild((n) => walk(n, tsAst));
296329

297330
//resolve stores
331+
if (isPropsDeclarationRune) {
332+
//we filter out every pendingStore resolution that `isPropsId` if the variable names `props` comes from `$props()`
333+
pendingStoreResolutions = pendingStoreResolutions.filter(({ isPropsId }) => !isPropsId);
334+
}
298335
pendingStoreResolutions.map(resolveStore);
299336

300337
// declare implicit reactive variables we found in the script
Lines changed: 13 additions & 0 deletions
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}
Lines changed: 13 additions & 0 deletions
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_;
Lines changed: 6 additions & 0 deletions
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}
Lines changed: 13 additions & 0 deletions
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_;
Lines changed: 6 additions & 0 deletions
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)
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