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,4 +1,4 @@
|
|
|
1
|
-
/** @import { Block, Component, Dependency, BlockWithTryBoundaryAndCatch, DeferredTrackedEntry } from '#client' */
|
|
1
|
+
/** @import { AppendIntoAnchor, Block, Component, Dependency, BlockWithTryBoundaryAndCatch, DeferredTrackedEntry } from '#client' */
|
|
2
2
|
/** @import { NAMESPACE_URI } from './constants.js' */
|
|
3
3
|
/** @typedef {TrackedValue} Tracked */
|
|
4
4
|
/** @typedef {DerivedValue} Derived */
|
|
@@ -18,50 +18,51 @@ import {
|
|
|
18
18
|
DERIVED,
|
|
19
19
|
COMPUTED_PROPERTY,
|
|
20
20
|
CONTAINS_TEARDOWN,
|
|
21
|
-
CONTAINS_UPDATE,
|
|
22
21
|
DESTROYED,
|
|
23
22
|
EFFECT_BLOCK,
|
|
23
|
+
FOR_BLOCK,
|
|
24
24
|
PAUSED,
|
|
25
25
|
PRE_EFFECT_BLOCK,
|
|
26
26
|
ROOT_BLOCK,
|
|
27
27
|
TRACKED,
|
|
28
28
|
UNINITIALIZED,
|
|
29
29
|
REF_PROP,
|
|
30
|
-
TRACKED_OBJECT,
|
|
31
30
|
DEFAULT_NAMESPACE,
|
|
32
31
|
TRACKED_UPDATED,
|
|
33
32
|
SUSPENSE_PENDING,
|
|
34
33
|
SUSPENSE_REJECTED,
|
|
35
34
|
TRY_BLOCK,
|
|
36
35
|
DIRECT_CHILD_BLOCK,
|
|
37
|
-
|
|
36
|
+
SCHEDULED,
|
|
37
|
+
SELECTOR,
|
|
38
|
+
IF_BLOCK,
|
|
39
|
+
RELEASED,
|
|
40
|
+
RENDER_ENTRY,
|
|
41
|
+
CREATES_DERIVEDS,
|
|
38
42
|
} from './constants.js';
|
|
39
43
|
import {
|
|
40
44
|
begin_boundary_request,
|
|
41
45
|
complete_boundary_request,
|
|
42
46
|
get_boundary_with_catch,
|
|
43
47
|
get_pending_boundary,
|
|
48
|
+
handle_boundary_error,
|
|
44
49
|
register_boundary_deferred,
|
|
45
50
|
register_boundary_paused_block,
|
|
46
51
|
replace_boundary_request,
|
|
47
52
|
} from './try.js';
|
|
48
53
|
import { is_ripple_object } from './utils.js';
|
|
54
|
+
import { render_value } from './expression.js';
|
|
55
|
+
import { throw_invalid_component_type } from './component.js';
|
|
49
56
|
|
|
50
57
|
import {
|
|
51
|
-
iterable_array_from,
|
|
52
58
|
define_property,
|
|
53
59
|
get_descriptor,
|
|
54
|
-
get_own_property_symbols,
|
|
55
60
|
is_array,
|
|
56
61
|
object_keys,
|
|
57
62
|
} from '@tsrx/core/runtime/language-helpers';
|
|
58
63
|
import { get_async_track_result } from '../../../utils/async.js';
|
|
59
|
-
import {
|
|
60
|
-
throw_tracked_index_reference_error,
|
|
61
|
-
throw_tracked_index_value_error,
|
|
62
|
-
} from '../../../utils/errors.js';
|
|
63
64
|
import { get_track_async_script_id } from '../../../utils/track-async-serialization.js';
|
|
64
|
-
import
|
|
65
|
+
import { revive } from './transport.js';
|
|
65
66
|
import { hydrating, track_hash_reference } from './hydration.js';
|
|
66
67
|
import { create_ref_prop as create_core_ref_prop } from '@tsrx/core/runtime/ref';
|
|
67
68
|
|
|
@@ -81,8 +82,25 @@ export let active_namespace = DEFAULT_NAMESPACE;
|
|
|
81
82
|
/** @type {boolean} */
|
|
82
83
|
export let is_mutating_allowed = true;
|
|
83
84
|
|
|
84
|
-
/**
|
|
85
|
-
|
|
85
|
+
/**
|
|
86
|
+
* Tracked values written during the current flush that hold their previous
|
|
87
|
+
* value in `o`, for teardowns that read them; released when the flush ends.
|
|
88
|
+
* @type {(Tracked | Derived)[]}
|
|
89
|
+
*/
|
|
90
|
+
var old_value_holders = [];
|
|
91
|
+
/** Nesting depth of running flushes; old values are released at depth zero. */
|
|
92
|
+
var flush_depth = 0;
|
|
93
|
+
|
|
94
|
+
/** @returns {void} */
|
|
95
|
+
function release_old_values() {
|
|
96
|
+
var holders = old_value_holders;
|
|
97
|
+
var length = holders.length;
|
|
98
|
+
if (length === 0) return;
|
|
99
|
+
for (var i = 0; i < length; i++) {
|
|
100
|
+
holders[i].o = UNINITIALIZED;
|
|
101
|
+
}
|
|
102
|
+
holders.length = 0;
|
|
103
|
+
}
|
|
86
104
|
|
|
87
105
|
// Used for controlling the flush of blocks
|
|
88
106
|
/** @type {number} */
|
|
@@ -92,14 +110,18 @@ let scheduler_mode = FLUSH_MICROTASK;
|
|
|
92
110
|
let is_micro_task_queued = false;
|
|
93
111
|
/** @type {number} */
|
|
94
112
|
let clock = 0;
|
|
95
|
-
/**
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
113
|
+
/**
|
|
114
|
+
* Blocks scheduled for the next flush. `sorted` tracks whether they were
|
|
115
|
+
* pushed in creation order, so the common case avoids a sort.
|
|
116
|
+
* @typedef {{ blocks: Block[]; sorted: boolean; last: number }} Queue
|
|
117
|
+
*/
|
|
118
|
+
/** @type {Queue} */
|
|
119
|
+
let queue = create_queue();
|
|
120
|
+
|
|
121
|
+
/** @returns {Queue} */
|
|
122
|
+
function create_queue() {
|
|
123
|
+
return { blocks: [], sorted: true, last: 0 };
|
|
124
|
+
}
|
|
103
125
|
/** @type {(() => void)[]} */
|
|
104
126
|
let queued_microtasks = [];
|
|
105
127
|
/** @type {number} */
|
|
@@ -163,7 +185,10 @@ export function run_teardown(block) {
|
|
|
163
185
|
active_reaction = null;
|
|
164
186
|
tracking = false;
|
|
165
187
|
teardown = true;
|
|
166
|
-
|
|
188
|
+
// Runtime-internal teardowns keyed on block state get it as their
|
|
189
|
+
// argument, so they need no per-block closure; user effects have
|
|
190
|
+
// null state.
|
|
191
|
+
fn.call(null, block.s);
|
|
167
192
|
} finally {
|
|
168
193
|
active_block = previous_block;
|
|
169
194
|
active_reaction = previous_reaction;
|
|
@@ -213,6 +238,7 @@ function update_derived(computed) {
|
|
|
213
238
|
function update_tracked_value_clock(tracked, value) {
|
|
214
239
|
tracked.__v = value;
|
|
215
240
|
tracked.c = increment_clock();
|
|
241
|
+
mark_subscribers(tracked);
|
|
216
242
|
}
|
|
217
243
|
|
|
218
244
|
/**
|
|
@@ -252,11 +278,11 @@ function run_derived(computed) {
|
|
|
252
278
|
|
|
253
279
|
var value = computed.fn();
|
|
254
280
|
|
|
255
|
-
computed
|
|
281
|
+
finish_dependencies(computed, active_dependency);
|
|
256
282
|
|
|
257
283
|
return value;
|
|
258
284
|
} catch (error) {
|
|
259
|
-
computed
|
|
285
|
+
finish_dependencies(computed, active_dependency);
|
|
260
286
|
if (error === ASYNC_DERIVED_READ_THROWN) {
|
|
261
287
|
// Check if any dependency is rejected — if so, propagate rejection
|
|
262
288
|
var dep = active_dependency;
|
|
@@ -287,7 +313,7 @@ function run_derived(computed) {
|
|
|
287
313
|
export function handle_error(error, block) {
|
|
288
314
|
var boundary_with_catch = get_boundary_with_catch(block);
|
|
289
315
|
if (boundary_with_catch !== null) {
|
|
290
|
-
boundary_with_catch
|
|
316
|
+
handle_boundary_error(boundary_with_catch, error);
|
|
291
317
|
return boundary_with_catch;
|
|
292
318
|
}
|
|
293
319
|
|
|
@@ -295,93 +321,152 @@ export function handle_error(error, block) {
|
|
|
295
321
|
}
|
|
296
322
|
|
|
297
323
|
/**
|
|
324
|
+
* The error path of {@link run_block}, kept out of that hot function so a
|
|
325
|
+
* healthy mount never compiles it: routes real errors to the nearest catch
|
|
326
|
+
* boundary and pauses a block that read a pending async value under its
|
|
327
|
+
* pending boundary.
|
|
328
|
+
* @param {unknown} error
|
|
298
329
|
* @param {Block} block
|
|
299
330
|
*/
|
|
300
|
-
|
|
331
|
+
function handle_run_error(error, block) {
|
|
332
|
+
var is_component_direct = false;
|
|
333
|
+
var is_try_fn_block = false;
|
|
334
|
+
finish_dependencies(block, active_dependency);
|
|
335
|
+
// When a derived read throws ASYNC_DERIVED_READ_THROWN, it means the
|
|
336
|
+
// derived is still SUSPENSE_PENDING. The dependency was already registered,
|
|
337
|
+
// so we swallow the throw and let the parent continue processing. When
|
|
338
|
+
// the derived settles, the block will be dirty and rerun automatically.
|
|
339
|
+
if (error !== ASYNC_DERIVED_READ_THROWN) {
|
|
340
|
+
handle_error(error, block);
|
|
341
|
+
} else if (
|
|
342
|
+
// pending async tracked was read outside allowed blocks
|
|
343
|
+
(is_component_direct = active_component?.b === block) ||
|
|
344
|
+
(is_try_fn_block =
|
|
345
|
+
block.p !== null && (block.p.f & TRY_BLOCK) !== 0 && (block.f & DIRECT_CHILD_BLOCK) !== 0)
|
|
346
|
+
) {
|
|
347
|
+
throw new Error(
|
|
348
|
+
`Reads on pending tracked values directly inside ${is_component_direct ? 'component' : 'try/pending/catch'} body are prohibited. Use trackPending() test or peek() for safe access or create another derived instead.`,
|
|
349
|
+
);
|
|
350
|
+
} else {
|
|
351
|
+
// pending async tracked was read and threw ASYNC_DERIVED_READ_THROWN
|
|
352
|
+
var boundary = get_pending_boundary(block);
|
|
353
|
+
if (boundary !== null) {
|
|
354
|
+
pause_block(block);
|
|
355
|
+
register_boundary_paused_block(boundary, block);
|
|
356
|
+
|
|
357
|
+
// Register deferred boundary completions for async tracked deps.
|
|
358
|
+
// This handles the case where a child boundary reads a tracked value
|
|
359
|
+
// whose resolution is managed by a different (parent) boundary.
|
|
360
|
+
var dep = block.d;
|
|
361
|
+
while (dep !== null) {
|
|
362
|
+
var dep_tracked = /** @type {Tracked} */ (dep.t);
|
|
363
|
+
if (
|
|
364
|
+
(dep_tracked.__v === SUSPENSE_PENDING || dep_tracked.__v === SUSPENSE_REJECTED) &&
|
|
365
|
+
(dep_tracked.f & TRACKED) !== 0
|
|
366
|
+
) {
|
|
367
|
+
var deferred_req = begin_boundary_request(boundary);
|
|
368
|
+
var entry = /** @type {DeferredTrackedEntry} */ ({ b: boundary, r: deferred_req });
|
|
369
|
+
if (dep_tracked.d === null) {
|
|
370
|
+
dep_tracked.d = [entry];
|
|
371
|
+
} else {
|
|
372
|
+
dep_tracked.d.push(entry);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
dep = dep.n;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Clears what a block's previous run left behind before it runs again. A
|
|
383
|
+
* list's children are all item branches, so there is nothing to sweep; an if
|
|
384
|
+
* block's children are its branch, which it replaces itself only when the
|
|
385
|
+
* condition changes. Returns the deriveds the previous run created, to be
|
|
386
|
+
* released once the new run has destroyed whatever read them (an if block
|
|
387
|
+
* swaps its branch inside its own run).
|
|
388
|
+
* @param {Block} block
|
|
389
|
+
* @returns {Derived[] | null}
|
|
390
|
+
*/
|
|
391
|
+
function prepare_rerun(block) {
|
|
392
|
+
if ((block.f & (FOR_BLOCK | IF_BLOCK)) === 0) {
|
|
393
|
+
destroy_non_branch_children(block);
|
|
394
|
+
}
|
|
395
|
+
run_teardown(block);
|
|
396
|
+
return (block.f & CREATES_DERIVEDS) !== 0 ? take_created_deriveds(block) : null;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* @param {Block} block
|
|
401
|
+
* @param {(state?: any) => void} teardown
|
|
402
|
+
*/
|
|
403
|
+
function register_teardown(block, teardown) {
|
|
404
|
+
block.t = teardown;
|
|
405
|
+
/** @type {Block | null} */
|
|
406
|
+
var current = block;
|
|
407
|
+
|
|
408
|
+
while (current !== null && (current.f & CONTAINS_TEARDOWN) === 0) {
|
|
409
|
+
current.f ^= CONTAINS_TEARDOWN;
|
|
410
|
+
current = current.p;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* @param {Block} block
|
|
416
|
+
* @param {boolean} [first_run] true when the block has no children, teardown,
|
|
417
|
+
* or dependencies yet, so that cleanup can be skipped
|
|
418
|
+
*/
|
|
419
|
+
export function run_block(block, first_run = false) {
|
|
301
420
|
var previous_block = active_block;
|
|
302
421
|
var previous_reaction = active_reaction;
|
|
303
422
|
var previous_tracking = tracking;
|
|
304
423
|
var previous_dependency = active_dependency;
|
|
305
424
|
var previous_component = active_component;
|
|
425
|
+
/** @type {Derived[] | null} */
|
|
426
|
+
var previous_deriveds = null;
|
|
306
427
|
|
|
307
428
|
try {
|
|
308
429
|
active_block = block;
|
|
309
430
|
active_reaction = block;
|
|
310
431
|
active_component = block.co;
|
|
311
432
|
|
|
312
|
-
|
|
313
|
-
|
|
433
|
+
if (!first_run) {
|
|
434
|
+
previous_deriveds = prepare_rerun(block);
|
|
435
|
+
}
|
|
314
436
|
|
|
315
437
|
tracking = (block.f & (ROOT_BLOCK | BRANCH_BLOCK)) === 0;
|
|
316
438
|
active_dependency = null;
|
|
317
439
|
var res = block.fn(block.s);
|
|
318
440
|
|
|
319
441
|
if (typeof res === 'function') {
|
|
320
|
-
block
|
|
321
|
-
/** @type {Block | null} */
|
|
322
|
-
let current = block;
|
|
323
|
-
|
|
324
|
-
while (current !== null && (current.f & CONTAINS_TEARDOWN) === 0) {
|
|
325
|
-
current.f ^= CONTAINS_TEARDOWN;
|
|
326
|
-
current = current.p;
|
|
327
|
-
}
|
|
442
|
+
register_teardown(block, res);
|
|
328
443
|
}
|
|
329
444
|
|
|
330
|
-
block.d
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
block.d = active_dependency;
|
|
335
|
-
// When a derived read throws ASYNC_DERIVED_READ_THROWN, it means the
|
|
336
|
-
// derived is still SUSPENSE_PENDING. The dependency was already registered,
|
|
337
|
-
// so we swallow the throw and let the parent continue processing. When
|
|
338
|
-
// the derived settles, the block will be dirty and rerun automatically.
|
|
339
|
-
if (error !== ASYNC_DERIVED_READ_THROWN) {
|
|
340
|
-
handle_error(error, block);
|
|
341
|
-
} else if (
|
|
342
|
-
// pending async tracked was read outside allowed blocks
|
|
343
|
-
(is_component_direct = active_component?.b === block) ||
|
|
344
|
-
(is_try_fn_block =
|
|
345
|
-
block.p !== null && (block.p.f & TRY_BLOCK) !== 0 && (block.f & DIRECT_CHILD_BLOCK) !== 0)
|
|
346
|
-
) {
|
|
347
|
-
throw new Error(
|
|
348
|
-
`Reads on pending tracked values directly inside ${is_component_direct ? 'component' : 'try/pending/catch'} body are prohibited. Use trackPending() test or peek() for safe access or create another derived instead.`,
|
|
349
|
-
);
|
|
350
|
-
} else {
|
|
351
|
-
// pending async tracked was read and threw ASYNC_DERIVED_READ_THROWN
|
|
352
|
-
var boundary = get_pending_boundary(block);
|
|
353
|
-
if (boundary !== null) {
|
|
354
|
-
pause_block(block);
|
|
355
|
-
register_boundary_paused_block(boundary, block);
|
|
356
|
-
|
|
357
|
-
// Register deferred boundary completions for async tracked deps.
|
|
358
|
-
// This handles the case where a child boundary reads a tracked value
|
|
359
|
-
// whose resolution is managed by a different (parent) boundary.
|
|
360
|
-
var dep = block.d;
|
|
361
|
-
while (dep !== null) {
|
|
362
|
-
var dep_tracked = /** @type {Tracked} */ (dep.t);
|
|
363
|
-
if (
|
|
364
|
-
(dep_tracked.__v === SUSPENSE_PENDING || dep_tracked.__v === SUSPENSE_REJECTED) &&
|
|
365
|
-
(dep_tracked.f & TRACKED) !== 0
|
|
366
|
-
) {
|
|
367
|
-
var deferred_req = begin_boundary_request(boundary);
|
|
368
|
-
var entry = /** @type {DeferredTrackedEntry} */ ({ b: boundary, r: deferred_req });
|
|
369
|
-
if (dep_tracked.d === null) {
|
|
370
|
-
dep_tracked.d = [entry];
|
|
371
|
-
} else {
|
|
372
|
-
dep_tracked.d.push(entry);
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
dep = dep.n;
|
|
376
|
-
}
|
|
445
|
+
if (block.d === null) {
|
|
446
|
+
// First run (or no dependencies so far): nothing stale to unlink.
|
|
447
|
+
if (active_dependency !== null) {
|
|
448
|
+
block.d = active_dependency;
|
|
377
449
|
}
|
|
450
|
+
} else {
|
|
451
|
+
finish_dependencies(block, active_dependency);
|
|
378
452
|
}
|
|
453
|
+
} catch (error) {
|
|
454
|
+
handle_run_error(error, block);
|
|
379
455
|
} finally {
|
|
380
456
|
active_block = previous_block;
|
|
381
457
|
active_reaction = previous_reaction;
|
|
382
458
|
tracking = previous_tracking;
|
|
383
459
|
active_dependency = previous_dependency;
|
|
384
460
|
active_component = previous_component;
|
|
461
|
+
|
|
462
|
+
// The previous run's deriveds, whether this run finished or threw, and
|
|
463
|
+
// after this run's dependencies replaced the old ones (so a derived the
|
|
464
|
+
// old run read is not kept alive by that stale link). Those still read
|
|
465
|
+
// stay recorded under the block for its next rerun or destruction: a
|
|
466
|
+
// rerun that keeps the same branch must not lose them.
|
|
467
|
+
if (previous_deriveds !== null) {
|
|
468
|
+
keep_deriveds(block, release_deriveds(previous_deriveds));
|
|
469
|
+
}
|
|
385
470
|
}
|
|
386
471
|
}
|
|
387
472
|
|
|
@@ -406,11 +491,11 @@ class TrackedValue {
|
|
|
406
491
|
/**
|
|
407
492
|
* @param {any} v
|
|
408
493
|
* @param {Block} block
|
|
409
|
-
* @param {{ get?: Function; set?: Function }} a
|
|
494
|
+
* @param {{ get?: Function; set?: Function | true }} a
|
|
410
495
|
* @param {string} [hash]
|
|
411
496
|
*/
|
|
412
497
|
constructor(v, block, a, hash) {
|
|
413
|
-
/** @type {{ get?: Function; set?: Function }} */
|
|
498
|
+
/** @type {{ get?: Function; set?: Function | true }} */
|
|
414
499
|
this.a = a;
|
|
415
500
|
/** @type {Block} */
|
|
416
501
|
this.b = block;
|
|
@@ -420,22 +505,14 @@ class TrackedValue {
|
|
|
420
505
|
this.d = null;
|
|
421
506
|
/** @type {number} */
|
|
422
507
|
this.f = TRACKED;
|
|
423
|
-
/** @type {
|
|
508
|
+
/** @type {any} hydration hash, or the key of a selector match flag */
|
|
424
509
|
this.h = hash;
|
|
510
|
+
/** @type {Dependency | null} */
|
|
511
|
+
this.sb = null;
|
|
425
512
|
/** @type {any} */
|
|
426
513
|
this.__v = v;
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
get [0]() {
|
|
430
|
-
return throw_tracked_index_value_error();
|
|
431
|
-
}
|
|
432
|
-
/** @param {any} v */
|
|
433
|
-
set [0](v) {
|
|
434
|
-
throw_tracked_index_value_error();
|
|
435
|
-
}
|
|
436
|
-
/** @returns {Tracked} */
|
|
437
|
-
get [1]() {
|
|
438
|
-
return throw_tracked_index_reference_error();
|
|
514
|
+
/** @type {any} previous value while a flush with teardowns is running */
|
|
515
|
+
this.o = UNINITIALIZED;
|
|
439
516
|
}
|
|
440
517
|
/** @returns {any} */
|
|
441
518
|
get value() {
|
|
@@ -445,14 +522,16 @@ class TrackedValue {
|
|
|
445
522
|
set value(v) {
|
|
446
523
|
set(this, v);
|
|
447
524
|
}
|
|
448
|
-
/**
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
525
|
+
/**
|
|
526
|
+
* A read-only view: a derived over this value, for a receiver that should
|
|
527
|
+
* read but not write it. Equivalent to `track(() => tracked.value)`. The
|
|
528
|
+
* view is owned by the block that creates it, not by this value's block, so
|
|
529
|
+
* a view made in a component is released with that component even when the
|
|
530
|
+
* value outlives it.
|
|
531
|
+
* @returns {Derived}
|
|
532
|
+
*/
|
|
533
|
+
readOnly() {
|
|
534
|
+
return derived(() => get_tracked(this), /** @type {Block} */ (active_block));
|
|
456
535
|
}
|
|
457
536
|
}
|
|
458
537
|
|
|
@@ -460,11 +539,11 @@ class DerivedValue {
|
|
|
460
539
|
/**
|
|
461
540
|
* @param {Function} fn
|
|
462
541
|
* @param {Block} block
|
|
463
|
-
* @param {{ get?: Function; set?: Function }} a
|
|
542
|
+
* @param {{ get?: Function; set?: Function | true }} a
|
|
464
543
|
* @param {string} [hash]
|
|
465
544
|
*/
|
|
466
545
|
constructor(fn, block, a, hash) {
|
|
467
|
-
/** @type {{ get?: Function; set?: Function }} */
|
|
546
|
+
/** @type {{ get?: Function; set?: Function | true }} */
|
|
468
547
|
this.a = a;
|
|
469
548
|
/** @type {Block} */
|
|
470
549
|
this.b = block;
|
|
@@ -482,20 +561,12 @@ class DerivedValue {
|
|
|
482
561
|
this.fn = fn;
|
|
483
562
|
/** @type {string | undefined} */
|
|
484
563
|
this.h = hash;
|
|
564
|
+
/** @type {Dependency | null} */
|
|
565
|
+
this.sb = null;
|
|
485
566
|
/** @type {any} */
|
|
486
567
|
this.__v = UNINITIALIZED;
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
get [0]() {
|
|
490
|
-
return throw_tracked_index_value_error();
|
|
491
|
-
}
|
|
492
|
-
/** @param {any} v */
|
|
493
|
-
set [0](v) {
|
|
494
|
-
throw_tracked_index_value_error();
|
|
495
|
-
}
|
|
496
|
-
/** @returns {Derived} */
|
|
497
|
-
get [1]() {
|
|
498
|
-
return throw_tracked_index_reference_error();
|
|
568
|
+
/** @type {any} previous value while a flush with teardowns is running */
|
|
569
|
+
this.o = UNINITIALIZED;
|
|
499
570
|
}
|
|
500
571
|
/** @returns {any} */
|
|
501
572
|
get value() {
|
|
@@ -505,14 +576,16 @@ class DerivedValue {
|
|
|
505
576
|
set value(v) {
|
|
506
577
|
set(this, v);
|
|
507
578
|
}
|
|
508
|
-
/**
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
579
|
+
/**
|
|
580
|
+
* A read-only view (see `TrackedValue#readOnly`). A derived without a
|
|
581
|
+
* setter is already read-only and is returned as is; a writable one is
|
|
582
|
+
* wrapped in a derived that follows it.
|
|
583
|
+
* @returns {Derived}
|
|
584
|
+
*/
|
|
585
|
+
readOnly() {
|
|
586
|
+
return this.a.set === undefined
|
|
587
|
+
? this
|
|
588
|
+
: derived(() => get_derived(this), /** @type {Block} */ (active_block));
|
|
516
589
|
}
|
|
517
590
|
}
|
|
518
591
|
|
|
@@ -527,7 +600,7 @@ if (DEV) {
|
|
|
527
600
|
* @param {Block} block
|
|
528
601
|
* @param {string} [hash]
|
|
529
602
|
* @param {(value: any) => any} [get]
|
|
530
|
-
* @param {(next: any, prev: any) => any} [set]
|
|
603
|
+
* @param {((next: any, prev: any) => any) | true} [set]
|
|
531
604
|
* @returns {Tracked}
|
|
532
605
|
*/
|
|
533
606
|
export function tracked(v, block, hash, get, set) {
|
|
@@ -545,25 +618,126 @@ export function tracked(v, block, hash, get, set) {
|
|
|
545
618
|
* @param {Block} block
|
|
546
619
|
* @param {string} [hash]
|
|
547
620
|
* @param {(value: any) => any} [get]
|
|
548
|
-
* @param {(next: any, prev: any) => any} [set]
|
|
621
|
+
* @param {((next: any, prev: any) => any) | true} [set]
|
|
549
622
|
* @returns {Derived}
|
|
550
623
|
*/
|
|
551
624
|
export function derived(fn, block, hash, get, set) {
|
|
552
625
|
var d = /** @type {Derived} */ (
|
|
553
626
|
new DerivedValue(fn, block || active_block, get || set ? { get, set } : empty_get_set, hash)
|
|
554
627
|
);
|
|
628
|
+
// The run that creates a derived owns its release: when that block reruns
|
|
629
|
+
// or is destroyed, the derived is unsubscribed from its sources unless a
|
|
630
|
+
// reader that is still alive holds it (see `release_deriveds`).
|
|
631
|
+
var creator = active_block;
|
|
632
|
+
if (creator !== null) {
|
|
633
|
+
var created = created_deriveds.get(creator);
|
|
634
|
+
if (created === undefined) {
|
|
635
|
+
created_deriveds.set(creator, [d]);
|
|
636
|
+
creator.f |= CREATES_DERIVEDS;
|
|
637
|
+
} else {
|
|
638
|
+
created.push(d);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
555
641
|
if (hydrating && hash !== undefined) {
|
|
556
642
|
track_hash_reference.set(hash, d);
|
|
557
643
|
}
|
|
558
644
|
return d;
|
|
559
645
|
}
|
|
560
646
|
|
|
647
|
+
/**
|
|
648
|
+
* The deriveds each block's latest run created, keyed by the block. A side
|
|
649
|
+
* table rather than a block field: most blocks never create a derived, and
|
|
650
|
+
* block creation is the hot path, so blocks keep their shape. A block with an
|
|
651
|
+
* entry carries `CREATES_DERIVEDS` in its flags, so a rerun or destroy of any
|
|
652
|
+
* other block never looks here.
|
|
653
|
+
* @type {Map<Block, Derived[]>}
|
|
654
|
+
*/
|
|
655
|
+
var created_deriveds = new Map();
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* Removes and returns the deriveds `block`'s latest run created, or null.
|
|
659
|
+
* @param {Block} block
|
|
660
|
+
* @returns {Derived[] | null}
|
|
661
|
+
*/
|
|
662
|
+
export function take_created_deriveds(block) {
|
|
663
|
+
var deriveds = created_deriveds.get(block);
|
|
664
|
+
block.f &= ~CREATES_DERIVEDS;
|
|
665
|
+
if (deriveds === undefined) {
|
|
666
|
+
return null;
|
|
667
|
+
}
|
|
668
|
+
created_deriveds.delete(block);
|
|
669
|
+
return deriveds;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
/**
|
|
673
|
+
* Releases the deriveds a block run created, once that run's readers are
|
|
674
|
+
* gone: the block reran (its previous run's readers were destroyed by the
|
|
675
|
+
* rerun) or was destroyed. A derived that a live reader still holds (the
|
|
676
|
+
* branch is still showing, or it was handed to a longer-lived scope) is
|
|
677
|
+
* kept. Walked newest first, so a derived read by a later one of the same
|
|
678
|
+
* run sees that reader unlinked before it is examined; the survivors are
|
|
679
|
+
* packed into the tail of the same array as they are met, which leaves them
|
|
680
|
+
* in creation order for the next pass, and slid to the front at the end.
|
|
681
|
+
* @param {Derived[]} deriveds in creation order; reused for the result
|
|
682
|
+
* @returns {Derived[] | null} the deriveds kept, in creation order, if any
|
|
683
|
+
*/
|
|
684
|
+
export function release_deriveds(deriveds) {
|
|
685
|
+
var length = deriveds.length;
|
|
686
|
+
var kept = length;
|
|
687
|
+
for (var i = length - 1; i >= 0; i--) {
|
|
688
|
+
var derived = deriveds[i];
|
|
689
|
+
var alive = false;
|
|
690
|
+
for (var sub = derived.sb; sub !== null; sub = sub.sn) {
|
|
691
|
+
if ((sub.r.f & DESTROYED) === 0) {
|
|
692
|
+
alive = true;
|
|
693
|
+
break;
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
if (alive) {
|
|
697
|
+
// `kept` never drops below `i`, so this only overwrites visited slots.
|
|
698
|
+
deriveds[--kept] = derived;
|
|
699
|
+
} else {
|
|
700
|
+
finish_dependencies(derived, null);
|
|
701
|
+
destroy_computed_children(derived);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
if (kept === length) {
|
|
705
|
+
return null;
|
|
706
|
+
}
|
|
707
|
+
if (kept !== 0) {
|
|
708
|
+
deriveds.copyWithin(0, kept);
|
|
709
|
+
deriveds.length = length - kept;
|
|
710
|
+
}
|
|
711
|
+
return deriveds;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* Records deriveds under `block` again after a rerun kept them, ahead of
|
|
716
|
+
* whatever the new run created: the kept ones are older, and the release
|
|
717
|
+
* order (newest first) relies on the list being in creation order.
|
|
718
|
+
* @param {Block} block
|
|
719
|
+
* @param {Derived[] | null} kept
|
|
720
|
+
*/
|
|
721
|
+
function keep_deriveds(block, kept) {
|
|
722
|
+
if (kept === null) {
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
var created = created_deriveds.get(block);
|
|
726
|
+
if (created !== undefined) {
|
|
727
|
+
for (var i = 0; i < created.length; i++) {
|
|
728
|
+
kept.push(created[i]);
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
created_deriveds.set(block, kept);
|
|
732
|
+
block.f |= CREATES_DERIVEDS;
|
|
733
|
+
}
|
|
734
|
+
|
|
561
735
|
/**
|
|
562
736
|
* @param {any} v
|
|
563
737
|
* @param {Block} b
|
|
564
738
|
* @param {string} [hash]
|
|
565
739
|
* @param {(value: any) => any} [get]
|
|
566
|
-
* @param {(next: any, prev: any) => any} [set]
|
|
740
|
+
* @param {((next: any, prev: any) => any) | true} [set]
|
|
567
741
|
* @returns {Tracked | Derived}
|
|
568
742
|
*/
|
|
569
743
|
export function track(v, b, hash, get, set) {
|
|
@@ -617,7 +791,8 @@ export function track_async(fn, b, hash) {
|
|
|
617
791
|
|
|
618
792
|
if (envelope.ok) {
|
|
619
793
|
had_hydration_data = true;
|
|
620
|
-
hydration_value =
|
|
794
|
+
hydration_value =
|
|
795
|
+
envelope.payload === undefined ? envelope.value : revive(envelope.payload);
|
|
621
796
|
hydration_deps = envelope.deps;
|
|
622
797
|
} else {
|
|
623
798
|
// trigger the catch block
|
|
@@ -696,7 +871,6 @@ export function track_async(fn, b, hash) {
|
|
|
696
871
|
// Set to pending before calling fn() in case it's sync.
|
|
697
872
|
if (t.__v !== SUSPENSE_PENDING) {
|
|
698
873
|
update_tracked_value_clock(t, SUSPENSE_PENDING);
|
|
699
|
-
schedule_update(t.b);
|
|
700
874
|
}
|
|
701
875
|
|
|
702
876
|
// Temporarily allow mutations so set() doesn't throw inside the pre-effect
|
|
@@ -715,7 +889,6 @@ export function track_async(fn, b, hash) {
|
|
|
715
889
|
while (dep !== null) {
|
|
716
890
|
if (dep.t.__v === SUSPENSE_REJECTED) {
|
|
717
891
|
update_tracked_value_clock(t, SUSPENSE_REJECTED);
|
|
718
|
-
schedule_update(t.b);
|
|
719
892
|
complete_deferred_boundaries(t, false);
|
|
720
893
|
if (request_id > 0 && boundary !== null) {
|
|
721
894
|
complete_boundary_request(boundary, request_id, false);
|
|
@@ -748,7 +921,6 @@ export function track_async(fn, b, hash) {
|
|
|
748
921
|
if (async_result === null) {
|
|
749
922
|
// Sync result
|
|
750
923
|
update_tracked_value_clock(t, result);
|
|
751
|
-
schedule_update(t.b);
|
|
752
924
|
if (request_id > 0 && boundary !== null) {
|
|
753
925
|
complete_boundary_request(boundary, request_id);
|
|
754
926
|
request_id = 0;
|
|
@@ -769,7 +941,6 @@ export function track_async(fn, b, hash) {
|
|
|
769
941
|
return;
|
|
770
942
|
}
|
|
771
943
|
update_tracked_value_clock(t, resolved);
|
|
772
|
-
schedule_update(t.b);
|
|
773
944
|
complete_deferred_boundaries(t);
|
|
774
945
|
if (request_id > 0 && boundary !== null) {
|
|
775
946
|
complete_boundary_request(boundary, request_id);
|
|
@@ -792,13 +963,12 @@ export function track_async(fn, b, hash) {
|
|
|
792
963
|
}
|
|
793
964
|
|
|
794
965
|
update_tracked_value_clock(t, SUSPENSE_REJECTED);
|
|
795
|
-
schedule_update(t.b);
|
|
796
966
|
complete_deferred_boundaries(t, false);
|
|
797
967
|
|
|
798
968
|
// Route error to catch boundary
|
|
799
969
|
var boundary_with_catch = get_boundary_with_catch(call_site_block);
|
|
800
970
|
if (boundary_with_catch !== null) {
|
|
801
|
-
boundary_with_catch
|
|
971
|
+
handle_boundary_error(boundary_with_catch, error);
|
|
802
972
|
}
|
|
803
973
|
|
|
804
974
|
if (request_id > 0 && boundary !== null) {
|
|
@@ -865,16 +1035,190 @@ function create_dependency(tracked) {
|
|
|
865
1035
|
if (existing !== null) {
|
|
866
1036
|
reaction.d = existing.n;
|
|
867
1037
|
existing.c = tracked.c;
|
|
868
|
-
existing.t = tracked;
|
|
869
1038
|
existing.n = null;
|
|
1039
|
+
if (existing.t !== tracked) {
|
|
1040
|
+
unlink_subscriber(existing);
|
|
1041
|
+
existing.t = tracked;
|
|
1042
|
+
link_subscriber(existing, tracked);
|
|
1043
|
+
}
|
|
870
1044
|
return existing;
|
|
871
1045
|
}
|
|
872
1046
|
|
|
873
|
-
|
|
1047
|
+
// link_subscriber, inline: the first read of every block run lands here.
|
|
1048
|
+
var head = tracked.sb;
|
|
1049
|
+
/** @type {Dependency} */
|
|
1050
|
+
var dependency = {
|
|
874
1051
|
c: tracked.c,
|
|
875
1052
|
t: tracked,
|
|
876
1053
|
n: null,
|
|
1054
|
+
r: reaction,
|
|
1055
|
+
sp: null,
|
|
1056
|
+
sn: head,
|
|
877
1057
|
};
|
|
1058
|
+
if (head !== null) {
|
|
1059
|
+
head.sp = dependency;
|
|
1060
|
+
}
|
|
1061
|
+
tracked.sb = dependency;
|
|
1062
|
+
return dependency;
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
/**
|
|
1066
|
+
* @param {Dependency} dependency
|
|
1067
|
+
* @param {Tracked | Derived} tracked
|
|
1068
|
+
*/
|
|
1069
|
+
function link_subscriber(dependency, tracked) {
|
|
1070
|
+
var head = tracked.sb;
|
|
1071
|
+
dependency.sn = head;
|
|
1072
|
+
if (head !== null) {
|
|
1073
|
+
head.sp = dependency;
|
|
1074
|
+
}
|
|
1075
|
+
tracked.sb = dependency;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
/**
|
|
1079
|
+
* @param {Dependency} dependency
|
|
1080
|
+
*/
|
|
1081
|
+
export function unlink_subscriber(dependency) {
|
|
1082
|
+
var prev = dependency.sp;
|
|
1083
|
+
var next = dependency.sn;
|
|
1084
|
+
if (prev !== null) {
|
|
1085
|
+
prev.sn = next;
|
|
1086
|
+
} else {
|
|
1087
|
+
var tracked = dependency.t;
|
|
1088
|
+
// Already unlinked (a destroyed block's dependency can be pruned by a
|
|
1089
|
+
// write during its own teardown, then unlinked again by
|
|
1090
|
+
// remove_dependencies); it must not be mistaken for the list head.
|
|
1091
|
+
if (tracked.sb !== dependency) {
|
|
1092
|
+
return;
|
|
1093
|
+
}
|
|
1094
|
+
tracked.sb = next;
|
|
1095
|
+
if (next === null && (tracked.f & SELECTOR) !== 0) {
|
|
1096
|
+
release_selector_key(/** @type {Tracked} */ (tracked));
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
if (next !== null) {
|
|
1100
|
+
next.sp = prev;
|
|
1101
|
+
}
|
|
1102
|
+
dependency.sp = dependency.sn = null;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
/**
|
|
1106
|
+
* `n` counts released keys still in the map.
|
|
1107
|
+
* @typedef {{ get: undefined; set: undefined; m: Map<any, Tracked>; n: number }} SelectorAccessors
|
|
1108
|
+
*/
|
|
1109
|
+
|
|
1110
|
+
/** Released selector keys kept for reuse before the map is swept. */
|
|
1111
|
+
var SELECTOR_SWEEP_THRESHOLD = 1024;
|
|
1112
|
+
|
|
1113
|
+
/**
|
|
1114
|
+
* The last subscriber of a selector key left. The entry stays in the map so
|
|
1115
|
+
* a key that comes back (a list re-rendering the same items) reuses it
|
|
1116
|
+
* instead of allocating and inserting again; once enough released keys pile
|
|
1117
|
+
* up they are swept out, so the map stays bounded.
|
|
1118
|
+
* @param {Tracked} tracked
|
|
1119
|
+
*/
|
|
1120
|
+
function release_selector_key(tracked) {
|
|
1121
|
+
var accessors = /** @type {SelectorAccessors} */ (tracked.a);
|
|
1122
|
+
tracked.f |= RELEASED;
|
|
1123
|
+
if (++accessors.n > SELECTOR_SWEEP_THRESHOLD) {
|
|
1124
|
+
var m = accessors.m;
|
|
1125
|
+
for (var [key, t] of m) {
|
|
1126
|
+
if ((t.f & RELEASED) !== 0) {
|
|
1127
|
+
m.delete(key);
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
accessors.n = 0;
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
/**
|
|
1135
|
+
* A key found in the map again after its subscribers had all left.
|
|
1136
|
+
* @param {Tracked} tracked
|
|
1137
|
+
*/
|
|
1138
|
+
export function revive_selector_key(tracked) {
|
|
1139
|
+
tracked.f ^= RELEASED;
|
|
1140
|
+
/** @type {SelectorAccessors} */ (tracked.a).n--;
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
/**
|
|
1144
|
+
* A tracked match flag for one selector key. The selector's shared accessor
|
|
1145
|
+
* object carries the map and the key rides in the hash slot, so the entry can
|
|
1146
|
+
* be released from `unlink_subscriber` without an object per key.
|
|
1147
|
+
* @param {boolean} value
|
|
1148
|
+
* @param {Block} block
|
|
1149
|
+
* @param {SelectorAccessors} accessors
|
|
1150
|
+
* @param {any} key
|
|
1151
|
+
* @returns {Tracked}
|
|
1152
|
+
*/
|
|
1153
|
+
export function selector_tracked(value, block, accessors, key) {
|
|
1154
|
+
var t = /** @type {Tracked} */ (new TrackedValue(value, block, accessors, key));
|
|
1155
|
+
t.f |= SELECTOR;
|
|
1156
|
+
return t;
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
/**
|
|
1160
|
+
* Install the dependency chain produced by a run, unsubscribing from any
|
|
1161
|
+
* previous dependencies that were not read again.
|
|
1162
|
+
* @param {Block | Derived} reaction
|
|
1163
|
+
* @param {Dependency | null} dependencies
|
|
1164
|
+
*/
|
|
1165
|
+
function finish_dependencies(reaction, dependencies) {
|
|
1166
|
+
var stale = reaction.d;
|
|
1167
|
+
while (stale !== null) {
|
|
1168
|
+
unlink_subscriber(stale);
|
|
1169
|
+
stale = stale.n;
|
|
1170
|
+
}
|
|
1171
|
+
reaction.d = dependencies;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
/**
|
|
1175
|
+
* Unsubscribe a block from every tracked value it read. Dependencies on
|
|
1176
|
+
* values owned by an already-destroyed block are dropped without unlinking,
|
|
1177
|
+
* since the owner's subscriber list dies with it.
|
|
1178
|
+
* @param {Block} block
|
|
1179
|
+
*/
|
|
1180
|
+
export function remove_dependencies(block) {
|
|
1181
|
+
var dependency = block.d;
|
|
1182
|
+
while (dependency !== null) {
|
|
1183
|
+
var owner = dependency.t.b;
|
|
1184
|
+
if (owner === null || (owner.f & DESTROYED) === 0) {
|
|
1185
|
+
unlink_subscriber(dependency);
|
|
1186
|
+
}
|
|
1187
|
+
dependency = dependency.n;
|
|
1188
|
+
}
|
|
1189
|
+
block.d = null;
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
/**
|
|
1193
|
+
* Schedule every reaction subscribed to `tracked`. Deriveds are lazy, so their
|
|
1194
|
+
* own subscribers are marked instead; subscribers that were destroyed without
|
|
1195
|
+
* unlinking are pruned here.
|
|
1196
|
+
* @param {Tracked | Derived} tracked
|
|
1197
|
+
*/
|
|
1198
|
+
function mark_subscribers(tracked) {
|
|
1199
|
+
var dependency = tracked.sb;
|
|
1200
|
+
while (dependency !== null) {
|
|
1201
|
+
var next = dependency.sn;
|
|
1202
|
+
var reaction = dependency.r;
|
|
1203
|
+
var flags = reaction.f;
|
|
1204
|
+
if ((flags & DERIVED) !== 0) {
|
|
1205
|
+
var derived = /** @type {Derived} */ (reaction);
|
|
1206
|
+
// Marking the derived's own subscribers first prunes its destroyed
|
|
1207
|
+
// readers, so a derived whose owner is gone and that nothing reads any
|
|
1208
|
+
// more is dropped on this write; one still read elsewhere keeps
|
|
1209
|
+
// forwarding notifications.
|
|
1210
|
+
mark_subscribers(derived);
|
|
1211
|
+
var derived_owner = derived.b;
|
|
1212
|
+
if (derived_owner !== null && (derived_owner.f & DESTROYED) !== 0 && derived.sb === null) {
|
|
1213
|
+
unlink_subscriber(dependency);
|
|
1214
|
+
}
|
|
1215
|
+
} else if ((flags & DESTROYED) !== 0) {
|
|
1216
|
+
unlink_subscriber(dependency);
|
|
1217
|
+
} else {
|
|
1218
|
+
schedule_update(/** @type {Block} */ (reaction));
|
|
1219
|
+
}
|
|
1220
|
+
dependency = next;
|
|
1221
|
+
}
|
|
878
1222
|
}
|
|
879
1223
|
|
|
880
1224
|
/**
|
|
@@ -941,125 +1285,114 @@ function trigger_track_get(fn, v) {
|
|
|
941
1285
|
}
|
|
942
1286
|
|
|
943
1287
|
/**
|
|
944
|
-
* @param {Block}
|
|
1288
|
+
* @param {Block} a
|
|
1289
|
+
* @param {Block} b
|
|
1290
|
+
* @returns {number}
|
|
945
1291
|
*/
|
|
946
|
-
function
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
var pre_effects = [];
|
|
950
|
-
var other_blocks = [];
|
|
951
|
-
var effects = [];
|
|
952
|
-
// The nearest enclosing directly-scheduled block ("update source"). While it is
|
|
953
|
-
// non-null we are inside a source's subtree and scan every descendant. Above
|
|
954
|
-
// sources we only follow the CONTAINS_UPDATE routing path, so sibling subtrees
|
|
955
|
-
// that contain no update are skipped. When scoping is disabled we treat the
|
|
956
|
-
// whole root tree as one source — the original full-tree scan.
|
|
957
|
-
/** @type {Block | null} */
|
|
958
|
-
var scope_root = disable_scoped_flush ? root_block : null;
|
|
1292
|
+
function by_block_id(a, b) {
|
|
1293
|
+
return a.i - b.i;
|
|
1294
|
+
}
|
|
959
1295
|
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
1296
|
+
/**
|
|
1297
|
+
* Run every scheduled block, in creation order (so a parent runs before its
|
|
1298
|
+
* descendants), in three phases: pre-effects, render blocks, then effects.
|
|
1299
|
+
* @param {Queue} pending
|
|
1300
|
+
*/
|
|
1301
|
+
function flush_queue(pending) {
|
|
1302
|
+
var blocks = pending.blocks;
|
|
1303
|
+
var length = blocks.length;
|
|
963
1304
|
|
|
964
|
-
|
|
965
|
-
|
|
1305
|
+
if (length > 0) {
|
|
1306
|
+
if (!pending.sorted) {
|
|
1307
|
+
blocks.sort(by_block_id);
|
|
966
1308
|
}
|
|
967
1309
|
|
|
968
|
-
|
|
969
|
-
current.f ^= UPDATE_SOURCE;
|
|
970
|
-
if (scope_root === null) {
|
|
971
|
-
scope_root = current;
|
|
972
|
-
}
|
|
973
|
-
}
|
|
1310
|
+
var has_effects = false;
|
|
974
1311
|
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
other_blocks.push(current);
|
|
1312
|
+
for (var i = 0; i < length; i++) {
|
|
1313
|
+
var block = blocks[i];
|
|
1314
|
+
var flags = block.f;
|
|
1315
|
+
block.f = flags & ~SCHEDULED;
|
|
1316
|
+
if ((flags & (PRE_EFFECT_BLOCK | EFFECT_BLOCK)) !== 0) {
|
|
1317
|
+
has_effects = true;
|
|
982
1318
|
}
|
|
983
|
-
|
|
984
|
-
var child = current.first;
|
|
1319
|
+
}
|
|
985
1320
|
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
1321
|
+
// New schedules land in the queue that replaced `pending`, so the array
|
|
1322
|
+
// can be run in place. Effects need the three-phase ordering; a queue of
|
|
1323
|
+
// only render blocks (the common flush) runs straight through.
|
|
1324
|
+
if (has_effects) {
|
|
1325
|
+
run_phases(blocks, length);
|
|
1326
|
+
} else {
|
|
1327
|
+
run_phase(blocks);
|
|
990
1328
|
}
|
|
991
1329
|
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
1330
|
+
blocks.length = 0;
|
|
1331
|
+
pending.sorted = true;
|
|
1332
|
+
pending.last = 0;
|
|
1333
|
+
}
|
|
995
1334
|
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
parent = parent.p;
|
|
1335
|
+
if (queued_post_block_flush.length > 0) {
|
|
1336
|
+
var callbacks = queued_post_block_flush;
|
|
1337
|
+
queued_post_block_flush = [];
|
|
1338
|
+
for (var j = 0; j < callbacks.length; j++) {
|
|
1339
|
+
callbacks[j]();
|
|
1002
1340
|
}
|
|
1003
1341
|
}
|
|
1342
|
+
}
|
|
1004
1343
|
|
|
1005
|
-
|
|
1344
|
+
/**
|
|
1345
|
+
* Runs a queue that contains effects in three phases: pre-effects, render
|
|
1346
|
+
* blocks, then effects. Kept out of {@link flush_queue} so a render-only flush
|
|
1347
|
+
* never compiles it.
|
|
1348
|
+
* @param {Block[]} blocks
|
|
1349
|
+
* @param {number} length
|
|
1350
|
+
*/
|
|
1351
|
+
function run_phases(blocks, length) {
|
|
1352
|
+
/** @type {Block[]} */
|
|
1353
|
+
var pre_effects = [];
|
|
1354
|
+
/** @type {Block[]} */
|
|
1355
|
+
var other_blocks = [];
|
|
1356
|
+
/** @type {Block[]} */
|
|
1357
|
+
var effects = [];
|
|
1006
1358
|
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
var block = pre_effects[i];
|
|
1359
|
+
for (var i = 0; i < length; i++) {
|
|
1360
|
+
var block = blocks[i];
|
|
1361
|
+
var flags = block.f;
|
|
1011
1362
|
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
}
|
|
1016
|
-
} catch (error) {
|
|
1017
|
-
handle_error(error, block);
|
|
1363
|
+
// A paused block is re-checked when it resumes; a destroyed one is gone.
|
|
1364
|
+
if ((flags & (PAUSED | DESTROYED)) !== 0) {
|
|
1365
|
+
continue;
|
|
1018
1366
|
}
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
try {
|
|
1027
|
-
if ((block.f & (PAUSED | DESTROYED)) === 0 && is_block_dirty(block)) {
|
|
1028
|
-
run_block(block);
|
|
1029
|
-
}
|
|
1030
|
-
} catch (error) {
|
|
1031
|
-
handle_error(error, block);
|
|
1367
|
+
if ((flags & PRE_EFFECT_BLOCK) !== 0) {
|
|
1368
|
+
pre_effects.push(block);
|
|
1369
|
+
} else if ((flags & EFFECT_BLOCK) !== 0) {
|
|
1370
|
+
effects.push(block);
|
|
1371
|
+
} else {
|
|
1372
|
+
other_blocks.push(block);
|
|
1032
1373
|
}
|
|
1033
1374
|
}
|
|
1034
1375
|
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
var block = effects[i];
|
|
1039
|
-
|
|
1040
|
-
try {
|
|
1041
|
-
if ((block.f & (PAUSED | DESTROYED)) === 0 && is_block_dirty(block)) {
|
|
1042
|
-
run_block(block);
|
|
1043
|
-
}
|
|
1044
|
-
} catch (error) {
|
|
1045
|
-
handle_error(error, block);
|
|
1046
|
-
}
|
|
1047
|
-
}
|
|
1376
|
+
run_phase(pre_effects);
|
|
1377
|
+
run_phase(other_blocks);
|
|
1378
|
+
run_phase(effects);
|
|
1048
1379
|
}
|
|
1049
1380
|
|
|
1050
1381
|
/**
|
|
1051
|
-
* @param {Block[]}
|
|
1382
|
+
* @param {Block[]} blocks
|
|
1052
1383
|
*/
|
|
1053
|
-
function
|
|
1054
|
-
for (
|
|
1055
|
-
|
|
1056
|
-
|
|
1384
|
+
function run_phase(blocks) {
|
|
1385
|
+
for (var i = 0; i < blocks.length; i++) {
|
|
1386
|
+
var block = blocks[i];
|
|
1387
|
+
var flags = block.f;
|
|
1057
1388
|
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1389
|
+
try {
|
|
1390
|
+
if ((flags & (PAUSED | DESTROYED)) === 0 && is_block_dirty(block)) {
|
|
1391
|
+
// A block that has never run has no children or teardown to clear.
|
|
1392
|
+
run_block(block, (flags & BLOCK_HAS_RUN) === 0);
|
|
1393
|
+
}
|
|
1394
|
+
} catch (error) {
|
|
1395
|
+
handle_error(error, block);
|
|
1063
1396
|
}
|
|
1064
1397
|
}
|
|
1065
1398
|
}
|
|
@@ -1091,14 +1424,21 @@ function flush_microtasks() {
|
|
|
1091
1424
|
'Maximum update depth exceeded. This typically indicates that an effect reads and writes the same piece of state.',
|
|
1092
1425
|
);
|
|
1093
1426
|
}
|
|
1094
|
-
var
|
|
1095
|
-
|
|
1096
|
-
|
|
1427
|
+
var pending = queue;
|
|
1428
|
+
queue = create_queue();
|
|
1429
|
+
flush_depth++;
|
|
1430
|
+
try {
|
|
1431
|
+
flush_queue(pending);
|
|
1432
|
+
} finally {
|
|
1433
|
+
flush_depth--;
|
|
1434
|
+
}
|
|
1097
1435
|
|
|
1098
1436
|
if (!is_micro_task_queued) {
|
|
1099
1437
|
flush_count = 0;
|
|
1100
1438
|
}
|
|
1101
|
-
|
|
1439
|
+
if (flush_depth === 0) {
|
|
1440
|
+
release_old_values();
|
|
1441
|
+
}
|
|
1102
1442
|
}
|
|
1103
1443
|
|
|
1104
1444
|
/**
|
|
@@ -1128,64 +1468,27 @@ export function queue_post_block_flush_callback(fn) {
|
|
|
1128
1468
|
* @param {Block} block
|
|
1129
1469
|
*/
|
|
1130
1470
|
export function schedule_update(block) {
|
|
1471
|
+
if ((block.f & SCHEDULED) !== 0) {
|
|
1472
|
+
return;
|
|
1473
|
+
}
|
|
1474
|
+
block.f |= SCHEDULED;
|
|
1475
|
+
|
|
1131
1476
|
if (scheduler_mode === FLUSH_MICROTASK) {
|
|
1132
1477
|
queue_microtask();
|
|
1133
1478
|
}
|
|
1134
|
-
// The scheduled block roots the subtree that flush_updates scans for dirty
|
|
1135
|
-
// subscribers. Mark it even if it (or an ancestor) is already on a routing
|
|
1136
|
-
// path, so the early return below still records it as a scan root.
|
|
1137
|
-
block.f |= UPDATE_SOURCE;
|
|
1138
|
-
let current = block;
|
|
1139
|
-
|
|
1140
|
-
while (current !== null) {
|
|
1141
|
-
var flags = current.f;
|
|
1142
|
-
if ((flags & CONTAINS_UPDATE) !== 0) return;
|
|
1143
|
-
current.f ^= CONTAINS_UPDATE;
|
|
1144
|
-
if ((flags & ROOT_BLOCK) !== 0) {
|
|
1145
|
-
break;
|
|
1146
|
-
}
|
|
1147
|
-
current = /** @type {Block} */ (current.p);
|
|
1148
|
-
}
|
|
1149
1479
|
|
|
1150
|
-
|
|
1480
|
+
var id = block.i;
|
|
1481
|
+
if (id < queue.last) {
|
|
1482
|
+
queue.sorted = false;
|
|
1483
|
+
}
|
|
1484
|
+
queue.last = id;
|
|
1485
|
+
queue.blocks.push(block);
|
|
1151
1486
|
}
|
|
1152
1487
|
|
|
1153
1488
|
/**
|
|
1154
1489
|
* @param {Tracked | Derived} tracked
|
|
1155
1490
|
*/
|
|
1156
1491
|
function register_dependency(tracked) {
|
|
1157
|
-
if (!disable_scoped_flush && active_block !== null && active_block !== tracked.b) {
|
|
1158
|
-
// Scoped flush only scans the owner's subtree for dirty subscribers, valid
|
|
1159
|
-
// only while every subscriber lives inside it. The subscriber↔owner
|
|
1160
|
-
// ancestry is structural and stable for a block's lifetime (its `.p` chain
|
|
1161
|
-
// never changes — DOM moves don't reparent blocks), so we only need to
|
|
1162
|
-
// verify *new* dependency edges: if this reaction already depended on
|
|
1163
|
-
// `tracked` on its previous run (it's in the prior chain), the ancestry
|
|
1164
|
-
// walk was already done — skip it. This keeps the (possibly deep) walk off
|
|
1165
|
-
// the hot path for the common case of stable subscriptions.
|
|
1166
|
-
var already_seen = false;
|
|
1167
|
-
var prev_dep = active_reaction === null ? null : active_reaction.d;
|
|
1168
|
-
while (prev_dep !== null) {
|
|
1169
|
-
if (prev_dep.t === tracked) {
|
|
1170
|
-
already_seen = true;
|
|
1171
|
-
break;
|
|
1172
|
-
}
|
|
1173
|
-
prev_dep = prev_dep.n;
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1176
|
-
if (!already_seen) {
|
|
1177
|
-
var owner = tracked.b;
|
|
1178
|
-
/** @type {Block | null} */
|
|
1179
|
-
var node = active_block;
|
|
1180
|
-
while (node !== null && node !== owner) {
|
|
1181
|
-
node = node.p;
|
|
1182
|
-
}
|
|
1183
|
-
if (node === null) {
|
|
1184
|
-
disable_scoped_flush = true;
|
|
1185
|
-
}
|
|
1186
|
-
}
|
|
1187
|
-
}
|
|
1188
|
-
|
|
1189
1492
|
var dependency = active_dependency;
|
|
1190
1493
|
|
|
1191
1494
|
if (dependency === null) {
|
|
@@ -1247,75 +1550,26 @@ export function get(tracked) {
|
|
|
1247
1550
|
: get_tracked(/** @type {Tracked} */ (tracked));
|
|
1248
1551
|
}
|
|
1249
1552
|
|
|
1250
|
-
/**
|
|
1251
|
-
* @param {any} lazy
|
|
1252
|
-
* @param {number} [index]
|
|
1253
|
-
* @returns {any}
|
|
1254
|
-
*/
|
|
1255
|
-
export function lazy_array_get(lazy, index = 0) {
|
|
1256
|
-
if (is_array(lazy)) {
|
|
1257
|
-
return lazy[index];
|
|
1258
|
-
}
|
|
1259
|
-
var flags = lazy.f;
|
|
1260
|
-
if (flags === TRACKED) {
|
|
1261
|
-
return index === 0
|
|
1262
|
-
? get_tracked(/** @type {Tracked} */ (lazy))
|
|
1263
|
-
: index === 1
|
|
1264
|
-
? lazy
|
|
1265
|
-
: undefined;
|
|
1266
|
-
}
|
|
1267
|
-
if (flags === DERIVED) {
|
|
1268
|
-
return index === 0
|
|
1269
|
-
? get_derived(/** @type {Derived} */ (lazy))
|
|
1270
|
-
: index === 1
|
|
1271
|
-
? lazy
|
|
1272
|
-
: undefined;
|
|
1273
|
-
}
|
|
1274
|
-
return iterable_array_from(lazy, index)[0];
|
|
1275
|
-
}
|
|
1276
|
-
|
|
1277
|
-
/**
|
|
1278
|
-
* @param {any} lazy
|
|
1279
|
-
* @param {number} [index]
|
|
1280
|
-
* @returns {any[]}
|
|
1281
|
-
*/
|
|
1282
|
-
export function lazy_array_rest(lazy, index = 0) {
|
|
1283
|
-
if (is_array(lazy)) {
|
|
1284
|
-
return lazy.slice(index);
|
|
1285
|
-
}
|
|
1286
|
-
var flags = lazy.f;
|
|
1287
|
-
if (flags === TRACKED) {
|
|
1288
|
-
return index === 0
|
|
1289
|
-
? [get_tracked(/** @type {Tracked} */ (lazy)), lazy]
|
|
1290
|
-
: index === 1
|
|
1291
|
-
? [lazy]
|
|
1292
|
-
: [];
|
|
1293
|
-
}
|
|
1294
|
-
if (flags === DERIVED) {
|
|
1295
|
-
return index === 0
|
|
1296
|
-
? [get_derived(/** @type {Derived} */ (lazy)), lazy]
|
|
1297
|
-
: index === 1
|
|
1298
|
-
? [lazy]
|
|
1299
|
-
: [];
|
|
1300
|
-
}
|
|
1301
|
-
return iterable_array_from(lazy, index);
|
|
1302
|
-
}
|
|
1303
|
-
|
|
1304
1553
|
/**
|
|
1305
1554
|
* @param {Tracked} tracked
|
|
1306
1555
|
*/
|
|
1307
1556
|
export function get_tracked(tracked) {
|
|
1308
1557
|
var value = tracked.__v;
|
|
1309
1558
|
if (tracking) {
|
|
1310
|
-
register_dependency
|
|
1559
|
+
// register_dependency, inline for the first read of a run.
|
|
1560
|
+
if (active_dependency === null) {
|
|
1561
|
+
active_dependency = create_dependency(tracked);
|
|
1562
|
+
} else {
|
|
1563
|
+
register_dependency(tracked);
|
|
1564
|
+
}
|
|
1311
1565
|
}
|
|
1312
1566
|
|
|
1313
1567
|
if (value === SUSPENSE_PENDING || value === SUSPENSE_REJECTED) {
|
|
1314
1568
|
throw ASYNC_DERIVED_READ_THROWN;
|
|
1315
1569
|
}
|
|
1316
1570
|
|
|
1317
|
-
if (teardown &&
|
|
1318
|
-
value =
|
|
1571
|
+
if (teardown && tracked.o !== UNINITIALIZED) {
|
|
1572
|
+
value = tracked.o;
|
|
1319
1573
|
}
|
|
1320
1574
|
var get = tracked.a.get;
|
|
1321
1575
|
if (get !== undefined) {
|
|
@@ -1324,57 +1578,6 @@ export function get_tracked(tracked) {
|
|
|
1324
1578
|
return value;
|
|
1325
1579
|
}
|
|
1326
1580
|
|
|
1327
|
-
/**
|
|
1328
|
-
* @param {any} lazy
|
|
1329
|
-
* @param {any} value
|
|
1330
|
-
* @param {number} [index]
|
|
1331
|
-
* @returns {void}
|
|
1332
|
-
*/
|
|
1333
|
-
export function lazy_array_set(lazy, value, index = 0) {
|
|
1334
|
-
if (is_array(lazy)) {
|
|
1335
|
-
lazy[index] = value;
|
|
1336
|
-
return;
|
|
1337
|
-
}
|
|
1338
|
-
var flags = lazy.f;
|
|
1339
|
-
if (flags === TRACKED || flags === DERIVED) {
|
|
1340
|
-
if (index === 0) {
|
|
1341
|
-
set(/** @type {Derived | Tracked} */ (lazy), value);
|
|
1342
|
-
return;
|
|
1343
|
-
}
|
|
1344
|
-
if (index === 1) {
|
|
1345
|
-
throw_tracked_index_reference_error();
|
|
1346
|
-
}
|
|
1347
|
-
return;
|
|
1348
|
-
}
|
|
1349
|
-
lazy[index] = value;
|
|
1350
|
-
}
|
|
1351
|
-
|
|
1352
|
-
/**
|
|
1353
|
-
* @param {any} lazy
|
|
1354
|
-
* @param {number} [index]
|
|
1355
|
-
* @param {number} [d]
|
|
1356
|
-
* @returns {number}
|
|
1357
|
-
*/
|
|
1358
|
-
export function lazy_array_update(lazy, index = 0, d = 1) {
|
|
1359
|
-
var value = lazy_array_get(lazy, index);
|
|
1360
|
-
var result = d === 1 ? value++ : value--;
|
|
1361
|
-
lazy_array_set(lazy, value, index);
|
|
1362
|
-
return result;
|
|
1363
|
-
}
|
|
1364
|
-
|
|
1365
|
-
/**
|
|
1366
|
-
* @param {any} lazy
|
|
1367
|
-
* @param {number} [index]
|
|
1368
|
-
* @param {number} [d]
|
|
1369
|
-
* @returns {number}
|
|
1370
|
-
*/
|
|
1371
|
-
export function lazy_array_update_pre(lazy, index = 0, d = 1) {
|
|
1372
|
-
var value = lazy_array_get(lazy, index);
|
|
1373
|
-
var new_value = d === 1 ? ++value : --value;
|
|
1374
|
-
lazy_array_set(lazy, new_value, index);
|
|
1375
|
-
return new_value;
|
|
1376
|
-
}
|
|
1377
|
-
|
|
1378
1581
|
/**
|
|
1379
1582
|
* @param {Derived | Tracked} tracked
|
|
1380
1583
|
* @param {any} value
|
|
@@ -1392,24 +1595,42 @@ export function set(tracked, value) {
|
|
|
1392
1595
|
var tracked_block = tracked.b;
|
|
1393
1596
|
|
|
1394
1597
|
if ((tracked_block.f & CONTAINS_TEARDOWN) !== 0) {
|
|
1395
|
-
if (
|
|
1396
|
-
|
|
1397
|
-
} else {
|
|
1398
|
-
old_values.set(tracked, old_value);
|
|
1598
|
+
if (tracked.o === UNINITIALIZED) {
|
|
1599
|
+
old_value_holders.push(tracked);
|
|
1399
1600
|
}
|
|
1601
|
+
tracked.o = teardown ? value : old_value;
|
|
1400
1602
|
}
|
|
1401
1603
|
|
|
1402
1604
|
let set = tracked.a.set;
|
|
1403
|
-
if (set
|
|
1605
|
+
if (typeof set === 'function') {
|
|
1404
1606
|
value = untrack(() => set(value, old_value));
|
|
1607
|
+
} else if (DEV && set === undefined && (tracked.f & DERIVED) !== 0) {
|
|
1608
|
+
warn_readonly_derived_write(/** @type {Derived} */ (tracked));
|
|
1405
1609
|
}
|
|
1406
1610
|
|
|
1407
1611
|
tracked.__v = value;
|
|
1408
1612
|
tracked.c = increment_clock();
|
|
1409
|
-
|
|
1613
|
+
mark_subscribers(tracked);
|
|
1410
1614
|
}
|
|
1411
1615
|
}
|
|
1412
1616
|
|
|
1617
|
+
/** @type {WeakSet<object>} */
|
|
1618
|
+
var warned_derived = new WeakSet();
|
|
1619
|
+
|
|
1620
|
+
/**
|
|
1621
|
+
* A derived created without a setter is read-only by contract (`Derived<V>`);
|
|
1622
|
+
* a write still lands as a temporary value until the next recompute, so in
|
|
1623
|
+
* development it is reported once per derived.
|
|
1624
|
+
* @param {Derived} derived
|
|
1625
|
+
*/
|
|
1626
|
+
function warn_readonly_derived_write(derived) {
|
|
1627
|
+
if (warned_derived.has(derived)) return;
|
|
1628
|
+
warned_derived.add(derived);
|
|
1629
|
+
console.warn(
|
|
1630
|
+
'Writing to a read-only derived. Create it with a setter, `track(fn, undefined, true)` or `track(fn, get, set)`, when it is meant to be written.',
|
|
1631
|
+
);
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1413
1634
|
/**
|
|
1414
1635
|
* @template T
|
|
1415
1636
|
* @param {() => T} fn
|
|
@@ -1435,144 +1656,43 @@ export function untrack(fn) {
|
|
|
1435
1656
|
*/
|
|
1436
1657
|
export function flush_sync(fn) {
|
|
1437
1658
|
var previous_scheduler_mode = scheduler_mode;
|
|
1438
|
-
var
|
|
1659
|
+
var previous_queue = queue;
|
|
1439
1660
|
|
|
1661
|
+
flush_depth++;
|
|
1440
1662
|
try {
|
|
1441
|
-
/** @type {Block[]} */
|
|
1442
|
-
var root_blocks = [];
|
|
1443
|
-
|
|
1444
1663
|
scheduler_mode = FLUSH_SYNC;
|
|
1445
|
-
|
|
1664
|
+
queue = create_queue();
|
|
1446
1665
|
is_micro_task_queued = false;
|
|
1447
1666
|
|
|
1448
|
-
|
|
1667
|
+
// Drains previous_queue, which then stays empty for the restore below.
|
|
1668
|
+
flush_queue(previous_queue);
|
|
1449
1669
|
|
|
1450
1670
|
var result = fn?.();
|
|
1451
1671
|
|
|
1452
|
-
|
|
1453
|
-
|
|
1672
|
+
// Each pass runs the blocks scheduled by the previous one.
|
|
1673
|
+
while (queue.blocks.length > 0) {
|
|
1674
|
+
var pending = queue;
|
|
1675
|
+
queue = create_queue();
|
|
1676
|
+
flush_queue(pending);
|
|
1454
1677
|
}
|
|
1455
1678
|
|
|
1456
1679
|
flush_count = 0;
|
|
1457
1680
|
|
|
1681
|
+
// Old values only matter to teardowns run by the flush in progress; a
|
|
1682
|
+
// sync flush nested in another flush (an effect calling `flushSync`)
|
|
1683
|
+
// leaves them for the outer flush's remaining teardowns.
|
|
1684
|
+
if (flush_depth === 1) {
|
|
1685
|
+
release_old_values();
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1458
1688
|
return /** @type {T} */ (result);
|
|
1459
1689
|
} finally {
|
|
1690
|
+
flush_depth--;
|
|
1460
1691
|
scheduler_mode = previous_scheduler_mode;
|
|
1461
|
-
|
|
1692
|
+
queue = previous_queue;
|
|
1462
1693
|
}
|
|
1463
1694
|
}
|
|
1464
1695
|
|
|
1465
|
-
/**
|
|
1466
|
-
* @param {() => Object} fn
|
|
1467
|
-
* @returns {Object}
|
|
1468
|
-
*/
|
|
1469
|
-
export function spread_props(fn) {
|
|
1470
|
-
return proxy_props(fn);
|
|
1471
|
-
}
|
|
1472
|
-
|
|
1473
|
-
/**
|
|
1474
|
-
* @param {() => Object} fn
|
|
1475
|
-
* @returns {Object}
|
|
1476
|
-
*/
|
|
1477
|
-
export function proxy_props(fn) {
|
|
1478
|
-
const memo = derived(fn, /** @type {Block} */ (active_block));
|
|
1479
|
-
|
|
1480
|
-
return new Proxy(
|
|
1481
|
-
{},
|
|
1482
|
-
{
|
|
1483
|
-
get(_, property) {
|
|
1484
|
-
/** @type {Record<string | symbol, any> | Record<string | symbol, any>[]} */
|
|
1485
|
-
var obj = get_derived(memo);
|
|
1486
|
-
|
|
1487
|
-
// Handle array of objects/spreads (for multiple props)
|
|
1488
|
-
if (is_array(obj)) {
|
|
1489
|
-
// Search in reverse order (right-to-left) since later props override earlier ones
|
|
1490
|
-
/** @type {Record<string | symbol, any>} */
|
|
1491
|
-
var item;
|
|
1492
|
-
for (var i = obj.length - 1; i >= 0; i--) {
|
|
1493
|
-
item = obj[i];
|
|
1494
|
-
if (property in item) {
|
|
1495
|
-
return item[property];
|
|
1496
|
-
}
|
|
1497
|
-
}
|
|
1498
|
-
return undefined;
|
|
1499
|
-
}
|
|
1500
|
-
|
|
1501
|
-
// Single object case
|
|
1502
|
-
return obj[property];
|
|
1503
|
-
},
|
|
1504
|
-
has(_, property) {
|
|
1505
|
-
if (property === TRACKED_OBJECT) {
|
|
1506
|
-
return true;
|
|
1507
|
-
}
|
|
1508
|
-
/** @type {Record<string | symbol, any> | Record<string | symbol, any>[]} */
|
|
1509
|
-
var obj = get_derived(memo);
|
|
1510
|
-
|
|
1511
|
-
// Handle array of objects/spreads
|
|
1512
|
-
if (is_array(obj)) {
|
|
1513
|
-
for (var i = obj.length - 1; i >= 0; i--) {
|
|
1514
|
-
if (property in obj[i]) {
|
|
1515
|
-
return true;
|
|
1516
|
-
}
|
|
1517
|
-
}
|
|
1518
|
-
return false;
|
|
1519
|
-
}
|
|
1520
|
-
|
|
1521
|
-
return property in obj;
|
|
1522
|
-
},
|
|
1523
|
-
getOwnPropertyDescriptor(_, key) {
|
|
1524
|
-
/** @type {Record<string | symbol, any> | Record<string | symbol, any>[]} */
|
|
1525
|
-
var obj = get_derived(memo);
|
|
1526
|
-
|
|
1527
|
-
// Handle array of objects/spreads
|
|
1528
|
-
if (is_array(obj)) {
|
|
1529
|
-
/** @type {Record<string | symbol, any>} */
|
|
1530
|
-
var item;
|
|
1531
|
-
for (var i = obj.length - 1; i >= 0; i--) {
|
|
1532
|
-
item = obj[i];
|
|
1533
|
-
if (key in item) {
|
|
1534
|
-
return get_descriptor(item, key);
|
|
1535
|
-
}
|
|
1536
|
-
}
|
|
1537
|
-
return undefined;
|
|
1538
|
-
}
|
|
1539
|
-
|
|
1540
|
-
if (key in obj) {
|
|
1541
|
-
return get_descriptor(obj, key);
|
|
1542
|
-
}
|
|
1543
|
-
},
|
|
1544
|
-
ownKeys() {
|
|
1545
|
-
/** @type {Record<string | symbol, any> | Record<string | symbol, any>[]} */
|
|
1546
|
-
var obj = get_derived(memo);
|
|
1547
|
-
/** @type {Record<string | symbol, 1>} */
|
|
1548
|
-
var done = {};
|
|
1549
|
-
/** @type {(string | symbol)[]} */
|
|
1550
|
-
var keys = [];
|
|
1551
|
-
|
|
1552
|
-
// Handle array of objects/spreads
|
|
1553
|
-
if (is_array(obj)) {
|
|
1554
|
-
// Collect all keys from all objects, order doesn't matter
|
|
1555
|
-
/** @type {Record<string | symbol, any>} */
|
|
1556
|
-
var item;
|
|
1557
|
-
for (var i = 0; i < obj.length; i++) {
|
|
1558
|
-
item = obj[i];
|
|
1559
|
-
for (const key of Reflect.ownKeys(item)) {
|
|
1560
|
-
if (done[key]) {
|
|
1561
|
-
continue;
|
|
1562
|
-
}
|
|
1563
|
-
done[key] = 1;
|
|
1564
|
-
keys.push(key);
|
|
1565
|
-
}
|
|
1566
|
-
}
|
|
1567
|
-
return keys;
|
|
1568
|
-
}
|
|
1569
|
-
|
|
1570
|
-
return Reflect.ownKeys(obj);
|
|
1571
|
-
},
|
|
1572
|
-
},
|
|
1573
|
-
);
|
|
1574
|
-
}
|
|
1575
|
-
|
|
1576
1696
|
/**
|
|
1577
1697
|
* @template T
|
|
1578
1698
|
* @param {() => T} fn
|
|
@@ -1742,7 +1862,7 @@ export function safe_scope(err = 'Cannot access outside of a component context')
|
|
|
1742
1862
|
export function create_component_ctx() {
|
|
1743
1863
|
return {
|
|
1744
1864
|
b: active_block,
|
|
1745
|
-
c: null,
|
|
1865
|
+
c: active_component === null ? null : active_component.c,
|
|
1746
1866
|
e: null,
|
|
1747
1867
|
m: false,
|
|
1748
1868
|
p: active_component,
|
|
@@ -1753,8 +1873,7 @@ export function create_component_ctx() {
|
|
|
1753
1873
|
* @returns {void}
|
|
1754
1874
|
*/
|
|
1755
1875
|
export function push_component() {
|
|
1756
|
-
|
|
1757
|
-
active_component = component;
|
|
1876
|
+
active_component = create_component_ctx();
|
|
1758
1877
|
}
|
|
1759
1878
|
|
|
1760
1879
|
/**
|
|
@@ -1763,27 +1882,168 @@ export function push_component() {
|
|
|
1763
1882
|
export function pop_component() {
|
|
1764
1883
|
var component = /** @type {Component} */ (active_component);
|
|
1765
1884
|
component.m = true;
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
var previous_block = active_block;
|
|
1772
|
-
var previous_reaction = active_reaction;
|
|
1885
|
+
if (component.e !== null) {
|
|
1886
|
+
create_deferred_effects(component.e);
|
|
1887
|
+
}
|
|
1888
|
+
active_component = component.p;
|
|
1889
|
+
}
|
|
1773
1890
|
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1891
|
+
/**
|
|
1892
|
+
* Renders a component: `fn(props)` runs under a fresh component context (the
|
|
1893
|
+
* owner of the component's context values and deferred effects), and the
|
|
1894
|
+
* element it returns renders before `anchor`.
|
|
1895
|
+
* @param {Function} fn
|
|
1896
|
+
* @param {Node | AppendIntoAnchor} anchor
|
|
1897
|
+
* @param {Record<string, any>} props
|
|
1898
|
+
* @param {Block | null} [block=active_block]
|
|
1899
|
+
* @returns {void}
|
|
1900
|
+
*/
|
|
1901
|
+
export function render_component(fn, anchor, props, block = active_block) {
|
|
1902
|
+
// An optional component (an undefined prop, an import that resolved to
|
|
1903
|
+
// nothing) renders nothing; any other non-function is a programming error.
|
|
1904
|
+
if (fn == null) {
|
|
1905
|
+
return;
|
|
1906
|
+
}
|
|
1907
|
+
if (typeof fn !== 'function') {
|
|
1908
|
+
throw_invalid_component_type(fn);
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1911
|
+
// push_component, inline: one component per call is the common case.
|
|
1912
|
+
var parent = active_component;
|
|
1913
|
+
/** @type {Component} */
|
|
1914
|
+
var component = (active_component = {
|
|
1915
|
+
b: active_block,
|
|
1916
|
+
c: parent === null ? null : parent.c,
|
|
1917
|
+
e: null,
|
|
1918
|
+
m: false,
|
|
1919
|
+
p: parent,
|
|
1920
|
+
});
|
|
1921
|
+
|
|
1922
|
+
// A module-level component carries its render function under a symbol
|
|
1923
|
+
// (see the compiler): calling it directly skips the element the component
|
|
1924
|
+
// would return only to be rendered here.
|
|
1925
|
+
var render = /** @type {any} */ (fn)[RENDER_ENTRY];
|
|
1926
|
+
if (render !== undefined) {
|
|
1927
|
+
render(anchor, block, props);
|
|
1928
|
+
} else {
|
|
1929
|
+
render_value(fn(props), /** @type {ChildNode} */ (anchor), block);
|
|
1930
|
+
}
|
|
1931
|
+
|
|
1932
|
+
// pop_component, inline.
|
|
1933
|
+
component.m = true;
|
|
1934
|
+
if (component.e !== null) {
|
|
1935
|
+
create_deferred_effects(component.e);
|
|
1783
1936
|
}
|
|
1784
1937
|
active_component = component.p;
|
|
1785
1938
|
}
|
|
1786
1939
|
|
|
1940
|
+
/**
|
|
1941
|
+
* A reaction that stands in for a block whose creation is being decided (see
|
|
1942
|
+
* `probe_if`). Flagged destroyed so a write during the probe prunes
|
|
1943
|
+
* its subscription instead of scheduling it.
|
|
1944
|
+
* @type {any}
|
|
1945
|
+
*/
|
|
1946
|
+
var probe_reaction = { f: DESTROYED, d: null, blocks: null };
|
|
1947
|
+
|
|
1948
|
+
/**
|
|
1949
|
+
* Evaluates an if condition once, tracked, against a scratch reaction that is
|
|
1950
|
+
* never scheduled. When the evaluation recorded no dependency the condition
|
|
1951
|
+
* can never re-run (a block with no dependencies is never scheduled), so the
|
|
1952
|
+
* selected branch is rendered straight away, untracked, and true is returned:
|
|
1953
|
+
* the if needs no block. Otherwise the recorded links are unlinked again and
|
|
1954
|
+
* false is returned: the caller creates the block, whose own first run
|
|
1955
|
+
* evaluates the condition and subscribes it. The links are never handed to
|
|
1956
|
+
* the block, because a write during the block's first run (a child's setup,
|
|
1957
|
+
* a nested if) would prune links that still point at this destroyed reaction
|
|
1958
|
+
* before the block could take them over. A throwing condition (a pending
|
|
1959
|
+
* async read) unlinks what it recorded and rethrows.
|
|
1960
|
+
* @param {(x: any) => any} fn
|
|
1961
|
+
* @param {any} x
|
|
1962
|
+
* @param {Node | import('#client').AppendIntoAnchor} node
|
|
1963
|
+
* @returns {boolean} whether the branch was rendered without a block
|
|
1964
|
+
*/
|
|
1965
|
+
export function probe_if(fn, x, node) {
|
|
1966
|
+
var previous_reaction = active_reaction;
|
|
1967
|
+
var previous_tracking = tracking;
|
|
1968
|
+
var previous_dependency = active_dependency;
|
|
1969
|
+
active_reaction = probe_reaction;
|
|
1970
|
+
tracking = true;
|
|
1971
|
+
active_dependency = null;
|
|
1972
|
+
/** @type {Dependency | null} */
|
|
1973
|
+
var recorded;
|
|
1974
|
+
/** @type {any} */
|
|
1975
|
+
var branch;
|
|
1976
|
+
try {
|
|
1977
|
+
branch = fn(x);
|
|
1978
|
+
recorded = active_dependency;
|
|
1979
|
+
} catch (error) {
|
|
1980
|
+
unlink_dependencies(active_dependency);
|
|
1981
|
+
active_reaction = previous_reaction;
|
|
1982
|
+
tracking = previous_tracking;
|
|
1983
|
+
active_dependency = previous_dependency;
|
|
1984
|
+
throw error;
|
|
1985
|
+
}
|
|
1986
|
+
active_reaction = previous_reaction;
|
|
1987
|
+
active_dependency = previous_dependency;
|
|
1988
|
+
if (recorded !== null) {
|
|
1989
|
+
unlink_dependencies(recorded);
|
|
1990
|
+
tracking = previous_tracking;
|
|
1991
|
+
return false;
|
|
1992
|
+
}
|
|
1993
|
+
// The branch renders untracked, like a branch block would; `tracking` is
|
|
1994
|
+
// restored by the enclosing `run_block` if the branch throws.
|
|
1995
|
+
if (branch !== undefined) {
|
|
1996
|
+
tracking = false;
|
|
1997
|
+
branch(node, x);
|
|
1998
|
+
}
|
|
1999
|
+
tracking = previous_tracking;
|
|
2000
|
+
return true;
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
/**
|
|
2004
|
+
* @param {Dependency | null} dependency the head of a recorded chain
|
|
2005
|
+
*/
|
|
2006
|
+
function unlink_dependencies(dependency) {
|
|
2007
|
+
while (dependency !== null) {
|
|
2008
|
+
unlink_subscriber(dependency);
|
|
2009
|
+
dependency = dependency.n;
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
|
|
2013
|
+
/**
|
|
2014
|
+
* Calls `fn(arg)` with tracking off, so reads inside it subscribe nothing.
|
|
2015
|
+
* `tracking` is restored by the enclosing `run_block` if `fn` throws.
|
|
2016
|
+
* @param {(arg: any, context: any) => void} fn
|
|
2017
|
+
* @param {any} arg
|
|
2018
|
+
* @param {any} [context]
|
|
2019
|
+
*/
|
|
2020
|
+
export function run_untracked(fn, arg, context) {
|
|
2021
|
+
var previous_tracking = tracking;
|
|
2022
|
+
tracking = false;
|
|
2023
|
+
fn(arg, context);
|
|
2024
|
+
tracking = previous_tracking;
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
/**
|
|
2028
|
+
* Creates the effects a component registered while rendering, each under the
|
|
2029
|
+
* block and reaction that were active at its `effect()` call.
|
|
2030
|
+
* @param {any[]} effects flat triples: fn, block, reaction (see `user_effect`)
|
|
2031
|
+
*/
|
|
2032
|
+
function create_deferred_effects(effects) {
|
|
2033
|
+
// Creating an effect block only links and schedules it, so nothing here
|
|
2034
|
+
// can throw between saving and restoring the active block.
|
|
2035
|
+
var previous_block = active_block;
|
|
2036
|
+
var previous_reaction = active_reaction;
|
|
2037
|
+
var length = effects.length;
|
|
2038
|
+
for (var i = 0; i < length; i += 3) {
|
|
2039
|
+
active_block = /** @type {Block} */ (effects[i + 1]);
|
|
2040
|
+
active_reaction = /** @type {Block | Derived | null} */ (effects[i + 2]);
|
|
2041
|
+
effect(/** @type {Function} */ (effects[i]));
|
|
2042
|
+
}
|
|
2043
|
+
active_block = previous_block;
|
|
2044
|
+
active_reaction = previous_reaction;
|
|
2045
|
+
}
|
|
2046
|
+
|
|
1787
2047
|
/**
|
|
1788
2048
|
* @template T
|
|
1789
2049
|
* @param {() => T} fn
|
|
@@ -1815,40 +2075,3 @@ export function ref_prop() {
|
|
|
1815
2075
|
export function create_ref_prop(get_ref_value, set_ref_value) {
|
|
1816
2076
|
return create_core_ref_prop(() => untrack(get_ref_value), set_ref_value);
|
|
1817
2077
|
}
|
|
1818
|
-
|
|
1819
|
-
/**
|
|
1820
|
-
* @template T
|
|
1821
|
-
* @param {T | undefined} value
|
|
1822
|
-
* @param {T} fallback
|
|
1823
|
-
* @returns {T}
|
|
1824
|
-
*/
|
|
1825
|
-
export function fallback(value, fallback) {
|
|
1826
|
-
return value === undefined ? fallback : value;
|
|
1827
|
-
}
|
|
1828
|
-
|
|
1829
|
-
/**
|
|
1830
|
-
* @param {Record<string | symbol, unknown>} obj
|
|
1831
|
-
* @param {string[]} exclude_keys
|
|
1832
|
-
* @returns {Record<string | symbol, unknown>}
|
|
1833
|
-
*/
|
|
1834
|
-
export function exclude_from_object(obj, exclude_keys) {
|
|
1835
|
-
var keys = object_keys(obj);
|
|
1836
|
-
/** @type {Record<string | symbol, unknown>} */
|
|
1837
|
-
var new_obj = {};
|
|
1838
|
-
|
|
1839
|
-
for (const key of keys) {
|
|
1840
|
-
if (!exclude_keys.includes(key)) {
|
|
1841
|
-
new_obj[key] = obj[key];
|
|
1842
|
-
}
|
|
1843
|
-
}
|
|
1844
|
-
|
|
1845
|
-
for (const symbol of get_own_property_symbols(obj)) {
|
|
1846
|
-
var ref_fn = obj[symbol];
|
|
1847
|
-
|
|
1848
|
-
if (symbol.description === REF_PROP) {
|
|
1849
|
-
new_obj[symbol] = ref_fn;
|
|
1850
|
-
}
|
|
1851
|
-
}
|
|
1852
|
-
|
|
1853
|
-
return new_obj;
|
|
1854
|
-
}
|