ripple 0.4.2 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +107 -0
- package/package.json +9 -3
- package/src/jsx-runtime.d.ts +2 -1
- package/src/runtime/array.js +15 -9
- package/src/runtime/index-client.js +25 -7
- package/src/runtime/index-server.js +1 -0
- package/src/runtime/internal/client/attributes.js +313 -0
- package/src/runtime/internal/client/blocks.js +4 -14
- package/src/runtime/internal/client/component.js +2 -5
- package/src/runtime/internal/client/composite.js +14 -6
- package/src/runtime/internal/client/constants.js +6 -6
- package/src/runtime/internal/client/context.js +3 -2
- package/src/runtime/internal/client/css.js +11 -26
- package/src/runtime/internal/client/errors.js +188 -0
- package/src/runtime/internal/client/events.js +79 -34
- package/src/runtime/internal/client/expression.js +21 -116
- package/src/runtime/internal/client/for.js +108 -232
- package/src/runtime/internal/client/head.js +4 -3
- package/src/runtime/internal/client/html.js +5 -3
- package/src/runtime/internal/client/hydrate.js +484 -0
- package/src/runtime/internal/client/hydration-enabled.js +7 -0
- package/src/runtime/internal/client/hydration.js +16 -81
- package/src/runtime/internal/client/if.js +13 -9
- package/src/runtime/internal/client/index.js +14 -6
- package/src/runtime/internal/client/operations.js +11 -7
- package/src/runtime/internal/client/portal.js +3 -2
- package/src/runtime/internal/client/render.js +42 -325
- package/src/runtime/internal/client/root-boundary-enabled.js +7 -0
- package/src/runtime/internal/client/runtime.js +87 -363
- package/src/runtime/internal/client/template-ns.js +47 -0
- package/src/runtime/internal/client/template.js +63 -140
- package/src/runtime/internal/client/track-async.js +356 -0
- package/src/runtime/internal/client/try.js +133 -319
- package/src/runtime/internal/client/types.d.ts +48 -24
- package/src/runtime/internal/server/index.js +31 -29
- package/src/runtime/internal/server/prerender.js +27 -0
- package/src/server/index.js +1 -0
- package/src/utils/class-name.js +28 -0
- package/tests/client/basic/basic.errors.test.tsrx +3 -3
- package/tests/client/compiler/__snapshots__/compiler.typescript.test.tsrx.snap +0 -2
- package/tests/client/compiler/compiler.basic.test.tsrx +2 -2
- package/tests/client/compiler/compiler.tracked-access.test.tsrx +3 -3
- package/tests/client/composite/composite.props.test.tsrx +10 -10
- package/tests/client/derived-release.test.tsrx +3 -3
- package/tests/client/for-item.test.tsrx +39 -0
- package/tests/client/for-selector.test.tsrx +95 -0
- package/tests/hydration/compiled/client/basic.js +87 -87
- package/tests/hydration/compiled/client/composite.js +5 -5
- package/tests/hydration/compiled/client/events.js +40 -48
- package/tests/hydration/compiled/client/for.js +162 -181
- package/tests/hydration/compiled/client/fragment-cursor.js +521 -289
- package/tests/hydration/compiled/client/head.js +22 -22
- package/tests/hydration/compiled/client/hmr.js +4 -4
- package/tests/hydration/compiled/client/html-in-template.js +5 -5
- package/tests/hydration/compiled/client/html.js +152 -162
- package/tests/hydration/compiled/client/if-children.js +58 -53
- package/tests/hydration/compiled/client/if-fragment-controlflow.js +39 -39
- package/tests/hydration/compiled/client/if.js +26 -26
- package/tests/hydration/compiled/client/mixed-control-flow.js +56 -68
- package/tests/hydration/compiled/client/nested-control-flow.js +139 -271
- package/tests/hydration/compiled/client/portal.js +10 -10
- package/tests/hydration/compiled/client/reactivity.js +29 -29
- package/tests/hydration/compiled/client/return.js +2 -2
- package/tests/hydration/compiled/client/streaming.js +33 -35
- package/tests/hydration/compiled/client/switch.js +25 -25
- package/tests/hydration/compiled/client/track-async-serialization.js +41 -41
- package/tests/hydration/compiled/client/try.js +15 -15
- package/tests/hydration/compiled/client/typed-text.js +7 -7
- package/tests/hydration/compiled/server/basic.js +6 -6
- package/tests/hydration/compiled/server/events.js +8 -8
- package/tests/hydration/compiled/server/for.js +22 -22
- package/tests/hydration/compiled/server/fragment-cursor.js +188 -52
- package/tests/hydration/compiled/server/head.js +6 -6
- package/tests/hydration/compiled/server/hmr.js +1 -1
- package/tests/hydration/compiled/server/html.js +1 -1
- package/tests/hydration/compiled/server/if-children.js +9 -9
- package/tests/hydration/compiled/server/if.js +5 -5
- package/tests/hydration/compiled/server/mixed-control-flow.js +4 -4
- package/tests/hydration/compiled/server/portal.js +1 -1
- package/tests/hydration/compiled/server/reactivity.js +9 -9
- package/tests/hydration/compiled/server/streaming.js +9 -9
- package/tests/hydration/compiled/server/switch.js +4 -4
- package/tests/hydration/compiled/server/track-async-serialization.js +16 -16
- package/tests/hydration/compiled/server/try.js +4 -4
- package/tests/hydration/compiled/server/typed-text.js +1 -1
- package/tests/hydration/components/fragment-cursor.tsrx +60 -0
- package/tests/hydration/components/track-async-serialization.tsrx +2 -2
- package/tests/hydration/fragment-cursor.test.js +34 -1
- package/tests/hydration/track-async-serialization.test.js +1 -1
- package/tests/server/basic.components.test.tsrx +3 -3
- package/tests/server/track-async-serialization.test.tsrx +6 -6
- package/tests/utils/tracked-types.test.js +3 -3
- package/types/index.d.ts +8 -8
- package/types/server.d.ts +17 -0
|
@@ -4,13 +4,7 @@
|
|
|
4
4
|
/** @typedef {DerivedValue} Derived */
|
|
5
5
|
|
|
6
6
|
import { DEV } from 'esm-env';
|
|
7
|
-
import {
|
|
8
|
-
destroy_block,
|
|
9
|
-
destroy_non_branch_children,
|
|
10
|
-
effect,
|
|
11
|
-
pause_block,
|
|
12
|
-
pre_effect,
|
|
13
|
-
} from './blocks.js';
|
|
7
|
+
import { destroy_block, destroy_non_branch_children, effect } from './blocks.js';
|
|
14
8
|
import {
|
|
15
9
|
ASYNC_DERIVED_READ_THROWN,
|
|
16
10
|
BLOCK_HAS_RUN,
|
|
@@ -28,11 +22,8 @@ import {
|
|
|
28
22
|
UNINITIALIZED,
|
|
29
23
|
REF_PROP,
|
|
30
24
|
DEFAULT_NAMESPACE,
|
|
31
|
-
TRACKED_UPDATED,
|
|
32
25
|
SUSPENSE_PENDING,
|
|
33
26
|
SUSPENSE_REJECTED,
|
|
34
|
-
TRY_BLOCK,
|
|
35
|
-
DIRECT_CHILD_BLOCK,
|
|
36
27
|
SCHEDULED,
|
|
37
28
|
SELECTOR,
|
|
38
29
|
IF_BLOCK,
|
|
@@ -41,17 +32,8 @@ import {
|
|
|
41
32
|
RENDER_ENTRY,
|
|
42
33
|
CREATES_DERIVEDS,
|
|
43
34
|
} from './constants.js';
|
|
44
|
-
import {
|
|
45
|
-
begin_boundary_request,
|
|
46
|
-
complete_boundary_request,
|
|
47
|
-
get_boundary_with_catch,
|
|
48
|
-
get_pending_boundary,
|
|
49
|
-
handle_boundary_error,
|
|
50
|
-
register_boundary_deferred,
|
|
51
|
-
register_boundary_paused_block,
|
|
52
|
-
replace_boundary_request,
|
|
53
|
-
} from './try.js';
|
|
54
35
|
import { is_ripple_object } from './utils.js';
|
|
36
|
+
import { scope_orphan, set_in_derived, track_orphan, update_depth_exceeded } from './errors.js';
|
|
55
37
|
import { render_value } from './expression.js';
|
|
56
38
|
import { throw_invalid_component_type } from './component.js';
|
|
57
39
|
|
|
@@ -61,10 +43,8 @@ import {
|
|
|
61
43
|
is_array,
|
|
62
44
|
object_keys,
|
|
63
45
|
} from '@tsrx/core/runtime/language-helpers';
|
|
64
|
-
import { get_async_track_result } from '../../../utils/async.js';
|
|
65
|
-
import { get_track_async_script_id } from '../../../utils/track-async-serialization.js';
|
|
66
|
-
import { revive } from './transport.js';
|
|
67
46
|
import { hydrating, track_hash_reference } from './hydration.js';
|
|
47
|
+
import { HYDRATION } from 'ripple/internal/client/hydration-enabled';
|
|
68
48
|
import { create_ref_prop as create_core_ref_prop } from '@tsrx/core/runtime/ref';
|
|
69
49
|
|
|
70
50
|
const FLUSH_MICROTASK = 0;
|
|
@@ -130,7 +110,7 @@ let flush_count = 0;
|
|
|
130
110
|
/** @type {(() => void)[]} */
|
|
131
111
|
var queued_post_block_flush = [];
|
|
132
112
|
/** @type {null | Dependency} */
|
|
133
|
-
let active_dependency = null;
|
|
113
|
+
export let active_dependency = null;
|
|
134
114
|
|
|
135
115
|
export let tracking = false;
|
|
136
116
|
export let teardown = false;
|
|
@@ -170,6 +150,28 @@ export function set_tracking(value) {
|
|
|
170
150
|
tracking = value;
|
|
171
151
|
}
|
|
172
152
|
|
|
153
|
+
/**
|
|
154
|
+
* @param {boolean} value
|
|
155
|
+
*/
|
|
156
|
+
export function set_mutating_allowed(value) {
|
|
157
|
+
is_mutating_allowed = value;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Handles a block whose run read a pending async value (see
|
|
162
|
+
* `track-async.js`). Installed by the first `trackAsync()`, so an application
|
|
163
|
+
* without one carries none of the boundary request machinery.
|
|
164
|
+
* @type {((block: Block) => void) | null}
|
|
165
|
+
*/
|
|
166
|
+
let pending_read = null;
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* @param {(block: Block) => void} fn
|
|
170
|
+
*/
|
|
171
|
+
export function set_pending_read_handler(fn) {
|
|
172
|
+
pending_read = fn;
|
|
173
|
+
}
|
|
174
|
+
|
|
173
175
|
/**
|
|
174
176
|
* @param {Block} block
|
|
175
177
|
*/
|
|
@@ -236,7 +238,7 @@ function update_derived(computed) {
|
|
|
236
238
|
* @param {Tracked} tracked
|
|
237
239
|
* @param {any} value
|
|
238
240
|
*/
|
|
239
|
-
function update_tracked_value_clock(tracked, value) {
|
|
241
|
+
export function update_tracked_value_clock(tracked, value) {
|
|
240
242
|
tracked.__v = value;
|
|
241
243
|
tracked.c = increment_clock();
|
|
242
244
|
mark_subscribers(tracked);
|
|
@@ -306,76 +308,51 @@ function run_derived(computed) {
|
|
|
306
308
|
}
|
|
307
309
|
}
|
|
308
310
|
|
|
311
|
+
/**
|
|
312
|
+
* Routes an error thrown by a block into the nearest boundary with a catch
|
|
313
|
+
* branch (see `try.js`). Installed by the first `try_block`, so a bundle whose
|
|
314
|
+
* mount and components create no boundary carries no catch machinery.
|
|
315
|
+
* @type {((error: unknown, block: Block) => BlockWithTryBoundaryAndCatch | null) | null}
|
|
316
|
+
*/
|
|
317
|
+
let catch_router = null;
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* @param {(error: unknown, block: Block) => BlockWithTryBoundaryAndCatch | null} fn
|
|
321
|
+
*/
|
|
322
|
+
export function set_catch_router(fn) {
|
|
323
|
+
catch_router = fn;
|
|
324
|
+
}
|
|
325
|
+
|
|
309
326
|
/**
|
|
310
327
|
* @param {unknown} error
|
|
311
328
|
* @param {Block} block
|
|
312
329
|
* @returns {BlockWithTryBoundaryAndCatch}
|
|
313
330
|
*/
|
|
314
331
|
export function handle_error(error, block) {
|
|
315
|
-
var boundary_with_catch =
|
|
316
|
-
if (boundary_with_catch
|
|
317
|
-
|
|
318
|
-
return boundary_with_catch;
|
|
332
|
+
var boundary_with_catch = catch_router === null ? null : catch_router(error, block);
|
|
333
|
+
if (boundary_with_catch === null) {
|
|
334
|
+
throw error;
|
|
319
335
|
}
|
|
320
|
-
|
|
321
|
-
throw error;
|
|
336
|
+
return boundary_with_catch;
|
|
322
337
|
}
|
|
323
338
|
|
|
324
339
|
/**
|
|
325
340
|
* The error path of {@link run_block}, kept out of that hot function so a
|
|
326
341
|
* healthy mount never compiles it: routes real errors to the nearest catch
|
|
327
|
-
* boundary and
|
|
328
|
-
*
|
|
342
|
+
* boundary, and a read of a pending async value to the handler `trackAsync`
|
|
343
|
+
* installs (the read is registered as a dependency, so the block re-runs once
|
|
344
|
+
* the value settles).
|
|
329
345
|
* @param {unknown} error
|
|
330
346
|
* @param {Block} block
|
|
331
347
|
*/
|
|
332
348
|
function handle_run_error(error, block) {
|
|
333
|
-
var is_component_direct = false;
|
|
334
|
-
var is_try_fn_block = false;
|
|
335
349
|
finish_dependencies(block, active_dependency);
|
|
336
|
-
// When a derived read throws ASYNC_DERIVED_READ_THROWN, it means the
|
|
337
|
-
// derived is still SUSPENSE_PENDING. The dependency was already registered,
|
|
338
|
-
// so we swallow the throw and let the parent continue processing. When
|
|
339
|
-
// the derived settles, the block will be dirty and rerun automatically.
|
|
340
350
|
if (error !== ASYNC_DERIVED_READ_THROWN) {
|
|
341
351
|
handle_error(error, block);
|
|
342
|
-
} else if (
|
|
343
|
-
|
|
344
|
-
(is_component_direct = active_component?.b === block) ||
|
|
345
|
-
(is_try_fn_block =
|
|
346
|
-
block.p !== null && (block.p.f & TRY_BLOCK) !== 0 && (block.f & DIRECT_CHILD_BLOCK) !== 0)
|
|
347
|
-
) {
|
|
348
|
-
throw new Error(
|
|
349
|
-
`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.`,
|
|
350
|
-
);
|
|
352
|
+
} else if (pending_read !== null) {
|
|
353
|
+
pending_read(block);
|
|
351
354
|
} else {
|
|
352
|
-
|
|
353
|
-
var boundary = get_pending_boundary(block);
|
|
354
|
-
if (boundary !== null) {
|
|
355
|
-
pause_block(block);
|
|
356
|
-
register_boundary_paused_block(boundary, block);
|
|
357
|
-
|
|
358
|
-
// Register deferred boundary completions for async tracked deps.
|
|
359
|
-
// This handles the case where a child boundary reads a tracked value
|
|
360
|
-
// whose resolution is managed by a different (parent) boundary.
|
|
361
|
-
var dep = block.d;
|
|
362
|
-
while (dep !== null) {
|
|
363
|
-
var dep_tracked = /** @type {Tracked} */ (dep.t);
|
|
364
|
-
if (
|
|
365
|
-
(dep_tracked.__v === SUSPENSE_PENDING || dep_tracked.__v === SUSPENSE_REJECTED) &&
|
|
366
|
-
(dep_tracked.f & TRACKED) !== 0
|
|
367
|
-
) {
|
|
368
|
-
var deferred_req = begin_boundary_request(boundary);
|
|
369
|
-
var entry = /** @type {DeferredTrackedEntry} */ ({ b: boundary, r: deferred_req });
|
|
370
|
-
if (dep_tracked.d === null) {
|
|
371
|
-
dep_tracked.d = [entry];
|
|
372
|
-
} else {
|
|
373
|
-
dep_tracked.d.push(entry);
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
dep = dep.n;
|
|
377
|
-
}
|
|
378
|
-
}
|
|
355
|
+
throw error;
|
|
379
356
|
}
|
|
380
357
|
}
|
|
381
358
|
|
|
@@ -421,11 +398,12 @@ function register_teardown(block, teardown) {
|
|
|
421
398
|
* dependencies a nested `item` records on it. Errors are handled as
|
|
422
399
|
* `run_block` handles them.
|
|
423
400
|
* @param {Block} block
|
|
424
|
-
* @param {(anchor: any, value: any) => void} fn
|
|
401
|
+
* @param {(anchor: any, value: any, index?: any, key?: any) => void} fn
|
|
425
402
|
* @param {any} anchor
|
|
426
403
|
* @param {any} value
|
|
404
|
+
* @param {any} [key] a keyed list item's key (see `create_item`)
|
|
427
405
|
*/
|
|
428
|
-
export function run_branch(block, fn, anchor, value) {
|
|
406
|
+
export function run_branch(block, fn, anchor, value, key) {
|
|
429
407
|
var previous_block = active_block;
|
|
430
408
|
var previous_reaction = active_reaction;
|
|
431
409
|
var previous_tracking = tracking;
|
|
@@ -438,7 +416,7 @@ export function run_branch(block, fn, anchor, value) {
|
|
|
438
416
|
active_component = block.co;
|
|
439
417
|
tracking = false;
|
|
440
418
|
active_dependency = null;
|
|
441
|
-
fn(anchor, value);
|
|
419
|
+
fn(anchor, value, undefined, key);
|
|
442
420
|
if (active_dependency !== null) {
|
|
443
421
|
block.d = active_dependency;
|
|
444
422
|
}
|
|
@@ -514,21 +492,6 @@ export function run_block(block, first_run = false) {
|
|
|
514
492
|
|
|
515
493
|
var empty_get_set = { get: undefined, set: undefined };
|
|
516
494
|
|
|
517
|
-
/**
|
|
518
|
-
* Complete all deferred boundary requests registered on a tracked value.
|
|
519
|
-
* @param {Tracked} t
|
|
520
|
-
* @param {boolean} [show_resolved=true]
|
|
521
|
-
*/
|
|
522
|
-
function complete_deferred_boundaries(t, show_resolved = true) {
|
|
523
|
-
if (t.d !== null) {
|
|
524
|
-
for (var i = 0; i < t.d.length; i++) {
|
|
525
|
-
var entry = t.d[i];
|
|
526
|
-
complete_boundary_request(entry.b, entry.r, show_resolved);
|
|
527
|
-
}
|
|
528
|
-
t.d = null;
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
|
|
532
495
|
class TrackedValue {
|
|
533
496
|
/**
|
|
534
497
|
* @param {any} v
|
|
@@ -564,17 +527,6 @@ class TrackedValue {
|
|
|
564
527
|
set value(v) {
|
|
565
528
|
set(this, v);
|
|
566
529
|
}
|
|
567
|
-
/**
|
|
568
|
-
* A read-only view: a derived over this value, for a receiver that should
|
|
569
|
-
* read but not write it. Equivalent to `track(() => tracked.value)`. The
|
|
570
|
-
* view is owned by the block that creates it, not by this value's block, so
|
|
571
|
-
* a view made in a component is released with that component even when the
|
|
572
|
-
* value outlives it.
|
|
573
|
-
* @returns {Derived}
|
|
574
|
-
*/
|
|
575
|
-
readOnly() {
|
|
576
|
-
return derived(() => get_tracked(this), /** @type {Block} */ (active_block));
|
|
577
|
-
}
|
|
578
530
|
}
|
|
579
531
|
|
|
580
532
|
class DerivedValue {
|
|
@@ -618,17 +570,6 @@ class DerivedValue {
|
|
|
618
570
|
set value(v) {
|
|
619
571
|
set(this, v);
|
|
620
572
|
}
|
|
621
|
-
/**
|
|
622
|
-
* A read-only view (see `TrackedValue#readOnly`). A derived without a
|
|
623
|
-
* setter is already read-only and is returned as is; a writable one is
|
|
624
|
-
* wrapped in a derived that follows it.
|
|
625
|
-
* @returns {Derived}
|
|
626
|
-
*/
|
|
627
|
-
readOnly() {
|
|
628
|
-
return this.a.set === undefined
|
|
629
|
-
? this
|
|
630
|
-
: derived(() => get_derived(this), /** @type {Block} */ (active_block));
|
|
631
|
-
}
|
|
632
573
|
}
|
|
633
574
|
|
|
634
575
|
if (DEV) {
|
|
@@ -649,7 +590,7 @@ export function tracked(v, block, hash, get, set) {
|
|
|
649
590
|
var t = /** @type {Tracked} */ (
|
|
650
591
|
new TrackedValue(v, block || active_block, get || set ? { get, set } : empty_get_set, hash)
|
|
651
592
|
);
|
|
652
|
-
if (hydrating && hash !== undefined) {
|
|
593
|
+
if (HYDRATION && hydrating && hash !== undefined) {
|
|
653
594
|
track_hash_reference.set(hash, t);
|
|
654
595
|
}
|
|
655
596
|
return t;
|
|
@@ -680,7 +621,7 @@ export function derived(fn, block, hash, get, set) {
|
|
|
680
621
|
created.push(d);
|
|
681
622
|
}
|
|
682
623
|
}
|
|
683
|
-
if (hydrating && hash !== undefined) {
|
|
624
|
+
if (HYDRATION && hydrating && hash !== undefined) {
|
|
684
625
|
track_hash_reference.set(hash, d);
|
|
685
626
|
}
|
|
686
627
|
return d;
|
|
@@ -774,6 +715,30 @@ function keep_deriveds(block, kept) {
|
|
|
774
715
|
block.f |= CREATES_DERIVEDS;
|
|
775
716
|
}
|
|
776
717
|
|
|
718
|
+
/**
|
|
719
|
+
* A read-only view of a tracked or derived value, for a receiver that should
|
|
720
|
+
* read but not write it: a derived over a tracked (or a writable derived),
|
|
721
|
+
* equivalent to `track(() => value.value)`; a read-only derived as it is; a
|
|
722
|
+
* plain value as it is, like `get`. The view is owned by the block that
|
|
723
|
+
* creates it, not by the value's block, so a view made in a component is
|
|
724
|
+
* released with that component even when the value outlives it.
|
|
725
|
+
* @param {any} value
|
|
726
|
+
* @param {Block} [block]
|
|
727
|
+
* @returns {any}
|
|
728
|
+
*/
|
|
729
|
+
export function track_read_only(value, block) {
|
|
730
|
+
if (!is_ripple_object(value)) {
|
|
731
|
+
return value;
|
|
732
|
+
}
|
|
733
|
+
var owner = block || /** @type {Block} */ (active_block);
|
|
734
|
+
if ((value.f & DERIVED) !== 0) {
|
|
735
|
+
var d = /** @type {Derived} */ (value);
|
|
736
|
+
return d.a.set === undefined ? d : derived(() => get_derived(d), owner);
|
|
737
|
+
}
|
|
738
|
+
var t = /** @type {Tracked} */ (value);
|
|
739
|
+
return derived(() => get_tracked(t), owner);
|
|
740
|
+
}
|
|
741
|
+
|
|
777
742
|
/**
|
|
778
743
|
* @param {any} v
|
|
779
744
|
* @param {Block} b
|
|
@@ -787,7 +752,7 @@ export function track(v, b, hash, get, set) {
|
|
|
787
752
|
return v;
|
|
788
753
|
}
|
|
789
754
|
if (b === null) {
|
|
790
|
-
|
|
755
|
+
track_orphan();
|
|
791
756
|
}
|
|
792
757
|
|
|
793
758
|
if (typeof v === 'function') {
|
|
@@ -796,243 +761,6 @@ export function track(v, b, hash, get, set) {
|
|
|
796
761
|
return tracked(v, b, hash, get, set);
|
|
797
762
|
}
|
|
798
763
|
|
|
799
|
-
/**
|
|
800
|
-
* @param {any} fn
|
|
801
|
-
* @param {Block} b
|
|
802
|
-
* @param {string} hash - Unique hash for SSR serialization/hydration
|
|
803
|
-
* @returns {Tracked | void}
|
|
804
|
-
*/
|
|
805
|
-
export function track_async(fn, b, hash) {
|
|
806
|
-
if (is_ripple_object(fn)) {
|
|
807
|
-
return fn;
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
var target_block = b || active_block;
|
|
811
|
-
if (target_block === null) {
|
|
812
|
-
throw new TypeError('trackAsync() requires a valid component context');
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
if (typeof fn !== 'function') {
|
|
816
|
-
throw new TypeError(
|
|
817
|
-
'trackAsync() only accepts function arguments that return a promise or an object with a promise property',
|
|
818
|
-
);
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
// During hydration, attempt to read serialized data from SSR
|
|
822
|
-
var had_hydration_data = false;
|
|
823
|
-
var hydration_value;
|
|
824
|
-
/** @type {string[] | undefined} */
|
|
825
|
-
var hydration_deps;
|
|
826
|
-
|
|
827
|
-
if (hydrating) {
|
|
828
|
-
var script_id = get_track_async_script_id(hash);
|
|
829
|
-
var script_el = document.getElementById(script_id);
|
|
830
|
-
if (script_el) {
|
|
831
|
-
var envelope = JSON.parse(/** @type {string} */ (script_el.textContent));
|
|
832
|
-
script_el.remove();
|
|
833
|
-
|
|
834
|
-
if (envelope.ok) {
|
|
835
|
-
had_hydration_data = true;
|
|
836
|
-
hydration_value =
|
|
837
|
-
envelope.payload === undefined ? envelope.value : revive(envelope.payload);
|
|
838
|
-
hydration_deps = envelope.deps;
|
|
839
|
-
} else {
|
|
840
|
-
// trigger the catch block
|
|
841
|
-
throw new Error(envelope.error?.message ?? 'Unknown server error');
|
|
842
|
-
}
|
|
843
|
-
}
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
var t = tracked(had_hydration_data ? hydration_value : SUSPENSE_PENDING, target_block, hash);
|
|
847
|
-
|
|
848
|
-
// Capture the call-site block for boundary lookups. target_block is the
|
|
849
|
-
// component's block (passed by compiler), but the actual try/pending/catch
|
|
850
|
-
// boundary is an ancestor of active_block (the block executing trackAsync).
|
|
851
|
-
var call_site_block = /** @type {Block} */ (active_block);
|
|
852
|
-
|
|
853
|
-
var version = 0;
|
|
854
|
-
/** @type {AbortController | null} */
|
|
855
|
-
var abort_controller = null;
|
|
856
|
-
var request_id = 0;
|
|
857
|
-
/** @type {Block | null} */
|
|
858
|
-
var boundary = null;
|
|
859
|
-
|
|
860
|
-
// TODO: decide if instead of insisting on pending, we create our own boundary
|
|
861
|
-
// we currently require a pending block upstream but we could also
|
|
862
|
-
// create a try/pending/catch boundary at mount and hydration like
|
|
863
|
-
// we do on the server so that there is always a boundary present.
|
|
864
|
-
// It can handle global pending when none were provided.
|
|
865
|
-
// Not sure about the catch boundary because if none were provided,
|
|
866
|
-
// the whole app for any error will be unmounted with the catch block rendered
|
|
867
|
-
|
|
868
|
-
// Find boundary from the call-site block.
|
|
869
|
-
boundary = get_pending_boundary(active_block);
|
|
870
|
-
if (boundary === null) {
|
|
871
|
-
throw new Error('Missing parent `try { ... } pending { ... }` statement');
|
|
872
|
-
}
|
|
873
|
-
|
|
874
|
-
// If we hydrated with resolved data, the SSR already completed this request.
|
|
875
|
-
// Otherwise mark a pending request on the boundary for the client-side run.
|
|
876
|
-
if (!had_hydration_data) {
|
|
877
|
-
request_id = begin_boundary_request(boundary);
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
pre_effect(() => {
|
|
881
|
-
if (had_hydration_data) {
|
|
882
|
-
// First run after hydration: skip fn() entirely (the SSR already
|
|
883
|
-
// produced the resolved value) and instead register the direct
|
|
884
|
-
// dependencies from the serialized deps list so future dep changes
|
|
885
|
-
// trigger a re-run via the normal async path.
|
|
886
|
-
had_hydration_data = false;
|
|
887
|
-
if (hydration_deps !== undefined) {
|
|
888
|
-
for (var i = 0; i < hydration_deps.length; i++) {
|
|
889
|
-
var dep_ref = track_hash_reference.get(hydration_deps[i]);
|
|
890
|
-
if (dep_ref !== undefined) {
|
|
891
|
-
get(dep_ref);
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
return;
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
var current_version = ++version;
|
|
899
|
-
|
|
900
|
-
// Abort previous in-flight request
|
|
901
|
-
if (abort_controller !== null && abort_controller.signal.aborted === false) {
|
|
902
|
-
abort_controller.abort(TRACKED_UPDATED);
|
|
903
|
-
}
|
|
904
|
-
abort_controller = null;
|
|
905
|
-
|
|
906
|
-
// Manage boundary request: replace if in-flight, or begin new if previous completed
|
|
907
|
-
if (request_id > 0 && boundary !== null) {
|
|
908
|
-
request_id = replace_boundary_request(boundary, request_id);
|
|
909
|
-
} else if (boundary !== null) {
|
|
910
|
-
request_id = begin_boundary_request(boundary);
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
// Set to pending before calling fn() in case it's sync.
|
|
914
|
-
if (t.__v !== SUSPENSE_PENDING) {
|
|
915
|
-
update_tracked_value_clock(t, SUSPENSE_PENDING);
|
|
916
|
-
}
|
|
917
|
-
|
|
918
|
-
// Temporarily allow mutations so set() doesn't throw inside the pre-effect
|
|
919
|
-
var previous_is_mutating_allowed = is_mutating_allowed;
|
|
920
|
-
is_mutating_allowed = true;
|
|
921
|
-
|
|
922
|
-
var result;
|
|
923
|
-
try {
|
|
924
|
-
result = fn();
|
|
925
|
-
} catch (e) {
|
|
926
|
-
is_mutating_allowed = previous_is_mutating_allowed;
|
|
927
|
-
if (e === ASYNC_DERIVED_READ_THROWN) {
|
|
928
|
-
// A dependency is still pending or rejected (e.g. chained trackAsync).
|
|
929
|
-
// Check if any dependency is rejected — if so, propagate rejection.
|
|
930
|
-
var dep = active_dependency;
|
|
931
|
-
while (dep !== null) {
|
|
932
|
-
if (dep.t.__v === SUSPENSE_REJECTED) {
|
|
933
|
-
update_tracked_value_clock(t, SUSPENSE_REJECTED);
|
|
934
|
-
complete_deferred_boundaries(t, false);
|
|
935
|
-
if (request_id > 0 && boundary !== null) {
|
|
936
|
-
complete_boundary_request(boundary, request_id, false);
|
|
937
|
-
request_id = 0;
|
|
938
|
-
}
|
|
939
|
-
return;
|
|
940
|
-
}
|
|
941
|
-
dep = dep.n;
|
|
942
|
-
}
|
|
943
|
-
// Dependencies are pending, not rejected — register deferred
|
|
944
|
-
// rejection so that if the boundary goes to catch mode, this
|
|
945
|
-
// tracked value is also set to REJECTED.
|
|
946
|
-
if (request_id > 0 && boundary !== null) {
|
|
947
|
-
register_boundary_deferred(boundary, request_id, () => {
|
|
948
|
-
update_tracked_value_clock(t, SUSPENSE_REJECTED);
|
|
949
|
-
});
|
|
950
|
-
}
|
|
951
|
-
return;
|
|
952
|
-
}
|
|
953
|
-
throw e;
|
|
954
|
-
}
|
|
955
|
-
is_mutating_allowed = previous_is_mutating_allowed;
|
|
956
|
-
|
|
957
|
-
// Check if the result is async
|
|
958
|
-
var previous_tracking = tracking;
|
|
959
|
-
tracking = false;
|
|
960
|
-
var async_result = get_async_track_result(result);
|
|
961
|
-
tracking = previous_tracking;
|
|
962
|
-
|
|
963
|
-
if (async_result === null) {
|
|
964
|
-
// Sync result
|
|
965
|
-
update_tracked_value_clock(t, result);
|
|
966
|
-
if (request_id > 0 && boundary !== null) {
|
|
967
|
-
complete_boundary_request(boundary, request_id);
|
|
968
|
-
request_id = 0;
|
|
969
|
-
}
|
|
970
|
-
return;
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
// Capture per-invocation so async closures (rejection handler, teardown)
|
|
974
|
-
// have a stable reference. The shared abort_controller is only read
|
|
975
|
-
// synchronously at the top of the pre_effect to abort the previous request.
|
|
976
|
-
var current_abort_controller = async_result.abort_controller;
|
|
977
|
-
abort_controller = current_abort_controller;
|
|
978
|
-
|
|
979
|
-
async_result.promise.then(
|
|
980
|
-
(resolved) => {
|
|
981
|
-
if (current_version !== version) {
|
|
982
|
-
// stale
|
|
983
|
-
return;
|
|
984
|
-
}
|
|
985
|
-
update_tracked_value_clock(t, resolved);
|
|
986
|
-
complete_deferred_boundaries(t);
|
|
987
|
-
if (request_id > 0 && boundary !== null) {
|
|
988
|
-
complete_boundary_request(boundary, request_id);
|
|
989
|
-
request_id = 0;
|
|
990
|
-
}
|
|
991
|
-
},
|
|
992
|
-
(error) => {
|
|
993
|
-
if (current_version !== version) return; // stale
|
|
994
|
-
|
|
995
|
-
var is_internal_abort =
|
|
996
|
-
error === TRACKED_UPDATED || current_abort_controller?.signal?.reason === TRACKED_UPDATED;
|
|
997
|
-
if (is_internal_abort) {
|
|
998
|
-
// Internal abort (superseded by a new request) — don't set rejected
|
|
999
|
-
if (request_id > 0 && boundary !== null) {
|
|
1000
|
-
complete_boundary_request(boundary, request_id, false);
|
|
1001
|
-
request_id = 0;
|
|
1002
|
-
}
|
|
1003
|
-
complete_deferred_boundaries(t, false);
|
|
1004
|
-
return;
|
|
1005
|
-
}
|
|
1006
|
-
|
|
1007
|
-
update_tracked_value_clock(t, SUSPENSE_REJECTED);
|
|
1008
|
-
complete_deferred_boundaries(t, false);
|
|
1009
|
-
|
|
1010
|
-
// Route error to catch boundary
|
|
1011
|
-
var boundary_with_catch = get_boundary_with_catch(call_site_block);
|
|
1012
|
-
if (boundary_with_catch !== null) {
|
|
1013
|
-
handle_boundary_error(boundary_with_catch, error);
|
|
1014
|
-
}
|
|
1015
|
-
|
|
1016
|
-
if (request_id > 0 && boundary !== null) {
|
|
1017
|
-
var should_show_resolved =
|
|
1018
|
-
boundary_with_catch === boundary || boundary === null ? false : true;
|
|
1019
|
-
complete_boundary_request(boundary, request_id, should_show_resolved);
|
|
1020
|
-
request_id = 0;
|
|
1021
|
-
}
|
|
1022
|
-
},
|
|
1023
|
-
);
|
|
1024
|
-
|
|
1025
|
-
return () => {
|
|
1026
|
-
// Teardown: abort in-flight request when block is destroyed
|
|
1027
|
-
if (current_abort_controller !== null && current_abort_controller.signal.aborted === false) {
|
|
1028
|
-
current_abort_controller.abort(TRACKED_UPDATED);
|
|
1029
|
-
}
|
|
1030
|
-
};
|
|
1031
|
-
});
|
|
1032
|
-
|
|
1033
|
-
return t;
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
764
|
/**
|
|
1037
765
|
* @param {(Derived | Tracked) | (() => any)} t
|
|
1038
766
|
* @returns {boolean}
|
|
@@ -1463,9 +1191,7 @@ function flush_microtasks() {
|
|
|
1463
1191
|
|
|
1464
1192
|
flush_count++;
|
|
1465
1193
|
if (flush_count > 1001) {
|
|
1466
|
-
|
|
1467
|
-
'Maximum update depth exceeded. This typically indicates that an effect reads and writes the same piece of state.',
|
|
1468
|
-
);
|
|
1194
|
+
update_depth_exceeded();
|
|
1469
1195
|
}
|
|
1470
1196
|
var pending = queue;
|
|
1471
1197
|
queue = create_queue();
|
|
@@ -1627,9 +1353,7 @@ export function get_tracked(tracked) {
|
|
|
1627
1353
|
*/
|
|
1628
1354
|
export function set(tracked, value) {
|
|
1629
1355
|
if (!is_mutating_allowed) {
|
|
1630
|
-
|
|
1631
|
-
'Assignments or updates to tracked values are not allowed during computed "track(() => ...)" evaluation',
|
|
1632
|
-
);
|
|
1356
|
+
set_in_derived();
|
|
1633
1357
|
}
|
|
1634
1358
|
|
|
1635
1359
|
var old_value = tracked.__v;
|
|
@@ -1894,9 +1618,9 @@ export function scope() {
|
|
|
1894
1618
|
* @param {string} [err]
|
|
1895
1619
|
* @returns {Block | never}
|
|
1896
1620
|
*/
|
|
1897
|
-
export function safe_scope(err
|
|
1621
|
+
export function safe_scope(err) {
|
|
1898
1622
|
if (active_scope === null) {
|
|
1899
|
-
|
|
1623
|
+
scope_orphan(err);
|
|
1900
1624
|
}
|
|
1901
1625
|
|
|
1902
1626
|
return /** @type {Block} */ (active_scope);
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { get_first_child } from './operations.js';
|
|
2
|
+
import { set_ns_parser, template } from './template.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Create fragment with proper namespace using Svelte's wrapping approach
|
|
6
|
+
* @param {string} content
|
|
7
|
+
* @param {'svg' | 'math'} ns
|
|
8
|
+
* @returns {DocumentFragment}
|
|
9
|
+
*/
|
|
10
|
+
function from_namespace(content, ns) {
|
|
11
|
+
var wrapped = `<${ns}>${content}</${ns}>`;
|
|
12
|
+
|
|
13
|
+
var elem = document.createElement('template');
|
|
14
|
+
elem.innerHTML = wrapped;
|
|
15
|
+
var fragment = elem.content;
|
|
16
|
+
|
|
17
|
+
var root = /** @type {Element} */ (get_first_child(fragment));
|
|
18
|
+
var result = document.createDocumentFragment();
|
|
19
|
+
|
|
20
|
+
var first;
|
|
21
|
+
while ((first = get_first_child(root))) {
|
|
22
|
+
result.appendChild(/** @type {Node} */ (first));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return result;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Makes namespaced template parsing available: called by every path that can
|
|
30
|
+
* clone a template into the SVG or MathML namespace, so an app without one
|
|
31
|
+
* never loads it.
|
|
32
|
+
*/
|
|
33
|
+
export function install_ns_templates() {
|
|
34
|
+
set_ns_parser(from_namespace);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* `template()` for content compiled in the SVG or MathML namespace.
|
|
39
|
+
* @param {string} content
|
|
40
|
+
* @param {number} [flags]
|
|
41
|
+
* @param {number} [count]
|
|
42
|
+
* @returns {() => Node}
|
|
43
|
+
*/
|
|
44
|
+
export function template_ns(content, flags, count) {
|
|
45
|
+
set_ns_parser(from_namespace);
|
|
46
|
+
return template(content, flags, count);
|
|
47
|
+
}
|