ripple 0.3.128 → 0.4.1
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 +294 -0
- package/package.json +11 -4
- package/src/jsx-runtime.d.ts +12 -2
- 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 +44 -43
- 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 +329 -277
- 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 +123 -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 +70 -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/jsx-runtime-types.test.js +67 -2
- package/tests/utils/tracked-types.test.js +117 -0
- package/tests/utils/vite-plugin-config.test.js +23 -0
- package/types/index.d.ts +49 -9
- 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/compiler/__snapshots__/compiler.assignments.test.rsrx.snap +0 -12
- package/tests/client/compiler/__snapshots__/compiler.typescript.test.rsrx.snap +0 -46
- 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 */
|
|
@@ -27,7 +27,6 @@ import {
|
|
|
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,
|
|
@@ -36,33 +35,34 @@ import {
|
|
|
36
35
|
DIRECT_CHILD_BLOCK,
|
|
37
36
|
SCHEDULED,
|
|
38
37
|
SELECTOR,
|
|
38
|
+
IF_BLOCK,
|
|
39
|
+
RELEASED,
|
|
40
|
+
RENDER_ENTRY,
|
|
41
|
+
CREATES_DERIVEDS,
|
|
39
42
|
} from './constants.js';
|
|
40
43
|
import {
|
|
41
44
|
begin_boundary_request,
|
|
42
45
|
complete_boundary_request,
|
|
43
46
|
get_boundary_with_catch,
|
|
44
47
|
get_pending_boundary,
|
|
48
|
+
handle_boundary_error,
|
|
45
49
|
register_boundary_deferred,
|
|
46
50
|
register_boundary_paused_block,
|
|
47
51
|
replace_boundary_request,
|
|
48
52
|
} from './try.js';
|
|
49
53
|
import { is_ripple_object } from './utils.js';
|
|
54
|
+
import { render_value } from './expression.js';
|
|
55
|
+
import { throw_invalid_component_type } from './component.js';
|
|
50
56
|
|
|
51
57
|
import {
|
|
52
|
-
iterable_array_from,
|
|
53
58
|
define_property,
|
|
54
59
|
get_descriptor,
|
|
55
|
-
get_own_property_symbols,
|
|
56
60
|
is_array,
|
|
57
61
|
object_keys,
|
|
58
62
|
} from '@tsrx/core/runtime/language-helpers';
|
|
59
63
|
import { get_async_track_result } from '../../../utils/async.js';
|
|
60
|
-
import {
|
|
61
|
-
throw_tracked_index_reference_error,
|
|
62
|
-
throw_tracked_index_value_error,
|
|
63
|
-
} from '../../../utils/errors.js';
|
|
64
64
|
import { get_track_async_script_id } from '../../../utils/track-async-serialization.js';
|
|
65
|
-
import
|
|
65
|
+
import { revive } from './transport.js';
|
|
66
66
|
import { hydrating, track_hash_reference } from './hydration.js';
|
|
67
67
|
import { create_ref_prop as create_core_ref_prop } from '@tsrx/core/runtime/ref';
|
|
68
68
|
|
|
@@ -82,8 +82,25 @@ export let active_namespace = DEFAULT_NAMESPACE;
|
|
|
82
82
|
/** @type {boolean} */
|
|
83
83
|
export let is_mutating_allowed = true;
|
|
84
84
|
|
|
85
|
-
/**
|
|
86
|
-
|
|
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
|
+
}
|
|
87
104
|
|
|
88
105
|
// Used for controlling the flush of blocks
|
|
89
106
|
/** @type {number} */
|
|
@@ -168,7 +185,10 @@ export function run_teardown(block) {
|
|
|
168
185
|
active_reaction = null;
|
|
169
186
|
tracking = false;
|
|
170
187
|
teardown = true;
|
|
171
|
-
|
|
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);
|
|
172
192
|
} finally {
|
|
173
193
|
active_block = previous_block;
|
|
174
194
|
active_reaction = previous_reaction;
|
|
@@ -293,13 +313,104 @@ function run_derived(computed) {
|
|
|
293
313
|
export function handle_error(error, block) {
|
|
294
314
|
var boundary_with_catch = get_boundary_with_catch(block);
|
|
295
315
|
if (boundary_with_catch !== null) {
|
|
296
|
-
boundary_with_catch
|
|
316
|
+
handle_boundary_error(boundary_with_catch, error);
|
|
297
317
|
return boundary_with_catch;
|
|
298
318
|
}
|
|
299
319
|
|
|
300
320
|
throw error;
|
|
301
321
|
}
|
|
302
322
|
|
|
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
|
|
329
|
+
* @param {Block} block
|
|
330
|
+
*/
|
|
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
|
+
|
|
303
414
|
/**
|
|
304
415
|
* @param {Block} block
|
|
305
416
|
* @param {boolean} [first_run] true when the block has no children, teardown,
|
|
@@ -311,6 +422,8 @@ export function run_block(block, first_run = false) {
|
|
|
311
422
|
var previous_tracking = tracking;
|
|
312
423
|
var previous_dependency = active_dependency;
|
|
313
424
|
var previous_component = active_component;
|
|
425
|
+
/** @type {Derived[] | null} */
|
|
426
|
+
var previous_deriveds = null;
|
|
314
427
|
|
|
315
428
|
try {
|
|
316
429
|
active_block = block;
|
|
@@ -318,11 +431,7 @@ export function run_block(block, first_run = false) {
|
|
|
318
431
|
active_component = block.co;
|
|
319
432
|
|
|
320
433
|
if (!first_run) {
|
|
321
|
-
|
|
322
|
-
if ((block.f & FOR_BLOCK) === 0) {
|
|
323
|
-
destroy_non_branch_children(block);
|
|
324
|
-
}
|
|
325
|
-
run_teardown(block);
|
|
434
|
+
previous_deriveds = prepare_rerun(block);
|
|
326
435
|
}
|
|
327
436
|
|
|
328
437
|
tracking = (block.f & (ROOT_BLOCK | BRANCH_BLOCK)) === 0;
|
|
@@ -330,71 +439,34 @@ export function run_block(block, first_run = false) {
|
|
|
330
439
|
var res = block.fn(block.s);
|
|
331
440
|
|
|
332
441
|
if (typeof res === 'function') {
|
|
333
|
-
block
|
|
334
|
-
/** @type {Block | null} */
|
|
335
|
-
let current = block;
|
|
336
|
-
|
|
337
|
-
while (current !== null && (current.f & CONTAINS_TEARDOWN) === 0) {
|
|
338
|
-
current.f ^= CONTAINS_TEARDOWN;
|
|
339
|
-
current = current.p;
|
|
340
|
-
}
|
|
442
|
+
register_teardown(block, res);
|
|
341
443
|
}
|
|
342
444
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
finish_dependencies(block, active_dependency);
|
|
348
|
-
// When a derived read throws ASYNC_DERIVED_READ_THROWN, it means the
|
|
349
|
-
// derived is still SUSPENSE_PENDING. The dependency was already registered,
|
|
350
|
-
// so we swallow the throw and let the parent continue processing. When
|
|
351
|
-
// the derived settles, the block will be dirty and rerun automatically.
|
|
352
|
-
if (error !== ASYNC_DERIVED_READ_THROWN) {
|
|
353
|
-
handle_error(error, block);
|
|
354
|
-
} else if (
|
|
355
|
-
// pending async tracked was read outside allowed blocks
|
|
356
|
-
(is_component_direct = active_component?.b === block) ||
|
|
357
|
-
(is_try_fn_block =
|
|
358
|
-
block.p !== null && (block.p.f & TRY_BLOCK) !== 0 && (block.f & DIRECT_CHILD_BLOCK) !== 0)
|
|
359
|
-
) {
|
|
360
|
-
throw new Error(
|
|
361
|
-
`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.`,
|
|
362
|
-
);
|
|
363
|
-
} else {
|
|
364
|
-
// pending async tracked was read and threw ASYNC_DERIVED_READ_THROWN
|
|
365
|
-
var boundary = get_pending_boundary(block);
|
|
366
|
-
if (boundary !== null) {
|
|
367
|
-
pause_block(block);
|
|
368
|
-
register_boundary_paused_block(boundary, block);
|
|
369
|
-
|
|
370
|
-
// Register deferred boundary completions for async tracked deps.
|
|
371
|
-
// This handles the case where a child boundary reads a tracked value
|
|
372
|
-
// whose resolution is managed by a different (parent) boundary.
|
|
373
|
-
var dep = block.d;
|
|
374
|
-
while (dep !== null) {
|
|
375
|
-
var dep_tracked = /** @type {Tracked} */ (dep.t);
|
|
376
|
-
if (
|
|
377
|
-
(dep_tracked.__v === SUSPENSE_PENDING || dep_tracked.__v === SUSPENSE_REJECTED) &&
|
|
378
|
-
(dep_tracked.f & TRACKED) !== 0
|
|
379
|
-
) {
|
|
380
|
-
var deferred_req = begin_boundary_request(boundary);
|
|
381
|
-
var entry = /** @type {DeferredTrackedEntry} */ ({ b: boundary, r: deferred_req });
|
|
382
|
-
if (dep_tracked.d === null) {
|
|
383
|
-
dep_tracked.d = [entry];
|
|
384
|
-
} else {
|
|
385
|
-
dep_tracked.d.push(entry);
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
dep = dep.n;
|
|
389
|
-
}
|
|
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;
|
|
390
449
|
}
|
|
450
|
+
} else {
|
|
451
|
+
finish_dependencies(block, active_dependency);
|
|
391
452
|
}
|
|
453
|
+
} catch (error) {
|
|
454
|
+
handle_run_error(error, block);
|
|
392
455
|
} finally {
|
|
393
456
|
active_block = previous_block;
|
|
394
457
|
active_reaction = previous_reaction;
|
|
395
458
|
tracking = previous_tracking;
|
|
396
459
|
active_dependency = previous_dependency;
|
|
397
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
|
+
}
|
|
398
470
|
}
|
|
399
471
|
}
|
|
400
472
|
|
|
@@ -419,11 +491,11 @@ class TrackedValue {
|
|
|
419
491
|
/**
|
|
420
492
|
* @param {any} v
|
|
421
493
|
* @param {Block} block
|
|
422
|
-
* @param {{ get?: Function; set?: Function }} a
|
|
494
|
+
* @param {{ get?: Function; set?: Function | true }} a
|
|
423
495
|
* @param {string} [hash]
|
|
424
496
|
*/
|
|
425
497
|
constructor(v, block, a, hash) {
|
|
426
|
-
/** @type {{ get?: Function; set?: Function }} */
|
|
498
|
+
/** @type {{ get?: Function; set?: Function | true }} */
|
|
427
499
|
this.a = a;
|
|
428
500
|
/** @type {Block} */
|
|
429
501
|
this.b = block;
|
|
@@ -439,18 +511,8 @@ class TrackedValue {
|
|
|
439
511
|
this.sb = null;
|
|
440
512
|
/** @type {any} */
|
|
441
513
|
this.__v = v;
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
get [0]() {
|
|
445
|
-
return throw_tracked_index_value_error();
|
|
446
|
-
}
|
|
447
|
-
/** @param {any} v */
|
|
448
|
-
set [0](v) {
|
|
449
|
-
throw_tracked_index_value_error();
|
|
450
|
-
}
|
|
451
|
-
/** @returns {Tracked} */
|
|
452
|
-
get [1]() {
|
|
453
|
-
return throw_tracked_index_reference_error();
|
|
514
|
+
/** @type {any} previous value while a flush with teardowns is running */
|
|
515
|
+
this.o = UNINITIALIZED;
|
|
454
516
|
}
|
|
455
517
|
/** @returns {any} */
|
|
456
518
|
get value() {
|
|
@@ -460,14 +522,16 @@ class TrackedValue {
|
|
|
460
522
|
set value(v) {
|
|
461
523
|
set(this, v);
|
|
462
524
|
}
|
|
463
|
-
/**
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
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));
|
|
471
535
|
}
|
|
472
536
|
}
|
|
473
537
|
|
|
@@ -475,11 +539,11 @@ class DerivedValue {
|
|
|
475
539
|
/**
|
|
476
540
|
* @param {Function} fn
|
|
477
541
|
* @param {Block} block
|
|
478
|
-
* @param {{ get?: Function; set?: Function }} a
|
|
542
|
+
* @param {{ get?: Function; set?: Function | true }} a
|
|
479
543
|
* @param {string} [hash]
|
|
480
544
|
*/
|
|
481
545
|
constructor(fn, block, a, hash) {
|
|
482
|
-
/** @type {{ get?: Function; set?: Function }} */
|
|
546
|
+
/** @type {{ get?: Function; set?: Function | true }} */
|
|
483
547
|
this.a = a;
|
|
484
548
|
/** @type {Block} */
|
|
485
549
|
this.b = block;
|
|
@@ -501,18 +565,8 @@ class DerivedValue {
|
|
|
501
565
|
this.sb = null;
|
|
502
566
|
/** @type {any} */
|
|
503
567
|
this.__v = UNINITIALIZED;
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
get [0]() {
|
|
507
|
-
return throw_tracked_index_value_error();
|
|
508
|
-
}
|
|
509
|
-
/** @param {any} v */
|
|
510
|
-
set [0](v) {
|
|
511
|
-
throw_tracked_index_value_error();
|
|
512
|
-
}
|
|
513
|
-
/** @returns {Derived} */
|
|
514
|
-
get [1]() {
|
|
515
|
-
return throw_tracked_index_reference_error();
|
|
568
|
+
/** @type {any} previous value while a flush with teardowns is running */
|
|
569
|
+
this.o = UNINITIALIZED;
|
|
516
570
|
}
|
|
517
571
|
/** @returns {any} */
|
|
518
572
|
get value() {
|
|
@@ -522,14 +576,16 @@ class DerivedValue {
|
|
|
522
576
|
set value(v) {
|
|
523
577
|
set(this, v);
|
|
524
578
|
}
|
|
525
|
-
/**
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
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));
|
|
533
589
|
}
|
|
534
590
|
}
|
|
535
591
|
|
|
@@ -544,7 +600,7 @@ if (DEV) {
|
|
|
544
600
|
* @param {Block} block
|
|
545
601
|
* @param {string} [hash]
|
|
546
602
|
* @param {(value: any) => any} [get]
|
|
547
|
-
* @param {(next: any, prev: any) => any} [set]
|
|
603
|
+
* @param {((next: any, prev: any) => any) | true} [set]
|
|
548
604
|
* @returns {Tracked}
|
|
549
605
|
*/
|
|
550
606
|
export function tracked(v, block, hash, get, set) {
|
|
@@ -562,25 +618,126 @@ export function tracked(v, block, hash, get, set) {
|
|
|
562
618
|
* @param {Block} block
|
|
563
619
|
* @param {string} [hash]
|
|
564
620
|
* @param {(value: any) => any} [get]
|
|
565
|
-
* @param {(next: any, prev: any) => any} [set]
|
|
621
|
+
* @param {((next: any, prev: any) => any) | true} [set]
|
|
566
622
|
* @returns {Derived}
|
|
567
623
|
*/
|
|
568
624
|
export function derived(fn, block, hash, get, set) {
|
|
569
625
|
var d = /** @type {Derived} */ (
|
|
570
626
|
new DerivedValue(fn, block || active_block, get || set ? { get, set } : empty_get_set, hash)
|
|
571
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
|
+
}
|
|
572
641
|
if (hydrating && hash !== undefined) {
|
|
573
642
|
track_hash_reference.set(hash, d);
|
|
574
643
|
}
|
|
575
644
|
return d;
|
|
576
645
|
}
|
|
577
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
|
+
|
|
578
735
|
/**
|
|
579
736
|
* @param {any} v
|
|
580
737
|
* @param {Block} b
|
|
581
738
|
* @param {string} [hash]
|
|
582
739
|
* @param {(value: any) => any} [get]
|
|
583
|
-
* @param {(next: any, prev: any) => any} [set]
|
|
740
|
+
* @param {((next: any, prev: any) => any) | true} [set]
|
|
584
741
|
* @returns {Tracked | Derived}
|
|
585
742
|
*/
|
|
586
743
|
export function track(v, b, hash, get, set) {
|
|
@@ -634,7 +791,8 @@ export function track_async(fn, b, hash) {
|
|
|
634
791
|
|
|
635
792
|
if (envelope.ok) {
|
|
636
793
|
had_hydration_data = true;
|
|
637
|
-
hydration_value =
|
|
794
|
+
hydration_value =
|
|
795
|
+
envelope.payload === undefined ? envelope.value : revive(envelope.payload);
|
|
638
796
|
hydration_deps = envelope.deps;
|
|
639
797
|
} else {
|
|
640
798
|
// trigger the catch block
|
|
@@ -810,7 +968,7 @@ export function track_async(fn, b, hash) {
|
|
|
810
968
|
// Route error to catch boundary
|
|
811
969
|
var boundary_with_catch = get_boundary_with_catch(call_site_block);
|
|
812
970
|
if (boundary_with_catch !== null) {
|
|
813
|
-
boundary_with_catch
|
|
971
|
+
handle_boundary_error(boundary_with_catch, error);
|
|
814
972
|
}
|
|
815
973
|
|
|
816
974
|
if (request_id > 0 && boundary !== null) {
|
|
@@ -886,6 +1044,8 @@ function create_dependency(tracked) {
|
|
|
886
1044
|
return existing;
|
|
887
1045
|
}
|
|
888
1046
|
|
|
1047
|
+
// link_subscriber, inline: the first read of every block run lands here.
|
|
1048
|
+
var head = tracked.sb;
|
|
889
1049
|
/** @type {Dependency} */
|
|
890
1050
|
var dependency = {
|
|
891
1051
|
c: tracked.c,
|
|
@@ -893,9 +1053,12 @@ function create_dependency(tracked) {
|
|
|
893
1053
|
n: null,
|
|
894
1054
|
r: reaction,
|
|
895
1055
|
sp: null,
|
|
896
|
-
sn:
|
|
1056
|
+
sn: head,
|
|
897
1057
|
};
|
|
898
|
-
|
|
1058
|
+
if (head !== null) {
|
|
1059
|
+
head.sp = dependency;
|
|
1060
|
+
}
|
|
1061
|
+
tracked.sb = dependency;
|
|
899
1062
|
return dependency;
|
|
900
1063
|
}
|
|
901
1064
|
|
|
@@ -930,8 +1093,7 @@ export function unlink_subscriber(dependency) {
|
|
|
930
1093
|
}
|
|
931
1094
|
tracked.sb = next;
|
|
932
1095
|
if (next === null && (tracked.f & SELECTOR) !== 0) {
|
|
933
|
-
|
|
934
|
-
/** @type {SelectorAccessors} */ (tracked.a).m.delete(tracked.h);
|
|
1096
|
+
release_selector_key(/** @type {Tracked} */ (tracked));
|
|
935
1097
|
}
|
|
936
1098
|
}
|
|
937
1099
|
if (next !== null) {
|
|
@@ -941,9 +1103,43 @@ export function unlink_subscriber(dependency) {
|
|
|
941
1103
|
}
|
|
942
1104
|
|
|
943
1105
|
/**
|
|
944
|
-
*
|
|
1106
|
+
* `n` counts released keys still in the map.
|
|
1107
|
+
* @typedef {{ get: undefined; set: undefined; m: Map<any, Tracked>; n: number }} SelectorAccessors
|
|
945
1108
|
*/
|
|
946
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
|
+
|
|
947
1143
|
/**
|
|
948
1144
|
* A tracked match flag for one selector key. The selector's shared accessor
|
|
949
1145
|
* object carries the map and the key rides in the hash slot, so the entry can
|
|
@@ -1007,13 +1203,14 @@ function mark_subscribers(tracked) {
|
|
|
1007
1203
|
var flags = reaction.f;
|
|
1008
1204
|
if ((flags & DERIVED) !== 0) {
|
|
1009
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);
|
|
1010
1211
|
var derived_owner = derived.b;
|
|
1011
|
-
// A derived whose owner is gone and that nothing reads any more is
|
|
1012
|
-
// pruned; one still read elsewhere keeps forwarding notifications.
|
|
1013
1212
|
if (derived_owner !== null && (derived_owner.f & DESTROYED) !== 0 && derived.sb === null) {
|
|
1014
1213
|
unlink_subscriber(dependency);
|
|
1015
|
-
} else {
|
|
1016
|
-
mark_subscribers(derived);
|
|
1017
1214
|
}
|
|
1018
1215
|
} else if ((flags & DESTROYED) !== 0) {
|
|
1019
1216
|
unlink_subscriber(dependency);
|
|
@@ -1103,11 +1300,55 @@ function by_block_id(a, b) {
|
|
|
1103
1300
|
*/
|
|
1104
1301
|
function flush_queue(pending) {
|
|
1105
1302
|
var blocks = pending.blocks;
|
|
1303
|
+
var length = blocks.length;
|
|
1304
|
+
|
|
1305
|
+
if (length > 0) {
|
|
1306
|
+
if (!pending.sorted) {
|
|
1307
|
+
blocks.sort(by_block_id);
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
var has_effects = false;
|
|
1311
|
+
|
|
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;
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
|
|
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);
|
|
1328
|
+
}
|
|
1106
1329
|
|
|
1107
|
-
|
|
1108
|
-
|
|
1330
|
+
blocks.length = 0;
|
|
1331
|
+
pending.sorted = true;
|
|
1332
|
+
pending.last = 0;
|
|
1109
1333
|
}
|
|
1110
1334
|
|
|
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]();
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
|
|
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) {
|
|
1111
1352
|
/** @type {Block[]} */
|
|
1112
1353
|
var pre_effects = [];
|
|
1113
1354
|
/** @type {Block[]} */
|
|
@@ -1115,10 +1356,9 @@ function flush_queue(pending) {
|
|
|
1115
1356
|
/** @type {Block[]} */
|
|
1116
1357
|
var effects = [];
|
|
1117
1358
|
|
|
1118
|
-
for (var i = 0; i <
|
|
1359
|
+
for (var i = 0; i < length; i++) {
|
|
1119
1360
|
var block = blocks[i];
|
|
1120
1361
|
var flags = block.f;
|
|
1121
|
-
block.f = flags & ~SCHEDULED;
|
|
1122
1362
|
|
|
1123
1363
|
// A paused block is re-checked when it resumes; a destroyed one is gone.
|
|
1124
1364
|
if ((flags & (PAUSED | DESTROYED)) !== 0) {
|
|
@@ -1133,21 +1373,9 @@ function flush_queue(pending) {
|
|
|
1133
1373
|
}
|
|
1134
1374
|
}
|
|
1135
1375
|
|
|
1136
|
-
blocks.length = 0;
|
|
1137
|
-
pending.sorted = true;
|
|
1138
|
-
pending.last = 0;
|
|
1139
|
-
|
|
1140
1376
|
run_phase(pre_effects);
|
|
1141
1377
|
run_phase(other_blocks);
|
|
1142
1378
|
run_phase(effects);
|
|
1143
|
-
|
|
1144
|
-
if (queued_post_block_flush.length > 0) {
|
|
1145
|
-
var callbacks = queued_post_block_flush;
|
|
1146
|
-
queued_post_block_flush = [];
|
|
1147
|
-
for (var j = 0; j < callbacks.length; j++) {
|
|
1148
|
-
callbacks[j]();
|
|
1149
|
-
}
|
|
1150
|
-
}
|
|
1151
1379
|
}
|
|
1152
1380
|
|
|
1153
1381
|
/**
|
|
@@ -1156,10 +1384,12 @@ function flush_queue(pending) {
|
|
|
1156
1384
|
function run_phase(blocks) {
|
|
1157
1385
|
for (var i = 0; i < blocks.length; i++) {
|
|
1158
1386
|
var block = blocks[i];
|
|
1387
|
+
var flags = block.f;
|
|
1159
1388
|
|
|
1160
1389
|
try {
|
|
1161
|
-
if ((
|
|
1162
|
-
|
|
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);
|
|
1163
1393
|
}
|
|
1164
1394
|
} catch (error) {
|
|
1165
1395
|
handle_error(error, block);
|
|
@@ -1196,12 +1426,19 @@ function flush_microtasks() {
|
|
|
1196
1426
|
}
|
|
1197
1427
|
var pending = queue;
|
|
1198
1428
|
queue = create_queue();
|
|
1199
|
-
|
|
1429
|
+
flush_depth++;
|
|
1430
|
+
try {
|
|
1431
|
+
flush_queue(pending);
|
|
1432
|
+
} finally {
|
|
1433
|
+
flush_depth--;
|
|
1434
|
+
}
|
|
1200
1435
|
|
|
1201
1436
|
if (!is_micro_task_queued) {
|
|
1202
1437
|
flush_count = 0;
|
|
1203
1438
|
}
|
|
1204
|
-
|
|
1439
|
+
if (flush_depth === 0) {
|
|
1440
|
+
release_old_values();
|
|
1441
|
+
}
|
|
1205
1442
|
}
|
|
1206
1443
|
|
|
1207
1444
|
/**
|
|
@@ -1313,75 +1550,26 @@ export function get(tracked) {
|
|
|
1313
1550
|
: get_tracked(/** @type {Tracked} */ (tracked));
|
|
1314
1551
|
}
|
|
1315
1552
|
|
|
1316
|
-
/**
|
|
1317
|
-
* @param {any} lazy
|
|
1318
|
-
* @param {number} [index]
|
|
1319
|
-
* @returns {any}
|
|
1320
|
-
*/
|
|
1321
|
-
export function lazy_array_get(lazy, index = 0) {
|
|
1322
|
-
if (is_array(lazy)) {
|
|
1323
|
-
return lazy[index];
|
|
1324
|
-
}
|
|
1325
|
-
var flags = lazy.f;
|
|
1326
|
-
if (flags === TRACKED) {
|
|
1327
|
-
return index === 0
|
|
1328
|
-
? get_tracked(/** @type {Tracked} */ (lazy))
|
|
1329
|
-
: index === 1
|
|
1330
|
-
? lazy
|
|
1331
|
-
: undefined;
|
|
1332
|
-
}
|
|
1333
|
-
if (flags === DERIVED) {
|
|
1334
|
-
return index === 0
|
|
1335
|
-
? get_derived(/** @type {Derived} */ (lazy))
|
|
1336
|
-
: index === 1
|
|
1337
|
-
? lazy
|
|
1338
|
-
: undefined;
|
|
1339
|
-
}
|
|
1340
|
-
return iterable_array_from(lazy, index)[0];
|
|
1341
|
-
}
|
|
1342
|
-
|
|
1343
|
-
/**
|
|
1344
|
-
* @param {any} lazy
|
|
1345
|
-
* @param {number} [index]
|
|
1346
|
-
* @returns {any[]}
|
|
1347
|
-
*/
|
|
1348
|
-
export function lazy_array_rest(lazy, index = 0) {
|
|
1349
|
-
if (is_array(lazy)) {
|
|
1350
|
-
return lazy.slice(index);
|
|
1351
|
-
}
|
|
1352
|
-
var flags = lazy.f;
|
|
1353
|
-
if (flags === TRACKED) {
|
|
1354
|
-
return index === 0
|
|
1355
|
-
? [get_tracked(/** @type {Tracked} */ (lazy)), lazy]
|
|
1356
|
-
: index === 1
|
|
1357
|
-
? [lazy]
|
|
1358
|
-
: [];
|
|
1359
|
-
}
|
|
1360
|
-
if (flags === DERIVED) {
|
|
1361
|
-
return index === 0
|
|
1362
|
-
? [get_derived(/** @type {Derived} */ (lazy)), lazy]
|
|
1363
|
-
: index === 1
|
|
1364
|
-
? [lazy]
|
|
1365
|
-
: [];
|
|
1366
|
-
}
|
|
1367
|
-
return iterable_array_from(lazy, index);
|
|
1368
|
-
}
|
|
1369
|
-
|
|
1370
1553
|
/**
|
|
1371
1554
|
* @param {Tracked} tracked
|
|
1372
1555
|
*/
|
|
1373
1556
|
export function get_tracked(tracked) {
|
|
1374
1557
|
var value = tracked.__v;
|
|
1375
1558
|
if (tracking) {
|
|
1376
|
-
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
|
+
}
|
|
1377
1565
|
}
|
|
1378
1566
|
|
|
1379
1567
|
if (value === SUSPENSE_PENDING || value === SUSPENSE_REJECTED) {
|
|
1380
1568
|
throw ASYNC_DERIVED_READ_THROWN;
|
|
1381
1569
|
}
|
|
1382
1570
|
|
|
1383
|
-
if (teardown &&
|
|
1384
|
-
value =
|
|
1571
|
+
if (teardown && tracked.o !== UNINITIALIZED) {
|
|
1572
|
+
value = tracked.o;
|
|
1385
1573
|
}
|
|
1386
1574
|
var get = tracked.a.get;
|
|
1387
1575
|
if (get !== undefined) {
|
|
@@ -1390,57 +1578,6 @@ export function get_tracked(tracked) {
|
|
|
1390
1578
|
return value;
|
|
1391
1579
|
}
|
|
1392
1580
|
|
|
1393
|
-
/**
|
|
1394
|
-
* @param {any} lazy
|
|
1395
|
-
* @param {any} value
|
|
1396
|
-
* @param {number} [index]
|
|
1397
|
-
* @returns {void}
|
|
1398
|
-
*/
|
|
1399
|
-
export function lazy_array_set(lazy, value, index = 0) {
|
|
1400
|
-
if (is_array(lazy)) {
|
|
1401
|
-
lazy[index] = value;
|
|
1402
|
-
return;
|
|
1403
|
-
}
|
|
1404
|
-
var flags = lazy.f;
|
|
1405
|
-
if (flags === TRACKED || flags === DERIVED) {
|
|
1406
|
-
if (index === 0) {
|
|
1407
|
-
set(/** @type {Derived | Tracked} */ (lazy), value);
|
|
1408
|
-
return;
|
|
1409
|
-
}
|
|
1410
|
-
if (index === 1) {
|
|
1411
|
-
throw_tracked_index_reference_error();
|
|
1412
|
-
}
|
|
1413
|
-
return;
|
|
1414
|
-
}
|
|
1415
|
-
lazy[index] = value;
|
|
1416
|
-
}
|
|
1417
|
-
|
|
1418
|
-
/**
|
|
1419
|
-
* @param {any} lazy
|
|
1420
|
-
* @param {number} [index]
|
|
1421
|
-
* @param {number} [d]
|
|
1422
|
-
* @returns {number}
|
|
1423
|
-
*/
|
|
1424
|
-
export function lazy_array_update(lazy, index = 0, d = 1) {
|
|
1425
|
-
var value = lazy_array_get(lazy, index);
|
|
1426
|
-
var result = d === 1 ? value++ : value--;
|
|
1427
|
-
lazy_array_set(lazy, value, index);
|
|
1428
|
-
return result;
|
|
1429
|
-
}
|
|
1430
|
-
|
|
1431
|
-
/**
|
|
1432
|
-
* @param {any} lazy
|
|
1433
|
-
* @param {number} [index]
|
|
1434
|
-
* @param {number} [d]
|
|
1435
|
-
* @returns {number}
|
|
1436
|
-
*/
|
|
1437
|
-
export function lazy_array_update_pre(lazy, index = 0, d = 1) {
|
|
1438
|
-
var value = lazy_array_get(lazy, index);
|
|
1439
|
-
var new_value = d === 1 ? ++value : --value;
|
|
1440
|
-
lazy_array_set(lazy, new_value, index);
|
|
1441
|
-
return new_value;
|
|
1442
|
-
}
|
|
1443
|
-
|
|
1444
1581
|
/**
|
|
1445
1582
|
* @param {Derived | Tracked} tracked
|
|
1446
1583
|
* @param {any} value
|
|
@@ -1458,16 +1595,17 @@ export function set(tracked, value) {
|
|
|
1458
1595
|
var tracked_block = tracked.b;
|
|
1459
1596
|
|
|
1460
1597
|
if ((tracked_block.f & CONTAINS_TEARDOWN) !== 0) {
|
|
1461
|
-
if (
|
|
1462
|
-
|
|
1463
|
-
} else {
|
|
1464
|
-
old_values.set(tracked, old_value);
|
|
1598
|
+
if (tracked.o === UNINITIALIZED) {
|
|
1599
|
+
old_value_holders.push(tracked);
|
|
1465
1600
|
}
|
|
1601
|
+
tracked.o = teardown ? value : old_value;
|
|
1466
1602
|
}
|
|
1467
1603
|
|
|
1468
1604
|
let set = tracked.a.set;
|
|
1469
|
-
if (set
|
|
1605
|
+
if (typeof set === 'function') {
|
|
1470
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));
|
|
1471
1609
|
}
|
|
1472
1610
|
|
|
1473
1611
|
tracked.__v = value;
|
|
@@ -1476,6 +1614,23 @@ export function set(tracked, value) {
|
|
|
1476
1614
|
}
|
|
1477
1615
|
}
|
|
1478
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
|
+
|
|
1479
1634
|
/**
|
|
1480
1635
|
* @template T
|
|
1481
1636
|
* @param {() => T} fn
|
|
@@ -1503,6 +1658,7 @@ export function flush_sync(fn) {
|
|
|
1503
1658
|
var previous_scheduler_mode = scheduler_mode;
|
|
1504
1659
|
var previous_queue = queue;
|
|
1505
1660
|
|
|
1661
|
+
flush_depth++;
|
|
1506
1662
|
try {
|
|
1507
1663
|
scheduler_mode = FLUSH_SYNC;
|
|
1508
1664
|
queue = create_queue();
|
|
@@ -1513,130 +1669,30 @@ export function flush_sync(fn) {
|
|
|
1513
1669
|
|
|
1514
1670
|
var result = fn?.();
|
|
1515
1671
|
|
|
1516
|
-
|
|
1517
|
-
|
|
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);
|
|
1518
1677
|
}
|
|
1519
1678
|
|
|
1520
1679
|
flush_count = 0;
|
|
1521
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
|
+
|
|
1522
1688
|
return /** @type {T} */ (result);
|
|
1523
1689
|
} finally {
|
|
1690
|
+
flush_depth--;
|
|
1524
1691
|
scheduler_mode = previous_scheduler_mode;
|
|
1525
1692
|
queue = previous_queue;
|
|
1526
1693
|
}
|
|
1527
1694
|
}
|
|
1528
1695
|
|
|
1529
|
-
/**
|
|
1530
|
-
* @param {() => Object} fn
|
|
1531
|
-
* @returns {Object}
|
|
1532
|
-
*/
|
|
1533
|
-
export function spread_props(fn) {
|
|
1534
|
-
return proxy_props(fn);
|
|
1535
|
-
}
|
|
1536
|
-
|
|
1537
|
-
/**
|
|
1538
|
-
* @param {() => Object} fn
|
|
1539
|
-
* @returns {Object}
|
|
1540
|
-
*/
|
|
1541
|
-
export function proxy_props(fn) {
|
|
1542
|
-
const memo = derived(fn, /** @type {Block} */ (active_block));
|
|
1543
|
-
|
|
1544
|
-
return new Proxy(
|
|
1545
|
-
{},
|
|
1546
|
-
{
|
|
1547
|
-
get(_, property) {
|
|
1548
|
-
/** @type {Record<string | symbol, any> | Record<string | symbol, any>[]} */
|
|
1549
|
-
var obj = get_derived(memo);
|
|
1550
|
-
|
|
1551
|
-
// Handle array of objects/spreads (for multiple props)
|
|
1552
|
-
if (is_array(obj)) {
|
|
1553
|
-
// Search in reverse order (right-to-left) since later props override earlier ones
|
|
1554
|
-
/** @type {Record<string | symbol, any>} */
|
|
1555
|
-
var item;
|
|
1556
|
-
for (var i = obj.length - 1; i >= 0; i--) {
|
|
1557
|
-
item = obj[i];
|
|
1558
|
-
if (property in item) {
|
|
1559
|
-
return item[property];
|
|
1560
|
-
}
|
|
1561
|
-
}
|
|
1562
|
-
return undefined;
|
|
1563
|
-
}
|
|
1564
|
-
|
|
1565
|
-
// Single object case
|
|
1566
|
-
return obj[property];
|
|
1567
|
-
},
|
|
1568
|
-
has(_, property) {
|
|
1569
|
-
if (property === TRACKED_OBJECT) {
|
|
1570
|
-
return true;
|
|
1571
|
-
}
|
|
1572
|
-
/** @type {Record<string | symbol, any> | Record<string | symbol, any>[]} */
|
|
1573
|
-
var obj = get_derived(memo);
|
|
1574
|
-
|
|
1575
|
-
// Handle array of objects/spreads
|
|
1576
|
-
if (is_array(obj)) {
|
|
1577
|
-
for (var i = obj.length - 1; i >= 0; i--) {
|
|
1578
|
-
if (property in obj[i]) {
|
|
1579
|
-
return true;
|
|
1580
|
-
}
|
|
1581
|
-
}
|
|
1582
|
-
return false;
|
|
1583
|
-
}
|
|
1584
|
-
|
|
1585
|
-
return property in obj;
|
|
1586
|
-
},
|
|
1587
|
-
getOwnPropertyDescriptor(_, key) {
|
|
1588
|
-
/** @type {Record<string | symbol, any> | Record<string | symbol, any>[]} */
|
|
1589
|
-
var obj = get_derived(memo);
|
|
1590
|
-
|
|
1591
|
-
// Handle array of objects/spreads
|
|
1592
|
-
if (is_array(obj)) {
|
|
1593
|
-
/** @type {Record<string | symbol, any>} */
|
|
1594
|
-
var item;
|
|
1595
|
-
for (var i = obj.length - 1; i >= 0; i--) {
|
|
1596
|
-
item = obj[i];
|
|
1597
|
-
if (key in item) {
|
|
1598
|
-
return get_descriptor(item, key);
|
|
1599
|
-
}
|
|
1600
|
-
}
|
|
1601
|
-
return undefined;
|
|
1602
|
-
}
|
|
1603
|
-
|
|
1604
|
-
if (key in obj) {
|
|
1605
|
-
return get_descriptor(obj, key);
|
|
1606
|
-
}
|
|
1607
|
-
},
|
|
1608
|
-
ownKeys() {
|
|
1609
|
-
/** @type {Record<string | symbol, any> | Record<string | symbol, any>[]} */
|
|
1610
|
-
var obj = get_derived(memo);
|
|
1611
|
-
/** @type {Record<string | symbol, 1>} */
|
|
1612
|
-
var done = {};
|
|
1613
|
-
/** @type {(string | symbol)[]} */
|
|
1614
|
-
var keys = [];
|
|
1615
|
-
|
|
1616
|
-
// Handle array of objects/spreads
|
|
1617
|
-
if (is_array(obj)) {
|
|
1618
|
-
// Collect all keys from all objects, order doesn't matter
|
|
1619
|
-
/** @type {Record<string | symbol, any>} */
|
|
1620
|
-
var item;
|
|
1621
|
-
for (var i = 0; i < obj.length; i++) {
|
|
1622
|
-
item = obj[i];
|
|
1623
|
-
for (const key of Reflect.ownKeys(item)) {
|
|
1624
|
-
if (done[key]) {
|
|
1625
|
-
continue;
|
|
1626
|
-
}
|
|
1627
|
-
done[key] = 1;
|
|
1628
|
-
keys.push(key);
|
|
1629
|
-
}
|
|
1630
|
-
}
|
|
1631
|
-
return keys;
|
|
1632
|
-
}
|
|
1633
|
-
|
|
1634
|
-
return Reflect.ownKeys(obj);
|
|
1635
|
-
},
|
|
1636
|
-
},
|
|
1637
|
-
);
|
|
1638
|
-
}
|
|
1639
|
-
|
|
1640
1696
|
/**
|
|
1641
1697
|
* @template T
|
|
1642
1698
|
* @param {() => T} fn
|
|
@@ -1806,7 +1862,7 @@ export function safe_scope(err = 'Cannot access outside of a component context')
|
|
|
1806
1862
|
export function create_component_ctx() {
|
|
1807
1863
|
return {
|
|
1808
1864
|
b: active_block,
|
|
1809
|
-
c: null,
|
|
1865
|
+
c: active_component === null ? null : active_component.c,
|
|
1810
1866
|
e: null,
|
|
1811
1867
|
m: false,
|
|
1812
1868
|
p: active_component,
|
|
@@ -1817,8 +1873,7 @@ export function create_component_ctx() {
|
|
|
1817
1873
|
* @returns {void}
|
|
1818
1874
|
*/
|
|
1819
1875
|
export function push_component() {
|
|
1820
|
-
|
|
1821
|
-
active_component = component;
|
|
1876
|
+
active_component = create_component_ctx();
|
|
1822
1877
|
}
|
|
1823
1878
|
|
|
1824
1879
|
/**
|
|
@@ -1827,27 +1882,168 @@ export function push_component() {
|
|
|
1827
1882
|
export function pop_component() {
|
|
1828
1883
|
var component = /** @type {Component} */ (active_component);
|
|
1829
1884
|
component.m = true;
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
var previous_block = active_block;
|
|
1836
|
-
var previous_reaction = active_reaction;
|
|
1885
|
+
if (component.e !== null) {
|
|
1886
|
+
create_deferred_effects(component.e);
|
|
1887
|
+
}
|
|
1888
|
+
active_component = component.p;
|
|
1889
|
+
}
|
|
1837
1890
|
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
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);
|
|
1847
1936
|
}
|
|
1848
1937
|
active_component = component.p;
|
|
1849
1938
|
}
|
|
1850
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
|
+
|
|
1851
2047
|
/**
|
|
1852
2048
|
* @template T
|
|
1853
2049
|
* @param {() => T} fn
|
|
@@ -1879,40 +2075,3 @@ export function ref_prop() {
|
|
|
1879
2075
|
export function create_ref_prop(get_ref_value, set_ref_value) {
|
|
1880
2076
|
return create_core_ref_prop(() => untrack(get_ref_value), set_ref_value);
|
|
1881
2077
|
}
|
|
1882
|
-
|
|
1883
|
-
/**
|
|
1884
|
-
* @template T
|
|
1885
|
-
* @param {T | undefined} value
|
|
1886
|
-
* @param {T} fallback
|
|
1887
|
-
* @returns {T}
|
|
1888
|
-
*/
|
|
1889
|
-
export function fallback(value, fallback) {
|
|
1890
|
-
return value === undefined ? fallback : value;
|
|
1891
|
-
}
|
|
1892
|
-
|
|
1893
|
-
/**
|
|
1894
|
-
* @param {Record<string | symbol, unknown>} obj
|
|
1895
|
-
* @param {string[]} exclude_keys
|
|
1896
|
-
* @returns {Record<string | symbol, unknown>}
|
|
1897
|
-
*/
|
|
1898
|
-
export function exclude_from_object(obj, exclude_keys) {
|
|
1899
|
-
var keys = object_keys(obj);
|
|
1900
|
-
/** @type {Record<string | symbol, unknown>} */
|
|
1901
|
-
var new_obj = {};
|
|
1902
|
-
|
|
1903
|
-
for (const key of keys) {
|
|
1904
|
-
if (!exclude_keys.includes(key)) {
|
|
1905
|
-
new_obj[key] = obj[key];
|
|
1906
|
-
}
|
|
1907
|
-
}
|
|
1908
|
-
|
|
1909
|
-
for (const symbol of get_own_property_symbols(obj)) {
|
|
1910
|
-
var ref_fn = obj[symbol];
|
|
1911
|
-
|
|
1912
|
-
if (symbol.description === REF_PROP) {
|
|
1913
|
-
new_obj[symbol] = ref_fn;
|
|
1914
|
-
}
|
|
1915
|
-
}
|
|
1916
|
-
|
|
1917
|
-
return new_obj;
|
|
1918
|
-
}
|