ripple 0.3.127 → 0.4.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.
- package/CHANGELOG.md +293 -0
- package/package.json +10 -4
- package/src/runtime/element.js +23 -6
- package/src/runtime/index-client.js +81 -41
- package/src/runtime/index-server.js +1 -0
- package/src/runtime/internal/client/blocks.js +192 -114
- package/src/runtime/internal/client/component.js +4 -30
- package/src/runtime/internal/client/composite.js +12 -13
- package/src/runtime/internal/client/constants.js +14 -5
- package/src/runtime/internal/client/context.js +12 -19
- package/src/runtime/internal/client/css.js +7 -9
- package/src/runtime/internal/client/events.js +178 -90
- package/src/runtime/internal/client/expression.js +185 -124
- package/src/runtime/internal/client/for.js +616 -264
- package/src/runtime/internal/client/head.js +10 -5
- package/src/runtime/internal/client/html.js +1 -0
- package/src/runtime/internal/client/hydration.js +152 -10
- package/src/runtime/internal/client/if.js +239 -50
- package/src/runtime/internal/client/index.js +9 -13
- package/src/runtime/internal/client/operations.js +44 -51
- package/src/runtime/internal/client/portal.js +163 -85
- package/src/runtime/internal/client/render.js +44 -25
- package/src/runtime/internal/client/rpc.js +3 -3
- package/src/runtime/internal/client/runtime.js +799 -576
- package/src/runtime/internal/client/selector.js +77 -0
- package/src/runtime/internal/client/template.js +133 -158
- package/src/runtime/internal/client/transport.js +38 -0
- package/src/runtime/internal/client/try.js +465 -426
- package/src/runtime/internal/client/types.d.ts +65 -21
- package/src/runtime/internal/client/utils.js +1 -3
- package/src/runtime/internal/server/dynamic.js +20 -21
- package/src/runtime/internal/server/index.js +327 -275
- package/src/runtime/internal/server/rpc.js +3 -2
- package/src/runtime/internal/server/transport.js +16 -0
- package/src/runtime/transport.js +21 -0
- package/tests/client/__snapshots__/for.test.tsrx.snap +0 -5
- package/tests/client/array/array.copy-within.test.tsrx +12 -12
- package/tests/client/array/array.derived.test.tsrx +46 -46
- package/tests/client/array/array.iteration.test.tsrx +10 -10
- package/tests/client/array/array.mutations.test.tsrx +20 -20
- package/tests/client/array/array.static.test.tsrx +11 -11
- package/tests/client/array/array.to-methods.test.tsrx +6 -6
- package/tests/client/async-suspend.test.tsrx +74 -75
- package/tests/client/basic/basic.attributes.test.tsrx +86 -83
- package/tests/client/basic/basic.collections.test.tsrx +12 -12
- package/tests/client/basic/basic.components.test.tsrx +99 -25
- package/tests/client/basic/basic.errors.test.tsrx +18 -18
- package/tests/client/basic/basic.events.test.tsrx +42 -42
- package/tests/client/basic/basic.get-set.test.tsrx +8 -8
- package/tests/client/basic/basic.reactivity.test.tsrx +97 -29
- package/tests/client/basic/basic.rendering.test.tsrx +25 -25
- package/tests/client/basic/basic.utilities.test.tsrx +3 -3
- package/tests/client/boundaries.test.tsrx +8 -8
- package/tests/client/boxed-locals.test.tsrx +452 -0
- package/tests/client/compiler/__snapshots__/compiler.assignments.test.tsrx.snap +6 -6
- package/tests/client/compiler/compiler.assignments.test.tsrx +9 -73
- package/tests/client/compiler/compiler.attributes.test.tsrx +23 -23
- package/tests/client/compiler/compiler.basic.test.tsrx +15 -60
- package/tests/client/compiler/compiler.tracked-access.test.tsrx +18 -43
- package/tests/client/compiler/compiler.try-in-function.test.tsrx +2 -2
- package/tests/client/composite/__snapshots__/composite.render.test.tsrx.snap +0 -1
- package/tests/client/composite/composite.dynamic-components.test.tsrx +77 -6
- package/tests/client/composite/composite.props.test.tsrx +149 -12
- package/tests/client/composite/composite.reactivity.test.tsrx +51 -52
- package/tests/client/composite/composite.render.test.tsrx +26 -9
- package/tests/client/css/scoped-styles.test.tsrx +8 -8
- package/tests/client/date.test.tsrx +42 -42
- package/tests/client/derived-release.test.tsrx +370 -0
- package/tests/client/dynamic-elements.test.tsrx +45 -45
- package/tests/client/events.test.tsrx +97 -71
- package/tests/client/for-selector.test.tsrx +221 -0
- package/tests/client/for-single-root-items.test.tsrx +118 -3
- package/tests/client/for.test.tsrx +332 -31
- package/tests/client/head.test.tsrx +19 -19
- package/tests/client/html.test.tsrx +11 -9
- package/tests/client/if-block.test.tsrx +80 -0
- package/tests/client/map.test.tsrx +16 -16
- package/tests/client/media-query.test.tsrx +7 -7
- package/tests/client/portal.test.tsrx +224 -26
- package/tests/client/primitive-text.test.tsrx +50 -0
- package/tests/client/prop-kind-switch.test.tsrx +141 -0
- package/tests/client/ref.test.tsrx +17 -17
- package/tests/client/return.test.tsrx +26 -3
- package/tests/client/root-boundary.test.tsrx +42 -0
- package/tests/client/scoped-flush.test.tsrx +8 -8
- package/tests/client/set.test.tsrx +6 -6
- package/tests/client/svg.test.tsrx +11 -11
- package/tests/client/switch.test.tsrx +44 -44
- package/tests/client/track-async-hydration.test.tsrx +4 -4
- package/tests/client/try.test.tsrx +151 -83
- package/tests/client/tsx.test.tsrx +43 -40
- package/tests/client/url/url.derived.test.tsrx +6 -6
- package/tests/client/url-search-params/url-search-params.derived.test.tsrx +8 -8
- package/tests/client/url-search-params/url-search-params.iteration.test.tsrx +10 -10
- package/tests/client/url-search-params/url-search-params.mutation.test.tsrx +10 -10
- package/tests/client/url-search-params/url-search-params.retrieval.test.tsrx +18 -18
- package/tests/client/url-search-params/url-search-params.serialization.test.tsrx +2 -2
- package/tests/hydration/basic.test.js +74 -1
- package/tests/hydration/build-components.js +22 -1
- package/tests/hydration/compiled/client/basic.js +1142 -713
- package/tests/hydration/compiled/client/composite.js +151 -100
- package/tests/hydration/compiled/client/events.js +190 -150
- package/tests/hydration/compiled/client/for.js +1472 -1126
- package/tests/hydration/compiled/client/fragment-cursor.js +2341 -0
- package/tests/hydration/compiled/client/head.js +255 -199
- package/tests/hydration/compiled/client/hmr.js +54 -41
- package/tests/hydration/compiled/client/html-in-template.js +54 -39
- package/tests/hydration/compiled/client/html.js +1633 -1263
- package/tests/hydration/compiled/client/if-children.js +420 -270
- package/tests/hydration/compiled/client/if-fragment-controlflow.js +363 -317
- package/tests/hydration/compiled/client/if.js +229 -219
- package/tests/hydration/compiled/client/mixed-control-flow.js +420 -400
- package/tests/hydration/compiled/client/nested-control-flow.js +1326 -1255
- package/tests/hydration/compiled/client/portal.js +87 -95
- package/tests/hydration/compiled/client/reactivity.js +140 -83
- package/tests/hydration/compiled/client/return.js +28 -19
- package/tests/hydration/compiled/client/streaming.js +390 -306
- package/tests/hydration/compiled/client/switch.js +258 -266
- package/tests/hydration/compiled/client/track-async-serialization.js +448 -280
- package/tests/hydration/compiled/client/try.js +173 -129
- package/tests/hydration/compiled/client/typed-text.js +71 -0
- package/tests/hydration/compiled/fixtures/money.js +10 -0
- package/tests/hydration/compiled/server/basic.js +123 -6
- package/tests/hydration/compiled/server/composite.js +16 -30
- package/tests/hydration/compiled/server/events.js +19 -19
- package/tests/hydration/compiled/server/for.js +109 -49
- package/tests/hydration/compiled/server/fragment-cursor.js +1687 -0
- package/tests/hydration/compiled/server/head.js +20 -28
- package/tests/hydration/compiled/server/hmr.js +2 -2
- package/tests/hydration/compiled/server/html.js +71 -247
- package/tests/hydration/compiled/server/if-children.js +107 -15
- package/tests/hydration/compiled/server/if.js +11 -15
- package/tests/hydration/compiled/server/mixed-control-flow.js +8 -8
- package/tests/hydration/compiled/server/portal.js +14 -22
- package/tests/hydration/compiled/server/reactivity.js +14 -46
- package/tests/hydration/compiled/server/streaming.js +19 -19
- package/tests/hydration/compiled/server/switch.js +8 -8
- package/tests/hydration/compiled/server/track-async-serialization.js +150 -23
- package/tests/hydration/compiled/server/try.js +8 -8
- package/tests/hydration/compiled/server/typed-text.js +17 -0
- package/tests/hydration/components/basic.tsrx +44 -8
- package/tests/hydration/components/composite.tsrx +2 -2
- package/tests/hydration/components/events.tsrx +25 -25
- package/tests/hydration/components/for.tsrx +115 -67
- package/tests/hydration/components/fragment-cursor.tsrx +650 -0
- package/tests/hydration/components/head.tsrx +16 -16
- package/tests/hydration/components/hmr.tsrx +2 -2
- package/tests/hydration/components/html.tsrx +7 -7
- package/tests/hydration/components/if-children.tsrx +72 -25
- package/tests/hydration/components/if.tsrx +18 -18
- package/tests/hydration/components/mixed-control-flow.tsrx +11 -11
- package/tests/hydration/components/portal.tsrx +3 -3
- package/tests/hydration/components/reactivity.tsrx +16 -16
- package/tests/hydration/components/streaming.tsrx +20 -20
- package/tests/hydration/components/switch.tsrx +20 -20
- package/tests/hydration/components/text-types.ts +4 -0
- package/tests/hydration/components/track-async-serialization.tsrx +80 -26
- package/tests/hydration/components/try.tsrx +8 -8
- package/tests/hydration/components/typed-text.tsrx +22 -0
- package/tests/hydration/fixtures/money.js +10 -0
- package/tests/hydration/for.test.js +36 -0
- package/tests/hydration/fragment-cursor.test.js +111 -0
- package/tests/hydration/if-children.test.js +24 -0
- package/tests/hydration/streaming.test.js +19 -0
- package/tests/hydration/track-async-serialization.test.js +87 -2
- package/tests/hydration/tsconfig.text-types.json +10 -0
- package/tests/hydration/typed-text.test.js +34 -0
- package/tests/server/await.test.tsrx +3 -3
- package/tests/server/basic.attributes.test.tsrx +42 -42
- package/tests/server/basic.components.test.tsrx +64 -8
- package/tests/server/basic.test.tsrx +34 -32
- package/tests/server/compiler.test.tsrx +1 -70
- package/tests/server/composite.props.test.tsrx +6 -6
- package/tests/server/dynamic-elements.test.tsrx +31 -8
- package/tests/server/for.test.tsrx +94 -0
- package/tests/server/head.test.tsrx +11 -11
- package/tests/server/scoped-styles.test.tsrx +2 -2
- package/tests/server/streaming-ssr.test.tsrx +48 -43
- package/tests/server/track-async-serialization.test.tsrx +204 -21
- package/tests/server/try.test.tsrx +48 -48
- package/tests/types/transport.ts +40 -0
- package/tests/utils/vite-plugin-config.test.js +23 -0
- package/types/index.d.ts +48 -7
- package/types/server.d.ts +3 -0
- package/types/transport.d.ts +15 -0
- package/src/runtime/internal/client/switch.js +0 -113
- package/src/utils/errors.js +0 -13
- package/tests/client/lazy-array.test.tsrx +0 -31
- package/tests/client/lazy-destructuring.test.tsrx +0 -438
- package/tests/client/tracked-index-access.test.tsrx +0 -113
- package/tests/server/lazy-destructuring.test.tsrx +0 -595
- package/tests/server/tracked-index-access.test.tsrx +0 -76
|
@@ -1,84 +1,110 @@
|
|
|
1
|
-
/** @import { Block, Tracked } from '#client' */
|
|
1
|
+
/** @import { AppendIntoAnchor, Block, Tracked } from '#client' */
|
|
2
2
|
|
|
3
3
|
import { IS_CONTROLLED, IS_INDEXED, ROOT_CONTROLLED } from '../../../constants.js';
|
|
4
4
|
import {
|
|
5
|
+
block as create_block,
|
|
5
6
|
branch,
|
|
6
7
|
destroy_block,
|
|
7
8
|
destroy_block_children,
|
|
8
9
|
get_first_node,
|
|
9
10
|
get_last_node,
|
|
11
|
+
own_anchor,
|
|
10
12
|
render,
|
|
11
13
|
} from './blocks.js';
|
|
12
|
-
import { FOR_BLOCK, TRACKED_ARRAY } from './constants.js';
|
|
13
|
-
import { hydrate_next, hydrate_node, hydrating
|
|
14
|
-
import {
|
|
14
|
+
import { BRANCH_BLOCK, FOR_BLOCK, TRACKED_ARRAY } from './constants.js';
|
|
15
|
+
import { hydrate_first_child, hydrate_next, hydrate_node, hydrating } from './hydration.js';
|
|
16
|
+
import { get_last_child, next_sibling, resolve_anchor } from './operations.js';
|
|
15
17
|
import { append } from './template.js';
|
|
16
|
-
import { active_block, set,
|
|
18
|
+
import { active_block, set, set_tracking, tracked } from './runtime.js';
|
|
17
19
|
import { array_from, is_array } from '@tsrx/core/runtime/language-helpers';
|
|
18
20
|
|
|
19
21
|
/**
|
|
20
22
|
* @template V
|
|
21
|
-
* @param {Node} anchor
|
|
23
|
+
* @param {Node | AppendIntoAnchor} anchor
|
|
22
24
|
* @param {V} value
|
|
23
25
|
* @param {number} index
|
|
24
26
|
* @param {(anchor: Node, value: V | Tracked, index?: any) => Block} render_fn
|
|
25
27
|
* @param {boolean} is_indexed
|
|
26
28
|
* @param {boolean} is_keyed
|
|
29
|
+
* @param {((item: V) => any) | undefined} [map_item] a keyed loop's destructuring of the item (see `for_block_keyed`)
|
|
27
30
|
* @returns {Block}
|
|
28
31
|
*/
|
|
29
|
-
function create_item(anchor, value, index, render_fn, is_indexed, is_keyed) {
|
|
30
|
-
var
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
tracked_index = block.s.v;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
render_fn(anchor, tracked_value, tracked_index);
|
|
61
|
-
} else {
|
|
62
|
-
render_fn(anchor, tracked_value);
|
|
63
|
-
}
|
|
64
|
-
});
|
|
32
|
+
function create_item(anchor, value, index, render_fn, is_indexed, is_keyed, map_item) {
|
|
33
|
+
var block = /** @type {Block} */ (active_block);
|
|
34
|
+
var tracked_index = is_indexed ? tracked(index, block) : undefined;
|
|
35
|
+
var tracked_value = is_keyed
|
|
36
|
+
? tracked(map_item === undefined ? value : map_item(value), block)
|
|
37
|
+
: value;
|
|
38
|
+
var state = {
|
|
39
|
+
start: null,
|
|
40
|
+
end: null,
|
|
41
|
+
i: tracked_index,
|
|
42
|
+
v: tracked_value,
|
|
43
|
+
// The item as the collection holds it; a keyed diff compares against it.
|
|
44
|
+
r: value,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Passed through module state rather than a per-item closure; run_item
|
|
48
|
+
// reads them before rendering, so nested loops cannot observe a stale pair.
|
|
49
|
+
item_anchor = anchor;
|
|
50
|
+
item_render_fn = render_fn;
|
|
51
|
+
var b = create_block(BRANCH_BLOCK, run_item, state);
|
|
52
|
+
|
|
53
|
+
// The item's tracked value and index are owned by the item block itself.
|
|
54
|
+
if (is_keyed) {
|
|
55
|
+
/** @type {Tracked} */ (tracked_value).b = b;
|
|
56
|
+
}
|
|
57
|
+
if (is_indexed) {
|
|
58
|
+
/** @type {Tracked} */ (tracked_index).b = b;
|
|
59
|
+
}
|
|
65
60
|
return b;
|
|
66
61
|
}
|
|
67
62
|
|
|
68
63
|
/**
|
|
69
|
-
*
|
|
64
|
+
* The insertion point of a list: a node the items go before, or, for a
|
|
65
|
+
* controlled list (the sole content of its parent), an append-into sentinel so
|
|
66
|
+
* items append to the parent with no anchor node in the DOM.
|
|
67
|
+
* @typedef {Element | Text | AppendIntoAnchor} ListAnchor
|
|
68
|
+
*/
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @param {Element} parent
|
|
72
|
+
* @returns {AppendIntoAnchor}
|
|
73
|
+
*/
|
|
74
|
+
function controlled_anchor(parent) {
|
|
75
|
+
return { parent, into: true };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** @type {Node | AppendIntoAnchor | null} */
|
|
79
|
+
var item_anchor = null;
|
|
80
|
+
/** @type {((anchor: Node, value: any, index?: any) => Block) | null} */
|
|
81
|
+
var item_render_fn = null;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @param {{ i: Tracked | undefined, v: any }} state
|
|
85
|
+
*/
|
|
86
|
+
function run_item(state) {
|
|
87
|
+
var render_fn = /** @type {(anchor: Node, value: any, index?: any) => Block} */ (item_render_fn);
|
|
88
|
+
var anchor = /** @type {Node} */ (item_anchor);
|
|
89
|
+
item_render_fn = null;
|
|
90
|
+
item_anchor = null;
|
|
91
|
+
render_fn(anchor, state.v, state.i);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @param {ListAnchor} anchor
|
|
70
96
|
* @param {(anchor: Node) => void} render_empty
|
|
71
97
|
* @returns {Block}
|
|
72
98
|
*/
|
|
73
99
|
function create_empty(anchor, render_empty) {
|
|
74
100
|
return branch(() => {
|
|
75
|
-
render_empty(anchor);
|
|
101
|
+
render_empty(/** @type {Node} */ (anchor));
|
|
76
102
|
});
|
|
77
103
|
}
|
|
78
104
|
|
|
79
105
|
/**
|
|
80
106
|
* @param {Block} block
|
|
81
|
-
* @param {ChildNode} anchor
|
|
107
|
+
* @param {ChildNode | AppendIntoAnchor} anchor
|
|
82
108
|
* @returns {void}
|
|
83
109
|
*/
|
|
84
110
|
function move(block, anchor) {
|
|
@@ -99,21 +125,46 @@ function move(block, anchor) {
|
|
|
99
125
|
end = s.end;
|
|
100
126
|
}
|
|
101
127
|
|
|
128
|
+
// A controlled list appends into its parent (no anchor node); anything
|
|
129
|
+
// else inserts before its anchor.
|
|
130
|
+
/** @type {Node | null} */
|
|
131
|
+
var parent = null;
|
|
132
|
+
/** @type {ChildNode | null} */
|
|
133
|
+
var before = null;
|
|
134
|
+
if (/** @type {AppendIntoAnchor} */ (anchor).into === true) {
|
|
135
|
+
parent = /** @type {AppendIntoAnchor} */ (anchor).parent;
|
|
136
|
+
} else {
|
|
137
|
+
before = /** @type {ChildNode} */ (anchor);
|
|
138
|
+
}
|
|
139
|
+
|
|
102
140
|
if (node === end) {
|
|
103
|
-
|
|
141
|
+
insert_node(parent, before, node);
|
|
104
142
|
return;
|
|
105
143
|
}
|
|
106
144
|
while (node !== null) {
|
|
107
145
|
var next_node = /** @type {Node} */ (next_sibling(node));
|
|
108
|
-
|
|
146
|
+
insert_node(parent, before, node);
|
|
109
147
|
node = next_node;
|
|
110
148
|
if (node === end) {
|
|
111
|
-
|
|
149
|
+
insert_node(parent, before, /** @type {Node} */ (end));
|
|
112
150
|
break;
|
|
113
151
|
}
|
|
114
152
|
}
|
|
115
153
|
}
|
|
116
154
|
|
|
155
|
+
/**
|
|
156
|
+
* @param {Node | null} parent
|
|
157
|
+
* @param {ChildNode | null} before
|
|
158
|
+
* @param {Node} node
|
|
159
|
+
*/
|
|
160
|
+
function insert_node(parent, before, node) {
|
|
161
|
+
if (parent !== null) {
|
|
162
|
+
parent.appendChild(node);
|
|
163
|
+
} else {
|
|
164
|
+
/** @type {ChildNode} */ (before).before(node);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
117
168
|
/**
|
|
118
169
|
* Resolve the insertion anchor for a block at `index`: the first real DOM node
|
|
119
170
|
* at or after `index`, or `fallback` when every remaining block renders nothing.
|
|
@@ -123,8 +174,8 @@ function move(block, anchor) {
|
|
|
123
174
|
* @param {Block[]} blocks
|
|
124
175
|
* @param {number} index
|
|
125
176
|
* @param {number} length
|
|
126
|
-
* @param {
|
|
127
|
-
* @returns {ChildNode}
|
|
177
|
+
* @param {ListAnchor} fallback
|
|
178
|
+
* @returns {ChildNode | AppendIntoAnchor}
|
|
128
179
|
*/
|
|
129
180
|
function block_start(blocks, index, length, fallback) {
|
|
130
181
|
if (index >= length) {
|
|
@@ -162,9 +213,91 @@ function collection_to_array(collection) {
|
|
|
162
213
|
return array;
|
|
163
214
|
}
|
|
164
215
|
|
|
216
|
+
/**
|
|
217
|
+
* The state of a list block. The reconciled list (`array`, `blocks`, `keys`,
|
|
218
|
+
* `empty`) and the inputs the list is re-run with both live here, so a list
|
|
219
|
+
* allocates no closures.
|
|
220
|
+
*/
|
|
221
|
+
class ListState {
|
|
222
|
+
/** @type {any[]} */
|
|
223
|
+
array = [];
|
|
224
|
+
/** @type {Block[]} */
|
|
225
|
+
blocks = [];
|
|
226
|
+
/** @type {any[] | null} null until the first reconcile */
|
|
227
|
+
keys = null;
|
|
228
|
+
/** @type {Block | null} */
|
|
229
|
+
empty = null;
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* @param {ListAnchor} anchor
|
|
233
|
+
* @param {() => any} get_collection
|
|
234
|
+
* @param {(anchor: Node, value: any, index?: any) => Block} render_fn
|
|
235
|
+
* @param {boolean} is_controlled
|
|
236
|
+
* @param {boolean} is_indexed
|
|
237
|
+
* @param {((item: any) => any) | undefined} get_key
|
|
238
|
+
* @param {((anchor: Node) => void) | undefined} render_empty
|
|
239
|
+
* @param {((item: any) => any) | undefined} [map_item]
|
|
240
|
+
*/
|
|
241
|
+
constructor(
|
|
242
|
+
anchor,
|
|
243
|
+
get_collection,
|
|
244
|
+
render_fn,
|
|
245
|
+
is_controlled,
|
|
246
|
+
is_indexed,
|
|
247
|
+
get_key,
|
|
248
|
+
render_empty,
|
|
249
|
+
map_item,
|
|
250
|
+
) {
|
|
251
|
+
this.a = anchor;
|
|
252
|
+
this.g = get_collection;
|
|
253
|
+
this.r = render_fn;
|
|
254
|
+
this.c = is_controlled;
|
|
255
|
+
this.x = is_indexed;
|
|
256
|
+
this.k = get_key;
|
|
257
|
+
this.e = render_empty;
|
|
258
|
+
this.m = map_item;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* @param {ListState} state
|
|
264
|
+
*/
|
|
265
|
+
function run_for(state) {
|
|
266
|
+
var block = /** @type {Block} */ (active_block);
|
|
267
|
+
var array = collection_to_array(state.g());
|
|
268
|
+
|
|
269
|
+
// Items render untracked, as in a branch; the list tracks only its collection.
|
|
270
|
+
set_tracking(false);
|
|
271
|
+
reconcile_by_ref(state.a, block, array, state.r, state.c, state.x, state.e);
|
|
272
|
+
set_tracking(true);
|
|
273
|
+
|
|
274
|
+
// Re-anchor a hydrated list: the hydrated anchor is the block's start
|
|
275
|
+
// marker; later inserts and end moves must go before the cursor, which now
|
|
276
|
+
// sits after the hydrated items.
|
|
277
|
+
if (hydrating) {
|
|
278
|
+
state.a = /** @type {Element | Text} */ (hydrate_node);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* @param {ListState} state
|
|
284
|
+
*/
|
|
285
|
+
function run_for_keyed(state) {
|
|
286
|
+
var block = /** @type {Block} */ (active_block);
|
|
287
|
+
var array = collection_to_array(state.g());
|
|
288
|
+
|
|
289
|
+
set_tracking(false);
|
|
290
|
+
reconcile_by_key(state.a, block, array, state.r, state.c, state.x, state.k, state.e, state.m);
|
|
291
|
+
set_tracking(true);
|
|
292
|
+
|
|
293
|
+
if (hydrating) {
|
|
294
|
+
state.a = /** @type {Element | Text} */ (hydrate_node);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
165
298
|
/**
|
|
166
299
|
* @template V
|
|
167
|
-
* @param {Element} node
|
|
300
|
+
* @param {Element | AppendIntoAnchor} node
|
|
168
301
|
* @param {() => V[] | Iterable<V>} get_collection
|
|
169
302
|
* @param {(anchor: Node, value: V | Tracked, index?: any) => Block} render_fn
|
|
170
303
|
* @param {number} flags
|
|
@@ -175,16 +308,18 @@ export function for_block(node, get_collection, render_fn, flags, render_empty)
|
|
|
175
308
|
var is_controlled = (flags & IS_CONTROLLED) !== 0;
|
|
176
309
|
var is_indexed = (flags & IS_INDEXED) !== 0;
|
|
177
310
|
var root_controlled = (flags & ROOT_CONTROLLED) !== 0;
|
|
178
|
-
|
|
311
|
+
// A root-controlled list receives the component's `__anchor`, which may be
|
|
312
|
+
// an append-into sentinel; moves and end insertions need a real node.
|
|
313
|
+
var anchor = /** @type {ListAnchor} */ (root_controlled ? resolve_anchor(node) : node);
|
|
179
314
|
/** @type {Node | undefined} */
|
|
180
315
|
var boundary;
|
|
181
316
|
|
|
182
317
|
if (is_controlled) {
|
|
183
318
|
if (hydrating) {
|
|
184
|
-
|
|
185
|
-
|
|
319
|
+
// The cursor sits on the list's element; the items are its children.
|
|
320
|
+
hydrate_first_child();
|
|
186
321
|
} else {
|
|
187
|
-
anchor =
|
|
322
|
+
anchor = controlled_anchor(/** @type {Element} */ (node));
|
|
188
323
|
}
|
|
189
324
|
}
|
|
190
325
|
|
|
@@ -196,24 +331,24 @@ export function for_block(node, get_collection, render_fn, flags, render_empty)
|
|
|
196
331
|
}
|
|
197
332
|
|
|
198
333
|
render(
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
anchor = /** @type {Element | Text} */ (hydrate_node);
|
|
210
|
-
}
|
|
211
|
-
},
|
|
212
|
-
null,
|
|
334
|
+
run_for,
|
|
335
|
+
new ListState(
|
|
336
|
+
anchor,
|
|
337
|
+
get_collection,
|
|
338
|
+
render_fn,
|
|
339
|
+
is_controlled,
|
|
340
|
+
is_indexed,
|
|
341
|
+
undefined,
|
|
342
|
+
render_empty,
|
|
343
|
+
),
|
|
213
344
|
FOR_BLOCK,
|
|
214
345
|
);
|
|
215
346
|
|
|
347
|
+
if (!is_controlled) own_anchor(node, /** @type {Node} */ (anchor));
|
|
348
|
+
|
|
216
349
|
if (hydrating && root_controlled) {
|
|
350
|
+
// The original `node`: for a sentinel, `hydrate_append` performs the
|
|
351
|
+
// cursor advance that stands in for the eliminated sibling navigation.
|
|
217
352
|
append(/** @type {ChildNode} */ (node), /** @type {Node} */ (boundary));
|
|
218
353
|
}
|
|
219
354
|
}
|
|
@@ -221,19 +356,30 @@ export function for_block(node, get_collection, render_fn, flags, render_empty)
|
|
|
221
356
|
/**
|
|
222
357
|
* @template V
|
|
223
358
|
* @template K
|
|
224
|
-
* @param {Element} node
|
|
359
|
+
* @param {Element | AppendIntoAnchor} node
|
|
225
360
|
* @param {() => V[] | Iterable<V>} get_collection
|
|
226
361
|
* @param {(anchor: Node, value: V | Tracked, index?: any) => Block} render_fn
|
|
227
362
|
* @param {number} flags
|
|
228
|
-
* @param {(item: V) => K} [get_key]
|
|
363
|
+
* @param {(item: V) => K} [get_key] omitted for identity keys (`key item`)
|
|
229
364
|
* @param {(anchor: Node) => void} [render_empty]
|
|
365
|
+
* @param {(item: V) => any} [map_item] for a destructuring pattern with a rest
|
|
366
|
+
* element or a default: destructures the item once, natively, into an object
|
|
367
|
+
* of the pattern's names, which is what the item's tracked then holds
|
|
230
368
|
* @returns {void}
|
|
231
369
|
*/
|
|
232
|
-
export function for_block_keyed(
|
|
370
|
+
export function for_block_keyed(
|
|
371
|
+
node,
|
|
372
|
+
get_collection,
|
|
373
|
+
render_fn,
|
|
374
|
+
flags,
|
|
375
|
+
get_key,
|
|
376
|
+
render_empty,
|
|
377
|
+
map_item,
|
|
378
|
+
) {
|
|
233
379
|
var is_controlled = (flags & IS_CONTROLLED) !== 0;
|
|
234
380
|
var is_indexed = (flags & IS_INDEXED) !== 0;
|
|
235
381
|
var root_controlled = (flags & ROOT_CONTROLLED) !== 0;
|
|
236
|
-
var anchor = /** @type {
|
|
382
|
+
var anchor = /** @type {ListAnchor} */ (root_controlled ? resolve_anchor(node) : node);
|
|
237
383
|
/** @type {Node | undefined} */
|
|
238
384
|
var boundary;
|
|
239
385
|
|
|
@@ -241,10 +387,10 @@ export function for_block_keyed(node, get_collection, render_fn, flags, get_key,
|
|
|
241
387
|
var parent_node = /** @type {Element} */ (node);
|
|
242
388
|
|
|
243
389
|
if (hydrating) {
|
|
244
|
-
|
|
390
|
+
hydrate_first_child();
|
|
245
391
|
anchor = /** @type {Element | Text} */ (get_last_child(parent_node));
|
|
246
392
|
} else {
|
|
247
|
-
anchor =
|
|
393
|
+
anchor = controlled_anchor(parent_node);
|
|
248
394
|
}
|
|
249
395
|
}
|
|
250
396
|
|
|
@@ -256,46 +402,45 @@ export function for_block_keyed(node, get_collection, render_fn, flags, get_key,
|
|
|
256
402
|
}
|
|
257
403
|
|
|
258
404
|
render(
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
is_controlled,
|
|
271
|
-
is_indexed,
|
|
272
|
-
/** @type {(item: V) => K} */ (get_key),
|
|
273
|
-
render_empty,
|
|
274
|
-
);
|
|
275
|
-
});
|
|
276
|
-
},
|
|
277
|
-
null,
|
|
405
|
+
run_for_keyed,
|
|
406
|
+
new ListState(
|
|
407
|
+
anchor,
|
|
408
|
+
get_collection,
|
|
409
|
+
render_fn,
|
|
410
|
+
is_controlled,
|
|
411
|
+
is_indexed,
|
|
412
|
+
get_key,
|
|
413
|
+
render_empty,
|
|
414
|
+
map_item,
|
|
415
|
+
),
|
|
278
416
|
FOR_BLOCK,
|
|
279
417
|
);
|
|
280
418
|
|
|
419
|
+
if (!is_controlled) own_anchor(node, /** @type {Node} */ (anchor));
|
|
420
|
+
|
|
281
421
|
if (hydrating && root_controlled) {
|
|
422
|
+
// The original `node`: for a sentinel, `hydrate_append` performs the
|
|
423
|
+
// cursor advance that stands in for the eliminated sibling navigation.
|
|
282
424
|
append(/** @type {ChildNode} */ (node), /** @type {Node} */ (boundary));
|
|
283
425
|
}
|
|
284
426
|
}
|
|
285
427
|
|
|
286
428
|
/**
|
|
287
429
|
* @template V
|
|
288
|
-
* @param {
|
|
430
|
+
* @param {ListAnchor} anchor
|
|
289
431
|
* @param {Block} block
|
|
290
432
|
* @param {V[]} array
|
|
291
433
|
* @returns {void}
|
|
292
434
|
*/
|
|
293
435
|
function reconcile_fast_clear(anchor, block, array) {
|
|
294
436
|
var state = block.s;
|
|
295
|
-
var
|
|
437
|
+
var into = /** @type {AppendIntoAnchor} */ (anchor).into === true;
|
|
438
|
+
var parent_node = /** @type {Element} */ (
|
|
439
|
+
into ? /** @type {AppendIntoAnchor} */ (anchor).parent : /** @type {Node} */ (anchor).parentNode
|
|
440
|
+
);
|
|
296
441
|
parent_node.textContent = '';
|
|
297
442
|
destroy_block_children(block);
|
|
298
|
-
parent_node.append(anchor);
|
|
443
|
+
if (!into) parent_node.append(/** @type {Node} */ (anchor));
|
|
299
444
|
state.array = array;
|
|
300
445
|
state.blocks = [];
|
|
301
446
|
state.empty = null;
|
|
@@ -313,24 +458,33 @@ function update_index(block, index) {
|
|
|
313
458
|
/**
|
|
314
459
|
* @param {Block} block
|
|
315
460
|
* @param {any} value
|
|
461
|
+
* @param {((item: any) => any) | undefined} map_item
|
|
316
462
|
* @returns {void}
|
|
317
463
|
*/
|
|
318
|
-
function update_value(block, value) {
|
|
319
|
-
|
|
464
|
+
function update_value(block, value, map_item) {
|
|
465
|
+
var state = block.s;
|
|
466
|
+
if (state.r !== value) {
|
|
467
|
+
state.r = value;
|
|
468
|
+
set(state.v, map_item === undefined ? value : map_item(value));
|
|
469
|
+
}
|
|
320
470
|
}
|
|
321
471
|
|
|
322
472
|
/**
|
|
323
473
|
* @template V
|
|
324
474
|
* @template K
|
|
325
|
-
* @param {
|
|
475
|
+
* @param {ListAnchor} anchor
|
|
326
476
|
* @param {Block} block
|
|
327
477
|
* @param {V[]} b
|
|
328
478
|
* @param {(anchor: Node, value: V | Tracked, index?: any) => Block} render_fn
|
|
329
479
|
* @param {boolean} is_controlled
|
|
330
480
|
* @param {boolean} is_indexed
|
|
331
|
-
* @param {(item: V) => K} get_key
|
|
332
|
-
* @param {(anchor: Node) => void}
|
|
481
|
+
* @param {((item: V) => K) | undefined} get_key identity keys when omitted
|
|
482
|
+
* @param {((anchor: Node) => void) | undefined} render_empty
|
|
483
|
+
* @param {((item: V) => any) | undefined} map_item
|
|
333
484
|
* @returns {void}
|
|
485
|
+
*
|
|
486
|
+
* The first run only creates items, so it lives in this small function and
|
|
487
|
+
* the diff below is compiled only once a list actually changes.
|
|
334
488
|
*/
|
|
335
489
|
function reconcile_by_key(
|
|
336
490
|
anchor,
|
|
@@ -341,15 +495,75 @@ function reconcile_by_key(
|
|
|
341
495
|
is_indexed,
|
|
342
496
|
get_key,
|
|
343
497
|
render_empty,
|
|
498
|
+
map_item,
|
|
344
499
|
) {
|
|
345
|
-
var
|
|
500
|
+
var b_length = b.length;
|
|
501
|
+
var state = /** @type {ListState} */ (block.s);
|
|
502
|
+
|
|
503
|
+
if (state.keys === null && b_length > 0) {
|
|
504
|
+
var b_blocks = Array(b_length);
|
|
505
|
+
// Identity keys (`key item`) are the items themselves; the list keeps a
|
|
506
|
+
// copy, as the array it rendered may later be mutated in place.
|
|
507
|
+
var b_keys = get_key === undefined ? b.slice() : Array(b_length);
|
|
508
|
+
|
|
509
|
+
// One loop, no `map` callback machinery: most lists are short.
|
|
510
|
+
for (var j = 0; j < b_length; j++) {
|
|
511
|
+
var value = b[j];
|
|
512
|
+
if (get_key !== undefined) {
|
|
513
|
+
b_keys[j] = get_key(value);
|
|
514
|
+
}
|
|
515
|
+
b_blocks[j] = create_item(anchor, value, j, render_fn, is_indexed, true, map_item);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
state.array = b;
|
|
519
|
+
state.blocks = b_blocks;
|
|
520
|
+
state.keys = b_keys;
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
reconcile_by_key_diff(
|
|
525
|
+
anchor,
|
|
526
|
+
block,
|
|
527
|
+
b,
|
|
528
|
+
render_fn,
|
|
529
|
+
is_controlled,
|
|
530
|
+
is_indexed,
|
|
531
|
+
get_key,
|
|
532
|
+
render_empty,
|
|
533
|
+
map_item,
|
|
534
|
+
);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* Keyed diff for every run after the first (or a first run with an empty
|
|
539
|
+
* list). See {@link reconcile_by_key}.
|
|
540
|
+
* @template V, K
|
|
541
|
+
* @param {ListAnchor} anchor
|
|
542
|
+
* @param {Block} block
|
|
543
|
+
* @param {V[]} b
|
|
544
|
+
* @param {(anchor: Node, value: V | Tracked, index?: any) => Block} render_fn
|
|
545
|
+
* @param {boolean} is_controlled
|
|
546
|
+
* @param {boolean} is_indexed
|
|
547
|
+
* @param {((item: V) => K) | undefined} get_key
|
|
548
|
+
* @param {((anchor: Node) => void) | undefined} render_empty
|
|
549
|
+
* @param {((item: V) => any) | undefined} map_item
|
|
550
|
+
* @returns {void}
|
|
551
|
+
*/
|
|
552
|
+
function reconcile_by_key_diff(
|
|
553
|
+
anchor,
|
|
554
|
+
block,
|
|
555
|
+
b,
|
|
556
|
+
render_fn,
|
|
557
|
+
is_controlled,
|
|
558
|
+
is_indexed,
|
|
559
|
+
get_key,
|
|
560
|
+
render_empty,
|
|
561
|
+
map_item,
|
|
562
|
+
) {
|
|
563
|
+
var state = /** @type {ListState} */ (block.s);
|
|
346
564
|
|
|
347
565
|
// Variables used in conditional branches - declare with initial values
|
|
348
566
|
/** @type {number} */
|
|
349
|
-
var a_start = 0;
|
|
350
|
-
/** @type {number} */
|
|
351
|
-
var b_start = 0;
|
|
352
|
-
/** @type {number} */
|
|
353
567
|
var a_left = 0;
|
|
354
568
|
/** @type {number} */
|
|
355
569
|
var b_left = 0;
|
|
@@ -364,17 +578,8 @@ function reconcile_by_key(
|
|
|
364
578
|
/** @type {number} */
|
|
365
579
|
var i = 0;
|
|
366
580
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
array: [],
|
|
370
|
-
blocks: [],
|
|
371
|
-
keys: null,
|
|
372
|
-
empty: null,
|
|
373
|
-
};
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
var a = state.array;
|
|
377
|
-
var a_length = a.length;
|
|
581
|
+
var a_blocks = state.blocks;
|
|
582
|
+
var a_length = a_blocks.length;
|
|
378
583
|
var b_length = b.length;
|
|
379
584
|
var j = 0;
|
|
380
585
|
|
|
@@ -409,13 +614,20 @@ function reconcile_by_key(
|
|
|
409
614
|
}
|
|
410
615
|
return;
|
|
411
616
|
}
|
|
412
|
-
|
|
413
|
-
|
|
617
|
+
// Identity keys are the items themselves (copied, as the rendered array
|
|
618
|
+
// may later be mutated in place), so a matched key is also the item's
|
|
619
|
+
// current tracked value: only computed keys need `update_value`.
|
|
620
|
+
var b_keys = get_key === undefined ? b.slice() : b.map(get_key);
|
|
621
|
+
// A same-length run rewrites the block array in place: matched ends are
|
|
622
|
+
// already at their index, and the middle reads the old blocks from a copy
|
|
623
|
+
// taken before its first write.
|
|
624
|
+
var in_place = a_length === b_length;
|
|
625
|
+
var b_blocks = in_place ? a_blocks : Array(b_length);
|
|
414
626
|
|
|
415
627
|
// Fast-path for create
|
|
416
628
|
if (a_length === 0) {
|
|
417
629
|
for (; j < b_length; j++) {
|
|
418
|
-
b_blocks[j] = create_item(anchor, b[j], j, render_fn, is_indexed, true);
|
|
630
|
+
b_blocks[j] = create_item(anchor, b[j], j, render_fn, is_indexed, true, map_item);
|
|
419
631
|
}
|
|
420
632
|
state.array = b;
|
|
421
633
|
state.blocks = b_blocks;
|
|
@@ -423,78 +635,135 @@ function reconcile_by_key(
|
|
|
423
635
|
return;
|
|
424
636
|
}
|
|
425
637
|
|
|
426
|
-
|
|
427
|
-
var a_keys = state.keys;
|
|
428
|
-
var
|
|
429
|
-
var
|
|
430
|
-
var a_key = a_keys[j];
|
|
431
|
-
var b_key = b_keys[j];
|
|
638
|
+
// Set by every run that leaves items behind.
|
|
639
|
+
var a_keys = /** @type {any[]} */ (state.keys);
|
|
640
|
+
var a_start = 0;
|
|
641
|
+
var b_start = 0;
|
|
432
642
|
var a_end = a_length - 1;
|
|
433
643
|
var b_end = b_length - 1;
|
|
644
|
+
var b_val;
|
|
434
645
|
var b_block;
|
|
435
646
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
if (
|
|
441
|
-
|
|
647
|
+
if (get_key === undefined && !is_indexed) {
|
|
648
|
+
// Identity keys without an index: a matched item needs no update, so
|
|
649
|
+
// the unchanged prefix and suffix are skipped with plain compares.
|
|
650
|
+
while (a_start <= a_end && b_start <= b_end && a_keys[a_start] === b_keys[b_start]) {
|
|
651
|
+
if (!in_place) {
|
|
652
|
+
b_blocks[b_start] = a_blocks[a_start];
|
|
442
653
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
654
|
+
a_start++;
|
|
655
|
+
b_start++;
|
|
656
|
+
}
|
|
657
|
+
while (a_start <= a_end && b_start <= b_end && a_keys[a_end] === b_keys[b_end]) {
|
|
658
|
+
if (!in_place) {
|
|
659
|
+
b_blocks[b_end] = a_blocks[a_end];
|
|
447
660
|
}
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
a_key = a_keys[j];
|
|
451
|
-
b_key = b_keys[j];
|
|
661
|
+
a_end--;
|
|
662
|
+
b_end--;
|
|
452
663
|
}
|
|
664
|
+
}
|
|
453
665
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
666
|
+
// Match from both ends first, including the two end-crossing cases: an old
|
|
667
|
+
// item that moved to the far end of the new list, and a run whose ends were
|
|
668
|
+
// exchanged (a reversal, or a swap of two items). Those complete with plain
|
|
669
|
+
// moves; only what is left afterwards needs the map and LIS below.
|
|
670
|
+
while (a_start <= a_end && b_start <= b_end) {
|
|
671
|
+
if (a_keys[a_start] === b_keys[b_start]) {
|
|
672
|
+
b_val = b[b_start];
|
|
673
|
+
b_block = b_blocks[b_start] = a_blocks[a_start];
|
|
674
|
+
if (is_indexed) {
|
|
675
|
+
update_index(b_block, b_start);
|
|
676
|
+
}
|
|
677
|
+
if (get_key !== undefined) {
|
|
678
|
+
update_value(b_block, b_val, map_item);
|
|
679
|
+
}
|
|
680
|
+
a_start++;
|
|
681
|
+
b_start++;
|
|
682
|
+
continue;
|
|
683
|
+
}
|
|
684
|
+
if (a_keys[a_end] === b_keys[b_end]) {
|
|
685
|
+
b_val = b[b_end];
|
|
461
686
|
b_block = b_blocks[b_end] = a_blocks[a_end];
|
|
462
687
|
if (is_indexed) {
|
|
463
688
|
update_index(b_block, b_end);
|
|
464
689
|
}
|
|
465
|
-
|
|
690
|
+
if (get_key !== undefined) {
|
|
691
|
+
update_value(b_block, b_val, map_item);
|
|
692
|
+
}
|
|
466
693
|
a_end--;
|
|
467
694
|
b_end--;
|
|
468
|
-
|
|
469
|
-
|
|
695
|
+
continue;
|
|
696
|
+
}
|
|
697
|
+
if (a_start === a_end || a_blocks[a_start].s.start === null) {
|
|
698
|
+
break;
|
|
699
|
+
}
|
|
700
|
+
if (in_place) {
|
|
701
|
+
// An end-crossing move overwrites an old block before it is read.
|
|
702
|
+
a_blocks = a_blocks.slice();
|
|
703
|
+
in_place = false;
|
|
704
|
+
}
|
|
705
|
+
if (a_keys[a_end] === b_keys[b_start]) {
|
|
706
|
+
// Last old item is the next new one: move it in front of the old run.
|
|
707
|
+
b_val = b[b_start];
|
|
708
|
+
b_block = b_blocks[b_start] = a_blocks[a_end];
|
|
709
|
+
if (is_indexed) {
|
|
710
|
+
update_index(b_block, b_start);
|
|
470
711
|
}
|
|
471
|
-
|
|
712
|
+
if (get_key !== undefined) {
|
|
713
|
+
update_value(b_block, b_val, map_item);
|
|
714
|
+
}
|
|
715
|
+
move(b_block, /** @type {ChildNode} */ (a_blocks[a_start].s.start));
|
|
716
|
+
a_end--;
|
|
717
|
+
b_start++;
|
|
718
|
+
continue;
|
|
719
|
+
}
|
|
720
|
+
if (a_keys[a_start] === b_keys[b_end]) {
|
|
721
|
+
// First old item is the last new one: move it behind the old run.
|
|
472
722
|
b_val = b[b_end];
|
|
473
|
-
|
|
474
|
-
|
|
723
|
+
b_block = b_blocks[b_end] = a_blocks[a_start];
|
|
724
|
+
if (is_indexed) {
|
|
725
|
+
update_index(b_block, b_end);
|
|
726
|
+
}
|
|
727
|
+
if (get_key !== undefined) {
|
|
728
|
+
update_value(b_block, b_val, map_item);
|
|
729
|
+
}
|
|
730
|
+
move(b_block, block_start(b_blocks, b_end + 1, b_length, anchor));
|
|
731
|
+
a_start++;
|
|
732
|
+
b_end--;
|
|
733
|
+
continue;
|
|
475
734
|
}
|
|
735
|
+
break;
|
|
476
736
|
}
|
|
477
737
|
|
|
478
738
|
var fast_path_removal = false;
|
|
479
739
|
|
|
480
|
-
if (
|
|
481
|
-
if (
|
|
482
|
-
var
|
|
483
|
-
while (
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
740
|
+
if (a_start > a_end) {
|
|
741
|
+
if (b_start <= b_end) {
|
|
742
|
+
var target_node = block_start(b_blocks, b_end + 1, b_length, anchor);
|
|
743
|
+
while (b_start <= b_end) {
|
|
744
|
+
b_blocks[b_start] = create_item(
|
|
745
|
+
target_node,
|
|
746
|
+
b[b_start],
|
|
747
|
+
b_start,
|
|
748
|
+
render_fn,
|
|
749
|
+
is_indexed,
|
|
750
|
+
true,
|
|
751
|
+
map_item,
|
|
752
|
+
);
|
|
753
|
+
b_start++;
|
|
487
754
|
}
|
|
488
755
|
}
|
|
489
|
-
} else if (
|
|
490
|
-
while (
|
|
491
|
-
destroy_block(a_blocks[
|
|
756
|
+
} else if (b_start > b_end) {
|
|
757
|
+
while (a_start <= a_end) {
|
|
758
|
+
destroy_block(a_blocks[a_start++]);
|
|
492
759
|
}
|
|
493
760
|
} else {
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
761
|
+
if (in_place) {
|
|
762
|
+
a_blocks = a_blocks.slice();
|
|
763
|
+
in_place = false;
|
|
764
|
+
}
|
|
765
|
+
a_left = a_end - a_start + 1;
|
|
766
|
+
b_left = b_end - b_start + 1;
|
|
498
767
|
sources = new Int32Array(b_left + 1);
|
|
499
768
|
moved = false;
|
|
500
769
|
pos = 0;
|
|
@@ -506,13 +775,9 @@ function reconcile_by_key(
|
|
|
506
775
|
// When sizes are small, just loop them through
|
|
507
776
|
if (b_length < 4 || (a_left | b_left) < 32) {
|
|
508
777
|
for (i = a_start; i <= a_end; ++i) {
|
|
509
|
-
a_val = a[i];
|
|
510
|
-
a_key = a_keys[i];
|
|
511
778
|
if (patched < b_left) {
|
|
512
779
|
for (j = b_start; j <= b_end; j++) {
|
|
513
|
-
|
|
514
|
-
b_key = b_keys[j];
|
|
515
|
-
if (a_key === b_key) {
|
|
780
|
+
if (a_keys[i] === b_keys[j]) {
|
|
516
781
|
sources[j - b_start] = i + 1;
|
|
517
782
|
if (fast_path_removal) {
|
|
518
783
|
fast_path_removal = false;
|
|
@@ -525,11 +790,14 @@ function reconcile_by_key(
|
|
|
525
790
|
} else {
|
|
526
791
|
pos = j;
|
|
527
792
|
}
|
|
793
|
+
b_val = b[j];
|
|
528
794
|
b_block = b_blocks[j] = a_blocks[i];
|
|
529
795
|
if (is_indexed) {
|
|
530
796
|
update_index(b_block, j);
|
|
531
797
|
}
|
|
532
|
-
|
|
798
|
+
if (get_key !== undefined) {
|
|
799
|
+
update_value(b_block, b_val, map_item);
|
|
800
|
+
}
|
|
533
801
|
++patched;
|
|
534
802
|
break;
|
|
535
803
|
}
|
|
@@ -549,11 +817,8 @@ function reconcile_by_key(
|
|
|
549
817
|
}
|
|
550
818
|
|
|
551
819
|
for (i = a_start; i <= a_end; ++i) {
|
|
552
|
-
a_val = a[i];
|
|
553
|
-
a_key = a_keys[i];
|
|
554
|
-
|
|
555
820
|
if (patched < b_left) {
|
|
556
|
-
j = map.get(
|
|
821
|
+
j = map.get(a_keys[i]);
|
|
557
822
|
|
|
558
823
|
if (j !== undefined) {
|
|
559
824
|
if (fast_path_removal) {
|
|
@@ -568,12 +833,14 @@ function reconcile_by_key(
|
|
|
568
833
|
} else {
|
|
569
834
|
pos = j;
|
|
570
835
|
}
|
|
571
|
-
block = b_blocks[j] = a_blocks[i];
|
|
572
836
|
b_val = b[j];
|
|
837
|
+
b_block = b_blocks[j] = a_blocks[i];
|
|
573
838
|
if (is_indexed) {
|
|
574
|
-
update_index(
|
|
839
|
+
update_index(b_block, j);
|
|
840
|
+
}
|
|
841
|
+
if (get_key !== undefined) {
|
|
842
|
+
update_value(b_block, b_val, map_item);
|
|
575
843
|
}
|
|
576
|
-
update_value(block, b_val);
|
|
577
844
|
++patched;
|
|
578
845
|
} else if (!fast_path_removal) {
|
|
579
846
|
destroy_block(a_blocks[i]);
|
|
@@ -587,13 +854,50 @@ function reconcile_by_key(
|
|
|
587
854
|
|
|
588
855
|
if (fast_path_removal) {
|
|
589
856
|
reconcile_fast_clear(anchor, block, []);
|
|
590
|
-
reconcile_by_key(
|
|
857
|
+
reconcile_by_key(
|
|
858
|
+
anchor,
|
|
859
|
+
block,
|
|
860
|
+
b,
|
|
861
|
+
render_fn,
|
|
862
|
+
is_controlled,
|
|
863
|
+
is_indexed,
|
|
864
|
+
get_key,
|
|
865
|
+
render_empty,
|
|
866
|
+
map_item,
|
|
867
|
+
);
|
|
591
868
|
return;
|
|
592
869
|
} else if (moved) {
|
|
593
870
|
var next_pos = 0;
|
|
594
871
|
var seq = lis_algorithm(sources);
|
|
595
872
|
j = seq.length - 1;
|
|
596
873
|
|
|
874
|
+
// When most surviving items have to move anyway, re-lay the whole range
|
|
875
|
+
// in order before a fixed target: inserting before the same node is
|
|
876
|
+
// noticeably cheaper per item than moving into arbitrary positions.
|
|
877
|
+
if ((patched - seq.length) * 3 > b_left * 2) {
|
|
878
|
+
var relay_target = block_start(b_blocks, b_end + 1, b_length, anchor);
|
|
879
|
+
for (i = 0; i < b_left; i++) {
|
|
880
|
+
pos = i + b_start;
|
|
881
|
+
if (sources[i] === 0) {
|
|
882
|
+
b_blocks[pos] = create_item(
|
|
883
|
+
relay_target,
|
|
884
|
+
b[pos],
|
|
885
|
+
pos,
|
|
886
|
+
render_fn,
|
|
887
|
+
is_indexed,
|
|
888
|
+
true,
|
|
889
|
+
map_item,
|
|
890
|
+
);
|
|
891
|
+
} else {
|
|
892
|
+
move(b_blocks[pos], relay_target);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
state.array = b;
|
|
896
|
+
state.blocks = b_blocks;
|
|
897
|
+
state.keys = b_keys;
|
|
898
|
+
return;
|
|
899
|
+
}
|
|
900
|
+
|
|
597
901
|
for (i = b_left - 1; i >= 0; i--) {
|
|
598
902
|
if (sources[i] === 0) {
|
|
599
903
|
pos = i + b_start;
|
|
@@ -601,10 +905,9 @@ function reconcile_by_key(
|
|
|
601
905
|
next_pos = pos + 1;
|
|
602
906
|
|
|
603
907
|
var target = block_start(b_blocks, next_pos, b_length, anchor);
|
|
604
|
-
b_blocks[pos] = create_item(target, b_val, pos, render_fn, is_indexed, true);
|
|
908
|
+
b_blocks[pos] = create_item(target, b_val, pos, render_fn, is_indexed, true, map_item);
|
|
605
909
|
} else if (j < 0 || i !== seq[j]) {
|
|
606
910
|
pos = i + b_start;
|
|
607
|
-
b_val = b[pos];
|
|
608
911
|
next_pos = pos + 1;
|
|
609
912
|
|
|
610
913
|
var target = block_start(b_blocks, next_pos, b_length, anchor);
|
|
@@ -621,7 +924,7 @@ function reconcile_by_key(
|
|
|
621
924
|
next_pos = pos + 1;
|
|
622
925
|
|
|
623
926
|
var target = block_start(b_blocks, next_pos, b_length, anchor);
|
|
624
|
-
b_blocks[pos] = create_item(target, b_val, pos, render_fn, is_indexed, true);
|
|
927
|
+
b_blocks[pos] = create_item(target, b_val, pos, render_fn, is_indexed, true, map_item);
|
|
625
928
|
}
|
|
626
929
|
}
|
|
627
930
|
}
|
|
@@ -633,7 +936,7 @@ function reconcile_by_key(
|
|
|
633
936
|
|
|
634
937
|
/**
|
|
635
938
|
* @template V
|
|
636
|
-
* @param {
|
|
939
|
+
* @param {ListAnchor} anchor
|
|
637
940
|
* @param {Block} block
|
|
638
941
|
* @param {V[]} b
|
|
639
942
|
* @param {(anchor: Node, value: V | Tracked, index?: any) => Block} render_fn
|
|
@@ -643,39 +946,8 @@ function reconcile_by_key(
|
|
|
643
946
|
* @returns {void}
|
|
644
947
|
*/
|
|
645
948
|
function reconcile_by_ref(anchor, block, b, render_fn, is_controlled, is_indexed, render_empty) {
|
|
646
|
-
var state = block.s;
|
|
647
|
-
|
|
648
|
-
// Variables used in conditional branches - declare with initial values
|
|
649
|
-
/** @type {number} */
|
|
650
|
-
var a_start = 0;
|
|
651
|
-
/** @type {number} */
|
|
652
|
-
var b_start = 0;
|
|
653
|
-
/** @type {number} */
|
|
654
|
-
var a_left = 0;
|
|
655
|
-
/** @type {number} */
|
|
656
|
-
var b_left = 0;
|
|
657
|
-
/** @type {Int32Array} */
|
|
658
|
-
var sources = new Int32Array(0);
|
|
659
|
-
/** @type {boolean} */
|
|
660
|
-
var moved = false;
|
|
661
|
-
/** @type {number} */
|
|
662
|
-
var pos = 0;
|
|
663
|
-
/** @type {number} */
|
|
664
|
-
var patched = 0;
|
|
665
|
-
/** @type {number} */
|
|
666
|
-
var i = 0;
|
|
667
|
-
|
|
668
|
-
if (state === null) {
|
|
669
|
-
state = block.s = {
|
|
670
|
-
array: [],
|
|
671
|
-
blocks: [],
|
|
672
|
-
keys: null,
|
|
673
|
-
empty: null,
|
|
674
|
-
};
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
var a = state.array;
|
|
678
|
-
var a_length = a.length;
|
|
949
|
+
var state = /** @type {ListState} */ (block.s);
|
|
950
|
+
var a_length = state.array.length;
|
|
679
951
|
var b_length = b.length;
|
|
680
952
|
var j = 0;
|
|
681
953
|
|
|
@@ -721,67 +993,132 @@ function reconcile_by_ref(anchor, block, b, render_fn, is_controlled, is_indexed
|
|
|
721
993
|
return;
|
|
722
994
|
}
|
|
723
995
|
|
|
996
|
+
reconcile_by_ref_diff(anchor, block, b, b_blocks, render_fn, is_controlled, is_indexed);
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
/**
|
|
1000
|
+
* Diffs a non-empty list against its previous run. Separate from the empty and
|
|
1001
|
+
* create paths so a first render (a mount, a hydration) never compiles it.
|
|
1002
|
+
* @template V
|
|
1003
|
+
* @param {ListAnchor} anchor
|
|
1004
|
+
* @param {Block} block
|
|
1005
|
+
* @param {V[]} b
|
|
1006
|
+
* @param {Block[]} b_blocks
|
|
1007
|
+
* @param {(anchor: Node, value: V | Tracked, index?: any) => Block} render_fn
|
|
1008
|
+
* @param {boolean} is_controlled
|
|
1009
|
+
* @param {boolean} is_indexed
|
|
1010
|
+
* @returns {void}
|
|
1011
|
+
*/
|
|
1012
|
+
function reconcile_by_ref_diff(anchor, block, b, b_blocks, render_fn, is_controlled, is_indexed) {
|
|
1013
|
+
var state = /** @type {ListState} */ (block.s);
|
|
1014
|
+
|
|
1015
|
+
// Variables used in conditional branches - declare with initial values
|
|
1016
|
+
/** @type {number} */
|
|
1017
|
+
var a_left = 0;
|
|
1018
|
+
/** @type {number} */
|
|
1019
|
+
var b_left = 0;
|
|
1020
|
+
/** @type {Int32Array} */
|
|
1021
|
+
var sources = new Int32Array(0);
|
|
1022
|
+
/** @type {boolean} */
|
|
1023
|
+
var moved = false;
|
|
1024
|
+
/** @type {number} */
|
|
1025
|
+
var pos = 0;
|
|
1026
|
+
/** @type {number} */
|
|
1027
|
+
var patched = 0;
|
|
1028
|
+
/** @type {number} */
|
|
1029
|
+
var i = 0;
|
|
1030
|
+
|
|
1031
|
+
var a = state.array;
|
|
1032
|
+
var a_length = a.length;
|
|
1033
|
+
var b_length = b.length;
|
|
1034
|
+
var j = 0;
|
|
724
1035
|
var a_blocks = state.blocks;
|
|
725
|
-
var
|
|
726
|
-
var
|
|
1036
|
+
var a_start = 0;
|
|
1037
|
+
var b_start = 0;
|
|
727
1038
|
var a_end = a_length - 1;
|
|
728
1039
|
var b_end = b_length - 1;
|
|
1040
|
+
var b_val;
|
|
729
1041
|
var b_block;
|
|
730
1042
|
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
1043
|
+
// Match from both ends first, including the two end-crossing cases: an old
|
|
1044
|
+
// item that moved to the far end of the new list, and a run whose ends were
|
|
1045
|
+
// exchanged (a reversal, or a swap of two items). Those complete with plain
|
|
1046
|
+
// moves; only what is left afterwards needs the map and LIS below.
|
|
1047
|
+
while (a_start <= a_end && b_start <= b_end) {
|
|
1048
|
+
if (a[a_start] === b[b_start]) {
|
|
1049
|
+
b_val = b[b_start];
|
|
1050
|
+
b_block = b_blocks[b_start] = a_blocks[a_start];
|
|
735
1051
|
if (is_indexed) {
|
|
736
|
-
update_index(b_block,
|
|
1052
|
+
update_index(b_block, b_start);
|
|
737
1053
|
}
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
}
|
|
742
|
-
a_val = a[j];
|
|
743
|
-
b_val = b[j];
|
|
1054
|
+
a_start++;
|
|
1055
|
+
b_start++;
|
|
1056
|
+
continue;
|
|
744
1057
|
}
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
b_val = b[b_end];
|
|
748
|
-
|
|
749
|
-
while (a_val === b_val) {
|
|
750
|
-
a[a_end] = b_val;
|
|
1058
|
+
if (a[a_end] === b[b_end]) {
|
|
1059
|
+
b_val = b[b_end];
|
|
751
1060
|
b_block = b_blocks[b_end] = a_blocks[a_end];
|
|
752
1061
|
if (is_indexed) {
|
|
753
1062
|
update_index(b_block, b_end);
|
|
754
1063
|
}
|
|
755
1064
|
a_end--;
|
|
756
1065
|
b_end--;
|
|
757
|
-
|
|
758
|
-
|
|
1066
|
+
continue;
|
|
1067
|
+
}
|
|
1068
|
+
if (a_start === a_end || a_blocks[a_start].s.start === null) {
|
|
1069
|
+
break;
|
|
1070
|
+
}
|
|
1071
|
+
if (a[a_end] === b[b_start]) {
|
|
1072
|
+
// Last old item is the next new one: move it in front of the old run.
|
|
1073
|
+
b_val = b[b_start];
|
|
1074
|
+
b_block = b_blocks[b_start] = a_blocks[a_end];
|
|
1075
|
+
if (is_indexed) {
|
|
1076
|
+
update_index(b_block, b_start);
|
|
759
1077
|
}
|
|
760
|
-
|
|
1078
|
+
move(b_block, /** @type {ChildNode} */ (a_blocks[a_start].s.start));
|
|
1079
|
+
a_end--;
|
|
1080
|
+
b_start++;
|
|
1081
|
+
continue;
|
|
1082
|
+
}
|
|
1083
|
+
if (a[a_start] === b[b_end]) {
|
|
1084
|
+
// First old item is the last new one: move it behind the old run.
|
|
761
1085
|
b_val = b[b_end];
|
|
1086
|
+
b_block = b_blocks[b_end] = a_blocks[a_start];
|
|
1087
|
+
if (is_indexed) {
|
|
1088
|
+
update_index(b_block, b_end);
|
|
1089
|
+
}
|
|
1090
|
+
move(b_block, block_start(b_blocks, b_end + 1, b_length, anchor));
|
|
1091
|
+
a_start++;
|
|
1092
|
+
b_end--;
|
|
1093
|
+
continue;
|
|
762
1094
|
}
|
|
1095
|
+
break;
|
|
763
1096
|
}
|
|
764
1097
|
|
|
765
1098
|
var fast_path_removal = false;
|
|
766
1099
|
|
|
767
|
-
if (
|
|
768
|
-
if (
|
|
769
|
-
var
|
|
770
|
-
while (
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
1100
|
+
if (a_start > a_end) {
|
|
1101
|
+
if (b_start <= b_end) {
|
|
1102
|
+
var target_node = block_start(b_blocks, b_end + 1, b_length, anchor);
|
|
1103
|
+
while (b_start <= b_end) {
|
|
1104
|
+
b_blocks[b_start] = create_item(
|
|
1105
|
+
target_node,
|
|
1106
|
+
b[b_start],
|
|
1107
|
+
b_start,
|
|
1108
|
+
render_fn,
|
|
1109
|
+
is_indexed,
|
|
1110
|
+
false,
|
|
1111
|
+
);
|
|
1112
|
+
b_start++;
|
|
774
1113
|
}
|
|
775
1114
|
}
|
|
776
|
-
} else if (
|
|
777
|
-
while (
|
|
778
|
-
destroy_block(a_blocks[
|
|
1115
|
+
} else if (b_start > b_end) {
|
|
1116
|
+
while (a_start <= a_end) {
|
|
1117
|
+
destroy_block(a_blocks[a_start++]);
|
|
779
1118
|
}
|
|
780
1119
|
} else {
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
a_left = a_end - j + 1;
|
|
784
|
-
b_left = b_end - j + 1;
|
|
1120
|
+
a_left = a_end - a_start + 1;
|
|
1121
|
+
b_left = b_end - b_start + 1;
|
|
785
1122
|
sources = new Int32Array(b_left + 1);
|
|
786
1123
|
moved = false;
|
|
787
1124
|
pos = 0;
|
|
@@ -793,11 +1130,9 @@ function reconcile_by_ref(anchor, block, b, render_fn, is_controlled, is_indexed
|
|
|
793
1130
|
// When sizes are small, just loop them through
|
|
794
1131
|
if (b_length < 4 || (a_left | b_left) < 32) {
|
|
795
1132
|
for (i = a_start; i <= a_end; ++i) {
|
|
796
|
-
a_val = a[i];
|
|
797
1133
|
if (patched < b_left) {
|
|
798
1134
|
for (j = b_start; j <= b_end; j++) {
|
|
799
|
-
|
|
800
|
-
if (a_val === b_val) {
|
|
1135
|
+
if (a[i] === b[j]) {
|
|
801
1136
|
sources[j - b_start] = i + 1;
|
|
802
1137
|
if (fast_path_removal) {
|
|
803
1138
|
fast_path_removal = false;
|
|
@@ -810,6 +1145,7 @@ function reconcile_by_ref(anchor, block, b, render_fn, is_controlled, is_indexed
|
|
|
810
1145
|
} else {
|
|
811
1146
|
pos = j;
|
|
812
1147
|
}
|
|
1148
|
+
b_val = b[j];
|
|
813
1149
|
b_block = b_blocks[j] = a_blocks[i];
|
|
814
1150
|
if (is_indexed) {
|
|
815
1151
|
update_index(b_block, j);
|
|
@@ -833,10 +1169,8 @@ function reconcile_by_ref(anchor, block, b, render_fn, is_controlled, is_indexed
|
|
|
833
1169
|
}
|
|
834
1170
|
|
|
835
1171
|
for (i = a_start; i <= a_end; ++i) {
|
|
836
|
-
a_val = a[i];
|
|
837
|
-
|
|
838
1172
|
if (patched < b_left) {
|
|
839
|
-
j = map.get(
|
|
1173
|
+
j = map.get(a[i]);
|
|
840
1174
|
|
|
841
1175
|
if (j !== undefined) {
|
|
842
1176
|
if (fast_path_removal) {
|
|
@@ -851,9 +1185,10 @@ function reconcile_by_ref(anchor, block, b, render_fn, is_controlled, is_indexed
|
|
|
851
1185
|
} else {
|
|
852
1186
|
pos = j;
|
|
853
1187
|
}
|
|
854
|
-
|
|
1188
|
+
b_val = b[j];
|
|
1189
|
+
b_block = b_blocks[j] = a_blocks[i];
|
|
855
1190
|
if (is_indexed) {
|
|
856
|
-
update_index(
|
|
1191
|
+
update_index(b_block, j);
|
|
857
1192
|
}
|
|
858
1193
|
++patched;
|
|
859
1194
|
} else if (!fast_path_removal) {
|
|
@@ -875,6 +1210,24 @@ function reconcile_by_ref(anchor, block, b, render_fn, is_controlled, is_indexed
|
|
|
875
1210
|
var seq = lis_algorithm(sources);
|
|
876
1211
|
j = seq.length - 1;
|
|
877
1212
|
|
|
1213
|
+
// When most surviving items have to move anyway, re-lay the whole range
|
|
1214
|
+
// in order before a fixed target: inserting before the same node is
|
|
1215
|
+
// noticeably cheaper per item than moving into arbitrary positions.
|
|
1216
|
+
if ((patched - seq.length) * 3 > b_left * 2) {
|
|
1217
|
+
var relay_target = block_start(b_blocks, b_end + 1, b_length, anchor);
|
|
1218
|
+
for (i = 0; i < b_left; i++) {
|
|
1219
|
+
pos = i + b_start;
|
|
1220
|
+
if (sources[i] === 0) {
|
|
1221
|
+
b_blocks[pos] = create_item(relay_target, b[pos], pos, render_fn, is_indexed, false);
|
|
1222
|
+
} else {
|
|
1223
|
+
move(b_blocks[pos], relay_target);
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
state.array = b;
|
|
1227
|
+
state.blocks = b_blocks;
|
|
1228
|
+
return;
|
|
1229
|
+
}
|
|
1230
|
+
|
|
878
1231
|
for (i = b_left - 1; i >= 0; i--) {
|
|
879
1232
|
if (sources[i] === 0) {
|
|
880
1233
|
pos = i + b_start;
|
|
@@ -885,7 +1238,6 @@ function reconcile_by_ref(anchor, block, b, render_fn, is_controlled, is_indexed
|
|
|
885
1238
|
b_blocks[pos] = create_item(target, b_val, pos, render_fn, is_indexed, false);
|
|
886
1239
|
} else if (j < 0 || i !== seq[j]) {
|
|
887
1240
|
pos = i + b_start;
|
|
888
|
-
b_val = b[pos];
|
|
889
1241
|
next_pos = pos + 1;
|
|
890
1242
|
|
|
891
1243
|
var target = block_start(b_blocks, next_pos, b_length, anchor);
|