Skip to content

Commit 6e1c89f

Browse files
committed
merge main
2 parents fe6c00d + ee25c15 commit 6e1c89f

File tree

41 files changed

+635
-273
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+635
-273
lines changed

.changeset/flat-points-kick.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

documentation/docs/02-runes/02-$state.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Unlike other frameworks you may have encountered, there is no API for interactin
2020

2121
If `$state` is used with an array or a simple object, the result is a deeply reactive _state proxy_. [Proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) allow Svelte to run code when you read or write properties, including via methods like `array.push(...)`, triggering granular updates.
2222

23-
State is proxified recursively until Svelte finds something other than an array or simple object (like a class). In a case like this...
23+
State is proxified recursively until Svelte finds something other than an array or simple object (like a class or an object created with `Object.create`). In a case like this...
2424

2525
```js
2626
let todos = $state([

packages/svelte/CHANGELOG.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,25 @@
11
# svelte
22

3+
## 5.34.0
4+
5+
### Minor Changes
6+
7+
- feat: add source name logging to `$inspect.trace` ([#16060](https://github.com/sveltejs/svelte/pull/16060))
8+
9+
### Patch Changes
10+
11+
- fix: add `command` and `commandfor` to `HTMLButtonAttributes` ([#16117](https://github.com/sveltejs/svelte/pull/16117))
12+
13+
- fix: better `$inspect.trace()` output ([#16131](https://github.com/sveltejs/svelte/pull/16131))
14+
15+
- fix: properly hydrate dynamic css props components and remove element removal ([#16118](https://github.com/sveltejs/svelte/pull/16118))
16+
17+
## 5.33.19
18+
19+
### Patch Changes
20+
21+
- fix: reset `is_flushing` if `flushSync` is called and there's no scheduled effect ([#16119](https://github.com/sveltejs/svelte/pull/16119))
22+
323
## 5.33.18
424

525
### Patch Changes

packages/svelte/elements.d.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,17 @@ export interface HTMLButtonAttributes extends HTMLAttributes<HTMLButtonElement>
926926
value?: string | string[] | number | undefined | null;
927927
popovertarget?: string | undefined | null;
928928
popovertargetaction?: 'toggle' | 'show' | 'hide' | undefined | null;
929+
command?:
930+
| 'show-modal'
931+
| 'close'
932+
| 'request-close'
933+
| 'show-popover'
934+
| 'hide-popover'
935+
| 'toggle-popover'
936+
| (string & {})
937+
| undefined
938+
| null;
939+
commandfor?: string | undefined | null;
929940
}
930941

931942
export interface HTMLCanvasAttributes extends HTMLAttributes<HTMLCanvasElement> {

packages/svelte/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "svelte",
33
"description": "Cybernetically enhanced web apps",
44
"license": "MIT",
5-
"version": "5.33.18",
5+
"version": "5.34.0",
66
"type": "module",
77
"types": "./types/index.d.ts",
88
"engines": {

packages/svelte/src/compiler/phases/3-transform/client/visitors/AssignmentExpression.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,20 @@ function build_assignment(operator, left, right, context) {
6767
in_constructor: rune !== '$derived' && rune !== '$derived.by'
6868
};
6969

70-
return b.assignment(
71-
operator,
72-
b.member(b.this, field.key),
73-
/** @type {Expression} */ (context.visit(right, child_state))
74-
);
70+
let value = /** @type {Expression} */ (context.visit(right, child_state));
71+
72+
if (dev) {
73+
const declaration = context.path.findLast(
74+
(parent) => parent.type === 'ClassDeclaration' || parent.type === 'ClassExpression'
75+
);
76+
value = b.call(
77+
'$.tag',
78+
value,
79+
b.literal(`${declaration?.id?.name ?? '[class]'}.${name}`)
80+
);
81+
}
82+
83+
return b.assignment(operator, b.member(b.this, field.key), value);
7584
}
7685
}
7786

packages/svelte/src/compiler/phases/3-transform/client/visitors/ClassBody.js

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
/** @import { CallExpression, ClassBody, MethodDefinition, PropertyDefinition, StaticBlock } from 'estree' */
1+
/** @import { CallExpression, ClassBody, ClassDeclaration, ClassExpression, MethodDefinition, PropertyDefinition, StaticBlock } from 'estree' */
22
/** @import { StateField } from '#compiler' */
33
/** @import { Context } from '../types' */
44
import * as b from '#compiler/builders';
5+
import { dev } from '../../../../state.js';
6+
import { get_parent } from '../../../../utils/ast.js';
57
import { get_name } from '../../../nodes.js';
68

79
/**
@@ -50,6 +52,10 @@ export function ClassBody(node, context) {
5052
}
5153
}
5254

55+
const declaration = /** @type {ClassDeclaration | ClassExpression} */ (
56+
get_parent(context.path, -1)
57+
);
58+
5359
// Replace parts of the class body
5460
for (const definition of node.body) {
5561
if (definition.type !== 'PropertyDefinition') {
@@ -68,17 +74,26 @@ export function ClassBody(node, context) {
6874
}
6975

7076
if (name[0] === '#') {
71-
body.push(/** @type {PropertyDefinition} */ (context.visit(definition, child_state)));
77+
let value = definition.value
78+
? /** @type {CallExpression} */ (context.visit(definition.value, child_state))
79+
: undefined;
80+
81+
if (dev) {
82+
value = b.call('$.tag', value, b.literal(`${declaration.id?.name ?? '[class]'}.${name}`));
83+
}
84+
85+
body.push(b.prop_def(definition.key, value));
7286
} else if (field.node === definition) {
73-
const member = b.member(b.this, field.key);
87+
let call = /** @type {CallExpression} */ (context.visit(field.value, child_state));
7488

89+
if (dev) {
90+
call = b.call('$.tag', call, b.literal(`${declaration.id?.name ?? '[class]'}.${name}`));
91+
}
92+
const member = b.member(b.this, field.key);
7593
const should_proxy = field.type === '$state' && true; // TODO
7694

7795
body.push(
78-
b.prop_def(
79-
field.key,
80-
/** @type {CallExpression} */ (context.visit(field.value, child_state))
81-
),
96+
b.prop_def(field.key, call),
8297

8398
b.method('get', definition.key, [], [b.return(b.call('$.get', member))]),
8499

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,19 @@
1-
/** @import { Expression } from 'estree' */
21
/** @import { AST } from '#compiler' */
32
/** @import { ComponentContext } from '../types' */
4-
import * as b from '#compiler/builders';
3+
import { regex_is_valid_identifier } from '../../../patterns.js';
54
import { build_component } from './shared/component.js';
65

76
/**
87
* @param {AST.Component} node
98
* @param {ComponentContext} context
109
*/
1110
export function Component(node, context) {
12-
if (node.metadata.dynamic) {
13-
// Handle dynamic references to what seems like static inline components
14-
const component = build_component(node, '$$component', context, b.id('$$anchor'));
15-
context.state.init.push(
16-
b.stmt(
17-
b.call(
18-
'$.component',
19-
context.state.node,
20-
// TODO use untrack here to not update when binding changes?
21-
// Would align with Svelte 4 behavior, but it's arguably nicer/expected to update this
22-
b.thunk(/** @type {Expression} */ (context.visit(b.member_id(node.name)))),
23-
b.arrow([b.id('$$anchor'), b.id('$$component')], b.block([component]))
24-
)
25-
)
26-
);
27-
return;
28-
}
29-
30-
const component = build_component(node, node.name, context);
11+
const component = build_component(
12+
node,
13+
// if it's not dynamic we will just use the node name, if it is dynamic we will use the node name
14+
// only if it's a valid identifier, otherwise we will use a default name
15+
!node.metadata.dynamic || regex_is_valid_identifier.test(node.name) ? node.name : '$$component',
16+
context
17+
);
3118
context.state.init.push(component);
3219
}

packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ export function VariableDeclaration(node, context) {
9090
should_proxy(initial, context.state.scope)
9191
) {
9292
initial = b.call('$.proxy', initial);
93+
94+
if (dev) {
95+
initial = b.call('$.tag_proxy', initial, b.literal(id.name));
96+
}
9397
}
9498

9599
if (is_prop_source(binding, context.state)) {
@@ -128,12 +132,25 @@ export function VariableDeclaration(node, context) {
128132
const binding = /** @type {import('#compiler').Binding} */ (
129133
context.state.scope.get(id.name)
130134
);
131-
if (rune === '$state' && should_proxy(value, context.state.scope)) {
135+
const is_state = is_state_source(binding, context.state.analysis);
136+
const is_proxy = should_proxy(value, context.state.scope);
137+
138+
if (rune === '$state' && is_proxy) {
132139
value = b.call('$.proxy', value);
140+
141+
if (dev && !is_state) {
142+
value = b.call('$.tag_proxy', value, b.literal(id.name));
143+
}
133144
}
134-
if (is_state_source(binding, context.state.analysis)) {
145+
146+
if (is_state) {
135147
value = b.call('$.state', value);
148+
149+
if (dev) {
150+
value = b.call('$.tag', value, b.literal(id.name));
151+
}
136152
}
153+
137154
return value;
138155
};
139156

@@ -154,7 +171,11 @@ export function VariableDeclaration(node, context) {
154171
context.state.transform[id.name] = { read: get_value };
155172

156173
const expression = /** @type {Expression} */ (context.visit(b.thunk(value)));
157-
return b.declarator(id, b.call('$.derived', expression));
174+
const call = b.call('$.derived', expression);
175+
return b.declarator(
176+
id,
177+
dev ? b.call('$.tag', call, b.literal('[$state iterable]')) : call
178+
);
158179
}),
159180
...paths.map((path) => {
160181
const value = /** @type {Expression} */ (context.visit(path.expression));
@@ -203,7 +224,10 @@ export function VariableDeclaration(node, context) {
203224
let expression = /** @type {Expression} */ (context.visit(value));
204225
if (rune === '$derived') expression = b.thunk(expression);
205226

206-
declarations.push(b.declarator(declarator.id, b.call('$.derived', expression)));
227+
let call = b.call('$.derived', expression);
228+
if (dev) call = b.call('$.tag', call, b.literal(declarator.id.name));
229+
230+
declarations.push(b.declarator(declarator.id, call));
207231
}
208232
} else {
209233
const init = /** @type {CallExpression} */ (declarator.init);
@@ -216,8 +240,10 @@ export function VariableDeclaration(node, context) {
216240

217241
let expression = /** @type {Expression} */ (context.visit(value));
218242
if (rune === '$derived') expression = b.thunk(expression);
219-
220-
declarations.push(b.declarator(id, b.call('$.derived', expression)));
243+
const call = b.call('$.derived', expression);
244+
declarations.push(
245+
b.declarator(id, dev ? b.call('$.tag', call, b.literal('[$derived iterable]')) : call)
246+
);
221247
}
222248

223249
const { inserts, paths } = extract_paths(declarator.id, rhs);
@@ -227,12 +253,23 @@ export function VariableDeclaration(node, context) {
227253
context.state.transform[id.name] = { read: get_value };
228254

229255
const expression = /** @type {Expression} */ (context.visit(b.thunk(value)));
230-
declarations.push(b.declarator(id, b.call('$.derived', expression)));
256+
const call = b.call('$.derived', expression);
257+
declarations.push(
258+
b.declarator(id, dev ? b.call('$.tag', call, b.literal('[$derived iterable]')) : call)
259+
);
231260
}
232261

233262
for (const path of paths) {
234263
const expression = /** @type {Expression} */ (context.visit(path.expression));
235-
declarations.push(b.declarator(path.node, b.call('$.derived', b.thunk(expression))));
264+
const call = b.call('$.derived', b.thunk(expression));
265+
declarations.push(
266+
b.declarator(
267+
path.node,
268+
dev
269+
? b.call('$.tag', call, b.literal(/** @type {Identifier} */ (path.node).name))
270+
: call
271+
)
272+
);
236273
}
237274
}
238275

packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/component.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@ import { create_derived } from '../../utils.js';
1414
* @param {AST.Component | AST.SvelteComponent | AST.SvelteSelf} node
1515
* @param {string} component_name
1616
* @param {ComponentContext} context
17-
* @param {Expression} anchor
1817
* @returns {Statement}
1918
*/
20-
export function build_component(node, component_name, context, anchor = context.state.node) {
19+
export function build_component(node, component_name, context) {
20+
/**
21+
* @type {Expression}
22+
*/
23+
const anchor = context.state.node;
2124
/** @type {Array<Property[] | Expression>} */
2225
const props_and_spreads = [];
2326
/** @type {Array<() => void>} */
@@ -435,7 +438,7 @@ export function build_component(node, component_name, context, anchor = context.
435438
// TODO We can remove this ternary once we remove legacy mode, since in runes mode dynamic components
436439
// will be handled separately through the `$.component` function, and then the component name will
437440
// always be referenced through just the identifier here.
438-
node.type === 'SvelteComponent'
441+
node.type === 'SvelteComponent' || (node.type === 'Component' && node.metadata.dynamic)
439442
? component_name
440443
: /** @type {Expression} */ (context.visit(b.member_id(component_name))),
441444
node_id,
@@ -458,14 +461,18 @@ export function build_component(node, component_name, context, anchor = context.
458461
)
459462
];
460463

461-
if (node.type === 'SvelteComponent') {
464+
if (node.type === 'SvelteComponent' || (node.type === 'Component' && node.metadata.dynamic)) {
462465
const prev = fn;
463466

464467
fn = (node_id) => {
465468
return b.call(
466469
'$.component',
467470
node_id,
468-
b.thunk(/** @type {Expression} */ (context.visit(node.expression))),
471+
b.thunk(
472+
/** @type {Expression} */ (
473+
context.visit(node.type === 'Component' ? b.member_id(node.name) : node.expression)
474+
)
475+
),
469476
b.arrow(
470477
[b.id('$$anchor'), b.id(component_name)],
471478
b.block([...binding_initializers, b.stmt(prev(b.id('$$anchor')))])

0 commit comments

Comments
 (0)