ripple 0.4.2 → 0.4.3

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 (94) hide show
  1. package/CHANGELOG.md +107 -0
  2. package/package.json +9 -3
  3. package/src/jsx-runtime.d.ts +2 -1
  4. package/src/runtime/array.js +15 -9
  5. package/src/runtime/index-client.js +25 -7
  6. package/src/runtime/index-server.js +1 -0
  7. package/src/runtime/internal/client/attributes.js +313 -0
  8. package/src/runtime/internal/client/blocks.js +4 -14
  9. package/src/runtime/internal/client/component.js +2 -5
  10. package/src/runtime/internal/client/composite.js +14 -6
  11. package/src/runtime/internal/client/constants.js +6 -6
  12. package/src/runtime/internal/client/context.js +3 -2
  13. package/src/runtime/internal/client/css.js +11 -26
  14. package/src/runtime/internal/client/errors.js +188 -0
  15. package/src/runtime/internal/client/events.js +79 -34
  16. package/src/runtime/internal/client/expression.js +21 -116
  17. package/src/runtime/internal/client/for.js +108 -232
  18. package/src/runtime/internal/client/head.js +4 -3
  19. package/src/runtime/internal/client/html.js +5 -3
  20. package/src/runtime/internal/client/hydrate.js +484 -0
  21. package/src/runtime/internal/client/hydration-enabled.js +7 -0
  22. package/src/runtime/internal/client/hydration.js +16 -81
  23. package/src/runtime/internal/client/if.js +13 -9
  24. package/src/runtime/internal/client/index.js +14 -6
  25. package/src/runtime/internal/client/operations.js +11 -7
  26. package/src/runtime/internal/client/portal.js +3 -2
  27. package/src/runtime/internal/client/render.js +42 -325
  28. package/src/runtime/internal/client/root-boundary-enabled.js +7 -0
  29. package/src/runtime/internal/client/runtime.js +87 -363
  30. package/src/runtime/internal/client/template-ns.js +47 -0
  31. package/src/runtime/internal/client/template.js +63 -140
  32. package/src/runtime/internal/client/track-async.js +356 -0
  33. package/src/runtime/internal/client/try.js +133 -319
  34. package/src/runtime/internal/client/types.d.ts +48 -24
  35. package/src/runtime/internal/server/index.js +31 -29
  36. package/src/runtime/internal/server/prerender.js +27 -0
  37. package/src/server/index.js +1 -0
  38. package/src/utils/class-name.js +28 -0
  39. package/tests/client/basic/basic.errors.test.tsrx +3 -3
  40. package/tests/client/compiler/__snapshots__/compiler.typescript.test.tsrx.snap +0 -2
  41. package/tests/client/compiler/compiler.basic.test.tsrx +2 -2
  42. package/tests/client/compiler/compiler.tracked-access.test.tsrx +3 -3
  43. package/tests/client/composite/composite.props.test.tsrx +10 -10
  44. package/tests/client/derived-release.test.tsrx +3 -3
  45. package/tests/client/for-item.test.tsrx +39 -0
  46. package/tests/client/for-selector.test.tsrx +95 -0
  47. package/tests/hydration/compiled/client/basic.js +87 -87
  48. package/tests/hydration/compiled/client/composite.js +5 -5
  49. package/tests/hydration/compiled/client/events.js +40 -48
  50. package/tests/hydration/compiled/client/for.js +162 -181
  51. package/tests/hydration/compiled/client/fragment-cursor.js +521 -289
  52. package/tests/hydration/compiled/client/head.js +22 -22
  53. package/tests/hydration/compiled/client/hmr.js +4 -4
  54. package/tests/hydration/compiled/client/html-in-template.js +5 -5
  55. package/tests/hydration/compiled/client/html.js +152 -162
  56. package/tests/hydration/compiled/client/if-children.js +58 -53
  57. package/tests/hydration/compiled/client/if-fragment-controlflow.js +39 -39
  58. package/tests/hydration/compiled/client/if.js +26 -26
  59. package/tests/hydration/compiled/client/mixed-control-flow.js +56 -68
  60. package/tests/hydration/compiled/client/nested-control-flow.js +139 -271
  61. package/tests/hydration/compiled/client/portal.js +10 -10
  62. package/tests/hydration/compiled/client/reactivity.js +29 -29
  63. package/tests/hydration/compiled/client/return.js +2 -2
  64. package/tests/hydration/compiled/client/streaming.js +33 -35
  65. package/tests/hydration/compiled/client/switch.js +25 -25
  66. package/tests/hydration/compiled/client/track-async-serialization.js +41 -41
  67. package/tests/hydration/compiled/client/try.js +15 -15
  68. package/tests/hydration/compiled/client/typed-text.js +7 -7
  69. package/tests/hydration/compiled/server/basic.js +6 -6
  70. package/tests/hydration/compiled/server/events.js +8 -8
  71. package/tests/hydration/compiled/server/for.js +22 -22
  72. package/tests/hydration/compiled/server/fragment-cursor.js +188 -52
  73. package/tests/hydration/compiled/server/head.js +6 -6
  74. package/tests/hydration/compiled/server/hmr.js +1 -1
  75. package/tests/hydration/compiled/server/html.js +1 -1
  76. package/tests/hydration/compiled/server/if-children.js +9 -9
  77. package/tests/hydration/compiled/server/if.js +5 -5
  78. package/tests/hydration/compiled/server/mixed-control-flow.js +4 -4
  79. package/tests/hydration/compiled/server/portal.js +1 -1
  80. package/tests/hydration/compiled/server/reactivity.js +9 -9
  81. package/tests/hydration/compiled/server/streaming.js +9 -9
  82. package/tests/hydration/compiled/server/switch.js +4 -4
  83. package/tests/hydration/compiled/server/track-async-serialization.js +16 -16
  84. package/tests/hydration/compiled/server/try.js +4 -4
  85. package/tests/hydration/compiled/server/typed-text.js +1 -1
  86. package/tests/hydration/components/fragment-cursor.tsrx +60 -0
  87. package/tests/hydration/components/track-async-serialization.tsrx +2 -2
  88. package/tests/hydration/fragment-cursor.test.js +34 -1
  89. package/tests/hydration/track-async-serialization.test.js +1 -1
  90. package/tests/server/basic.components.test.tsrx +3 -3
  91. package/tests/server/track-async-serialization.test.tsrx +6 -6
  92. package/tests/utils/tracked-types.test.js +3 -3
  93. package/types/index.d.ts +8 -8
  94. package/types/server.d.ts +17 -0
@@ -25,31 +25,36 @@ import { get_last_child, next_sibling, resolve_anchor } from './operations.js';
25
25
  import { append } from './template.js';
26
26
  import { active_block, run_block, run_branch, set, set_tracking, tracked } from './runtime.js';
27
27
  import { array_from, is_array } from '@tsrx/core/runtime/language-helpers';
28
+ import { HYDRATION } from 'ripple/internal/client/hydration-enabled';
28
29
 
29
30
  /**
30
31
  * @template V
31
32
  * @param {Node | AppendIntoAnchor} anchor
32
33
  * @param {V} value
33
34
  * @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`)
35
+ * @param {any} key the key the item was matched by (keyed lists)
36
+ * @param {ListState} state the list's state: how items render
38
37
  * @returns {Block}
39
38
  */
40
- function create_item(anchor, value, index, render_fn, is_indexed, is_keyed, map_item) {
39
+ function create_item(anchor, value, index, key, state) {
41
40
  var block = /** @type {Block} */ (active_block);
42
- var tracked_index = is_indexed ? tracked(index, block) : undefined;
43
- var tracked_value = is_keyed
41
+ var render_fn = state.r;
42
+ var map_item = state.m;
43
+ var tracked_index = state.x ? tracked(index, block) : undefined;
44
+ var tracked_value = state.y
44
45
  ? tracked(map_item === undefined ? value : map_item(value), block)
45
46
  : value;
46
- var state = {
47
+ var item_state = {
47
48
  start: null,
48
49
  end: null,
49
50
  i: tracked_index,
50
51
  v: tracked_value,
51
52
  // The item as the collection holds it; a keyed diff compares against it.
52
53
  r: value,
54
+ // The key the item was matched by: fixed for the block's whole life, so
55
+ // the body reads it as a plain value (a compiled `@if (outer === item.key)`
56
+ // depends on the selector alone, not on the item).
57
+ k: key,
53
58
  // The render state of a body that carries its render block on the item
54
59
  // block itself (see `item`), or null.
55
60
  p: null,
@@ -59,8 +64,8 @@ function create_item(anchor, value, index, render_fn, is_indexed, is_keyed, map_
59
64
  // renders in place: allocated, linked and run through `run_branch`, with
60
65
  // none of the first-run bookkeeping a block that may re-run needs.
61
66
  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);
67
+ var lean = allocate_block(BRANCH_BLOCK, run_item, item_state);
68
+ run_branch(lean, render_fn, anchor, value, key);
64
69
  lean.f ^= BLOCK_HAS_RUN;
65
70
  return lean;
66
71
  }
@@ -69,18 +74,35 @@ function create_item(anchor, value, index, render_fn, is_indexed, is_keyed, map_
69
74
  // reads them before rendering, so nested loops cannot observe a stale pair.
70
75
  item_anchor = anchor;
71
76
  item_render_fn = render_fn;
72
- var b = create_block(BRANCH_BLOCK, run_item, state);
77
+ var b = create_block(BRANCH_BLOCK, run_item, item_state);
73
78
 
74
79
  // The item's tracked value and index are owned by the item block itself.
75
- if (is_keyed) {
80
+ if (tracked_value !== value) {
76
81
  /** @type {Tracked} */ (tracked_value).b = b;
77
82
  }
78
- if (is_indexed) {
83
+ if (tracked_index !== undefined) {
79
84
  /** @type {Tracked} */ (tracked_index).b = b;
80
85
  }
81
86
  return b;
82
87
  }
83
88
 
89
+ /**
90
+ * A matched item at its new index: its tracked index and, for a computed key,
91
+ * its tracked value follow the collection.
92
+ * @param {ListState} state
93
+ * @param {Block} block
94
+ * @param {any} value
95
+ * @param {number} index
96
+ */
97
+ function patch_item(state, block, value, index) {
98
+ if (state.x) {
99
+ update_index(block, index);
100
+ }
101
+ if (state.k !== undefined) {
102
+ update_value(block, value, state.m, state.l);
103
+ }
104
+ }
105
+
84
106
  /**
85
107
  * The insertion point of a list: a node the items go before, or, for a
86
108
  * controlled list (the sole content of its parent), an append-into sentinel so
@@ -93,16 +115,16 @@ function create_item(anchor, value, index, render_fn, is_indexed, is_keyed, map_
93
115
  * @returns {AppendIntoAnchor}
94
116
  */
95
117
  function controlled_anchor(parent) {
96
- return { parent, into: true };
118
+ return { parent, into: true, tail: false };
97
119
  }
98
120
 
99
121
  /** @type {Node | AppendIntoAnchor | null} */
100
122
  var item_anchor = null;
101
- /** @type {((anchor: Node, value: any, index?: any) => Block) | null} */
123
+ /** @type {((anchor: Node, value: any, index?: any, key?: any) => Block) | null} */
102
124
  var item_render_fn = null;
103
125
 
104
126
  /**
105
- * @param {{ i: Tracked | undefined, v: any, p: any }} state
127
+ * @param {{ i: Tracked | undefined, v: any, k: any, p: any }} state
106
128
  */
107
129
  function run_item(state) {
108
130
  var p = state.p;
@@ -115,11 +137,13 @@ function run_item(state) {
115
137
  )(p);
116
138
  return;
117
139
  }
118
- var render_fn = /** @type {(anchor: Node, value: any, index?: any) => Block} */ (item_render_fn);
140
+ var render_fn = /** @type {(anchor: Node, value: any, index?: any, key?: any) => Block} */ (
141
+ item_render_fn
142
+ );
119
143
  var anchor = /** @type {Node} */ (item_anchor);
120
144
  item_render_fn = null;
121
145
  item_anchor = null;
122
- render_fn(anchor, state.v, state.i);
146
+ render_fn(anchor, state.v, state.i, state.k);
123
147
  }
124
148
 
125
149
  /**
@@ -292,6 +316,7 @@ class ListState {
292
316
  * @param {((prev: any) => void) | undefined} update_fn the update function
293
317
  * of an item body that carries its render block (see `item`)
294
318
  * @param {boolean} is_local items are held as they are (`LOCAL_ITEMS`)
319
+ * @param {boolean} is_keyed each item holds a tracked of its value
295
320
  */
296
321
  constructor(
297
322
  anchor,
@@ -304,6 +329,7 @@ class ListState {
304
329
  map_item,
305
330
  update_fn,
306
331
  is_local,
332
+ is_keyed,
307
333
  ) {
308
334
  this.a = anchor;
309
335
  this.g = get_collection;
@@ -315,6 +341,7 @@ class ListState {
315
341
  this.m = map_item;
316
342
  this.u = update_fn;
317
343
  this.l = is_local;
344
+ this.y = is_keyed;
318
345
  }
319
346
  }
320
347
 
@@ -327,13 +354,13 @@ function run_for(state) {
327
354
 
328
355
  // Items render untracked, as in a branch; the list tracks only its collection.
329
356
  set_tracking(false);
330
- reconcile_by_ref(state.a, block, array, state.r, state.c, state.x, state.e);
357
+ reconcile_by_ref(state.a, block, array);
331
358
  set_tracking(true);
332
359
 
333
360
  // Re-anchor a hydrated list: the hydrated anchor is the block's start
334
361
  // marker; later inserts and end moves must go before the cursor, which now
335
362
  // sits after the hydrated items.
336
- if (hydrating) {
363
+ if (HYDRATION && hydrating) {
337
364
  state.a = /** @type {Element | Text} */ (hydrate_node);
338
365
  }
339
366
  }
@@ -346,21 +373,10 @@ function run_for_keyed(state) {
346
373
  var array = collection_to_array(state.g());
347
374
 
348
375
  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
- );
376
+ reconcile_by_key(state.a, block, array);
361
377
  set_tracking(true);
362
378
 
363
- if (hydrating) {
379
+ if (HYDRATION && hydrating) {
364
380
  state.a = /** @type {Element | Text} */ (hydrate_node);
365
381
  }
366
382
  }
@@ -387,7 +403,7 @@ export function for_block(node, get_collection, render_fn, flags, render_empty,
387
403
  var boundary;
388
404
 
389
405
  if (is_controlled) {
390
- if (hydrating) {
406
+ if (HYDRATION && hydrating) {
391
407
  // The cursor sits on the list's element; the items are its children.
392
408
  hydrate_first_child();
393
409
  } else {
@@ -395,7 +411,7 @@ export function for_block(node, get_collection, render_fn, flags, render_empty,
395
411
  }
396
412
  }
397
413
 
398
- if (hydrating) {
414
+ if (HYDRATION && hydrating) {
399
415
  if (root_controlled) {
400
416
  boundary = /** @type {Node} */ (hydrate_node);
401
417
  }
@@ -415,13 +431,14 @@ export function for_block(node, get_collection, render_fn, flags, render_empty,
415
431
  undefined,
416
432
  update_fn,
417
433
  false,
434
+ false,
418
435
  ),
419
436
  FOR_BLOCK,
420
437
  );
421
438
 
422
439
  if (!is_controlled) own_anchor(node, /** @type {Node} */ (anchor));
423
440
 
424
- if (hydrating && root_controlled) {
441
+ if (HYDRATION && hydrating && root_controlled) {
425
442
  // The original `node`: for a sentinel, `hydrate_append` performs the
426
443
  // cursor advance that stands in for the eliminated sibling navigation.
427
444
  append(/** @type {ChildNode} */ (node), /** @type {Node} */ (boundary));
@@ -464,7 +481,7 @@ export function for_block_keyed(
464
481
  if (is_controlled) {
465
482
  var parent_node = /** @type {Element} */ (node);
466
483
 
467
- if (hydrating) {
484
+ if (HYDRATION && hydrating) {
468
485
  hydrate_first_child();
469
486
  anchor = /** @type {Element | Text} */ (get_last_child(parent_node));
470
487
  } else {
@@ -472,7 +489,7 @@ export function for_block_keyed(
472
489
  }
473
490
  }
474
491
 
475
- if (hydrating) {
492
+ if (HYDRATION && hydrating) {
476
493
  if (root_controlled) {
477
494
  boundary = /** @type {Node} */ (hydrate_node);
478
495
  }
@@ -492,13 +509,14 @@ export function for_block_keyed(
492
509
  map_item,
493
510
  update_fn,
494
511
  (flags & LOCAL_ITEMS) !== 0,
512
+ (flags & LOCAL_ITEMS) === 0,
495
513
  ),
496
514
  FOR_BLOCK,
497
515
  );
498
516
 
499
517
  if (!is_controlled) own_anchor(node, /** @type {Node} */ (anchor));
500
518
 
501
- if (hydrating && root_controlled) {
519
+ if (HYDRATION && hydrating && root_controlled) {
502
520
  // The original `node`: for a sentinel, `hydrate_append` performs the
503
521
  // cursor advance that stands in for the eliminated sibling navigation.
504
522
  append(/** @type {ChildNode} */ (node), /** @type {Node} */ (boundary));
@@ -561,36 +579,18 @@ function update_value(block, value, map_item, is_local) {
561
579
 
562
580
  /**
563
581
  * @template V
564
- * @template K
565
582
  * @param {ListAnchor} anchor
566
583
  * @param {Block} block
567
584
  * @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
585
  * @returns {void}
576
586
  *
577
587
  * The first run only creates items, so it lives in this small function and
578
588
  * the diff below is compiled only once a list actually changes.
579
589
  */
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
- ) {
590
+ function reconcile_by_key(anchor, block, b) {
592
591
  var b_length = b.length;
593
592
  var state = /** @type {ListState} */ (block.s);
593
+ var get_key = state.k;
594
594
 
595
595
  if (state.keys === null && b_length > 0) {
596
596
  var b_blocks = Array(b_length);
@@ -604,7 +604,7 @@ function reconcile_by_key(
604
604
  if (get_key !== undefined) {
605
605
  b_keys[j] = get_key(value);
606
606
  }
607
- b_blocks[j] = create_item(anchor, value, j, render_fn, is_indexed, !is_local, map_item);
607
+ b_blocks[j] = create_item(anchor, value, j, b_keys[j], state);
608
608
  }
609
609
 
610
610
  state.array = b;
@@ -613,50 +613,24 @@ function reconcile_by_key(
613
613
  return;
614
614
  }
615
615
 
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
- );
616
+ reconcile_by_key_diff(anchor, block, b);
628
617
  }
629
618
 
630
619
  /**
631
620
  * Keyed diff for every run after the first (or a first run with an empty
632
621
  * list). See {@link reconcile_by_key}.
633
- * @template V, K
622
+ * @template V
634
623
  * @param {ListAnchor} anchor
635
624
  * @param {Block} block
636
625
  * @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
626
  * @returns {void}
645
627
  */
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;
628
+ function reconcile_by_key_diff(anchor, block, b) {
659
629
  var state = /** @type {ListState} */ (block.s);
630
+ var is_controlled = state.c;
631
+ var is_indexed = state.x;
632
+ var get_key = state.k;
633
+ var render_empty = state.e;
660
634
 
661
635
  // Variables used in conditional branches - declare with initial values
662
636
  /** @type {number} */
@@ -723,7 +697,7 @@ function reconcile_by_key_diff(
723
697
  // Fast-path for create
724
698
  if (a_length === 0) {
725
699
  for (; j < b_length; j++) {
726
- b_blocks[j] = create_item(anchor, b[j], j, render_fn, is_indexed, is_keyed, map_item);
700
+ b_blocks[j] = create_item(anchor, b[j], j, b_keys[j], state);
727
701
  }
728
702
  state.array = b;
729
703
  state.blocks = b_blocks;
@@ -765,27 +739,15 @@ function reconcile_by_key_diff(
765
739
  // moves; only what is left afterwards needs the map and LIS below.
766
740
  while (a_start <= a_end && b_start <= b_end) {
767
741
  if (a_keys[a_start] === b_keys[b_start]) {
768
- b_val = b[b_start];
769
742
  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
- }
743
+ patch_item(state, b_block, b[b_start], b_start);
776
744
  a_start++;
777
745
  b_start++;
778
746
  continue;
779
747
  }
780
748
  if (a_keys[a_end] === b_keys[b_end]) {
781
- b_val = b[b_end];
782
749
  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
- }
750
+ patch_item(state, b_block, b[b_end], b_end);
789
751
  a_end--;
790
752
  b_end--;
791
753
  continue;
@@ -800,14 +762,8 @@ function reconcile_by_key_diff(
800
762
  }
801
763
  if (a_keys[a_end] === b_keys[b_start]) {
802
764
  // Last old item is the next new one: move it in front of the old run.
803
- b_val = b[b_start];
804
765
  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
- }
766
+ patch_item(state, b_block, b[b_start], b_start);
811
767
  move(b_block, /** @type {ChildNode} */ (a_blocks[a_start].s.start));
812
768
  a_end--;
813
769
  b_start++;
@@ -815,14 +771,8 @@ function reconcile_by_key_diff(
815
771
  }
816
772
  if (a_keys[a_start] === b_keys[b_end]) {
817
773
  // First old item is the last new one: move it behind the old run.
818
- b_val = b[b_end];
819
774
  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
- }
775
+ patch_item(state, b_block, b[b_end], b_end);
826
776
  move(b_block, block_start(b_blocks, b_end + 1, b_length, anchor));
827
777
  a_start++;
828
778
  b_end--;
@@ -837,15 +787,7 @@ function reconcile_by_key_diff(
837
787
  if (b_start <= b_end) {
838
788
  var target_node = block_start(b_blocks, b_end + 1, b_length, anchor);
839
789
  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
- );
790
+ b_blocks[b_start] = create_item(target_node, b[b_start], b_start, b_keys[b_start], state);
849
791
  b_start++;
850
792
  }
851
793
  }
@@ -886,14 +828,8 @@ function reconcile_by_key_diff(
886
828
  } else {
887
829
  pos = j;
888
830
  }
889
- b_val = b[j];
890
831
  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
- }
832
+ patch_item(state, b_block, b[j], j);
897
833
  ++patched;
898
834
  break;
899
835
  }
@@ -929,14 +865,8 @@ function reconcile_by_key_diff(
929
865
  } else {
930
866
  pos = j;
931
867
  }
932
- b_val = b[j];
933
868
  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
- }
869
+ patch_item(state, b_block, b[j], j);
940
870
  ++patched;
941
871
  } else if (!fast_path_removal) {
942
872
  destroy_block(a_blocks[i]);
@@ -950,18 +880,7 @@ function reconcile_by_key_diff(
950
880
 
951
881
  if (fast_path_removal) {
952
882
  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
- );
883
+ reconcile_by_key(anchor, block, b);
965
884
  return;
966
885
  } else if (moved) {
967
886
  var next_pos = 0;
@@ -971,21 +890,7 @@ function reconcile_by_key_diff(
971
890
  // When most surviving items have to move anyway, re-lay the whole range
972
891
  // in order (see `relay`).
973
892
  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
- );
893
+ relay(anchor, a_blocks, a_start, a_end, b, b_blocks, b_start, b_end, sources, b_keys, state);
989
894
  state.array = b;
990
895
  state.blocks = b_blocks;
991
896
  state.keys = b_keys;
@@ -999,7 +904,7 @@ function reconcile_by_key_diff(
999
904
  next_pos = pos + 1;
1000
905
 
1001
906
  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);
907
+ b_blocks[pos] = create_item(target, b_val, pos, b_keys[pos], state);
1003
908
  } else if (j < 0 || i !== seq[j]) {
1004
909
  pos = i + b_start;
1005
910
  next_pos = pos + 1;
@@ -1018,7 +923,7 @@ function reconcile_by_key_diff(
1018
923
  next_pos = pos + 1;
1019
924
 
1020
925
  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);
926
+ b_blocks[pos] = create_item(target, b_val, pos, b_keys[pos], state);
1022
927
  }
1023
928
  }
1024
929
  }
@@ -1047,10 +952,8 @@ function reconcile_by_key_diff(
1047
952
  * @param {number} b_start
1048
953
  * @param {number} b_end
1049
954
  * @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
955
+ * @param {any[] | undefined} b_keys the new items' keys (a keyed list)
956
+ * @param {ListState} state
1054
957
  */
1055
958
  function relay(
1056
959
  anchor,
@@ -1062,10 +965,8 @@ function relay(
1062
965
  b_start,
1063
966
  b_end,
1064
967
  sources,
1065
- render_fn,
1066
- is_indexed,
1067
- is_keyed,
1068
- map_item,
968
+ b_keys,
969
+ state,
1069
970
  ) {
1070
971
  var b_length = b.length;
1071
972
  var end_target = block_start(b_blocks, b_end + 1, b_length, anchor);
@@ -1085,7 +986,13 @@ function relay(
1085
986
 
1086
987
  for (var pos = b_start; pos <= b_end; pos++) {
1087
988
  if (sources[pos - b_start] === 0) {
1088
- b_blocks[pos] = create_item(cursor, b[pos], pos, render_fn, is_indexed, is_keyed, map_item);
989
+ b_blocks[pos] = create_item(
990
+ cursor,
991
+ b[pos],
992
+ pos,
993
+ b_keys === undefined ? undefined : b_keys[pos],
994
+ state,
995
+ );
1089
996
  continue;
1090
997
  }
1091
998
  var block = b_blocks[pos];
@@ -1108,14 +1015,12 @@ function relay(
1108
1015
  * @param {ListAnchor} anchor
1109
1016
  * @param {Block} block
1110
1017
  * @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
1018
  * @returns {void}
1116
1019
  */
1117
- function reconcile_by_ref(anchor, block, b, render_fn, is_controlled, is_indexed, render_empty) {
1020
+ function reconcile_by_ref(anchor, block, b) {
1118
1021
  var state = /** @type {ListState} */ (block.s);
1022
+ var is_controlled = state.c;
1023
+ var render_empty = state.e;
1119
1024
  var a_length = state.array.length;
1120
1025
  var b_length = b.length;
1121
1026
  var j = 0;
@@ -1155,14 +1060,14 @@ function reconcile_by_ref(anchor, block, b, render_fn, is_controlled, is_indexed
1155
1060
  // Fast-path for create
1156
1061
  if (a_length === 0) {
1157
1062
  for (; j < b_length; j++) {
1158
- b_blocks[j] = create_item(anchor, b[j], j, render_fn, is_indexed, false);
1063
+ b_blocks[j] = create_item(anchor, b[j], j, undefined, state);
1159
1064
  }
1160
1065
  state.array = b;
1161
1066
  state.blocks = b_blocks;
1162
1067
  return;
1163
1068
  }
1164
1069
 
1165
- reconcile_by_ref_diff(anchor, block, b, b_blocks, render_fn, is_controlled, is_indexed);
1070
+ reconcile_by_ref_diff(anchor, block, b, b_blocks);
1166
1071
  }
1167
1072
 
1168
1073
  /**
@@ -1173,13 +1078,11 @@ function reconcile_by_ref(anchor, block, b, render_fn, is_controlled, is_indexed
1173
1078
  * @param {Block} block
1174
1079
  * @param {V[]} b
1175
1080
  * @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
1081
  * @returns {void}
1180
1082
  */
1181
- function reconcile_by_ref_diff(anchor, block, b, b_blocks, render_fn, is_controlled, is_indexed) {
1083
+ function reconcile_by_ref_diff(anchor, block, b, b_blocks) {
1182
1084
  var state = /** @type {ListState} */ (block.s);
1085
+ var is_controlled = state.c;
1183
1086
 
1184
1087
  // Variables used in conditional branches - declare with initial values
1185
1088
  /** @type {number} */
@@ -1215,21 +1118,15 @@ function reconcile_by_ref_diff(anchor, block, b, b_blocks, render_fn, is_control
1215
1118
  // moves; only what is left afterwards needs the map and LIS below.
1216
1119
  while (a_start <= a_end && b_start <= b_end) {
1217
1120
  if (a[a_start] === b[b_start]) {
1218
- b_val = b[b_start];
1219
1121
  b_block = b_blocks[b_start] = a_blocks[a_start];
1220
- if (is_indexed) {
1221
- update_index(b_block, b_start);
1222
- }
1122
+ patch_item(state, b_block, b[b_start], b_start);
1223
1123
  a_start++;
1224
1124
  b_start++;
1225
1125
  continue;
1226
1126
  }
1227
1127
  if (a[a_end] === b[b_end]) {
1228
- b_val = b[b_end];
1229
1128
  b_block = b_blocks[b_end] = a_blocks[a_end];
1230
- if (is_indexed) {
1231
- update_index(b_block, b_end);
1232
- }
1129
+ patch_item(state, b_block, b[b_end], b_end);
1233
1130
  a_end--;
1234
1131
  b_end--;
1235
1132
  continue;
@@ -1239,11 +1136,8 @@ function reconcile_by_ref_diff(anchor, block, b, b_blocks, render_fn, is_control
1239
1136
  }
1240
1137
  if (a[a_end] === b[b_start]) {
1241
1138
  // Last old item is the next new one: move it in front of the old run.
1242
- b_val = b[b_start];
1243
1139
  b_block = b_blocks[b_start] = a_blocks[a_end];
1244
- if (is_indexed) {
1245
- update_index(b_block, b_start);
1246
- }
1140
+ patch_item(state, b_block, b[b_start], b_start);
1247
1141
  move(b_block, /** @type {ChildNode} */ (a_blocks[a_start].s.start));
1248
1142
  a_end--;
1249
1143
  b_start++;
@@ -1251,11 +1145,8 @@ function reconcile_by_ref_diff(anchor, block, b, b_blocks, render_fn, is_control
1251
1145
  }
1252
1146
  if (a[a_start] === b[b_end]) {
1253
1147
  // First old item is the last new one: move it behind the old run.
1254
- b_val = b[b_end];
1255
1148
  b_block = b_blocks[b_end] = a_blocks[a_start];
1256
- if (is_indexed) {
1257
- update_index(b_block, b_end);
1258
- }
1149
+ patch_item(state, b_block, b[b_end], b_end);
1259
1150
  move(b_block, block_start(b_blocks, b_end + 1, b_length, anchor));
1260
1151
  a_start++;
1261
1152
  b_end--;
@@ -1270,14 +1161,7 @@ function reconcile_by_ref_diff(anchor, block, b, b_blocks, render_fn, is_control
1270
1161
  if (b_start <= b_end) {
1271
1162
  var target_node = block_start(b_blocks, b_end + 1, b_length, anchor);
1272
1163
  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
- );
1164
+ b_blocks[b_start] = create_item(target_node, b[b_start], b_start, undefined, state);
1281
1165
  b_start++;
1282
1166
  }
1283
1167
  }
@@ -1314,11 +1198,8 @@ function reconcile_by_ref_diff(anchor, block, b, b_blocks, render_fn, is_control
1314
1198
  } else {
1315
1199
  pos = j;
1316
1200
  }
1317
- b_val = b[j];
1318
1201
  b_block = b_blocks[j] = a_blocks[i];
1319
- if (is_indexed) {
1320
- update_index(b_block, j);
1321
- }
1202
+ patch_item(state, b_block, b[j], j);
1322
1203
  ++patched;
1323
1204
  break;
1324
1205
  }
@@ -1354,11 +1235,8 @@ function reconcile_by_ref_diff(anchor, block, b, b_blocks, render_fn, is_control
1354
1235
  } else {
1355
1236
  pos = j;
1356
1237
  }
1357
- b_val = b[j];
1358
1238
  b_block = b_blocks[j] = a_blocks[i];
1359
- if (is_indexed) {
1360
- update_index(b_block, j);
1361
- }
1239
+ patch_item(state, b_block, b[j], j);
1362
1240
  ++patched;
1363
1241
  } else if (!fast_path_removal) {
1364
1242
  destroy_block(a_blocks[i]);
@@ -1372,7 +1250,7 @@ function reconcile_by_ref_diff(anchor, block, b, b_blocks, render_fn, is_control
1372
1250
 
1373
1251
  if (fast_path_removal) {
1374
1252
  reconcile_fast_clear(anchor, block, []);
1375
- reconcile_by_ref(anchor, block, b, render_fn, is_controlled, is_indexed);
1253
+ reconcile_by_ref(anchor, block, b);
1376
1254
  return;
1377
1255
  } else if (moved) {
1378
1256
  var next_pos = 0;
@@ -1392,10 +1270,8 @@ function reconcile_by_ref_diff(anchor, block, b, b_blocks, render_fn, is_control
1392
1270
  b_start,
1393
1271
  b_end,
1394
1272
  sources,
1395
- render_fn,
1396
- is_indexed,
1397
- false,
1398
1273
  undefined,
1274
+ state,
1399
1275
  );
1400
1276
  state.array = b;
1401
1277
  state.blocks = b_blocks;
@@ -1409,7 +1285,7 @@ function reconcile_by_ref_diff(anchor, block, b, b_blocks, render_fn, is_control
1409
1285
  next_pos = pos + 1;
1410
1286
 
1411
1287
  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);
1288
+ b_blocks[pos] = create_item(target, b_val, pos, undefined, state);
1413
1289
  } else if (j < 0 || i !== seq[j]) {
1414
1290
  pos = i + b_start;
1415
1291
  next_pos = pos + 1;
@@ -1428,7 +1304,7 @@ function reconcile_by_ref_diff(anchor, block, b, b_blocks, render_fn, is_control
1428
1304
  next_pos = pos + 1;
1429
1305
 
1430
1306
  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);
1307
+ b_blocks[pos] = create_item(target, b_val, pos, undefined, state);
1432
1308
  }
1433
1309
  }
1434
1310
  }