svelte 5.41.1 → 5.41.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/compiler/index.js +1 -1
- package/package.json +1 -1
- package/src/compiler/phases/2-analyze/index.js +3 -3
- package/src/compiler/phases/2-analyze/visitors/AwaitExpression.js +13 -6
- package/src/compiler/phases/2-analyze/visitors/CallExpression.js +1 -1
- package/src/compiler/phases/2-analyze/visitors/ConstTag.js +3 -1
- package/src/compiler/phases/2-analyze/visitors/VariableDeclarator.js +0 -6
- package/src/compiler/phases/3-transform/client/visitors/CallExpression.js +21 -3
- package/src/compiler/phases/3-transform/server/visitors/CallExpression.js +10 -4
- package/src/compiler/phases/3-transform/utils.js +14 -25
- package/src/internal/client/dev/inspect.js +14 -4
- package/src/internal/client/dev/tracing.js +10 -1
- package/src/internal/client/dom/blocks/async.js +5 -0
- package/src/internal/client/dom/blocks/boundary.js +0 -7
- package/src/internal/client/reactivity/async.js +3 -8
- package/src/internal/client/reactivity/batch.js +134 -69
- package/src/internal/client/reactivity/deriveds.js +19 -10
- package/src/internal/client/reactivity/sources.js +1 -1
- package/src/internal/server/index.js +0 -9
- package/src/version.js +1 -1
- package/types/index.d.ts.map +1 -1
package/package.json
CHANGED
|
@@ -306,7 +306,7 @@ export function analyze_module(source, options) {
|
|
|
306
306
|
fragment: null,
|
|
307
307
|
parent_element: null,
|
|
308
308
|
reactive_statement: null,
|
|
309
|
-
|
|
309
|
+
derived_function_depth: -1
|
|
310
310
|
},
|
|
311
311
|
visitors
|
|
312
312
|
);
|
|
@@ -703,7 +703,7 @@ export function analyze_component(root, source, options) {
|
|
|
703
703
|
state_fields: new Map(),
|
|
704
704
|
function_depth: scope.function_depth,
|
|
705
705
|
reactive_statement: null,
|
|
706
|
-
|
|
706
|
+
derived_function_depth: -1
|
|
707
707
|
};
|
|
708
708
|
|
|
709
709
|
walk(/** @type {AST.SvelteNode} */ (ast), state, visitors);
|
|
@@ -771,7 +771,7 @@ export function analyze_component(root, source, options) {
|
|
|
771
771
|
expression: null,
|
|
772
772
|
state_fields: new Map(),
|
|
773
773
|
function_depth: scope.function_depth,
|
|
774
|
-
|
|
774
|
+
derived_function_depth: -1
|
|
775
775
|
};
|
|
776
776
|
|
|
777
777
|
walk(/** @type {AST.SvelteNode} */ (ast), state, visitors);
|
|
@@ -15,7 +15,10 @@ export function AwaitExpression(node, context) {
|
|
|
15
15
|
// b) awaits that precede other expressions in template or `$derived(...)`
|
|
16
16
|
if (
|
|
17
17
|
tla ||
|
|
18
|
-
(is_reactive_expression(
|
|
18
|
+
(is_reactive_expression(
|
|
19
|
+
context.path,
|
|
20
|
+
context.state.derived_function_depth === context.state.function_depth
|
|
21
|
+
) &&
|
|
19
22
|
!is_last_evaluated_expression(context.path, node))
|
|
20
23
|
) {
|
|
21
24
|
context.state.analysis.pickled_awaits.add(node);
|
|
@@ -53,9 +56,7 @@ export function AwaitExpression(node, context) {
|
|
|
53
56
|
* @param {boolean} in_derived
|
|
54
57
|
*/
|
|
55
58
|
export function is_reactive_expression(path, in_derived) {
|
|
56
|
-
if (in_derived)
|
|
57
|
-
return true;
|
|
58
|
-
}
|
|
59
|
+
if (in_derived) return true;
|
|
59
60
|
|
|
60
61
|
let i = path.length;
|
|
61
62
|
|
|
@@ -67,6 +68,7 @@ export function is_reactive_expression(path, in_derived) {
|
|
|
67
68
|
parent.type === 'FunctionExpression' ||
|
|
68
69
|
parent.type === 'FunctionDeclaration'
|
|
69
70
|
) {
|
|
71
|
+
// No reactive expression found between function and await
|
|
70
72
|
return false;
|
|
71
73
|
}
|
|
72
74
|
|
|
@@ -83,11 +85,16 @@ export function is_reactive_expression(path, in_derived) {
|
|
|
83
85
|
* @param {AST.SvelteNode[]} path
|
|
84
86
|
* @param {Expression | SpreadElement | Property} node
|
|
85
87
|
*/
|
|
86
|
-
|
|
88
|
+
function is_last_evaluated_expression(path, node) {
|
|
87
89
|
let i = path.length;
|
|
88
90
|
|
|
89
91
|
while (i--) {
|
|
90
|
-
const parent =
|
|
92
|
+
const parent = path[i];
|
|
93
|
+
|
|
94
|
+
if (parent.type === 'ConstTag') {
|
|
95
|
+
// {@const ...} tags are treated as deriveds and its contents should all get the preserve-reactivity treatment
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
91
98
|
|
|
92
99
|
// @ts-expect-error we could probably use a neater/more robust mechanism
|
|
93
100
|
if (parent.metadata) {
|
|
@@ -248,7 +248,7 @@ export function CallExpression(node, context) {
|
|
|
248
248
|
context.next({
|
|
249
249
|
...context.state,
|
|
250
250
|
function_depth: context.state.function_depth + 1,
|
|
251
|
-
|
|
251
|
+
derived_function_depth: context.state.function_depth + 1,
|
|
252
252
|
expression
|
|
253
253
|
});
|
|
254
254
|
|
|
@@ -38,6 +38,8 @@ export function ConstTag(node, context) {
|
|
|
38
38
|
context.visit(declaration.init, {
|
|
39
39
|
...context.state,
|
|
40
40
|
expression: node.metadata.expression,
|
|
41
|
-
|
|
41
|
+
// We're treating this like a $derived under the hood
|
|
42
|
+
function_depth: context.state.function_depth + 1,
|
|
43
|
+
derived_function_depth: context.state.function_depth + 1
|
|
42
44
|
});
|
|
43
45
|
}
|
|
@@ -64,12 +64,6 @@ export function VariableDeclarator(node, context) {
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
if (rune === '$derived') {
|
|
68
|
-
context.visit(node.id);
|
|
69
|
-
context.visit(/** @type {Expression} */ (node.init), { ...context.state, in_derived: true });
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
67
|
if (rune === '$props') {
|
|
74
68
|
if (node.id.type !== 'ObjectPattern' && node.id.type !== 'Identifier') {
|
|
75
69
|
e.props_invalid_identifier(node);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
/** @import { CallExpression, Expression } from 'estree' */
|
|
1
|
+
/** @import { CallExpression, Expression, MemberExpression } from 'estree' */
|
|
2
2
|
/** @import { Context } from '../types' */
|
|
3
3
|
import { dev, is_ignored } from '../../../../state.js';
|
|
4
4
|
import * as b from '#compiler/builders';
|
|
5
5
|
import { get_rune } from '../../../scope.js';
|
|
6
|
-
import { transform_inspect_rune } from '../../utils.js';
|
|
7
6
|
import { should_proxy } from '../utils.js';
|
|
7
|
+
import { get_inspect_args } from '../../utils.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* @param {CallExpression} node
|
|
@@ -73,7 +73,7 @@ export function CallExpression(node, context) {
|
|
|
73
73
|
|
|
74
74
|
case '$inspect':
|
|
75
75
|
case '$inspect().with':
|
|
76
|
-
return transform_inspect_rune(node, context);
|
|
76
|
+
return transform_inspect_rune(rune, node, context);
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
if (
|
|
@@ -104,3 +104,21 @@ export function CallExpression(node, context) {
|
|
|
104
104
|
|
|
105
105
|
context.next();
|
|
106
106
|
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @param {'$inspect' | '$inspect().with'} rune
|
|
110
|
+
* @param {CallExpression} node
|
|
111
|
+
* @param {Context} context
|
|
112
|
+
*/
|
|
113
|
+
function transform_inspect_rune(rune, node, context) {
|
|
114
|
+
if (!dev) return b.empty;
|
|
115
|
+
|
|
116
|
+
const { args, inspector } = get_inspect_args(rune, node, context.visit);
|
|
117
|
+
|
|
118
|
+
// by passing an arrow function, the log appears to come from the `$inspect` callsite
|
|
119
|
+
// rather than the `inspect.js` file containing the utility
|
|
120
|
+
const id = b.id('$$args');
|
|
121
|
+
const fn = b.arrow([b.rest(id)], b.call(inspector, b.spread(id)));
|
|
122
|
+
|
|
123
|
+
return b.call('$.inspect', b.thunk(b.array(args)), fn, rune === '$inspect' && b.true);
|
|
124
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
/** @import { CallExpression, Expression } from 'estree' */
|
|
1
|
+
/** @import { CallExpression, Expression, MemberExpression } from 'estree' */
|
|
2
2
|
/** @import { Context } from '../types.js' */
|
|
3
|
-
import { is_ignored } from '../../../../state.js';
|
|
3
|
+
import { dev, is_ignored } from '../../../../state.js';
|
|
4
4
|
import * as b from '#compiler/builders';
|
|
5
5
|
import { get_rune } from '../../../scope.js';
|
|
6
|
-
import {
|
|
6
|
+
import { get_inspect_args } from '../../utils.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @param {CallExpression} node
|
|
@@ -51,7 +51,13 @@ export function CallExpression(node, context) {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
if (rune === '$inspect' || rune === '$inspect().with') {
|
|
54
|
-
|
|
54
|
+
if (!dev) return b.empty;
|
|
55
|
+
|
|
56
|
+
const { args, inspector } = get_inspect_args(rune, node, context.visit);
|
|
57
|
+
|
|
58
|
+
return rune === '$inspect'
|
|
59
|
+
? b.call(inspector, b.literal('$inspect('), ...args, b.literal(')'))
|
|
60
|
+
: b.call(inspector, b.literal('init'), ...args);
|
|
55
61
|
}
|
|
56
62
|
|
|
57
63
|
context.next();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @import { Context } from 'zimmerframe' */
|
|
2
2
|
/** @import { TransformState } from './types.js' */
|
|
3
3
|
/** @import { AST, Binding, Namespace, ValidatedCompileOptions } from '#compiler' */
|
|
4
|
-
/** @import { Node, Expression, CallExpression } from 'estree' */
|
|
4
|
+
/** @import { Node, Expression, CallExpression, MemberExpression } from 'estree' */
|
|
5
5
|
import {
|
|
6
6
|
regex_ends_with_whitespaces,
|
|
7
7
|
regex_not_whitespace,
|
|
@@ -452,30 +452,19 @@ export function determine_namespace_for_children(node, namespace) {
|
|
|
452
452
|
}
|
|
453
453
|
|
|
454
454
|
/**
|
|
455
|
-
* @
|
|
455
|
+
* @param {'$inspect' | '$inspect().with'} rune
|
|
456
456
|
* @param {CallExpression} node
|
|
457
|
-
* @param {
|
|
457
|
+
* @param {(node: AST.SvelteNode) => AST.SvelteNode} visit
|
|
458
458
|
*/
|
|
459
|
-
export function
|
|
460
|
-
const
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
/** @type {
|
|
469
|
-
|
|
470
|
-
const with_arg = /** @type {Expression} */ (visit(node.arguments[0]));
|
|
471
|
-
|
|
472
|
-
return b.call(
|
|
473
|
-
'$.inspect',
|
|
474
|
-
as_fn ? b.thunk(b.array(inspect_args)) : b.array(inspect_args),
|
|
475
|
-
with_arg
|
|
476
|
-
);
|
|
477
|
-
} else {
|
|
478
|
-
const arg = node.arguments.map((arg) => /** @type {Expression} */ (visit(arg)));
|
|
479
|
-
return b.call('$.inspect', as_fn ? b.thunk(b.array(arg)) : b.array(arg));
|
|
480
|
-
}
|
|
459
|
+
export function get_inspect_args(rune, node, visit) {
|
|
460
|
+
const call =
|
|
461
|
+
rune === '$inspect'
|
|
462
|
+
? node
|
|
463
|
+
: /** @type {CallExpression} */ (/** @type {MemberExpression} */ (node.callee).object);
|
|
464
|
+
|
|
465
|
+
return {
|
|
466
|
+
args: call.arguments.map((arg) => /** @type {Expression} */ (visit(arg))),
|
|
467
|
+
inspector:
|
|
468
|
+
rune === '$inspect' ? 'console.log' : /** @type {Expression} */ (visit(node.arguments[0]))
|
|
469
|
+
};
|
|
481
470
|
}
|
|
@@ -2,13 +2,14 @@ import { UNINITIALIZED } from '../../../constants.js';
|
|
|
2
2
|
import { snapshot } from '../../shared/clone.js';
|
|
3
3
|
import { inspect_effect, render_effect, validate_effect } from '../reactivity/effects.js';
|
|
4
4
|
import { untrack } from '../runtime.js';
|
|
5
|
+
import { get_stack } from './tracing.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* @param {() => any[]} get_value
|
|
8
|
-
* @param {Function}
|
|
9
|
+
* @param {Function} inspector
|
|
10
|
+
* @param {boolean} show_stack
|
|
9
11
|
*/
|
|
10
|
-
|
|
11
|
-
export function inspect(get_value, inspector = console.log) {
|
|
12
|
+
export function inspect(get_value, inspector, show_stack = false) {
|
|
12
13
|
validate_effect('$inspect');
|
|
13
14
|
|
|
14
15
|
let initial = true;
|
|
@@ -28,7 +29,16 @@ export function inspect(get_value, inspector = console.log) {
|
|
|
28
29
|
|
|
29
30
|
var snap = snapshot(value, true, true);
|
|
30
31
|
untrack(() => {
|
|
31
|
-
|
|
32
|
+
if (show_stack) {
|
|
33
|
+
inspector(...snap);
|
|
34
|
+
|
|
35
|
+
if (!initial) {
|
|
36
|
+
// eslint-disable-next-line no-console
|
|
37
|
+
console.log(get_stack('UpdatedAt'));
|
|
38
|
+
}
|
|
39
|
+
} else {
|
|
40
|
+
inspector(initial ? 'init' : 'update', ...snap);
|
|
41
|
+
}
|
|
32
42
|
});
|
|
33
43
|
|
|
34
44
|
initial = false;
|
|
@@ -134,7 +134,16 @@ export function trace(label, fn) {
|
|
|
134
134
|
* @returns {Error & { stack: string } | null}
|
|
135
135
|
*/
|
|
136
136
|
export function get_stack(label) {
|
|
137
|
+
// @ts-ignore stackTraceLimit doesn't exist everywhere
|
|
138
|
+
const limit = Error.stackTraceLimit;
|
|
139
|
+
|
|
140
|
+
// @ts-ignore
|
|
141
|
+
Error.stackTraceLimit = Infinity;
|
|
137
142
|
let error = Error();
|
|
143
|
+
|
|
144
|
+
// @ts-ignore
|
|
145
|
+
Error.stackTraceLimit = limit;
|
|
146
|
+
|
|
138
147
|
const stack = error.stack;
|
|
139
148
|
|
|
140
149
|
if (!stack) return null;
|
|
@@ -151,7 +160,7 @@ export function get_stack(label) {
|
|
|
151
160
|
if (line.includes('validate_each_keys')) {
|
|
152
161
|
return null;
|
|
153
162
|
}
|
|
154
|
-
if (line.includes('svelte/src/internal')) {
|
|
163
|
+
if (line.includes('svelte/src/internal') || line.includes('svelte\\src\\internal')) {
|
|
155
164
|
continue;
|
|
156
165
|
}
|
|
157
166
|
new_lines.push(line);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** @import { TemplateNode, Value } from '#client' */
|
|
2
2
|
import { flatten } from '../../reactivity/async.js';
|
|
3
|
+
import { Batch, current_batch } from '../../reactivity/batch.js';
|
|
3
4
|
import { get } from '../../runtime.js';
|
|
4
5
|
import {
|
|
5
6
|
hydrate_next,
|
|
@@ -18,8 +19,11 @@ import { get_boundary } from './boundary.js';
|
|
|
18
19
|
*/
|
|
19
20
|
export function async(node, expressions, fn) {
|
|
20
21
|
var boundary = get_boundary();
|
|
22
|
+
var batch = /** @type {Batch} */ (current_batch);
|
|
23
|
+
var blocking = !boundary.is_pending();
|
|
21
24
|
|
|
22
25
|
boundary.update_pending_count(1);
|
|
26
|
+
batch.increment(blocking);
|
|
23
27
|
|
|
24
28
|
var was_hydrating = hydrating;
|
|
25
29
|
|
|
@@ -44,6 +48,7 @@ export function async(node, expressions, fn) {
|
|
|
44
48
|
fn(node, ...values);
|
|
45
49
|
} finally {
|
|
46
50
|
boundary.update_pending_count(-1);
|
|
51
|
+
batch.decrement(blocking);
|
|
47
52
|
}
|
|
48
53
|
|
|
49
54
|
if (was_hydrating) {
|
|
@@ -291,13 +291,6 @@ export class Boundary {
|
|
|
291
291
|
this.#anchor.before(this.#offscreen_fragment);
|
|
292
292
|
this.#offscreen_fragment = null;
|
|
293
293
|
}
|
|
294
|
-
|
|
295
|
-
// TODO this feels like a little bit of a kludge, but until we
|
|
296
|
-
// overhaul the boundary/batch relationship it's probably
|
|
297
|
-
// the most pragmatic solution available to us
|
|
298
|
-
queue_micro_task(() => {
|
|
299
|
-
Batch.ensure().flush();
|
|
300
|
-
});
|
|
301
294
|
}
|
|
302
295
|
}
|
|
303
296
|
|
|
@@ -218,10 +218,10 @@ export function unset_context() {
|
|
|
218
218
|
export async function async_body(anchor, fn) {
|
|
219
219
|
var boundary = get_boundary();
|
|
220
220
|
var batch = /** @type {Batch} */ (current_batch);
|
|
221
|
-
var
|
|
221
|
+
var blocking = !boundary.is_pending();
|
|
222
222
|
|
|
223
223
|
boundary.update_pending_count(1);
|
|
224
|
-
|
|
224
|
+
batch.increment(blocking);
|
|
225
225
|
|
|
226
226
|
var active = /** @type {Effect} */ (active_effect);
|
|
227
227
|
|
|
@@ -254,12 +254,7 @@ export async function async_body(anchor, fn) {
|
|
|
254
254
|
}
|
|
255
255
|
|
|
256
256
|
boundary.update_pending_count(-1);
|
|
257
|
-
|
|
258
|
-
if (pending) {
|
|
259
|
-
batch.flush();
|
|
260
|
-
} else {
|
|
261
|
-
batch.decrement();
|
|
262
|
-
}
|
|
257
|
+
batch.decrement(blocking);
|
|
263
258
|
|
|
264
259
|
unset_context();
|
|
265
260
|
}
|