ripple 0.3.128 → 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 +267 -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 +173 -91
- 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 +9 -0
- 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 +45 -25
- package/src/runtime/internal/client/for.js +409 -129
- 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 +4 -12
- package/src/runtime/internal/client/operations.js +40 -61
- package/src/runtime/internal/client/portal.js +163 -85
- package/src/runtime/internal/client/render.js +39 -39
- package/src/runtime/internal/client/rpc.js +3 -3
- package/src/runtime/internal/client/runtime.js +592 -433
- package/src/runtime/internal/client/selector.js +5 -2
- 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 +56 -23
- 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 +325 -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 +73 -38
- 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 +14 -14
- 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 +184 -171
- package/tests/hydration/compiled/client/for.js +1472 -1132
- package/tests/hydration/compiled/client/fragment-cursor.js +2341 -0
- package/tests/hydration/compiled/client/head.js +254 -201
- 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 -404
- package/tests/hydration/compiled/client/nested-control-flow.js +1326 -1277
- package/tests/hydration/compiled/client/portal.js +87 -95
- package/tests/hydration/compiled/client/reactivity.js +135 -101
- 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 +66 -18
- package/tests/hydration/compiled/server/for.js +117 -41
- package/tests/hydration/compiled/server/fragment-cursor.js +1687 -0
- package/tests/hydration/compiled/server/head.js +20 -20
- package/tests/hydration/compiled/server/hmr.js +2 -2
- package/tests/hydration/compiled/server/html.js +70 -238
- 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 -14
- 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,47 +1,54 @@
|
|
|
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) {
|
|
32
|
+
function create_item(anchor, value, index, render_fn, is_indexed, is_keyed, map_item) {
|
|
30
33
|
var block = /** @type {Block} */ (active_block);
|
|
31
34
|
var tracked_index = is_indexed ? tracked(index, block) : undefined;
|
|
32
|
-
var tracked_value = is_keyed
|
|
35
|
+
var tracked_value = is_keyed
|
|
36
|
+
? tracked(map_item === undefined ? value : map_item(value), block)
|
|
37
|
+
: value;
|
|
33
38
|
var state = {
|
|
34
39
|
start: null,
|
|
35
40
|
end: null,
|
|
36
41
|
i: tracked_index,
|
|
37
42
|
v: tracked_value,
|
|
43
|
+
// The item as the collection holds it; a keyed diff compares against it.
|
|
44
|
+
r: value,
|
|
38
45
|
};
|
|
39
46
|
|
|
40
47
|
// Passed through module state rather than a per-item closure; run_item
|
|
41
48
|
// reads them before rendering, so nested loops cannot observe a stale pair.
|
|
42
49
|
item_anchor = anchor;
|
|
43
50
|
item_render_fn = render_fn;
|
|
44
|
-
var b =
|
|
51
|
+
var b = create_block(BRANCH_BLOCK, run_item, state);
|
|
45
52
|
|
|
46
53
|
// The item's tracked value and index are owned by the item block itself.
|
|
47
54
|
if (is_keyed) {
|
|
@@ -53,7 +60,22 @@ function create_item(anchor, value, index, render_fn, is_indexed, is_keyed) {
|
|
|
53
60
|
return b;
|
|
54
61
|
}
|
|
55
62
|
|
|
56
|
-
/**
|
|
63
|
+
/**
|
|
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} */
|
|
57
79
|
var item_anchor = null;
|
|
58
80
|
/** @type {((anchor: Node, value: any, index?: any) => Block) | null} */
|
|
59
81
|
var item_render_fn = null;
|
|
@@ -70,19 +92,19 @@ function run_item(state) {
|
|
|
70
92
|
}
|
|
71
93
|
|
|
72
94
|
/**
|
|
73
|
-
* @param {
|
|
95
|
+
* @param {ListAnchor} anchor
|
|
74
96
|
* @param {(anchor: Node) => void} render_empty
|
|
75
97
|
* @returns {Block}
|
|
76
98
|
*/
|
|
77
99
|
function create_empty(anchor, render_empty) {
|
|
78
100
|
return branch(() => {
|
|
79
|
-
render_empty(anchor);
|
|
101
|
+
render_empty(/** @type {Node} */ (anchor));
|
|
80
102
|
});
|
|
81
103
|
}
|
|
82
104
|
|
|
83
105
|
/**
|
|
84
106
|
* @param {Block} block
|
|
85
|
-
* @param {ChildNode} anchor
|
|
107
|
+
* @param {ChildNode | AppendIntoAnchor} anchor
|
|
86
108
|
* @returns {void}
|
|
87
109
|
*/
|
|
88
110
|
function move(block, anchor) {
|
|
@@ -103,21 +125,46 @@ function move(block, anchor) {
|
|
|
103
125
|
end = s.end;
|
|
104
126
|
}
|
|
105
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
|
+
|
|
106
140
|
if (node === end) {
|
|
107
|
-
|
|
141
|
+
insert_node(parent, before, node);
|
|
108
142
|
return;
|
|
109
143
|
}
|
|
110
144
|
while (node !== null) {
|
|
111
145
|
var next_node = /** @type {Node} */ (next_sibling(node));
|
|
112
|
-
|
|
146
|
+
insert_node(parent, before, node);
|
|
113
147
|
node = next_node;
|
|
114
148
|
if (node === end) {
|
|
115
|
-
|
|
149
|
+
insert_node(parent, before, /** @type {Node} */ (end));
|
|
116
150
|
break;
|
|
117
151
|
}
|
|
118
152
|
}
|
|
119
153
|
}
|
|
120
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
|
+
|
|
121
168
|
/**
|
|
122
169
|
* Resolve the insertion anchor for a block at `index`: the first real DOM node
|
|
123
170
|
* at or after `index`, or `fallback` when every remaining block renders nothing.
|
|
@@ -127,8 +174,8 @@ function move(block, anchor) {
|
|
|
127
174
|
* @param {Block[]} blocks
|
|
128
175
|
* @param {number} index
|
|
129
176
|
* @param {number} length
|
|
130
|
-
* @param {
|
|
131
|
-
* @returns {ChildNode}
|
|
177
|
+
* @param {ListAnchor} fallback
|
|
178
|
+
* @returns {ChildNode | AppendIntoAnchor}
|
|
132
179
|
*/
|
|
133
180
|
function block_start(blocks, index, length, fallback) {
|
|
134
181
|
if (index >= length) {
|
|
@@ -166,9 +213,91 @@ function collection_to_array(collection) {
|
|
|
166
213
|
return array;
|
|
167
214
|
}
|
|
168
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
|
+
|
|
169
298
|
/**
|
|
170
299
|
* @template V
|
|
171
|
-
* @param {Element} node
|
|
300
|
+
* @param {Element | AppendIntoAnchor} node
|
|
172
301
|
* @param {() => V[] | Iterable<V>} get_collection
|
|
173
302
|
* @param {(anchor: Node, value: V | Tracked, index?: any) => Block} render_fn
|
|
174
303
|
* @param {number} flags
|
|
@@ -179,16 +308,18 @@ export function for_block(node, get_collection, render_fn, flags, render_empty)
|
|
|
179
308
|
var is_controlled = (flags & IS_CONTROLLED) !== 0;
|
|
180
309
|
var is_indexed = (flags & IS_INDEXED) !== 0;
|
|
181
310
|
var root_controlled = (flags & ROOT_CONTROLLED) !== 0;
|
|
182
|
-
|
|
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);
|
|
183
314
|
/** @type {Node | undefined} */
|
|
184
315
|
var boundary;
|
|
185
316
|
|
|
186
317
|
if (is_controlled) {
|
|
187
318
|
if (hydrating) {
|
|
188
|
-
|
|
189
|
-
|
|
319
|
+
// The cursor sits on the list's element; the items are its children.
|
|
320
|
+
hydrate_first_child();
|
|
190
321
|
} else {
|
|
191
|
-
anchor =
|
|
322
|
+
anchor = controlled_anchor(/** @type {Element} */ (node));
|
|
192
323
|
}
|
|
193
324
|
}
|
|
194
325
|
|
|
@@ -200,24 +331,24 @@ export function for_block(node, get_collection, render_fn, flags, render_empty)
|
|
|
200
331
|
}
|
|
201
332
|
|
|
202
333
|
render(
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
anchor = /** @type {Element | Text} */ (hydrate_node);
|
|
214
|
-
}
|
|
215
|
-
},
|
|
216
|
-
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
|
+
),
|
|
217
344
|
FOR_BLOCK,
|
|
218
345
|
);
|
|
219
346
|
|
|
347
|
+
if (!is_controlled) own_anchor(node, /** @type {Node} */ (anchor));
|
|
348
|
+
|
|
220
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.
|
|
221
352
|
append(/** @type {ChildNode} */ (node), /** @type {Node} */ (boundary));
|
|
222
353
|
}
|
|
223
354
|
}
|
|
@@ -225,19 +356,30 @@ export function for_block(node, get_collection, render_fn, flags, render_empty)
|
|
|
225
356
|
/**
|
|
226
357
|
* @template V
|
|
227
358
|
* @template K
|
|
228
|
-
* @param {Element} node
|
|
359
|
+
* @param {Element | AppendIntoAnchor} node
|
|
229
360
|
* @param {() => V[] | Iterable<V>} get_collection
|
|
230
361
|
* @param {(anchor: Node, value: V | Tracked, index?: any) => Block} render_fn
|
|
231
362
|
* @param {number} flags
|
|
232
|
-
* @param {(item: V) => K} [get_key]
|
|
363
|
+
* @param {(item: V) => K} [get_key] omitted for identity keys (`key item`)
|
|
233
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
|
|
234
368
|
* @returns {void}
|
|
235
369
|
*/
|
|
236
|
-
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
|
+
) {
|
|
237
379
|
var is_controlled = (flags & IS_CONTROLLED) !== 0;
|
|
238
380
|
var is_indexed = (flags & IS_INDEXED) !== 0;
|
|
239
381
|
var root_controlled = (flags & ROOT_CONTROLLED) !== 0;
|
|
240
|
-
var anchor = /** @type {
|
|
382
|
+
var anchor = /** @type {ListAnchor} */ (root_controlled ? resolve_anchor(node) : node);
|
|
241
383
|
/** @type {Node | undefined} */
|
|
242
384
|
var boundary;
|
|
243
385
|
|
|
@@ -245,10 +387,10 @@ export function for_block_keyed(node, get_collection, render_fn, flags, get_key,
|
|
|
245
387
|
var parent_node = /** @type {Element} */ (node);
|
|
246
388
|
|
|
247
389
|
if (hydrating) {
|
|
248
|
-
|
|
390
|
+
hydrate_first_child();
|
|
249
391
|
anchor = /** @type {Element | Text} */ (get_last_child(parent_node));
|
|
250
392
|
} else {
|
|
251
|
-
anchor =
|
|
393
|
+
anchor = controlled_anchor(parent_node);
|
|
252
394
|
}
|
|
253
395
|
}
|
|
254
396
|
|
|
@@ -260,46 +402,45 @@ export function for_block_keyed(node, get_collection, render_fn, flags, get_key,
|
|
|
260
402
|
}
|
|
261
403
|
|
|
262
404
|
render(
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
is_controlled,
|
|
275
|
-
is_indexed,
|
|
276
|
-
/** @type {(item: V) => K} */ (get_key),
|
|
277
|
-
render_empty,
|
|
278
|
-
);
|
|
279
|
-
});
|
|
280
|
-
},
|
|
281
|
-
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
|
+
),
|
|
282
416
|
FOR_BLOCK,
|
|
283
417
|
);
|
|
284
418
|
|
|
419
|
+
if (!is_controlled) own_anchor(node, /** @type {Node} */ (anchor));
|
|
420
|
+
|
|
285
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.
|
|
286
424
|
append(/** @type {ChildNode} */ (node), /** @type {Node} */ (boundary));
|
|
287
425
|
}
|
|
288
426
|
}
|
|
289
427
|
|
|
290
428
|
/**
|
|
291
429
|
* @template V
|
|
292
|
-
* @param {
|
|
430
|
+
* @param {ListAnchor} anchor
|
|
293
431
|
* @param {Block} block
|
|
294
432
|
* @param {V[]} array
|
|
295
433
|
* @returns {void}
|
|
296
434
|
*/
|
|
297
435
|
function reconcile_fast_clear(anchor, block, array) {
|
|
298
436
|
var state = block.s;
|
|
299
|
-
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
|
+
);
|
|
300
441
|
parent_node.textContent = '';
|
|
301
442
|
destroy_block_children(block);
|
|
302
|
-
parent_node.append(anchor);
|
|
443
|
+
if (!into) parent_node.append(/** @type {Node} */ (anchor));
|
|
303
444
|
state.array = array;
|
|
304
445
|
state.blocks = [];
|
|
305
446
|
state.empty = null;
|
|
@@ -317,27 +458,33 @@ function update_index(block, index) {
|
|
|
317
458
|
/**
|
|
318
459
|
* @param {Block} block
|
|
319
460
|
* @param {any} value
|
|
461
|
+
* @param {((item: any) => any) | undefined} map_item
|
|
320
462
|
* @returns {void}
|
|
321
463
|
*/
|
|
322
|
-
function update_value(block, value) {
|
|
323
|
-
var
|
|
324
|
-
if (
|
|
325
|
-
|
|
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));
|
|
326
469
|
}
|
|
327
470
|
}
|
|
328
471
|
|
|
329
472
|
/**
|
|
330
473
|
* @template V
|
|
331
474
|
* @template K
|
|
332
|
-
* @param {
|
|
475
|
+
* @param {ListAnchor} anchor
|
|
333
476
|
* @param {Block} block
|
|
334
477
|
* @param {V[]} b
|
|
335
478
|
* @param {(anchor: Node, value: V | Tracked, index?: any) => Block} render_fn
|
|
336
479
|
* @param {boolean} is_controlled
|
|
337
480
|
* @param {boolean} is_indexed
|
|
338
|
-
* @param {(item: V) => K} get_key
|
|
339
|
-
* @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
|
|
340
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.
|
|
341
488
|
*/
|
|
342
489
|
function reconcile_by_key(
|
|
343
490
|
anchor,
|
|
@@ -348,8 +495,72 @@ function reconcile_by_key(
|
|
|
348
495
|
is_indexed,
|
|
349
496
|
get_key,
|
|
350
497
|
render_empty,
|
|
498
|
+
map_item,
|
|
351
499
|
) {
|
|
352
|
-
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);
|
|
353
564
|
|
|
354
565
|
// Variables used in conditional branches - declare with initial values
|
|
355
566
|
/** @type {number} */
|
|
@@ -367,17 +578,8 @@ function reconcile_by_key(
|
|
|
367
578
|
/** @type {number} */
|
|
368
579
|
var i = 0;
|
|
369
580
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
array: [],
|
|
373
|
-
blocks: [],
|
|
374
|
-
keys: null,
|
|
375
|
-
empty: null,
|
|
376
|
-
};
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
var a = state.array;
|
|
380
|
-
var a_length = a.length;
|
|
581
|
+
var a_blocks = state.blocks;
|
|
582
|
+
var a_length = a_blocks.length;
|
|
381
583
|
var b_length = b.length;
|
|
382
584
|
var j = 0;
|
|
383
585
|
|
|
@@ -412,13 +614,20 @@ function reconcile_by_key(
|
|
|
412
614
|
}
|
|
413
615
|
return;
|
|
414
616
|
}
|
|
415
|
-
|
|
416
|
-
|
|
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);
|
|
417
626
|
|
|
418
627
|
// Fast-path for create
|
|
419
628
|
if (a_length === 0) {
|
|
420
629
|
for (; j < b_length; j++) {
|
|
421
|
-
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);
|
|
422
631
|
}
|
|
423
632
|
state.array = b;
|
|
424
633
|
state.blocks = b_blocks;
|
|
@@ -426,8 +635,8 @@ function reconcile_by_key(
|
|
|
426
635
|
return;
|
|
427
636
|
}
|
|
428
637
|
|
|
429
|
-
|
|
430
|
-
var a_keys = state.keys;
|
|
638
|
+
// Set by every run that leaves items behind.
|
|
639
|
+
var a_keys = /** @type {any[]} */ (state.keys);
|
|
431
640
|
var a_start = 0;
|
|
432
641
|
var b_start = 0;
|
|
433
642
|
var a_end = a_length - 1;
|
|
@@ -435,6 +644,25 @@ function reconcile_by_key(
|
|
|
435
644
|
var b_val;
|
|
436
645
|
var b_block;
|
|
437
646
|
|
|
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];
|
|
653
|
+
}
|
|
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];
|
|
660
|
+
}
|
|
661
|
+
a_end--;
|
|
662
|
+
b_end--;
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
438
666
|
// Match from both ends first, including the two end-crossing cases: an old
|
|
439
667
|
// item that moved to the far end of the new list, and a run whose ends were
|
|
440
668
|
// exchanged (a reversal, or a swap of two items). Those complete with plain
|
|
@@ -446,7 +674,9 @@ function reconcile_by_key(
|
|
|
446
674
|
if (is_indexed) {
|
|
447
675
|
update_index(b_block, b_start);
|
|
448
676
|
}
|
|
449
|
-
|
|
677
|
+
if (get_key !== undefined) {
|
|
678
|
+
update_value(b_block, b_val, map_item);
|
|
679
|
+
}
|
|
450
680
|
a_start++;
|
|
451
681
|
b_start++;
|
|
452
682
|
continue;
|
|
@@ -457,7 +687,9 @@ function reconcile_by_key(
|
|
|
457
687
|
if (is_indexed) {
|
|
458
688
|
update_index(b_block, b_end);
|
|
459
689
|
}
|
|
460
|
-
|
|
690
|
+
if (get_key !== undefined) {
|
|
691
|
+
update_value(b_block, b_val, map_item);
|
|
692
|
+
}
|
|
461
693
|
a_end--;
|
|
462
694
|
b_end--;
|
|
463
695
|
continue;
|
|
@@ -465,6 +697,11 @@ function reconcile_by_key(
|
|
|
465
697
|
if (a_start === a_end || a_blocks[a_start].s.start === null) {
|
|
466
698
|
break;
|
|
467
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
|
+
}
|
|
468
705
|
if (a_keys[a_end] === b_keys[b_start]) {
|
|
469
706
|
// Last old item is the next new one: move it in front of the old run.
|
|
470
707
|
b_val = b[b_start];
|
|
@@ -472,7 +709,9 @@ function reconcile_by_key(
|
|
|
472
709
|
if (is_indexed) {
|
|
473
710
|
update_index(b_block, b_start);
|
|
474
711
|
}
|
|
475
|
-
|
|
712
|
+
if (get_key !== undefined) {
|
|
713
|
+
update_value(b_block, b_val, map_item);
|
|
714
|
+
}
|
|
476
715
|
move(b_block, /** @type {ChildNode} */ (a_blocks[a_start].s.start));
|
|
477
716
|
a_end--;
|
|
478
717
|
b_start++;
|
|
@@ -485,7 +724,9 @@ function reconcile_by_key(
|
|
|
485
724
|
if (is_indexed) {
|
|
486
725
|
update_index(b_block, b_end);
|
|
487
726
|
}
|
|
488
|
-
|
|
727
|
+
if (get_key !== undefined) {
|
|
728
|
+
update_value(b_block, b_val, map_item);
|
|
729
|
+
}
|
|
489
730
|
move(b_block, block_start(b_blocks, b_end + 1, b_length, anchor));
|
|
490
731
|
a_start++;
|
|
491
732
|
b_end--;
|
|
@@ -507,6 +748,7 @@ function reconcile_by_key(
|
|
|
507
748
|
render_fn,
|
|
508
749
|
is_indexed,
|
|
509
750
|
true,
|
|
751
|
+
map_item,
|
|
510
752
|
);
|
|
511
753
|
b_start++;
|
|
512
754
|
}
|
|
@@ -516,6 +758,10 @@ function reconcile_by_key(
|
|
|
516
758
|
destroy_block(a_blocks[a_start++]);
|
|
517
759
|
}
|
|
518
760
|
} else {
|
|
761
|
+
if (in_place) {
|
|
762
|
+
a_blocks = a_blocks.slice();
|
|
763
|
+
in_place = false;
|
|
764
|
+
}
|
|
519
765
|
a_left = a_end - a_start + 1;
|
|
520
766
|
b_left = b_end - b_start + 1;
|
|
521
767
|
sources = new Int32Array(b_left + 1);
|
|
@@ -549,7 +795,9 @@ function reconcile_by_key(
|
|
|
549
795
|
if (is_indexed) {
|
|
550
796
|
update_index(b_block, j);
|
|
551
797
|
}
|
|
552
|
-
|
|
798
|
+
if (get_key !== undefined) {
|
|
799
|
+
update_value(b_block, b_val, map_item);
|
|
800
|
+
}
|
|
553
801
|
++patched;
|
|
554
802
|
break;
|
|
555
803
|
}
|
|
@@ -590,7 +838,9 @@ function reconcile_by_key(
|
|
|
590
838
|
if (is_indexed) {
|
|
591
839
|
update_index(b_block, j);
|
|
592
840
|
}
|
|
593
|
-
|
|
841
|
+
if (get_key !== undefined) {
|
|
842
|
+
update_value(b_block, b_val, map_item);
|
|
843
|
+
}
|
|
594
844
|
++patched;
|
|
595
845
|
} else if (!fast_path_removal) {
|
|
596
846
|
destroy_block(a_blocks[i]);
|
|
@@ -604,7 +854,17 @@ function reconcile_by_key(
|
|
|
604
854
|
|
|
605
855
|
if (fast_path_removal) {
|
|
606
856
|
reconcile_fast_clear(anchor, block, []);
|
|
607
|
-
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
|
+
);
|
|
608
868
|
return;
|
|
609
869
|
} else if (moved) {
|
|
610
870
|
var next_pos = 0;
|
|
@@ -619,7 +879,15 @@ function reconcile_by_key(
|
|
|
619
879
|
for (i = 0; i < b_left; i++) {
|
|
620
880
|
pos = i + b_start;
|
|
621
881
|
if (sources[i] === 0) {
|
|
622
|
-
b_blocks[pos] = create_item(
|
|
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
|
+
);
|
|
623
891
|
} else {
|
|
624
892
|
move(b_blocks[pos], relay_target);
|
|
625
893
|
}
|
|
@@ -637,7 +905,7 @@ function reconcile_by_key(
|
|
|
637
905
|
next_pos = pos + 1;
|
|
638
906
|
|
|
639
907
|
var target = block_start(b_blocks, next_pos, b_length, anchor);
|
|
640
|
-
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);
|
|
641
909
|
} else if (j < 0 || i !== seq[j]) {
|
|
642
910
|
pos = i + b_start;
|
|
643
911
|
next_pos = pos + 1;
|
|
@@ -656,7 +924,7 @@ function reconcile_by_key(
|
|
|
656
924
|
next_pos = pos + 1;
|
|
657
925
|
|
|
658
926
|
var target = block_start(b_blocks, next_pos, b_length, anchor);
|
|
659
|
-
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);
|
|
660
928
|
}
|
|
661
929
|
}
|
|
662
930
|
}
|
|
@@ -668,7 +936,7 @@ function reconcile_by_key(
|
|
|
668
936
|
|
|
669
937
|
/**
|
|
670
938
|
* @template V
|
|
671
|
-
* @param {
|
|
939
|
+
* @param {ListAnchor} anchor
|
|
672
940
|
* @param {Block} block
|
|
673
941
|
* @param {V[]} b
|
|
674
942
|
* @param {(anchor: Node, value: V | Tracked, index?: any) => Block} render_fn
|
|
@@ -678,35 +946,8 @@ function reconcile_by_key(
|
|
|
678
946
|
* @returns {void}
|
|
679
947
|
*/
|
|
680
948
|
function reconcile_by_ref(anchor, block, b, render_fn, is_controlled, is_indexed, render_empty) {
|
|
681
|
-
var state = block.s;
|
|
682
|
-
|
|
683
|
-
// Variables used in conditional branches - declare with initial values
|
|
684
|
-
/** @type {number} */
|
|
685
|
-
var a_left = 0;
|
|
686
|
-
/** @type {number} */
|
|
687
|
-
var b_left = 0;
|
|
688
|
-
/** @type {Int32Array} */
|
|
689
|
-
var sources = new Int32Array(0);
|
|
690
|
-
/** @type {boolean} */
|
|
691
|
-
var moved = false;
|
|
692
|
-
/** @type {number} */
|
|
693
|
-
var pos = 0;
|
|
694
|
-
/** @type {number} */
|
|
695
|
-
var patched = 0;
|
|
696
|
-
/** @type {number} */
|
|
697
|
-
var i = 0;
|
|
698
|
-
|
|
699
|
-
if (state === null) {
|
|
700
|
-
state = block.s = {
|
|
701
|
-
array: [],
|
|
702
|
-
blocks: [],
|
|
703
|
-
keys: null,
|
|
704
|
-
empty: null,
|
|
705
|
-
};
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
var a = state.array;
|
|
709
|
-
var a_length = a.length;
|
|
949
|
+
var state = /** @type {ListState} */ (block.s);
|
|
950
|
+
var a_length = state.array.length;
|
|
710
951
|
var b_length = b.length;
|
|
711
952
|
var j = 0;
|
|
712
953
|
|
|
@@ -752,6 +993,45 @@ function reconcile_by_ref(anchor, block, b, render_fn, is_controlled, is_indexed
|
|
|
752
993
|
return;
|
|
753
994
|
}
|
|
754
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;
|
|
755
1035
|
var a_blocks = state.blocks;
|
|
756
1036
|
var a_start = 0;
|
|
757
1037
|
var b_start = 0;
|