ripple 0.4.2 → 0.4.4

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 (98) hide show
  1. package/CHANGELOG.md +164 -0
  2. package/package.json +10 -4
  3. package/src/constants.js +6 -0
  4. package/src/jsx-runtime.d.ts +2 -1
  5. package/src/runtime/array.js +15 -9
  6. package/src/runtime/index-client.js +25 -7
  7. package/src/runtime/index-server.js +1 -0
  8. package/src/runtime/internal/client/attributes.js +439 -0
  9. package/src/runtime/internal/client/blocks.js +20 -20
  10. package/src/runtime/internal/client/component.js +2 -5
  11. package/src/runtime/internal/client/composite.js +295 -95
  12. package/src/runtime/internal/client/constants.js +14 -6
  13. package/src/runtime/internal/client/context.js +3 -2
  14. package/src/runtime/internal/client/css.js +11 -26
  15. package/src/runtime/internal/client/errors.js +188 -0
  16. package/src/runtime/internal/client/events.js +79 -34
  17. package/src/runtime/internal/client/expression.js +25 -120
  18. package/src/runtime/internal/client/for.js +113 -262
  19. package/src/runtime/internal/client/head.js +4 -3
  20. package/src/runtime/internal/client/html.js +5 -3
  21. package/src/runtime/internal/client/hydrate.js +484 -0
  22. package/src/runtime/internal/client/hydration-enabled.js +7 -0
  23. package/src/runtime/internal/client/hydration.js +16 -81
  24. package/src/runtime/internal/client/if.js +69 -10
  25. package/src/runtime/internal/client/index.js +18 -10
  26. package/src/runtime/internal/client/operations.js +11 -7
  27. package/src/runtime/internal/client/portal.js +3 -2
  28. package/src/runtime/internal/client/render.js +42 -325
  29. package/src/runtime/internal/client/root-boundary-enabled.js +7 -0
  30. package/src/runtime/internal/client/runtime.js +157 -371
  31. package/src/runtime/internal/client/template-ns.js +88 -0
  32. package/src/runtime/internal/client/template.js +118 -139
  33. package/src/runtime/internal/client/track-async.js +356 -0
  34. package/src/runtime/internal/client/try.js +133 -319
  35. package/src/runtime/internal/client/types.d.ts +48 -24
  36. package/src/runtime/internal/server/index.js +31 -29
  37. package/src/runtime/internal/server/prerender.js +27 -0
  38. package/src/server/index.js +1 -0
  39. package/src/utils/class-name.js +28 -0
  40. package/tests/client/basic/basic.errors.test.tsrx +3 -3
  41. package/tests/client/compiler/__snapshots__/compiler.typescript.test.tsrx.snap +0 -2
  42. package/tests/client/compiler/compiler.basic.test.tsrx +2 -2
  43. package/tests/client/compiler/compiler.tracked-access.test.tsrx +3 -3
  44. package/tests/client/composite/composite.dynamic-components.test.tsrx +40 -0
  45. package/tests/client/composite/composite.props.test.tsrx +10 -10
  46. package/tests/client/css/scoped-styles.test.tsrx +3 -1
  47. package/tests/client/derived-release.test.tsrx +3 -3
  48. package/tests/client/for-item.test.tsrx +39 -0
  49. package/tests/client/for-selector.test.tsrx +95 -0
  50. package/tests/client/svg.test.tsrx +273 -1
  51. package/tests/hydration/compiled/client/basic.js +88 -87
  52. package/tests/hydration/compiled/client/composite.js +15 -6
  53. package/tests/hydration/compiled/client/events.js +40 -48
  54. package/tests/hydration/compiled/client/for.js +191 -199
  55. package/tests/hydration/compiled/client/fragment-cursor.js +633 -334
  56. package/tests/hydration/compiled/client/head.js +22 -22
  57. package/tests/hydration/compiled/client/hmr.js +14 -5
  58. package/tests/hydration/compiled/client/html-in-template.js +5 -5
  59. package/tests/hydration/compiled/client/html.js +195 -177
  60. package/tests/hydration/compiled/client/if-children.js +136 -63
  61. package/tests/hydration/compiled/client/if-fragment-controlflow.js +63 -43
  62. package/tests/hydration/compiled/client/if.js +78 -30
  63. package/tests/hydration/compiled/client/mixed-control-flow.js +90 -72
  64. package/tests/hydration/compiled/client/nested-control-flow.js +266 -307
  65. package/tests/hydration/compiled/client/portal.js +20 -11
  66. package/tests/hydration/compiled/client/reactivity.js +29 -29
  67. package/tests/hydration/compiled/client/return.js +2 -2
  68. package/tests/hydration/compiled/client/streaming.js +33 -35
  69. package/tests/hydration/compiled/client/switch.js +25 -25
  70. package/tests/hydration/compiled/client/track-async-serialization.js +41 -41
  71. package/tests/hydration/compiled/client/try.js +15 -15
  72. package/tests/hydration/compiled/client/typed-text.js +8 -7
  73. package/tests/hydration/compiled/server/basic.js +6 -6
  74. package/tests/hydration/compiled/server/events.js +8 -8
  75. package/tests/hydration/compiled/server/for.js +22 -22
  76. package/tests/hydration/compiled/server/fragment-cursor.js +188 -52
  77. package/tests/hydration/compiled/server/head.js +6 -6
  78. package/tests/hydration/compiled/server/hmr.js +1 -1
  79. package/tests/hydration/compiled/server/html.js +1 -1
  80. package/tests/hydration/compiled/server/if-children.js +9 -9
  81. package/tests/hydration/compiled/server/if.js +5 -5
  82. package/tests/hydration/compiled/server/mixed-control-flow.js +4 -4
  83. package/tests/hydration/compiled/server/portal.js +1 -1
  84. package/tests/hydration/compiled/server/reactivity.js +9 -9
  85. package/tests/hydration/compiled/server/streaming.js +9 -9
  86. package/tests/hydration/compiled/server/switch.js +4 -4
  87. package/tests/hydration/compiled/server/track-async-serialization.js +16 -16
  88. package/tests/hydration/compiled/server/try.js +4 -4
  89. package/tests/hydration/compiled/server/typed-text.js +1 -1
  90. package/tests/hydration/components/fragment-cursor.tsrx +60 -0
  91. package/tests/hydration/components/track-async-serialization.tsrx +2 -2
  92. package/tests/hydration/fragment-cursor.test.js +34 -1
  93. package/tests/hydration/track-async-serialization.test.js +1 -1
  94. package/tests/server/basic.components.test.tsrx +3 -3
  95. package/tests/server/track-async-serialization.test.tsrx +6 -6
  96. package/tests/utils/tracked-types.test.js +3 -3
  97. package/types/index.d.ts +8 -8
  98. package/types/server.d.ts +17 -0
@@ -2,7 +2,6 @@
2
2
 
3
3
  import { IS_CONTROLLED, IS_INDEXED, LOCAL_ITEMS, ROOT_CONTROLLED } from '../../../constants.js';
4
4
  import {
5
- block as create_block,
6
5
  create_block as allocate_block,
7
6
  branch,
8
7
  destroy_block,
@@ -25,62 +24,75 @@ import { get_last_child, next_sibling, resolve_anchor } from './operations.js';
25
24
  import { append } from './template.js';
26
25
  import { active_block, run_block, run_branch, set, set_tracking, tracked } from './runtime.js';
27
26
  import { array_from, is_array } from '@tsrx/core/runtime/language-helpers';
27
+ import { HYDRATION } from 'ripple/internal/client/hydration-enabled';
28
28
 
29
29
  /**
30
30
  * @template V
31
31
  * @param {Node | AppendIntoAnchor} anchor
32
32
  * @param {V} value
33
33
  * @param {number} index
34
- * @param {(anchor: Node, value: V | Tracked, index?: any) => Block} render_fn
35
- * @param {boolean} is_indexed
36
- * @param {boolean} is_keyed
37
- * @param {((item: V) => any) | undefined} [map_item] a keyed loop's destructuring of the item (see `for_block_keyed`)
34
+ * @param {any} key the key the item was matched by (keyed lists)
35
+ * @param {ListState} state the list's state: how items render
38
36
  * @returns {Block}
39
37
  */
40
- function create_item(anchor, value, index, render_fn, is_indexed, is_keyed, map_item) {
38
+ function create_item(anchor, value, index, key, state) {
41
39
  var block = /** @type {Block} */ (active_block);
42
- var tracked_index = is_indexed ? tracked(index, block) : undefined;
43
- var tracked_value = is_keyed
40
+ var render_fn = state.r;
41
+ var map_item = state.m;
42
+ var tracked_index = state.x ? tracked(index, block) : undefined;
43
+ var tracked_value = state.y
44
44
  ? tracked(map_item === undefined ? value : map_item(value), block)
45
45
  : value;
46
- var state = {
46
+ var item_state = {
47
47
  start: null,
48
48
  end: null,
49
49
  i: tracked_index,
50
50
  v: tracked_value,
51
51
  // The item as the collection holds it; a keyed diff compares against it.
52
52
  r: value,
53
+ // The key the item was matched by: fixed for the block's whole life, so
54
+ // the body reads it as a plain value (a compiled `@if (outer === item.key)`
55
+ // depends on the selector alone, not on the item).
56
+ k: key,
53
57
  // The render state of a body that carries its render block on the item
54
58
  // block itself (see `item`), or null.
55
59
  p: null,
56
60
  };
57
61
 
58
- // An item without a tracked of its own (a plain list's, or a local one)
59
- // renders in place: allocated, linked and run through `run_branch`, with
60
- // none of the first-run bookkeeping a block that may re-run needs.
61
- if (tracked_value === value && tracked_index === undefined) {
62
- var lean = allocate_block(BRANCH_BLOCK, run_item, state);
63
- run_branch(lean, render_fn, anchor, value);
64
- lean.f ^= BLOCK_HAS_RUN;
65
- return lean;
66
- }
67
-
68
- // Passed through module state rather than a per-item closure; run_item
69
- // reads them before rendering, so nested loops cannot observe a stale pair.
70
- item_anchor = anchor;
71
- item_render_fn = render_fn;
72
- var b = create_block(BRANCH_BLOCK, run_item, state);
62
+ // The item renders in place: allocated, linked and run through
63
+ // `run_branch`, with none of the first-run bookkeeping a block that may
64
+ // re-run needs (a rerun is `run_item`'s, through `run_block`).
65
+ var b = allocate_block(BRANCH_BLOCK, run_item, item_state);
73
66
 
74
67
  // The item's tracked value and index are owned by the item block itself.
75
- if (is_keyed) {
68
+ if (tracked_value !== value) {
76
69
  /** @type {Tracked} */ (tracked_value).b = b;
77
70
  }
78
- if (is_indexed) {
71
+ if (tracked_index !== undefined) {
79
72
  /** @type {Tracked} */ (tracked_index).b = b;
80
73
  }
74
+ run_branch(b, render_fn, anchor, tracked_value, tracked_index, key);
75
+ b.f ^= BLOCK_HAS_RUN;
81
76
  return b;
82
77
  }
83
78
 
79
+ /**
80
+ * A matched item at its new index: its tracked index and, for a computed key,
81
+ * its tracked value follow the collection.
82
+ * @param {ListState} state
83
+ * @param {Block} block
84
+ * @param {any} value
85
+ * @param {number} index
86
+ */
87
+ function patch_item(state, block, value, index) {
88
+ if (state.x) {
89
+ update_index(block, index);
90
+ }
91
+ if (state.k !== undefined) {
92
+ update_value(block, value, state.m, state.l);
93
+ }
94
+ }
95
+
84
96
  /**
85
97
  * The insertion point of a list: a node the items go before, or, for a
86
98
  * controlled list (the sole content of its parent), an append-into sentinel so
@@ -93,33 +105,20 @@ function create_item(anchor, value, index, render_fn, is_indexed, is_keyed, map_
93
105
  * @returns {AppendIntoAnchor}
94
106
  */
95
107
  function controlled_anchor(parent) {
96
- return { parent, into: true };
108
+ return { parent, into: true, tail: false };
97
109
  }
98
110
 
99
- /** @type {Node | AppendIntoAnchor | null} */
100
- var item_anchor = null;
101
- /** @type {((anchor: Node, value: any, index?: any) => Block) | null} */
102
- var item_render_fn = null;
103
-
104
111
  /**
105
- * @param {{ i: Tracked | undefined, v: any, p: any }} state
112
+ * A re-run of an item that carries its render block (see `item`): only the
113
+ * body's update function, tracked. The first run is `run_branch`'s, in
114
+ * `create_item`; an item block with no render block of its own never re-runs.
115
+ * @param {{ i: Tracked | undefined, v: any, k: any, p: any }} state
106
116
  */
107
117
  function run_item(state) {
108
- var p = state.p;
109
- if (p !== null) {
110
- // A re-run of an item that carries its render block: only the body's
111
- // update function, tracked (see `item`).
112
- set_tracking(true);
113
- /** @type {(prev: any) => void} */ (
114
- /** @type {ListState} */ (/** @type {Block} */ (/** @type {Block} */ (active_block).p).s).u
115
- )(p);
116
- return;
117
- }
118
- var render_fn = /** @type {(anchor: Node, value: any, index?: any) => Block} */ (item_render_fn);
119
- var anchor = /** @type {Node} */ (item_anchor);
120
- item_render_fn = null;
121
- item_anchor = null;
122
- render_fn(anchor, state.v, state.i);
118
+ set_tracking(true);
119
+ /** @type {(prev: any) => void} */ (
120
+ /** @type {ListState} */ (/** @type {Block} */ (/** @type {Block} */ (active_block).p).s).u
121
+ )(state.p);
123
122
  }
124
123
 
125
124
  /**
@@ -292,6 +291,7 @@ class ListState {
292
291
  * @param {((prev: any) => void) | undefined} update_fn the update function
293
292
  * of an item body that carries its render block (see `item`)
294
293
  * @param {boolean} is_local items are held as they are (`LOCAL_ITEMS`)
294
+ * @param {boolean} is_keyed each item holds a tracked of its value
295
295
  */
296
296
  constructor(
297
297
  anchor,
@@ -304,6 +304,7 @@ class ListState {
304
304
  map_item,
305
305
  update_fn,
306
306
  is_local,
307
+ is_keyed,
307
308
  ) {
308
309
  this.a = anchor;
309
310
  this.g = get_collection;
@@ -315,6 +316,7 @@ class ListState {
315
316
  this.m = map_item;
316
317
  this.u = update_fn;
317
318
  this.l = is_local;
319
+ this.y = is_keyed;
318
320
  }
319
321
  }
320
322
 
@@ -327,13 +329,13 @@ function run_for(state) {
327
329
 
328
330
  // Items render untracked, as in a branch; the list tracks only its collection.
329
331
  set_tracking(false);
330
- reconcile_by_ref(state.a, block, array, state.r, state.c, state.x, state.e);
332
+ reconcile_by_ref(state.a, block, array);
331
333
  set_tracking(true);
332
334
 
333
335
  // Re-anchor a hydrated list: the hydrated anchor is the block's start
334
336
  // marker; later inserts and end moves must go before the cursor, which now
335
337
  // sits after the hydrated items.
336
- if (hydrating) {
338
+ if (HYDRATION && hydrating) {
337
339
  state.a = /** @type {Element | Text} */ (hydrate_node);
338
340
  }
339
341
  }
@@ -346,21 +348,10 @@ function run_for_keyed(state) {
346
348
  var array = collection_to_array(state.g());
347
349
 
348
350
  set_tracking(false);
349
- reconcile_by_key(
350
- state.a,
351
- block,
352
- array,
353
- state.r,
354
- state.c,
355
- state.x,
356
- state.k,
357
- state.e,
358
- state.m,
359
- state.l,
360
- );
351
+ reconcile_by_key(state.a, block, array);
361
352
  set_tracking(true);
362
353
 
363
- if (hydrating) {
354
+ if (HYDRATION && hydrating) {
364
355
  state.a = /** @type {Element | Text} */ (hydrate_node);
365
356
  }
366
357
  }
@@ -387,7 +378,7 @@ export function for_block(node, get_collection, render_fn, flags, render_empty,
387
378
  var boundary;
388
379
 
389
380
  if (is_controlled) {
390
- if (hydrating) {
381
+ if (HYDRATION && hydrating) {
391
382
  // The cursor sits on the list's element; the items are its children.
392
383
  hydrate_first_child();
393
384
  } else {
@@ -395,7 +386,7 @@ export function for_block(node, get_collection, render_fn, flags, render_empty,
395
386
  }
396
387
  }
397
388
 
398
- if (hydrating) {
389
+ if (HYDRATION && hydrating) {
399
390
  if (root_controlled) {
400
391
  boundary = /** @type {Node} */ (hydrate_node);
401
392
  }
@@ -415,13 +406,14 @@ export function for_block(node, get_collection, render_fn, flags, render_empty,
415
406
  undefined,
416
407
  update_fn,
417
408
  false,
409
+ false,
418
410
  ),
419
411
  FOR_BLOCK,
420
412
  );
421
413
 
422
414
  if (!is_controlled) own_anchor(node, /** @type {Node} */ (anchor));
423
415
 
424
- if (hydrating && root_controlled) {
416
+ if (HYDRATION && hydrating && root_controlled) {
425
417
  // The original `node`: for a sentinel, `hydrate_append` performs the
426
418
  // cursor advance that stands in for the eliminated sibling navigation.
427
419
  append(/** @type {ChildNode} */ (node), /** @type {Node} */ (boundary));
@@ -464,7 +456,7 @@ export function for_block_keyed(
464
456
  if (is_controlled) {
465
457
  var parent_node = /** @type {Element} */ (node);
466
458
 
467
- if (hydrating) {
459
+ if (HYDRATION && hydrating) {
468
460
  hydrate_first_child();
469
461
  anchor = /** @type {Element | Text} */ (get_last_child(parent_node));
470
462
  } else {
@@ -472,7 +464,7 @@ export function for_block_keyed(
472
464
  }
473
465
  }
474
466
 
475
- if (hydrating) {
467
+ if (HYDRATION && hydrating) {
476
468
  if (root_controlled) {
477
469
  boundary = /** @type {Node} */ (hydrate_node);
478
470
  }
@@ -492,13 +484,14 @@ export function for_block_keyed(
492
484
  map_item,
493
485
  update_fn,
494
486
  (flags & LOCAL_ITEMS) !== 0,
487
+ (flags & LOCAL_ITEMS) === 0,
495
488
  ),
496
489
  FOR_BLOCK,
497
490
  );
498
491
 
499
492
  if (!is_controlled) own_anchor(node, /** @type {Node} */ (anchor));
500
493
 
501
- if (hydrating && root_controlled) {
494
+ if (HYDRATION && hydrating && root_controlled) {
502
495
  // The original `node`: for a sentinel, `hydrate_append` performs the
503
496
  // cursor advance that stands in for the eliminated sibling navigation.
504
497
  append(/** @type {ChildNode} */ (node), /** @type {Node} */ (boundary));
@@ -561,36 +554,18 @@ function update_value(block, value, map_item, is_local) {
561
554
 
562
555
  /**
563
556
  * @template V
564
- * @template K
565
557
  * @param {ListAnchor} anchor
566
558
  * @param {Block} block
567
559
  * @param {V[]} b
568
- * @param {(anchor: Node, value: V | Tracked, index?: any) => Block} render_fn
569
- * @param {boolean} is_controlled
570
- * @param {boolean} is_indexed
571
- * @param {((item: V) => K) | undefined} get_key identity keys when omitted
572
- * @param {((anchor: Node) => void) | undefined} render_empty
573
- * @param {((item: V) => any) | undefined} map_item
574
- * @param {boolean} is_local items are held as they are (`LOCAL_ITEMS`)
575
560
  * @returns {void}
576
561
  *
577
562
  * The first run only creates items, so it lives in this small function and
578
563
  * the diff below is compiled only once a list actually changes.
579
564
  */
580
- function reconcile_by_key(
581
- anchor,
582
- block,
583
- b,
584
- render_fn,
585
- is_controlled,
586
- is_indexed,
587
- get_key,
588
- render_empty,
589
- map_item,
590
- is_local,
591
- ) {
565
+ function reconcile_by_key(anchor, block, b) {
592
566
  var b_length = b.length;
593
567
  var state = /** @type {ListState} */ (block.s);
568
+ var get_key = state.k;
594
569
 
595
570
  if (state.keys === null && b_length > 0) {
596
571
  var b_blocks = Array(b_length);
@@ -604,7 +579,7 @@ function reconcile_by_key(
604
579
  if (get_key !== undefined) {
605
580
  b_keys[j] = get_key(value);
606
581
  }
607
- b_blocks[j] = create_item(anchor, value, j, render_fn, is_indexed, !is_local, map_item);
582
+ b_blocks[j] = create_item(anchor, value, j, b_keys[j], state);
608
583
  }
609
584
 
610
585
  state.array = b;
@@ -613,50 +588,24 @@ function reconcile_by_key(
613
588
  return;
614
589
  }
615
590
 
616
- reconcile_by_key_diff(
617
- anchor,
618
- block,
619
- b,
620
- render_fn,
621
- is_controlled,
622
- is_indexed,
623
- get_key,
624
- render_empty,
625
- map_item,
626
- is_local,
627
- );
591
+ reconcile_by_key_diff(anchor, block, b);
628
592
  }
629
593
 
630
594
  /**
631
595
  * Keyed diff for every run after the first (or a first run with an empty
632
596
  * list). See {@link reconcile_by_key}.
633
- * @template V, K
597
+ * @template V
634
598
  * @param {ListAnchor} anchor
635
599
  * @param {Block} block
636
600
  * @param {V[]} b
637
- * @param {(anchor: Node, value: V | Tracked, index?: any) => Block} render_fn
638
- * @param {boolean} is_controlled
639
- * @param {boolean} is_indexed
640
- * @param {((item: V) => K) | undefined} get_key
641
- * @param {((anchor: Node) => void) | undefined} render_empty
642
- * @param {((item: V) => any) | undefined} map_item
643
- * @param {boolean} is_local items are held as they are (`LOCAL_ITEMS`)
644
601
  * @returns {void}
645
602
  */
646
- function reconcile_by_key_diff(
647
- anchor,
648
- block,
649
- b,
650
- render_fn,
651
- is_controlled,
652
- is_indexed,
653
- get_key,
654
- render_empty,
655
- map_item,
656
- is_local,
657
- ) {
658
- var is_keyed = !is_local;
603
+ function reconcile_by_key_diff(anchor, block, b) {
659
604
  var state = /** @type {ListState} */ (block.s);
605
+ var is_controlled = state.c;
606
+ var is_indexed = state.x;
607
+ var get_key = state.k;
608
+ var render_empty = state.e;
660
609
 
661
610
  // Variables used in conditional branches - declare with initial values
662
611
  /** @type {number} */
@@ -723,7 +672,7 @@ function reconcile_by_key_diff(
723
672
  // Fast-path for create
724
673
  if (a_length === 0) {
725
674
  for (; j < b_length; j++) {
726
- b_blocks[j] = create_item(anchor, b[j], j, render_fn, is_indexed, is_keyed, map_item);
675
+ b_blocks[j] = create_item(anchor, b[j], j, b_keys[j], state);
727
676
  }
728
677
  state.array = b;
729
678
  state.blocks = b_blocks;
@@ -765,27 +714,15 @@ function reconcile_by_key_diff(
765
714
  // moves; only what is left afterwards needs the map and LIS below.
766
715
  while (a_start <= a_end && b_start <= b_end) {
767
716
  if (a_keys[a_start] === b_keys[b_start]) {
768
- b_val = b[b_start];
769
717
  b_block = b_blocks[b_start] = a_blocks[a_start];
770
- if (is_indexed) {
771
- update_index(b_block, b_start);
772
- }
773
- if (get_key !== undefined) {
774
- update_value(b_block, b_val, map_item, is_local);
775
- }
718
+ patch_item(state, b_block, b[b_start], b_start);
776
719
  a_start++;
777
720
  b_start++;
778
721
  continue;
779
722
  }
780
723
  if (a_keys[a_end] === b_keys[b_end]) {
781
- b_val = b[b_end];
782
724
  b_block = b_blocks[b_end] = a_blocks[a_end];
783
- if (is_indexed) {
784
- update_index(b_block, b_end);
785
- }
786
- if (get_key !== undefined) {
787
- update_value(b_block, b_val, map_item, is_local);
788
- }
725
+ patch_item(state, b_block, b[b_end], b_end);
789
726
  a_end--;
790
727
  b_end--;
791
728
  continue;
@@ -800,14 +737,8 @@ function reconcile_by_key_diff(
800
737
  }
801
738
  if (a_keys[a_end] === b_keys[b_start]) {
802
739
  // Last old item is the next new one: move it in front of the old run.
803
- b_val = b[b_start];
804
740
  b_block = b_blocks[b_start] = a_blocks[a_end];
805
- if (is_indexed) {
806
- update_index(b_block, b_start);
807
- }
808
- if (get_key !== undefined) {
809
- update_value(b_block, b_val, map_item, is_local);
810
- }
741
+ patch_item(state, b_block, b[b_start], b_start);
811
742
  move(b_block, /** @type {ChildNode} */ (a_blocks[a_start].s.start));
812
743
  a_end--;
813
744
  b_start++;
@@ -815,14 +746,8 @@ function reconcile_by_key_diff(
815
746
  }
816
747
  if (a_keys[a_start] === b_keys[b_end]) {
817
748
  // First old item is the last new one: move it behind the old run.
818
- b_val = b[b_end];
819
749
  b_block = b_blocks[b_end] = a_blocks[a_start];
820
- if (is_indexed) {
821
- update_index(b_block, b_end);
822
- }
823
- if (get_key !== undefined) {
824
- update_value(b_block, b_val, map_item, is_local);
825
- }
750
+ patch_item(state, b_block, b[b_end], b_end);
826
751
  move(b_block, block_start(b_blocks, b_end + 1, b_length, anchor));
827
752
  a_start++;
828
753
  b_end--;
@@ -837,15 +762,7 @@ function reconcile_by_key_diff(
837
762
  if (b_start <= b_end) {
838
763
  var target_node = block_start(b_blocks, b_end + 1, b_length, anchor);
839
764
  while (b_start <= b_end) {
840
- b_blocks[b_start] = create_item(
841
- target_node,
842
- b[b_start],
843
- b_start,
844
- render_fn,
845
- is_indexed,
846
- is_keyed,
847
- map_item,
848
- );
765
+ b_blocks[b_start] = create_item(target_node, b[b_start], b_start, b_keys[b_start], state);
849
766
  b_start++;
850
767
  }
851
768
  }
@@ -886,14 +803,8 @@ function reconcile_by_key_diff(
886
803
  } else {
887
804
  pos = j;
888
805
  }
889
- b_val = b[j];
890
806
  b_block = b_blocks[j] = a_blocks[i];
891
- if (is_indexed) {
892
- update_index(b_block, j);
893
- }
894
- if (get_key !== undefined) {
895
- update_value(b_block, b_val, map_item, is_local);
896
- }
807
+ patch_item(state, b_block, b[j], j);
897
808
  ++patched;
898
809
  break;
899
810
  }
@@ -929,14 +840,8 @@ function reconcile_by_key_diff(
929
840
  } else {
930
841
  pos = j;
931
842
  }
932
- b_val = b[j];
933
843
  b_block = b_blocks[j] = a_blocks[i];
934
- if (is_indexed) {
935
- update_index(b_block, j);
936
- }
937
- if (get_key !== undefined) {
938
- update_value(b_block, b_val, map_item, is_local);
939
- }
844
+ patch_item(state, b_block, b[j], j);
940
845
  ++patched;
941
846
  } else if (!fast_path_removal) {
942
847
  destroy_block(a_blocks[i]);
@@ -950,18 +855,7 @@ function reconcile_by_key_diff(
950
855
 
951
856
  if (fast_path_removal) {
952
857
  reconcile_fast_clear(anchor, block, []);
953
- reconcile_by_key(
954
- anchor,
955
- block,
956
- b,
957
- render_fn,
958
- is_controlled,
959
- is_indexed,
960
- get_key,
961
- render_empty,
962
- map_item,
963
- is_local,
964
- );
858
+ reconcile_by_key(anchor, block, b);
965
859
  return;
966
860
  } else if (moved) {
967
861
  var next_pos = 0;
@@ -971,21 +865,7 @@ function reconcile_by_key_diff(
971
865
  // When most surviving items have to move anyway, re-lay the whole range
972
866
  // in order (see `relay`).
973
867
  if ((patched - seq.length) * 3 > b_left * 2) {
974
- relay(
975
- anchor,
976
- a_blocks,
977
- a_start,
978
- a_end,
979
- b,
980
- b_blocks,
981
- b_start,
982
- b_end,
983
- sources,
984
- render_fn,
985
- is_indexed,
986
- is_keyed,
987
- map_item,
988
- );
868
+ relay(anchor, a_blocks, a_start, a_end, b, b_blocks, b_start, b_end, sources, b_keys, state);
989
869
  state.array = b;
990
870
  state.blocks = b_blocks;
991
871
  state.keys = b_keys;
@@ -999,7 +879,7 @@ function reconcile_by_key_diff(
999
879
  next_pos = pos + 1;
1000
880
 
1001
881
  var target = block_start(b_blocks, next_pos, b_length, anchor);
1002
- b_blocks[pos] = create_item(target, b_val, pos, render_fn, is_indexed, is_keyed, map_item);
882
+ b_blocks[pos] = create_item(target, b_val, pos, b_keys[pos], state);
1003
883
  } else if (j < 0 || i !== seq[j]) {
1004
884
  pos = i + b_start;
1005
885
  next_pos = pos + 1;
@@ -1018,7 +898,7 @@ function reconcile_by_key_diff(
1018
898
  next_pos = pos + 1;
1019
899
 
1020
900
  var target = block_start(b_blocks, next_pos, b_length, anchor);
1021
- b_blocks[pos] = create_item(target, b_val, pos, render_fn, is_indexed, is_keyed, map_item);
901
+ b_blocks[pos] = create_item(target, b_val, pos, b_keys[pos], state);
1022
902
  }
1023
903
  }
1024
904
  }
@@ -1047,10 +927,8 @@ function reconcile_by_key_diff(
1047
927
  * @param {number} b_start
1048
928
  * @param {number} b_end
1049
929
  * @param {Int32Array} sources zero at the index of a new item
1050
- * @param {(anchor: Node, value: V | Tracked, index?: any) => Block} render_fn
1051
- * @param {boolean} is_indexed
1052
- * @param {boolean} is_keyed
1053
- * @param {((item: V) => any) | undefined} map_item
930
+ * @param {any[] | undefined} b_keys the new items' keys (a keyed list)
931
+ * @param {ListState} state
1054
932
  */
1055
933
  function relay(
1056
934
  anchor,
@@ -1062,10 +940,8 @@ function relay(
1062
940
  b_start,
1063
941
  b_end,
1064
942
  sources,
1065
- render_fn,
1066
- is_indexed,
1067
- is_keyed,
1068
- map_item,
943
+ b_keys,
944
+ state,
1069
945
  ) {
1070
946
  var b_length = b.length;
1071
947
  var end_target = block_start(b_blocks, b_end + 1, b_length, anchor);
@@ -1085,7 +961,13 @@ function relay(
1085
961
 
1086
962
  for (var pos = b_start; pos <= b_end; pos++) {
1087
963
  if (sources[pos - b_start] === 0) {
1088
- b_blocks[pos] = create_item(cursor, b[pos], pos, render_fn, is_indexed, is_keyed, map_item);
964
+ b_blocks[pos] = create_item(
965
+ cursor,
966
+ b[pos],
967
+ pos,
968
+ b_keys === undefined ? undefined : b_keys[pos],
969
+ state,
970
+ );
1089
971
  continue;
1090
972
  }
1091
973
  var block = b_blocks[pos];
@@ -1108,14 +990,12 @@ function relay(
1108
990
  * @param {ListAnchor} anchor
1109
991
  * @param {Block} block
1110
992
  * @param {V[]} b
1111
- * @param {(anchor: Node, value: V | Tracked, index?: any) => Block} render_fn
1112
- * @param {boolean} is_controlled
1113
- * @param {boolean} is_indexed
1114
- * @param {(anchor: Node) => void} [render_empty]
1115
993
  * @returns {void}
1116
994
  */
1117
- function reconcile_by_ref(anchor, block, b, render_fn, is_controlled, is_indexed, render_empty) {
995
+ function reconcile_by_ref(anchor, block, b) {
1118
996
  var state = /** @type {ListState} */ (block.s);
997
+ var is_controlled = state.c;
998
+ var render_empty = state.e;
1119
999
  var a_length = state.array.length;
1120
1000
  var b_length = b.length;
1121
1001
  var j = 0;
@@ -1155,14 +1035,14 @@ function reconcile_by_ref(anchor, block, b, render_fn, is_controlled, is_indexed
1155
1035
  // Fast-path for create
1156
1036
  if (a_length === 0) {
1157
1037
  for (; j < b_length; j++) {
1158
- b_blocks[j] = create_item(anchor, b[j], j, render_fn, is_indexed, false);
1038
+ b_blocks[j] = create_item(anchor, b[j], j, undefined, state);
1159
1039
  }
1160
1040
  state.array = b;
1161
1041
  state.blocks = b_blocks;
1162
1042
  return;
1163
1043
  }
1164
1044
 
1165
- reconcile_by_ref_diff(anchor, block, b, b_blocks, render_fn, is_controlled, is_indexed);
1045
+ reconcile_by_ref_diff(anchor, block, b, b_blocks);
1166
1046
  }
1167
1047
 
1168
1048
  /**
@@ -1173,13 +1053,11 @@ function reconcile_by_ref(anchor, block, b, render_fn, is_controlled, is_indexed
1173
1053
  * @param {Block} block
1174
1054
  * @param {V[]} b
1175
1055
  * @param {Block[]} b_blocks
1176
- * @param {(anchor: Node, value: V | Tracked, index?: any) => Block} render_fn
1177
- * @param {boolean} is_controlled
1178
- * @param {boolean} is_indexed
1179
1056
  * @returns {void}
1180
1057
  */
1181
- function reconcile_by_ref_diff(anchor, block, b, b_blocks, render_fn, is_controlled, is_indexed) {
1058
+ function reconcile_by_ref_diff(anchor, block, b, b_blocks) {
1182
1059
  var state = /** @type {ListState} */ (block.s);
1060
+ var is_controlled = state.c;
1183
1061
 
1184
1062
  // Variables used in conditional branches - declare with initial values
1185
1063
  /** @type {number} */
@@ -1215,21 +1093,15 @@ function reconcile_by_ref_diff(anchor, block, b, b_blocks, render_fn, is_control
1215
1093
  // moves; only what is left afterwards needs the map and LIS below.
1216
1094
  while (a_start <= a_end && b_start <= b_end) {
1217
1095
  if (a[a_start] === b[b_start]) {
1218
- b_val = b[b_start];
1219
1096
  b_block = b_blocks[b_start] = a_blocks[a_start];
1220
- if (is_indexed) {
1221
- update_index(b_block, b_start);
1222
- }
1097
+ patch_item(state, b_block, b[b_start], b_start);
1223
1098
  a_start++;
1224
1099
  b_start++;
1225
1100
  continue;
1226
1101
  }
1227
1102
  if (a[a_end] === b[b_end]) {
1228
- b_val = b[b_end];
1229
1103
  b_block = b_blocks[b_end] = a_blocks[a_end];
1230
- if (is_indexed) {
1231
- update_index(b_block, b_end);
1232
- }
1104
+ patch_item(state, b_block, b[b_end], b_end);
1233
1105
  a_end--;
1234
1106
  b_end--;
1235
1107
  continue;
@@ -1239,11 +1111,8 @@ function reconcile_by_ref_diff(anchor, block, b, b_blocks, render_fn, is_control
1239
1111
  }
1240
1112
  if (a[a_end] === b[b_start]) {
1241
1113
  // Last old item is the next new one: move it in front of the old run.
1242
- b_val = b[b_start];
1243
1114
  b_block = b_blocks[b_start] = a_blocks[a_end];
1244
- if (is_indexed) {
1245
- update_index(b_block, b_start);
1246
- }
1115
+ patch_item(state, b_block, b[b_start], b_start);
1247
1116
  move(b_block, /** @type {ChildNode} */ (a_blocks[a_start].s.start));
1248
1117
  a_end--;
1249
1118
  b_start++;
@@ -1251,11 +1120,8 @@ function reconcile_by_ref_diff(anchor, block, b, b_blocks, render_fn, is_control
1251
1120
  }
1252
1121
  if (a[a_start] === b[b_end]) {
1253
1122
  // First old item is the last new one: move it behind the old run.
1254
- b_val = b[b_end];
1255
1123
  b_block = b_blocks[b_end] = a_blocks[a_start];
1256
- if (is_indexed) {
1257
- update_index(b_block, b_end);
1258
- }
1124
+ patch_item(state, b_block, b[b_end], b_end);
1259
1125
  move(b_block, block_start(b_blocks, b_end + 1, b_length, anchor));
1260
1126
  a_start++;
1261
1127
  b_end--;
@@ -1270,14 +1136,7 @@ function reconcile_by_ref_diff(anchor, block, b, b_blocks, render_fn, is_control
1270
1136
  if (b_start <= b_end) {
1271
1137
  var target_node = block_start(b_blocks, b_end + 1, b_length, anchor);
1272
1138
  while (b_start <= b_end) {
1273
- b_blocks[b_start] = create_item(
1274
- target_node,
1275
- b[b_start],
1276
- b_start,
1277
- render_fn,
1278
- is_indexed,
1279
- false,
1280
- );
1139
+ b_blocks[b_start] = create_item(target_node, b[b_start], b_start, undefined, state);
1281
1140
  b_start++;
1282
1141
  }
1283
1142
  }
@@ -1314,11 +1173,8 @@ function reconcile_by_ref_diff(anchor, block, b, b_blocks, render_fn, is_control
1314
1173
  } else {
1315
1174
  pos = j;
1316
1175
  }
1317
- b_val = b[j];
1318
1176
  b_block = b_blocks[j] = a_blocks[i];
1319
- if (is_indexed) {
1320
- update_index(b_block, j);
1321
- }
1177
+ patch_item(state, b_block, b[j], j);
1322
1178
  ++patched;
1323
1179
  break;
1324
1180
  }
@@ -1354,11 +1210,8 @@ function reconcile_by_ref_diff(anchor, block, b, b_blocks, render_fn, is_control
1354
1210
  } else {
1355
1211
  pos = j;
1356
1212
  }
1357
- b_val = b[j];
1358
1213
  b_block = b_blocks[j] = a_blocks[i];
1359
- if (is_indexed) {
1360
- update_index(b_block, j);
1361
- }
1214
+ patch_item(state, b_block, b[j], j);
1362
1215
  ++patched;
1363
1216
  } else if (!fast_path_removal) {
1364
1217
  destroy_block(a_blocks[i]);
@@ -1372,7 +1225,7 @@ function reconcile_by_ref_diff(anchor, block, b, b_blocks, render_fn, is_control
1372
1225
 
1373
1226
  if (fast_path_removal) {
1374
1227
  reconcile_fast_clear(anchor, block, []);
1375
- reconcile_by_ref(anchor, block, b, render_fn, is_controlled, is_indexed);
1228
+ reconcile_by_ref(anchor, block, b);
1376
1229
  return;
1377
1230
  } else if (moved) {
1378
1231
  var next_pos = 0;
@@ -1392,10 +1245,8 @@ function reconcile_by_ref_diff(anchor, block, b, b_blocks, render_fn, is_control
1392
1245
  b_start,
1393
1246
  b_end,
1394
1247
  sources,
1395
- render_fn,
1396
- is_indexed,
1397
- false,
1398
1248
  undefined,
1249
+ state,
1399
1250
  );
1400
1251
  state.array = b;
1401
1252
  state.blocks = b_blocks;
@@ -1409,7 +1260,7 @@ function reconcile_by_ref_diff(anchor, block, b, b_blocks, render_fn, is_control
1409
1260
  next_pos = pos + 1;
1410
1261
 
1411
1262
  var target = block_start(b_blocks, next_pos, b_length, anchor);
1412
- b_blocks[pos] = create_item(target, b_val, pos, render_fn, is_indexed, false);
1263
+ b_blocks[pos] = create_item(target, b_val, pos, undefined, state);
1413
1264
  } else if (j < 0 || i !== seq[j]) {
1414
1265
  pos = i + b_start;
1415
1266
  next_pos = pos + 1;
@@ -1428,7 +1279,7 @@ function reconcile_by_ref_diff(anchor, block, b, b_blocks, render_fn, is_control
1428
1279
  next_pos = pos + 1;
1429
1280
 
1430
1281
  var target = block_start(b_blocks, next_pos, b_length, anchor);
1431
- b_blocks[pos] = create_item(target, b_val, pos, render_fn, is_indexed, false);
1282
+ b_blocks[pos] = create_item(target, b_val, pos, undefined, state);
1432
1283
  }
1433
1284
  }
1434
1285
  }