svelte 5.56.10 → 5.57.0

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 (81) hide show
  1. package/compiler/index.js +1 -1
  2. package/elements.d.ts +3 -0
  3. package/package.json +3 -3
  4. package/src/compiler/phases/1-parse/acorn.js +1 -1
  5. package/src/compiler/phases/1-parse/utils/html.js +12 -7
  6. package/src/compiler/phases/2-analyze/css/css-prune.js +10 -0
  7. package/src/compiler/phases/2-analyze/index.js +26 -3
  8. package/src/compiler/phases/2-analyze/visitors/AwaitExpression.js +10 -4
  9. package/src/compiler/phases/2-analyze/visitors/CallExpression.js +1 -1
  10. package/src/compiler/phases/2-analyze/visitors/DeclarationTag.js +2 -1
  11. package/src/compiler/phases/2-analyze/visitors/ExportNamedDeclaration.js +10 -10
  12. package/src/compiler/phases/2-analyze/visitors/SvelteBody.js +4 -4
  13. package/src/compiler/phases/2-analyze/visitors/SvelteDocument.js +4 -4
  14. package/src/compiler/phases/2-analyze/visitors/SvelteWindow.js +4 -4
  15. package/src/compiler/phases/2-analyze/visitors/shared/a11y/index.js +14 -2
  16. package/src/compiler/phases/2-analyze/visitors/shared/element.js +2 -8
  17. package/src/compiler/phases/2-analyze/visitors/shared/utils.js +23 -1
  18. package/src/compiler/phases/3-transform/client/transform-client.js +2 -2
  19. package/src/compiler/phases/3-transform/client/transform-template/index.js +6 -0
  20. package/src/compiler/phases/3-transform/client/utils.js +35 -8
  21. package/src/compiler/phases/3-transform/client/visitors/AwaitBlock.js +6 -6
  22. package/src/compiler/phases/3-transform/client/visitors/BindDirective.js +10 -13
  23. package/src/compiler/phases/3-transform/client/visitors/ConstTag.js +19 -8
  24. package/src/compiler/phases/3-transform/client/visitors/DeclarationTag.js +3 -2
  25. package/src/compiler/phases/3-transform/client/visitors/EachBlock.js +4 -1
  26. package/src/compiler/phases/3-transform/client/visitors/Fragment.js +2 -7
  27. package/src/compiler/phases/3-transform/client/visitors/HtmlTag.js +2 -1
  28. package/src/compiler/phases/3-transform/client/visitors/IfBlock.js +2 -1
  29. package/src/compiler/phases/3-transform/client/visitors/KeyBlock.js +2 -1
  30. package/src/compiler/phases/3-transform/client/visitors/RegularElement.js +106 -44
  31. package/src/compiler/phases/3-transform/client/visitors/SvelteElement.js +2 -1
  32. package/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +11 -4
  33. package/src/compiler/phases/3-transform/client/visitors/shared/element.js +6 -1
  34. package/src/compiler/phases/3-transform/client/visitors/shared/fragment.js +1 -6
  35. package/src/compiler/phases/3-transform/client/visitors/shared/utils.js +5 -5
  36. package/src/compiler/phases/3-transform/server/transform-server.js +20 -9
  37. package/src/compiler/phases/3-transform/server/visitors/AssignmentExpression.js +1 -1
  38. package/src/compiler/phases/3-transform/server/visitors/DeclarationTag.js +1 -1
  39. package/src/compiler/phases/3-transform/server/visitors/EachBlock.js +8 -2
  40. package/src/compiler/phases/3-transform/server/visitors/IfBlock.js +4 -4
  41. package/src/compiler/phases/3-transform/server/visitors/RegularElement.js +1 -1
  42. package/src/compiler/phases/3-transform/server/visitors/SvelteBoundary.js +9 -4
  43. package/src/compiler/phases/3-transform/server/visitors/shared/element.js +5 -4
  44. package/src/compiler/phases/3-transform/server/visitors/shared/utils.js +30 -0
  45. package/src/compiler/phases/bindings.js +3 -1
  46. package/src/compiler/phases/nodes.js +4 -0
  47. package/src/compiler/print/index.js +21 -16
  48. package/src/easing/index.js +62 -0
  49. package/src/internal/client/constants.js +9 -0
  50. package/src/internal/client/context.js +15 -5
  51. package/src/internal/client/dev/hmr.js +15 -4
  52. package/src/internal/client/dom/blocks/boundary.js +21 -12
  53. package/src/internal/client/dom/blocks/slot.js +19 -0
  54. package/src/internal/client/dom/blocks/svelte-head.js +8 -0
  55. package/src/internal/client/dom/elements/attributes.js +35 -34
  56. package/src/internal/client/dom/elements/bindings/select.js +99 -9
  57. package/src/internal/client/dom/elements/bindings/this.js +7 -2
  58. package/src/internal/client/dom/elements/transitions.js +81 -68
  59. package/src/internal/client/dom/operations.js +21 -1
  60. package/src/internal/client/error-handling.js +10 -2
  61. package/src/internal/client/index.js +9 -2
  62. package/src/internal/client/proxy.js +8 -3
  63. package/src/internal/client/reactivity/async.js +23 -3
  64. package/src/internal/client/reactivity/effects.js +14 -1
  65. package/src/internal/client/render.js +4 -8
  66. package/src/internal/client/runtime.js +45 -33
  67. package/src/internal/client/warnings.js +0 -11
  68. package/src/internal/server/abort-signal.js +8 -9
  69. package/src/internal/server/context.js +2 -2
  70. package/src/internal/server/index.js +1 -1
  71. package/src/internal/server/renderer.js +163 -52
  72. package/src/internal/shared/attributes.js +2 -1
  73. package/src/internal/shared/clone.js +2 -0
  74. package/src/internal/shared/context.js +3 -2
  75. package/src/legacy/legacy-server.js +1 -1
  76. package/src/reactivity/map.js +22 -0
  77. package/src/reactivity/url.js +2 -0
  78. package/src/transition/index.js +18 -7
  79. package/src/version.js +1 -1
  80. package/types/index.d.ts +135 -37
  81. package/types/index.d.ts.map +2 -2
@@ -8,7 +8,6 @@ import {
8
8
  set_component_context,
9
9
  set_dev_stack
10
10
  } from '../context.js';
11
- import { Boundary } from '../dom/blocks/boundary.js';
12
11
  import { invoke_error_boundary } from '../error-handling.js';
13
12
  import {
14
13
  active_effect,
@@ -25,7 +24,6 @@ import {
25
24
  set_reactivity_loss_tracker
26
25
  } from './deriveds.js';
27
26
  import { aborted } from './effects.js';
28
- import { queue_micro_task } from '../dom/task.js';
29
27
 
30
28
  /**
31
29
  * @param {Blocker[]} blockers
@@ -156,6 +154,9 @@ export function capture() {
156
154
  };
157
155
  }
158
156
 
157
+ /** `true` between a `save` thunk restoring a context and the end of that synchronous segment */
158
+ var restored = false;
159
+
159
160
  /**
160
161
  * Wraps an `await` expression in such a way that the effect context that was
161
162
  * active before the expression evaluated can be reapplied afterwards —
@@ -166,15 +167,32 @@ export function capture() {
166
167
  */
167
168
  export async function save(promise) {
168
169
  var restore = capture();
170
+ // the context restored by an earlier `save` in this expression must not
171
+ // outlive the synchronous segment that is about to end at this `await`
172
+ unsave();
169
173
  var value = await promise;
170
174
 
171
175
  return () => {
172
176
  restore();
173
- queue_micro_task(unset_context);
177
+ restored = true;
174
178
  return value;
175
179
  };
176
180
  }
177
181
 
182
+ /**
183
+ * Unset the context if a `save` thunk restored it in the current synchronous segment,
184
+ * so that a foreign microtask can never run inside a restored reaction context.
185
+ * Called at every suspension point, and at the end of async expression bodies —
186
+ * `async () => (await $.save(a))().b` becomes `async () => { try { return (await $.save(a))().b; } finally { $.unsave(); } }`
187
+ * @template T
188
+ * @param {T} [value]
189
+ * @returns {T}
190
+ */
191
+ export function unsave(value) {
192
+ if (restored) unset_context();
193
+ return /** @type {T} */ (value);
194
+ }
195
+
178
196
  /**
179
197
  * Reset `current_async_effect` after the `promise` resolves, so
180
198
  * that we can emit `await_reactivity_loss` warnings
@@ -183,6 +201,7 @@ export async function save(promise) {
183
201
  * @returns {Promise<() => T>}
184
202
  */
185
203
  export async function track_reactivity_loss(promise) {
204
+ unsave();
186
205
  var previous_reactivity_loss_tracker = reactivity_loss_tracker;
187
206
  // Ensure that unrelated reads after an async operation is kicked off don't cause false positives
188
207
  queueMicrotask(() => {
@@ -269,6 +288,7 @@ export async function* for_await_track_reactivity_loss(iterable) {
269
288
  }
270
289
 
271
290
  export function unset_context(deactivate_batch = true) {
291
+ restored = false;
272
292
  set_active_effect(null);
273
293
  set_active_reaction(null);
274
294
  set_component_context(null);
@@ -34,8 +34,10 @@ import {
34
34
  ASYNC,
35
35
  CONNECTED,
36
36
  MANAGED_EFFECT,
37
- DESTROYING
37
+ DESTROYING,
38
+ PAUSED
38
39
  } from '#client/constants';
40
+ import { invoke_error_boundary } from '../error-handling.js';
39
41
  import * as e from '../errors.js';
40
42
  import { DEV } from 'esm-env';
41
43
  import { define_property } from '../../shared/utils.js';
@@ -449,6 +451,11 @@ export function execute_effect_teardown(effect) {
449
451
  set_active_reaction(null);
450
452
  try {
451
453
  teardown.call(null);
454
+ } catch (error) {
455
+ // Route teardown errors through the boundary system so that a live
456
+ // ancestor <svelte:boundary> can handle them. Boundaries that are
457
+ // themselves mid-teardown are skipped by invoke_error_boundary.
458
+ invoke_error_boundary(error, effect.parent);
452
459
  } finally {
453
460
  set_is_destroying_effect(previously_destroying_effect);
454
461
  set_active_reaction(previous_reaction);
@@ -610,6 +617,7 @@ export function pause_effect(effect, callback, destroy = true) {
610
617
  /** @type {TransitionManager[]} */
611
618
  var transitions = [];
612
619
 
620
+ effect.f |= PAUSED;
613
621
  pause_children(effect, transitions, true);
614
622
 
615
623
  var fn = () => {
@@ -677,6 +685,7 @@ function pause_children(effect, transitions, local) {
677
685
  * @param {Effect} effect
678
686
  */
679
687
  export function resume_effect(effect) {
688
+ effect.f &= ~PAUSED;
680
689
  resume_children(effect, true);
681
690
  }
682
691
 
@@ -685,6 +694,10 @@ export function resume_effect(effect) {
685
694
  * @param {boolean} local
686
695
  */
687
696
  function resume_children(effect, local) {
697
+ // this subtree was paused for its own reasons (e.g. a block whose condition
698
+ // is still false) — its controller will resume or destroy it
699
+ if ((effect.f & PAUSED) !== 0) return;
700
+
688
701
  if ((effect.f & INERT) === 0) return;
689
702
  effect.f ^= INERT;
690
703
 
@@ -10,7 +10,7 @@ import {
10
10
  } from './dom/operations.js';
11
11
  import { HYDRATION_END, HYDRATION_ERROR, HYDRATION_START } from '../../constants.js';
12
12
  import { active_effect } from './runtime.js';
13
- import { push, pop, component_context } from './context.js';
13
+ import { push, pop, component_context, mark_as_component } from './context.js';
14
14
  import { component_root } from './reactivity/effects.js';
15
15
  import { hydrate_node, hydrating, set_hydrate_node, set_hydrating } from './dom/hydration.js';
16
16
  import { array_from } from '../shared/utils.js';
@@ -23,7 +23,7 @@ import * as w from './warnings.js';
23
23
  import * as e from './errors.js';
24
24
  import { assign_nodes } from './dom/template.js';
25
25
  import { is_passive_event } from '../../utils.js';
26
- import { COMMENT_NODE, STATE_SYMBOL, TEXT_CACHE } from './constants.js';
26
+ import { COMMENT_NODE, TEXT_CACHE } from './constants.js';
27
27
  import { boundary } from './dom/blocks/boundary.js';
28
28
 
29
29
  /**
@@ -193,7 +193,7 @@ function _mount(
193
193
 
194
194
  should_intro = intro;
195
195
  // @ts-expect-error the public typings are not what the actual function looks like
196
- component = Component(anchor_node, props) || {};
196
+ component = Component(anchor_node, props) || mark_as_component();
197
197
  should_intro = true;
198
198
 
199
199
  if (hydrating) {
@@ -323,11 +323,7 @@ export function unmount(component, options) {
323
323
  }
324
324
 
325
325
  if (DEV) {
326
- if (STATE_SYMBOL in component) {
327
- w.state_proxy_unmount();
328
- } else {
329
- w.lifecycle_double_unmount();
330
- }
326
+ w.lifecycle_double_unmount();
331
327
  }
332
328
 
333
329
  return Promise.resolve();
@@ -133,7 +133,7 @@ export function set_untracked_writes(value) {
133
133
  **/
134
134
  export let write_version = 1;
135
135
 
136
- /** @type {number} Used to version each read of a source of derived to avoid duplicating depedencies inside a reaction */
136
+ /** @type {number} Used to version each read of a source of derived to avoid duplicating dependencies inside a reaction */
137
137
  let read_version = 0;
138
138
 
139
139
  export let update_version = read_version;
@@ -258,37 +258,7 @@ export function update_reaction(reaction) {
258
258
  var fn = /** @type {Function} */ (reaction.fn);
259
259
  var result = fn();
260
260
  reaction.f |= REACTION_RAN;
261
- var deps = reaction.deps;
262
-
263
- // Don't remove reactions during fork;
264
- // they must remain for when fork is discarded
265
- var is_fork = current_batch?.is_fork;
266
-
267
- if (new_deps !== null) {
268
- var i;
269
-
270
- if (!is_fork) {
271
- remove_reactions(reaction, skipped_deps);
272
- }
273
-
274
- if (deps !== null && skipped_deps > 0) {
275
- deps.length = skipped_deps + new_deps.length;
276
- for (i = 0; i < new_deps.length; i++) {
277
- deps[skipped_deps + i] = new_deps[i];
278
- }
279
- } else {
280
- reaction.deps = deps = new_deps;
281
- }
282
-
283
- if (effect_tracking() && (reaction.f & CONNECTED) !== 0) {
284
- for (i = skipped_deps; i < deps.length; i++) {
285
- (deps[i].reactions ??= []).push(reaction);
286
- }
287
- }
288
- } else if (!is_fork && deps !== null && skipped_deps < deps.length) {
289
- remove_reactions(reaction, skipped_deps);
290
- deps.length = skipped_deps;
291
- }
261
+ var deps = update_dependencies(reaction);
292
262
 
293
263
  // If we're inside an effect and we have untracked writes, then we need to
294
264
  // ensure that if any of those untracked writes result in re-invalidation
@@ -300,7 +270,7 @@ export function update_reaction(reaction) {
300
270
  deps !== null &&
301
271
  (reaction.f & (DERIVED | MAYBE_DIRTY | DIRTY)) === 0
302
272
  ) {
303
- for (i = 0; i < /** @type {Source[]} */ (untracked_writes).length; i++) {
273
+ for (var i = 0; i < /** @type {Source[]} */ (untracked_writes).length; i++) {
304
274
  schedule_possible_effect_self_invalidation(
305
275
  untracked_writes[i],
306
276
  /** @type {Effect} */ (reaction)
@@ -344,6 +314,9 @@ export function update_reaction(reaction) {
344
314
 
345
315
  return result;
346
316
  } catch (error) {
317
+ // still commit the deps read before the throw, otherwise deriveds connected by this run keep no reader and the reaction never re-runs when they change
318
+ update_dependencies(reaction);
319
+
347
320
  return handle_error(error);
348
321
  } finally {
349
322
  reaction.f ^= REACTION_IS_UPDATING;
@@ -358,6 +331,45 @@ export function update_reaction(reaction) {
358
331
  }
359
332
  }
360
333
 
334
+ /**
335
+ * @param {Reaction} reaction
336
+ */
337
+ function update_dependencies(reaction) {
338
+ var deps = reaction.deps;
339
+
340
+ // Don't remove reactions during fork;
341
+ // they must remain for when fork is discarded
342
+ var is_fork = current_batch?.is_fork;
343
+
344
+ if (new_deps !== null) {
345
+ var i;
346
+
347
+ if (!is_fork) {
348
+ remove_reactions(reaction, skipped_deps);
349
+ }
350
+
351
+ if (deps !== null && skipped_deps > 0) {
352
+ deps.length = skipped_deps + new_deps.length;
353
+ for (i = 0; i < new_deps.length; i++) {
354
+ deps[skipped_deps + i] = new_deps[i];
355
+ }
356
+ } else {
357
+ reaction.deps = deps = new_deps;
358
+ }
359
+
360
+ if (effect_tracking() && (reaction.f & CONNECTED) !== 0) {
361
+ for (i = skipped_deps; i < deps.length; i++) {
362
+ (deps[i].reactions ??= []).push(reaction);
363
+ }
364
+ }
365
+ } else if (!is_fork && deps !== null && skipped_deps < deps.length) {
366
+ remove_reactions(reaction, skipped_deps);
367
+ deps.length = skipped_deps;
368
+ }
369
+
370
+ return deps;
371
+ }
372
+
361
373
  /**
362
374
  * @template V
363
375
  * @param {Reaction} signal
@@ -247,17 +247,6 @@ export function state_proxy_equality_mismatch(operator) {
247
247
  }
248
248
  }
249
249
 
250
- /**
251
- * Tried to unmount a state proxy, rather than a component
252
- */
253
- export function state_proxy_unmount() {
254
- if (DEV) {
255
- console.warn(`%c[svelte] state_proxy_unmount\n%cTried to unmount a state proxy, rather than a component\nhttps://svelte.dev/e/state_proxy_unmount`, bold, normal);
256
- } else {
257
- console.warn(`https://svelte.dev/e/state_proxy_unmount`);
258
- }
259
- }
260
-
261
250
  /**
262
251
  * A `<svelte:boundary>` `reset` function only resets the boundary the first time it is called
263
252
  */
@@ -1,13 +1,12 @@
1
- import { STALE_REACTION } from '#client/constants';
1
+ import { ssr_context } from './context.js';
2
2
 
3
- /** @type {AbortController | null} */
4
- let controller = null;
3
+ export function getAbortSignal() {
4
+ let context = ssr_context;
5
5
 
6
- export function abort() {
7
- controller?.abort(STALE_REACTION);
8
- controller = null;
9
- }
6
+ while (context !== null) {
7
+ if (context.r !== null) return context.r.global.get_abort_signal();
8
+ context = context.p;
9
+ }
10
10
 
11
- export function getAbortSignal() {
12
- return (controller ??= new AbortController()).signal;
11
+ return new AbortController().signal;
13
12
  }
@@ -12,11 +12,11 @@ export function set_ssr_context(v) {
12
12
 
13
13
  /**
14
14
  * @template T
15
- * @returns {[() => T, (context: T) => T]}
15
+ * @returns {[() => T, (context: T) => T, () => boolean]}
16
16
  * @since 5.40.0
17
17
  */
18
18
  export function createContext() {
19
- return /** @type {[() => T, (context: T) => T]} */ (
19
+ return /** @type {[() => T, (context: T) => T, () => boolean]} */ (
20
20
  create_context(getContext, setContext, hasContext)
21
21
  );
22
22
  }
@@ -1,5 +1,5 @@
1
1
  /** @import { ComponentType, SvelteComponent, Component } from 'svelte' */
2
- /** @import { Csp, RenderOutput } from '#server' */
2
+ /** @import { Csp, RenderOutput } from '../../server/public.js' */
3
3
  /** @import { Store } from '#shared' */
4
4
  export { FILENAME, HMR } from '../../constants.js';
5
5
  import { attr, clsx, to_class, to_style } from '../shared/attributes.js';