svelte 5.41.4 → 5.42.1

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.
Files changed (34) hide show
  1. package/compiler/index.js +1 -1
  2. package/package.json +1 -1
  3. package/src/compiler/phases/2-analyze/visitors/Attribute.js +5 -183
  4. package/src/compiler/phases/2-analyze/visitors/shared/function.js +0 -7
  5. package/src/compiler/phases/3-transform/client/utils.js +2 -124
  6. package/src/compiler/phases/3-transform/client/visitors/FunctionDeclaration.js +0 -11
  7. package/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +0 -18
  8. package/src/compiler/phases/3-transform/client/visitors/shared/events.js +1 -29
  9. package/src/compiler/phases/3-transform/client/visitors/shared/function.js +0 -13
  10. package/src/compiler/phases/3-transform/utils.js +0 -19
  11. package/src/compiler/phases/nodes.js +1 -1
  12. package/src/compiler/utils/builders.js +3 -6
  13. package/src/index-client.js +1 -1
  14. package/src/index-server.js +4 -0
  15. package/src/internal/client/constants.js +2 -1
  16. package/src/internal/client/context.js +8 -1
  17. package/src/internal/client/dev/inspect.js +12 -3
  18. package/src/internal/client/dev/tracing.js +1 -2
  19. package/src/internal/client/dom/blocks/branches.js +18 -3
  20. package/src/internal/client/dom/blocks/each.js +1 -1
  21. package/src/internal/client/dom/elements/attributes.js +2 -2
  22. package/src/internal/client/dom/elements/events.js +2 -7
  23. package/src/internal/client/error-handling.js +2 -2
  24. package/src/internal/client/errors.js +48 -0
  25. package/src/internal/client/proxy.js +5 -5
  26. package/src/internal/client/reactivity/batch.js +168 -22
  27. package/src/internal/client/reactivity/deriveds.js +5 -5
  28. package/src/internal/client/reactivity/effects.js +4 -4
  29. package/src/internal/client/reactivity/sources.js +19 -19
  30. package/src/internal/client/runtime.js +2 -2
  31. package/src/utils.js +1 -1
  32. package/src/version.js +1 -1
  33. package/types/index.d.ts +39 -5
  34. package/types/index.d.ts.map +5 -3
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "svelte",
3
3
  "description": "Cybernetically enhanced web apps",
4
4
  "license": "MIT",
5
- "version": "5.41.4",
5
+ "version": "5.42.1",
6
6
  "type": "module",
7
7
  "types": "./types/index.d.ts",
8
8
  "engines": {
@@ -1,12 +1,7 @@
1
- /** @import { ArrowFunctionExpression, Expression, FunctionDeclaration, FunctionExpression } from 'estree' */
2
- /** @import { AST, DelegatedEvent } from '#compiler' */
1
+ /** @import { AST } from '#compiler' */
3
2
  /** @import { Context } from '../types' */
4
- import { cannot_be_set_statically, is_capture_event, is_delegated } from '../../../../utils.js';
5
- import {
6
- get_attribute_chunks,
7
- get_attribute_expression,
8
- is_event_attribute
9
- } from '../../../utils/ast.js';
3
+ import { cannot_be_set_statically, can_delegate_event } from '../../../../utils.js';
4
+ import { get_attribute_chunks, is_event_attribute } from '../../../utils/ast.js';
10
5
  import { mark_subtree_dynamic } from './shared/fragment.js';
11
6
 
12
7
  /**
@@ -64,181 +59,8 @@ export function Attribute(node, context) {
64
59
  context.state.analysis.uses_event_attributes = true;
65
60
  }
66
61
 
67
- const expression = get_attribute_expression(node);
68
- const delegated_event = get_delegated_event(node.name.slice(2), expression, context);
69
-
70
- if (delegated_event !== null) {
71
- if (delegated_event.hoisted) {
72
- delegated_event.function.metadata.hoisted = true;
73
- }
74
-
75
- node.metadata.delegated = delegated_event;
76
- }
77
- }
78
- }
79
- }
80
-
81
- /** @type {DelegatedEvent} */
82
- const unhoisted = { hoisted: false };
83
-
84
- /**
85
- * Checks if given event attribute can be delegated/hoisted and returns the corresponding info if so
86
- * @param {string} event_name
87
- * @param {Expression | null} handler
88
- * @param {Context} context
89
- * @returns {null | DelegatedEvent}
90
- */
91
- function get_delegated_event(event_name, handler, context) {
92
- // Handle delegated event handlers. Bail out if not a delegated event.
93
- if (!handler || !is_delegated(event_name)) {
94
- return null;
95
- }
96
-
97
- // If we are not working with a RegularElement, then bail out.
98
- const element = context.path.at(-1);
99
- if (element?.type !== 'RegularElement') {
100
- return null;
101
- }
102
-
103
- /** @type {FunctionExpression | FunctionDeclaration | ArrowFunctionExpression | null} */
104
- let target_function = null;
105
- let binding = null;
106
-
107
- if (element.metadata.has_spread) {
108
- // event attribute becomes part of the dynamic spread array
109
- return unhoisted;
110
- }
111
-
112
- if (handler.type === 'ArrowFunctionExpression' || handler.type === 'FunctionExpression') {
113
- target_function = handler;
114
- } else if (handler.type === 'Identifier') {
115
- binding = context.state.scope.get(handler.name);
116
-
117
- if (context.state.analysis.module.scope.references.has(handler.name)) {
118
- // If a binding with the same name is referenced in the module scope (even if not declared there), bail out
119
- return unhoisted;
120
- }
121
-
122
- if (binding != null) {
123
- for (const { path } of binding.references) {
124
- const parent = path.at(-1);
125
- if (parent === undefined) return unhoisted;
126
-
127
- const grandparent = path.at(-2);
128
-
129
- /** @type {AST.RegularElement | null} */
130
- let element = null;
131
- /** @type {string | null} */
132
- let event_name = null;
133
- if (parent.type === 'OnDirective') {
134
- element = /** @type {AST.RegularElement} */ (grandparent);
135
- event_name = parent.name;
136
- } else if (
137
- parent.type === 'ExpressionTag' &&
138
- grandparent?.type === 'Attribute' &&
139
- is_event_attribute(grandparent)
140
- ) {
141
- element = /** @type {AST.RegularElement} */ (path.at(-3));
142
- const attribute = /** @type {AST.Attribute} */ (grandparent);
143
- event_name = get_attribute_event_name(attribute.name);
144
- }
145
-
146
- if (element && event_name) {
147
- if (
148
- element.type !== 'RegularElement' ||
149
- element.metadata.has_spread ||
150
- !is_delegated(event_name)
151
- ) {
152
- return unhoisted;
153
- }
154
- } else if (parent.type !== 'FunctionDeclaration' && parent.type !== 'VariableDeclarator') {
155
- return unhoisted;
156
- }
157
- }
62
+ node.metadata.delegated =
63
+ parent?.type === 'RegularElement' && can_delegate_event(node.name.slice(2));
158
64
  }
159
-
160
- // If the binding is exported, bail out
161
- if (context.state.analysis.exports.find((node) => node.name === handler.name)) {
162
- return unhoisted;
163
- }
164
-
165
- if (binding?.is_function()) {
166
- target_function = binding.initial;
167
- }
168
- }
169
-
170
- // If we can't find a function, or the function has multiple parameters, bail out
171
- if (target_function == null || target_function.params.length > 1) {
172
- return unhoisted;
173
- }
174
-
175
- const visited_references = new Set();
176
- const scope = target_function.metadata.scope;
177
- for (const [reference] of scope.references) {
178
- // Bail out if the arguments keyword is used or $host is referenced
179
- if (reference === 'arguments' || reference === '$host') return unhoisted;
180
- // Bail out if references a store subscription
181
- if (scope.get(`$${reference}`)?.kind === 'store_sub') return unhoisted;
182
-
183
- const binding = scope.get(reference);
184
- const local_binding = context.state.scope.get(reference);
185
-
186
- // if the function access a snippet that can't be hoisted we bail out
187
- if (
188
- local_binding !== null &&
189
- local_binding.initial?.type === 'SnippetBlock' &&
190
- !local_binding.initial.metadata.can_hoist
191
- ) {
192
- return unhoisted;
193
- }
194
-
195
- // If we are referencing a binding that is shadowed in another scope then bail out (unless it's declared within the function).
196
- if (
197
- local_binding !== null &&
198
- binding !== null &&
199
- local_binding.node !== binding.node &&
200
- scope.declarations.get(reference) !== binding
201
- ) {
202
- return unhoisted;
203
- }
204
-
205
- // If we have multiple references to the same store using $ prefix, bail out.
206
- if (
207
- binding !== null &&
208
- binding.kind === 'store_sub' &&
209
- visited_references.has(reference.slice(1))
210
- ) {
211
- return unhoisted;
212
- }
213
-
214
- // If we reference the index within an each block, then bail out.
215
- if (binding !== null && binding.initial?.type === 'EachBlock') return unhoisted;
216
-
217
- if (
218
- binding !== null &&
219
- // Bail out if the binding is a rest param
220
- (binding.declaration_kind === 'rest_param' ||
221
- // Bail out if we reference anything from the EachBlock (for now) that mutates in non-runes mode,
222
- (((!context.state.analysis.runes && binding.kind === 'each') ||
223
- // or any normal not reactive bindings that are mutated.
224
- binding.kind === 'normal') &&
225
- binding.updated))
226
- ) {
227
- return unhoisted;
228
- }
229
- visited_references.add(reference);
230
- }
231
-
232
- return { hoisted: true, function: target_function };
233
- }
234
-
235
- /**
236
- * @param {string} event_name
237
- */
238
- function get_attribute_event_name(event_name) {
239
- event_name = event_name.slice(2);
240
- if (is_capture_event(event_name)) {
241
- event_name = event_name.slice(0, -7);
242
65
  }
243
- return event_name;
244
66
  }
@@ -6,13 +6,6 @@
6
6
  * @param {Context} context
7
7
  */
8
8
  export function visit_function(node, context) {
9
- // TODO retire this in favour of a more general solution based on bindings
10
- node.metadata = {
11
- hoisted: false,
12
- hoisted_params: [],
13
- scope: context.state.scope
14
- };
15
-
16
9
  if (context.state.expression) {
17
10
  for (const [name] of context.state.scope.references) {
18
11
  const binding = context.state.scope.get(name);
@@ -1,6 +1,6 @@
1
- /** @import { ArrowFunctionExpression, AssignmentExpression, BlockStatement, Expression, FunctionDeclaration, FunctionExpression, Identifier, Node, Pattern, UpdateExpression } from 'estree' */
1
+ /** @import { BlockStatement, Expression, Identifier } from 'estree' */
2
2
  /** @import { Binding } from '#compiler' */
3
- /** @import { ClientTransformState, ComponentClientTransformState, ComponentContext } from './types.js' */
3
+ /** @import { ClientTransformState, ComponentClientTransformState } from './types.js' */
4
4
  /** @import { Analysis } from '../../types.js' */
5
5
  /** @import { Scope } from '../../scope.js' */
6
6
  import * as b from '#compiler/builders';
@@ -12,9 +12,6 @@ import {
12
12
  PROPS_IS_UPDATED,
13
13
  PROPS_IS_BINDABLE
14
14
  } from '../../../../constants.js';
15
- import { dev } from '../../../state.js';
16
- import { walk } from 'zimmerframe';
17
- import { validate_mutation } from './visitors/shared/utils.js';
18
15
 
19
16
  /**
20
17
  * @param {Binding} binding
@@ -46,125 +43,6 @@ export function build_getter(node, state) {
46
43
  return node;
47
44
  }
48
45
 
49
- /**
50
- * @param {FunctionDeclaration | FunctionExpression | ArrowFunctionExpression} node
51
- * @param {ComponentContext} context
52
- * @returns {Pattern[]}
53
- */
54
- function get_hoisted_params(node, context) {
55
- const scope = context.state.scope;
56
-
57
- /** @type {Identifier[]} */
58
- const params = [];
59
-
60
- /**
61
- * We only want to push if it's not already present to avoid name clashing
62
- * @param {Identifier} id
63
- */
64
- function push_unique(id) {
65
- if (!params.find((param) => param.name === id.name)) {
66
- params.push(id);
67
- }
68
- }
69
-
70
- for (const [reference] of scope.references) {
71
- let binding = scope.get(reference);
72
-
73
- if (binding !== null && !scope.declarations.has(reference) && binding.initial !== node) {
74
- if (binding.kind === 'store_sub') {
75
- // We need both the subscription for getting the value and the store for updating
76
- push_unique(b.id(binding.node.name));
77
- binding = /** @type {Binding} */ (scope.get(binding.node.name.slice(1)));
78
- }
79
-
80
- let expression = context.state.transform[reference]?.read(b.id(binding.node.name));
81
-
82
- if (
83
- // If it's a destructured derived binding, then we can extract the derived signal reference and use that.
84
- // TODO this code is bad, we need to kill it
85
- expression != null &&
86
- typeof expression !== 'function' &&
87
- expression.type === 'MemberExpression' &&
88
- expression.object.type === 'CallExpression' &&
89
- expression.object.callee.type === 'Identifier' &&
90
- expression.object.callee.name === '$.get' &&
91
- expression.object.arguments[0].type === 'Identifier'
92
- ) {
93
- push_unique(b.id(expression.object.arguments[0].name));
94
- } else if (
95
- // If we are referencing a simple $$props value, then we need to reference the object property instead
96
- (binding.kind === 'prop' || binding.kind === 'bindable_prop') &&
97
- !is_prop_source(binding, context.state)
98
- ) {
99
- push_unique(b.id('$$props'));
100
- } else if (
101
- // imports don't need to be hoisted
102
- binding.declaration_kind !== 'import'
103
- ) {
104
- // create a copy to remove start/end tags which would mess up source maps
105
- push_unique(b.id(binding.node.name));
106
- // rest props are often accessed through the $$props object for optimization reasons,
107
- // but we can't know if the delegated event handler will use it, so we need to add both as params
108
- if (binding.kind === 'rest_prop' && context.state.analysis.runes) {
109
- push_unique(b.id('$$props'));
110
- }
111
- }
112
- }
113
- }
114
-
115
- if (dev) {
116
- // this is a little hacky, but necessary for ownership validation
117
- // to work inside hoisted event handlers
118
-
119
- /**
120
- * @param {AssignmentExpression | UpdateExpression} node
121
- * @param {{ next: () => void, stop: () => void }} context
122
- */
123
- function visit(node, { next, stop }) {
124
- if (validate_mutation(node, /** @type {any} */ (context), node) !== node) {
125
- params.push(b.id('$$ownership_validator'));
126
- stop();
127
- } else {
128
- next();
129
- }
130
- }
131
-
132
- walk(/** @type {Node} */ (node), null, {
133
- AssignmentExpression: visit,
134
- UpdateExpression: visit
135
- });
136
- }
137
-
138
- return params;
139
- }
140
-
141
- /**
142
- * @param {FunctionDeclaration | FunctionExpression | ArrowFunctionExpression} node
143
- * @param {ComponentContext} context
144
- * @returns {Pattern[]}
145
- */
146
- export function build_hoisted_params(node, context) {
147
- const hoisted_params = get_hoisted_params(node, context);
148
- node.metadata.hoisted_params = hoisted_params;
149
-
150
- /** @type {Pattern[]} */
151
- const params = [];
152
-
153
- if (node.params.length === 0) {
154
- if (hoisted_params.length > 0) {
155
- // For the event object
156
- params.push(b.id(context.state.scope.generate('_')));
157
- }
158
- } else {
159
- for (const param of node.params) {
160
- params.push(/** @type {Pattern} */ (context.visit(param)));
161
- }
162
- }
163
-
164
- params.push(...hoisted_params);
165
- return params;
166
- }
167
-
168
46
  /**
169
47
  * @param {Binding} binding
170
48
  * @param {ComponentClientTransformState} state
@@ -1,7 +1,5 @@
1
1
  /** @import { FunctionDeclaration } from 'estree' */
2
2
  /** @import { ComponentContext } from '../types' */
3
- import { build_hoisted_params } from '../utils.js';
4
- import * as b from '#compiler/builders';
5
3
 
6
4
  /**
7
5
  * @param {FunctionDeclaration} node
@@ -10,14 +8,5 @@ import * as b from '#compiler/builders';
10
8
  export function FunctionDeclaration(node, context) {
11
9
  const state = { ...context.state, in_constructor: false, in_derived: false };
12
10
 
13
- if (node.metadata?.hoisted === true) {
14
- const params = build_hoisted_params(node, context);
15
- const body = context.visit(node.body, state);
16
-
17
- context.state.hoisted.push(/** @type {FunctionDeclaration} */ ({ ...node, params, body }));
18
-
19
- return b.empty;
20
- }
21
-
22
11
  context.next(state);
23
12
  }
@@ -7,7 +7,6 @@ import * as b from '#compiler/builders';
7
7
  import * as assert from '../../../../utils/assert.js';
8
8
  import { get_rune } from '../../../scope.js';
9
9
  import { get_prop_source, is_prop_source, is_state_source, should_proxy } from '../utils.js';
10
- import { is_hoisted_function } from '../../utils.js';
11
10
  import { get_value } from './shared/declarations.js';
12
11
 
13
12
  /**
@@ -32,13 +31,6 @@ export function VariableDeclaration(node, context) {
32
31
  rune === '$state.snapshot' ||
33
32
  rune === '$host'
34
33
  ) {
35
- if (init != null && is_hoisted_function(init)) {
36
- context.state.hoisted.push(
37
- b.const(declarator.id, /** @type {Expression} */ (context.visit(init)))
38
- );
39
-
40
- continue;
41
- }
42
34
  declarations.push(/** @type {VariableDeclarator} */ (context.visit(declarator)));
43
35
  continue;
44
36
  }
@@ -295,16 +287,6 @@ export function VariableDeclaration(node, context) {
295
287
  const has_props = bindings.some((binding) => binding.kind === 'bindable_prop');
296
288
 
297
289
  if (!has_state && !has_props) {
298
- const init = declarator.init;
299
-
300
- if (init != null && is_hoisted_function(init)) {
301
- context.state.hoisted.push(
302
- b.const(declarator.id, /** @type {Expression} */ (context.visit(init)))
303
- );
304
-
305
- continue;
306
- }
307
-
308
290
  declarations.push(/** @type {VariableDeclarator} */ (context.visit(declarator)));
309
291
  continue;
310
292
  }
@@ -26,40 +26,12 @@ export function visit_event_attribute(node, context) {
26
26
  let handler = build_event_handler(tag.expression, tag.metadata.expression, context);
27
27
 
28
28
  if (node.metadata.delegated) {
29
- let delegated_assignment;
30
-
31
29
  if (!context.state.events.has(event_name)) {
32
30
  context.state.events.add(event_name);
33
31
  }
34
32
 
35
- // Hoist function if we can, otherwise we leave the function as is
36
- if (node.metadata.delegated.hoisted) {
37
- if (node.metadata.delegated.function === tag.expression) {
38
- const func_name = context.state.scope.root.unique('on_' + event_name);
39
- context.state.hoisted.push(b.var(func_name, handler));
40
- handler = func_name;
41
- }
42
-
43
- const hoisted_params = /** @type {Expression[]} */ (
44
- node.metadata.delegated.function.metadata.hoisted_params
45
- );
46
-
47
- // When we hoist a function we assign an array with the function and all
48
- // hoisted closure params.
49
- if (hoisted_params) {
50
- const args = [handler, ...hoisted_params];
51
- delegated_assignment = b.array(args);
52
- } else {
53
- delegated_assignment = handler;
54
- }
55
- } else {
56
- delegated_assignment = handler;
57
- }
58
-
59
33
  context.state.init.push(
60
- b.stmt(
61
- b.assignment('=', b.member(context.state.node, '__' + event_name), delegated_assignment)
62
- )
34
+ b.stmt(b.assignment('=', b.member(context.state.node, '__' + event_name), handler))
63
35
  );
64
36
  } else {
65
37
  const statement = b.stmt(
@@ -1,14 +1,11 @@
1
1
  /** @import { ArrowFunctionExpression, FunctionExpression, Node } from 'estree' */
2
2
  /** @import { ComponentContext } from '../../types' */
3
- import { build_hoisted_params } from '../../utils.js';
4
3
 
5
4
  /**
6
5
  * @param {ArrowFunctionExpression | FunctionExpression} node
7
6
  * @param {ComponentContext} context
8
7
  */
9
8
  export const visit_function = (node, context) => {
10
- const metadata = node.metadata;
11
-
12
9
  let state = { ...context.state, in_constructor: false, in_derived: false };
13
10
 
14
11
  if (node.type === 'FunctionExpression') {
@@ -16,15 +13,5 @@ export const visit_function = (node, context) => {
16
13
  state.in_constructor = parent.type === 'MethodDefinition' && parent.kind === 'constructor';
17
14
  }
18
15
 
19
- if (metadata?.hoisted === true) {
20
- const params = build_hoisted_params(node, context);
21
-
22
- return /** @type {FunctionExpression} */ ({
23
- ...node,
24
- params,
25
- body: context.visit(node.body, state)
26
- });
27
- }
28
-
29
16
  context.next(state);
30
17
  };
@@ -1,36 +1,17 @@
1
- /** @import { Context } from 'zimmerframe' */
2
1
  /** @import { TransformState } from './types.js' */
3
2
  /** @import { AST, Binding, Namespace, ValidatedCompileOptions } from '#compiler' */
4
3
  /** @import { Node, Expression, CallExpression, MemberExpression } from 'estree' */
5
4
  import {
6
5
  regex_ends_with_whitespaces,
7
6
  regex_not_whitespace,
8
- regex_starts_with_newline,
9
7
  regex_starts_with_whitespaces
10
8
  } from '../patterns.js';
11
- import * as b from '#compiler/builders';
12
9
  import * as e from '../../errors.js';
13
10
  import { walk } from 'zimmerframe';
14
11
  import { extract_identifiers } from '../../utils/ast.js';
15
12
  import check_graph_for_cycles from '../2-analyze/utils/check_graph_for_cycles.js';
16
13
  import is_reference from 'is-reference';
17
14
  import { set_scope } from '../scope.js';
18
- import { dev } from '../../state.js';
19
-
20
- /**
21
- * @param {Node} node
22
- * @returns {boolean}
23
- */
24
- export function is_hoisted_function(node) {
25
- if (
26
- node.type === 'ArrowFunctionExpression' ||
27
- node.type === 'FunctionExpression' ||
28
- node.type === 'FunctionDeclaration'
29
- ) {
30
- return node.metadata?.hoisted === true;
31
- }
32
- return false;
33
- }
34
15
 
35
16
  /**
36
17
  * Match Svelte 4 behaviour by sorting ConstTag nodes in topological order
@@ -59,7 +59,7 @@ export function create_attribute(name, start, end, value) {
59
59
  name,
60
60
  value,
61
61
  metadata: {
62
- delegated: null,
62
+ delegated: false,
63
63
  needs_clsx: false
64
64
  }
65
65
  };
@@ -42,8 +42,7 @@ export function arrow(params, body, async = false) {
42
42
  body,
43
43
  expression: body.type !== 'BlockStatement',
44
44
  generator: false,
45
- async,
46
- metadata: /** @type {any} */ (null) // should not be used by codegen
45
+ async
47
46
  };
48
47
  }
49
48
 
@@ -237,8 +236,7 @@ export function function_declaration(id, params, body, async = false) {
237
236
  params,
238
237
  body,
239
238
  generator: false,
240
- async,
241
- metadata: /** @type {any} */ (null) // should not be used by codegen
239
+ async
242
240
  };
243
241
  }
244
242
 
@@ -595,8 +593,7 @@ function function_builder(id, params, body, async = false) {
595
593
  params,
596
594
  body,
597
595
  generator: false,
598
- async,
599
- metadata: /** @type {any} */ (null) // should not be used by codegen
596
+ async
600
597
  };
601
598
  }
602
599
 
@@ -241,7 +241,7 @@ function init_update_callbacks(context) {
241
241
  return (l.u ??= { a: [], b: [], m: [] });
242
242
  }
243
243
 
244
- export { flushSync } from './internal/client/reactivity/batch.js';
244
+ export { flushSync, fork } from './internal/client/reactivity/batch.js';
245
245
  export {
246
246
  createContext,
247
247
  getContext,
@@ -33,6 +33,10 @@ export function unmount() {
33
33
  e.lifecycle_function_unavailable('unmount');
34
34
  }
35
35
 
36
+ export function fork() {
37
+ e.lifecycle_function_unavailable('fork');
38
+ }
39
+
36
40
  export async function tick() {}
37
41
 
38
42
  export async function settled() {}
@@ -13,13 +13,14 @@ export const INERT = 1 << 13;
13
13
  export const DESTROYED = 1 << 14;
14
14
 
15
15
  // Flags exclusive to effects
16
+ /** Set once an effect that should run synchronously has run */
16
17
  export const EFFECT_RAN = 1 << 15;
17
18
  /**
18
19
  * 'Transparent' effects do not create a transition boundary.
19
20
  * This is on a block effect 99% of the time but may also be on a branch effect if its parent block effect was pruned
20
21
  */
21
22
  export const EFFECT_TRANSPARENT = 1 << 16;
22
- export const INSPECT_EFFECT = 1 << 17;
23
+ export const EAGER_EFFECT = 1 << 17;
23
24
  export const HEAD_EFFECT = 1 << 18;
24
25
  export const EFFECT_PRESERVED = 1 << 19;
25
26
  export const USER_EFFECT = 1 << 20;
@@ -128,7 +128,11 @@ export function setContext(key, context) {
128
128
 
129
129
  if (async_mode_flag) {
130
130
  var flags = /** @type {Effect} */ (active_effect).f;
131
- var valid = !active_reaction && (flags & BRANCH_EFFECT) !== 0 && (flags & EFFECT_RAN) === 0;
131
+ var valid =
132
+ !active_reaction &&
133
+ (flags & BRANCH_EFFECT) !== 0 &&
134
+ // pop() runs synchronously, so this indicates we're setting context after an await
135
+ !(/** @type {ComponentContext} */ (component_context).i);
132
136
 
133
137
  if (!valid) {
134
138
  e.set_context_after_init();
@@ -173,6 +177,7 @@ export function getAllContexts() {
173
177
  export function push(props, runes = false, fn) {
174
178
  component_context = {
175
179
  p: component_context,
180
+ i: false,
176
181
  c: null,
177
182
  e: null,
178
183
  s: props,
@@ -208,6 +213,8 @@ export function pop(component) {
208
213
  context.x = component;
209
214
  }
210
215
 
216
+ context.i = true;
217
+
211
218
  component_context = context.p;
212
219
 
213
220
  if (DEV) {
@@ -1,6 +1,6 @@
1
1
  import { UNINITIALIZED } from '../../../constants.js';
2
2
  import { snapshot } from '../../shared/clone.js';
3
- import { inspect_effect, render_effect, validate_effect } from '../reactivity/effects.js';
3
+ import { eager_effect, render_effect, validate_effect } from '../reactivity/effects.js';
4
4
  import { untrack } from '../runtime.js';
5
5
  import { get_stack } from './tracing.js';
6
6
 
@@ -19,7 +19,7 @@ export function inspect(get_value, inspector, show_stack = false) {
19
19
  // stack traces. As a consequence, reading the value might result
20
20
  // in an error (an `$inspect(object.property)` will run before the
21
21
  // `{#if object}...{/if}` that contains it)
22
- inspect_effect(() => {
22
+ eager_effect(() => {
23
23
  try {
24
24
  var value = get_value();
25
25
  } catch (e) {
@@ -33,8 +33,17 @@ export function inspect(get_value, inspector, show_stack = false) {
33
33
  inspector(...snap);
34
34
 
35
35
  if (!initial) {
36
+ const stack = get_stack('$inspect(...)');
36
37
  // eslint-disable-next-line no-console
37
- console.log(get_stack('UpdatedAt'));
38
+
39
+ if (stack) {
40
+ // eslint-disable-next-line no-console
41
+ console.groupCollapsed('stack trace');
42
+ // eslint-disable-next-line no-console
43
+ console.log(stack);
44
+ // eslint-disable-next-line no-console
45
+ console.groupEnd();
46
+ }
38
47
  }
39
48
  } else {
40
49
  inspector(initial ? 'init' : 'update', ...snap);