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
|
@@ -53,9 +53,9 @@ import {
|
|
|
53
53
|
} from '../client/constants.js';
|
|
54
54
|
import { DEV } from 'esm-env';
|
|
55
55
|
import { is_ripple_object } from '../client/utils.js';
|
|
56
|
-
import {
|
|
56
|
+
import { is_array } from '@tsrx/core/runtime/language-helpers';
|
|
57
57
|
import {
|
|
58
|
-
escape,
|
|
58
|
+
escape as escape_html,
|
|
59
59
|
escape_script,
|
|
60
60
|
is_boolean_attribute,
|
|
61
61
|
normalize_css_property_name,
|
|
@@ -79,10 +79,6 @@ import {
|
|
|
79
79
|
is_tag_valid_with_ancestor,
|
|
80
80
|
} from '../../../html-tree-validation.js';
|
|
81
81
|
import { get_async_track_result } from '../../../utils/async.js';
|
|
82
|
-
import {
|
|
83
|
-
throw_tracked_index_reference_error,
|
|
84
|
-
throw_tracked_index_value_error,
|
|
85
|
-
} from '../../../utils/errors.js';
|
|
86
82
|
import { get_track_async_script_id } from '../../../utils/track-async-serialization.js';
|
|
87
83
|
import * as devalue from 'devalue';
|
|
88
84
|
import {
|
|
@@ -94,12 +90,10 @@ import {
|
|
|
94
90
|
} from './blocks.js';
|
|
95
91
|
import { COMPONENT_BLOCK, ROOT_BLOCK, TRY_BLOCK } from './constants.js';
|
|
96
92
|
|
|
97
|
-
export { escape };
|
|
98
93
|
export { register_component_css as register_css } from './css-registry.js';
|
|
99
94
|
export { simple_hash, strong_hash } from '@tsrx/core/runtime/hash';
|
|
100
95
|
export { context } from './context.js';
|
|
101
96
|
export { try_block, component_block, regular_block } from './blocks.js';
|
|
102
|
-
export { array_slice };
|
|
103
97
|
export { is_tsrx_element, tsrx_element, normalize_children };
|
|
104
98
|
export { create_ref_prop };
|
|
105
99
|
|
|
@@ -181,6 +175,11 @@ export function render_expression(value) {
|
|
|
181
175
|
* @returns {void}
|
|
182
176
|
*/
|
|
183
177
|
export function render_component(fn, props) {
|
|
178
|
+
// An optional component (an undefined prop, an import that resolved to
|
|
179
|
+
// nothing) renders nothing; any other non-function is a programming error.
|
|
180
|
+
if (fn == null) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
184
183
|
if (typeof fn !== 'function' || is_tsrx_element(fn)) {
|
|
185
184
|
throw_invalid_component_type(fn);
|
|
186
185
|
}
|
|
@@ -283,7 +282,8 @@ let inside_async_track = false;
|
|
|
283
282
|
/** @type {ElementContext | undefined} */
|
|
284
283
|
let current_element;
|
|
285
284
|
/** @type {Set<string>} */
|
|
286
|
-
|
|
285
|
+
/** @type {Set<string> | null} */
|
|
286
|
+
let seen_warnings = null;
|
|
287
287
|
|
|
288
288
|
/**
|
|
289
289
|
* @returns {void}
|
|
@@ -294,7 +294,7 @@ export function reset_state() {
|
|
|
294
294
|
active_dependency = null;
|
|
295
295
|
inside_async_track = false;
|
|
296
296
|
tracking = false;
|
|
297
|
-
seen_warnings =
|
|
297
|
+
seen_warnings = null;
|
|
298
298
|
current_element = undefined;
|
|
299
299
|
}
|
|
300
300
|
|
|
@@ -461,6 +461,18 @@ function run_derived(computed) {
|
|
|
461
461
|
}
|
|
462
462
|
}
|
|
463
463
|
|
|
464
|
+
/**
|
|
465
|
+
* Runs `fn` after the current task's microtasks have drained, so work
|
|
466
|
+
* completing in the same task can be batched into it.
|
|
467
|
+
* @type {(fn: () => void) => void}
|
|
468
|
+
*/
|
|
469
|
+
const defer =
|
|
470
|
+
typeof setImmediate === 'function'
|
|
471
|
+
? setImmediate
|
|
472
|
+
: (fn) => {
|
|
473
|
+
setTimeout(fn, 0);
|
|
474
|
+
};
|
|
475
|
+
|
|
464
476
|
/**
|
|
465
477
|
* `<div translate={false}>` should be rendered as `<div translate="no">` and _not_
|
|
466
478
|
* `<div translate="false">`, which is equivalent to `<div translate="yes">`. There
|
|
@@ -481,8 +493,8 @@ export class Output {
|
|
|
481
493
|
#head = [];
|
|
482
494
|
/** @type {NestedArray<string>} */
|
|
483
495
|
#body = [];
|
|
484
|
-
/** @type {Set<string>} */
|
|
485
|
-
#css =
|
|
496
|
+
/** @type {Set<string> | null} root only */
|
|
497
|
+
#css = null;
|
|
486
498
|
/** @type {null | Output} */
|
|
487
499
|
#parent = null;
|
|
488
500
|
/** @type {StreamSink | null} */
|
|
@@ -501,8 +513,8 @@ export class Output {
|
|
|
501
513
|
#promise_reject = null;
|
|
502
514
|
#is_root = false;
|
|
503
515
|
#sync_run = false;
|
|
504
|
-
/** @type {Set<RegisteredAsyncOperation>} */
|
|
505
|
-
#async_operations =
|
|
516
|
+
/** @type {Set<RegisteredAsyncOperation> | null} created by the first registration */
|
|
517
|
+
#async_operations = null;
|
|
506
518
|
/** @type {null | 'head'} */
|
|
507
519
|
target = null;
|
|
508
520
|
/** @type {null | FlushUnit} */
|
|
@@ -513,13 +525,14 @@ export class Output {
|
|
|
513
525
|
#head_redirect = null;
|
|
514
526
|
// streaming state, only used on the root instance
|
|
515
527
|
#next_unit_id = 1;
|
|
516
|
-
/** @type {FlushUnit[]} */
|
|
517
|
-
#units =
|
|
518
|
-
/** @type {WeakMap<NestedArray<string>, FlushUnit>} */
|
|
519
|
-
#unit_slots =
|
|
520
|
-
/** @type {Set<string>} */
|
|
521
|
-
#sent_css =
|
|
528
|
+
/** @type {FlushUnit[] | null} */
|
|
529
|
+
#units = null;
|
|
530
|
+
/** @type {WeakMap<NestedArray<string>, FlushUnit> | null} */
|
|
531
|
+
#unit_slots = null;
|
|
532
|
+
/** @type {Set<string> | null} */
|
|
533
|
+
#sent_css = null;
|
|
522
534
|
#shell_flushed = false;
|
|
535
|
+
#flush_scheduled = false;
|
|
523
536
|
|
|
524
537
|
get root() {
|
|
525
538
|
return this.#root;
|
|
@@ -534,7 +547,7 @@ export class Output {
|
|
|
534
547
|
}
|
|
535
548
|
|
|
536
549
|
get css() {
|
|
537
|
-
return this.#css;
|
|
550
|
+
return /** @type {Set<string>} */ (this.#root.#css);
|
|
538
551
|
}
|
|
539
552
|
|
|
540
553
|
get promise() {
|
|
@@ -552,6 +565,10 @@ export class Output {
|
|
|
552
565
|
if (!parent) {
|
|
553
566
|
this.#root = this;
|
|
554
567
|
this.#is_root = true;
|
|
568
|
+
this.#css = new Set();
|
|
569
|
+
this.#units = [];
|
|
570
|
+
this.#unit_slots = new WeakMap();
|
|
571
|
+
this.#sent_css = new Set();
|
|
555
572
|
this.#promise = new Promise((resolve, reject) => {
|
|
556
573
|
this.#promise_resolve = resolve;
|
|
557
574
|
this.#promise_reject = reject;
|
|
@@ -654,7 +671,9 @@ export class Output {
|
|
|
654
671
|
}
|
|
655
672
|
this.#head.length = 0;
|
|
656
673
|
this.#body.length = 0;
|
|
657
|
-
this.#
|
|
674
|
+
if (this.#is_root) {
|
|
675
|
+
/** @type {Set<string>} */ (this.#css).clear();
|
|
676
|
+
}
|
|
658
677
|
}
|
|
659
678
|
|
|
660
679
|
/**
|
|
@@ -670,8 +689,9 @@ export class Output {
|
|
|
670
689
|
return;
|
|
671
690
|
}
|
|
672
691
|
if (root.#shell_flushed) {
|
|
673
|
-
|
|
674
|
-
|
|
692
|
+
var sent_css = /** @type {Set<string>} */ (root.#sent_css);
|
|
693
|
+
if (!sent_css.has(hash)) {
|
|
694
|
+
sent_css.add(hash);
|
|
675
695
|
var css_text = get_css_text(new Set([hash]));
|
|
676
696
|
if (css_text) {
|
|
677
697
|
root.#streamOutput.push('<style data-ripple-ssr>' + css_text + '</style>');
|
|
@@ -680,7 +700,7 @@ export class Output {
|
|
|
680
700
|
return;
|
|
681
701
|
}
|
|
682
702
|
}
|
|
683
|
-
root.#css.add(hash);
|
|
703
|
+
/** @type {Set<string>} */ (root.#css).add(hash);
|
|
684
704
|
}
|
|
685
705
|
|
|
686
706
|
/**
|
|
@@ -730,7 +750,7 @@ export class Output {
|
|
|
730
750
|
* @return {void}
|
|
731
751
|
*/
|
|
732
752
|
registerAsync(operation) {
|
|
733
|
-
this.#async_operations.add(operation);
|
|
753
|
+
(this.#async_operations ??= new Set()).add(operation);
|
|
734
754
|
this.#root._incrementPending();
|
|
735
755
|
}
|
|
736
756
|
|
|
@@ -739,19 +759,22 @@ export class Output {
|
|
|
739
759
|
* @returns {void}
|
|
740
760
|
*/
|
|
741
761
|
resolveAsync(operation) {
|
|
742
|
-
this.#async_operations
|
|
762
|
+
var operations = /** @type {Set<RegisteredAsyncOperation>} */ (this.#async_operations);
|
|
763
|
+
operations.delete(operation);
|
|
743
764
|
this.#root._decrementPending();
|
|
744
765
|
var unit = this.unit;
|
|
745
|
-
if (unit !== null && !unit.flushed && !unit.settled &&
|
|
766
|
+
if (unit !== null && !unit.flushed && !unit.settled && operations.size === 0) {
|
|
746
767
|
unit.settled = true;
|
|
747
768
|
this.#root._maybeFlushUnit(unit);
|
|
748
769
|
}
|
|
749
770
|
}
|
|
750
771
|
|
|
751
772
|
cancelAsyncOperations() {
|
|
752
|
-
|
|
773
|
+
var operations = this.#async_operations;
|
|
774
|
+
if (operations === null) return;
|
|
775
|
+
for (const operation of operations) {
|
|
753
776
|
operation.cancel();
|
|
754
|
-
|
|
777
|
+
operations.delete(operation);
|
|
755
778
|
this.clear();
|
|
756
779
|
this.#root._decrementPending();
|
|
757
780
|
}
|
|
@@ -761,7 +784,8 @@ export class Output {
|
|
|
761
784
|
* @returns {boolean}
|
|
762
785
|
*/
|
|
763
786
|
hasPendingAsyncOperations() {
|
|
764
|
-
|
|
787
|
+
var operations = this.#async_operations;
|
|
788
|
+
return operations !== null && operations.size > 0;
|
|
765
789
|
}
|
|
766
790
|
|
|
767
791
|
/**
|
|
@@ -804,8 +828,8 @@ export class Output {
|
|
|
804
828
|
error: null,
|
|
805
829
|
};
|
|
806
830
|
this.unit = unit;
|
|
807
|
-
root.#unit_slots.set(this.#body, unit);
|
|
808
|
-
root.#units.push(unit);
|
|
831
|
+
/** @type {WeakMap<NestedArray<string>, FlushUnit>} */ (root.#unit_slots).set(this.#body, unit);
|
|
832
|
+
/** @type {FlushUnit[]} */ (root.#units).push(unit);
|
|
809
833
|
return unit;
|
|
810
834
|
}
|
|
811
835
|
|
|
@@ -840,7 +864,9 @@ export class Output {
|
|
|
840
864
|
out += item;
|
|
841
865
|
continue;
|
|
842
866
|
}
|
|
843
|
-
var unit = this.#unit_slots.get(
|
|
867
|
+
var unit = /** @type {WeakMap<NestedArray<string>, FlushUnit>} */ (this.#unit_slots).get(
|
|
868
|
+
item,
|
|
869
|
+
);
|
|
844
870
|
if (unit !== undefined && !unit.flushed) {
|
|
845
871
|
if (unit.settled && !unit.errored) {
|
|
846
872
|
out += this.#collect_unit(unit, chunk);
|
|
@@ -877,9 +903,10 @@ export class Output {
|
|
|
877
903
|
#chunk_css(hashes) {
|
|
878
904
|
/** @type {Set<string>} */
|
|
879
905
|
var fresh = new Set();
|
|
906
|
+
var sent_css = /** @type {Set<string>} */ (this.#sent_css);
|
|
880
907
|
for (var hash of hashes) {
|
|
881
|
-
if (!
|
|
882
|
-
|
|
908
|
+
if (!sent_css.has(hash)) {
|
|
909
|
+
sent_css.add(hash);
|
|
883
910
|
fresh.add(hash);
|
|
884
911
|
}
|
|
885
912
|
}
|
|
@@ -901,33 +928,42 @@ export class Output {
|
|
|
901
928
|
if (this.#streamOutput === null || this.#stream_finished || !this.#shell_flushed) {
|
|
902
929
|
return;
|
|
903
930
|
}
|
|
904
|
-
if (!unit.settled || unit.flushed || !unit.slot_sent) {
|
|
931
|
+
if (!unit.settled || unit.flushed || !unit.slot_sent || this.#flush_scheduled) {
|
|
905
932
|
return;
|
|
906
933
|
}
|
|
907
|
-
|
|
908
|
-
|
|
934
|
+
// Units settling in the same macrotask (data arriving together, a
|
|
935
|
+
// batch of promises resolved by one timer or I/O callback) travel in
|
|
936
|
+
// one chunk: the flush runs once the current task's microtasks have
|
|
937
|
+
// drained. Closing the stream flushes whatever is still queued first.
|
|
938
|
+
this.#flush_scheduled = true;
|
|
939
|
+
defer(() => this.#flush_settled());
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
#flush_settled() {
|
|
943
|
+
this.#flush_scheduled = false;
|
|
944
|
+
if (!this.#stream_finished) {
|
|
945
|
+
this.#sweep_units();
|
|
946
|
+
}
|
|
909
947
|
}
|
|
910
948
|
|
|
911
949
|
/**
|
|
912
950
|
* @param {FlushUnit} unit
|
|
913
|
-
* @returns {
|
|
951
|
+
* @returns {string}
|
|
914
952
|
*/
|
|
915
|
-
#
|
|
916
|
-
var sink = /** @type {StreamSink} */ (this.#streamOutput);
|
|
953
|
+
#unit_chunk(unit) {
|
|
917
954
|
if (unit.errored) {
|
|
918
955
|
unit.flushed = true;
|
|
919
|
-
|
|
956
|
+
return (
|
|
920
957
|
'<script id="' +
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
958
|
+
STREAM_ERROR_SCRIPT_PREFIX +
|
|
959
|
+
unit.id +
|
|
960
|
+
'" type="application/json">' +
|
|
961
|
+
escape_inline_script(JSON.stringify({ message: unit.error })) +
|
|
962
|
+
'</script>' +
|
|
963
|
+
'<script>__RIPPLE_S__(' +
|
|
964
|
+
unit.id +
|
|
965
|
+
',1)</script>'
|
|
929
966
|
);
|
|
930
|
-
return;
|
|
931
967
|
}
|
|
932
968
|
/** @type {StreamChunk} */
|
|
933
969
|
var chunk = { css: new Set(), scripts: [], head: '' };
|
|
@@ -939,28 +975,32 @@ export class Output {
|
|
|
939
975
|
out += chunk.scripts.join('');
|
|
940
976
|
out += '<template ' + STREAM_CHUNK_ATTR + '="' + unit.id + '">' + html + '</template>';
|
|
941
977
|
out += '<script>__RIPPLE_S__(' + unit.id + ')</script>';
|
|
942
|
-
|
|
978
|
+
return out;
|
|
943
979
|
}
|
|
944
980
|
|
|
945
981
|
/**
|
|
946
|
-
*
|
|
947
|
-
* settled. Flushing a parent
|
|
948
|
-
* which can make further units eligible — loop until a fixpoint.
|
|
982
|
+
* Streams every unit whose slot has been sent and whose async work has
|
|
983
|
+
* settled, as one chunk. Flushing a parent marks nested unsettled slots
|
|
984
|
+
* as sent, which can make further units eligible — loop until a fixpoint.
|
|
949
985
|
* @returns {void}
|
|
950
986
|
*/
|
|
951
987
|
#sweep_units() {
|
|
952
|
-
var units = this.#units;
|
|
988
|
+
var units = /** @type {FlushUnit[]} */ (this.#units);
|
|
989
|
+
var out = '';
|
|
953
990
|
var progressed = true;
|
|
954
991
|
while (progressed) {
|
|
955
992
|
progressed = false;
|
|
956
993
|
for (var i = 0; i < units.length; i++) {
|
|
957
994
|
var unit = units[i];
|
|
958
995
|
if (unit.settled && !unit.flushed && unit.slot_sent) {
|
|
959
|
-
this.#
|
|
996
|
+
out += this.#unit_chunk(unit);
|
|
960
997
|
progressed = true;
|
|
961
998
|
}
|
|
962
999
|
}
|
|
963
1000
|
}
|
|
1001
|
+
if (out !== '') {
|
|
1002
|
+
/** @type {StreamSink} */ (this.#streamOutput).push(out);
|
|
1003
|
+
}
|
|
964
1004
|
}
|
|
965
1005
|
|
|
966
1006
|
/**
|
|
@@ -984,7 +1024,7 @@ export class Output {
|
|
|
984
1024
|
// the root boundary's slot is the shell body itself
|
|
985
1025
|
this.unit.slot_sent = true;
|
|
986
1026
|
}
|
|
987
|
-
for (var hash of this.#css) {
|
|
1027
|
+
for (var hash of /** @type {Set<string>} */ (this.#css)) {
|
|
988
1028
|
chunk.css.add(hash);
|
|
989
1029
|
}
|
|
990
1030
|
var template = this.#stream_template;
|
|
@@ -1003,8 +1043,9 @@ export class Output {
|
|
|
1003
1043
|
out += BLOCK_OPEN + body + BLOCK_CLOSE;
|
|
1004
1044
|
}
|
|
1005
1045
|
var has_open_units = false;
|
|
1006
|
-
|
|
1007
|
-
|
|
1046
|
+
var units = /** @type {FlushUnit[]} */ (this.#units);
|
|
1047
|
+
for (var i = 0; i < units.length; i++) {
|
|
1048
|
+
if (!units[i].flushed) {
|
|
1008
1049
|
has_open_units = true;
|
|
1009
1050
|
break;
|
|
1010
1051
|
}
|
|
@@ -1072,6 +1113,7 @@ export class Output {
|
|
|
1072
1113
|
_closeStream() {
|
|
1073
1114
|
if (this.#is_root) {
|
|
1074
1115
|
if (this.#streamOutput && this.#stream_started && !this.#stream_finished) {
|
|
1116
|
+
this.#sweep_units();
|
|
1075
1117
|
this.#stream_finished = true;
|
|
1076
1118
|
if (this.#stream_template !== null && this.#stream_template.after !== '') {
|
|
1077
1119
|
this.#streamOutput.push(this.#stream_template.after);
|
|
@@ -1113,17 +1155,28 @@ export class Output {
|
|
|
1113
1155
|
}
|
|
1114
1156
|
}
|
|
1115
1157
|
|
|
1158
|
+
/**
|
|
1159
|
+
* Concatenates a buffer tree (see `Output`) into one string. A hand-rolled
|
|
1160
|
+
* walk is far cheaper than `flat(Infinity).join('')` on a cold isolate, where
|
|
1161
|
+
* a render's cost is dominated by unoptimized code.
|
|
1162
|
+
* @param {NestedArray<string>} tree
|
|
1163
|
+
* @returns {string}
|
|
1164
|
+
*/
|
|
1165
|
+
function flatten_buffer(tree) {
|
|
1166
|
+
var out = '';
|
|
1167
|
+
for (var i = 0; i < tree.length; i++) {
|
|
1168
|
+
var item = tree[i];
|
|
1169
|
+
out += typeof item === 'string' ? item : flatten_buffer(item);
|
|
1170
|
+
}
|
|
1171
|
+
return out;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1116
1174
|
/**
|
|
1117
1175
|
* @param {RenderComponent} component
|
|
1118
|
-
* @param {BaseRenderOptions} [
|
|
1176
|
+
* @param {BaseRenderOptions} [options]
|
|
1119
1177
|
* @returns {Promise<RenderResult | RenderStreamResult>}
|
|
1120
1178
|
*/
|
|
1121
|
-
export async function render(component,
|
|
1122
|
-
/** @type {BaseRenderOptions} */
|
|
1123
|
-
var options = {
|
|
1124
|
-
...(passed_in_options.stream ? { closeStream: true } : {}),
|
|
1125
|
-
...passed_in_options,
|
|
1126
|
-
};
|
|
1179
|
+
export async function render(component, options = {}) {
|
|
1127
1180
|
/** @type {Error | null } */
|
|
1128
1181
|
var top_level_error = null;
|
|
1129
1182
|
var head = '';
|
|
@@ -1182,7 +1235,7 @@ export async function render(component, passed_in_options = {}) {
|
|
|
1182
1235
|
await output.promise;
|
|
1183
1236
|
reset_state();
|
|
1184
1237
|
|
|
1185
|
-
if (output.isStreamMode() && options.closeStream) {
|
|
1238
|
+
if (output.isStreamMode() && ('closeStream' in options ? options.closeStream : true)) {
|
|
1186
1239
|
output._closeStream();
|
|
1187
1240
|
}
|
|
1188
1241
|
|
|
@@ -1199,12 +1252,40 @@ export async function render(component, passed_in_options = {}) {
|
|
|
1199
1252
|
* @returns {void}
|
|
1200
1253
|
*/
|
|
1201
1254
|
function sync_buffers_to_string(output) {
|
|
1202
|
-
head =
|
|
1203
|
-
body = BLOCK_OPEN +
|
|
1255
|
+
head = flatten_buffer(output.head);
|
|
1256
|
+
body = BLOCK_OPEN + flatten_buffer(output.body) + BLOCK_CLOSE;
|
|
1204
1257
|
css = output.css;
|
|
1205
1258
|
}
|
|
1206
1259
|
}
|
|
1207
1260
|
|
|
1261
|
+
var CONTENT_SPECIAL = /[&<]/;
|
|
1262
|
+
var ATTR_SPECIAL = /[&"<]/;
|
|
1263
|
+
var SCRIPT_SPECIAL = /[<>]/;
|
|
1264
|
+
|
|
1265
|
+
/**
|
|
1266
|
+
* Escapes the characters that could end an inline `<script>` early. JSON
|
|
1267
|
+
* payloads rarely contain `<` or `>`, so one test replaces two global
|
|
1268
|
+
* replace scans in the common case.
|
|
1269
|
+
* @param {string} str
|
|
1270
|
+
* @returns {string}
|
|
1271
|
+
*/
|
|
1272
|
+
function escape_inline_script(str) {
|
|
1273
|
+
return SCRIPT_SPECIAL.test(str) ? escape_script(str) : str;
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
/**
|
|
1277
|
+
* Escapes text or attribute content. Strings without a character to escape
|
|
1278
|
+
* (the common case) return as they are after a single regex test; anything
|
|
1279
|
+
* else goes through the general escaper.
|
|
1280
|
+
* @param {unknown} value
|
|
1281
|
+
* @param {boolean} [is_attr]
|
|
1282
|
+
* @returns {string}
|
|
1283
|
+
*/
|
|
1284
|
+
export function escape(value, is_attr) {
|
|
1285
|
+
var str = typeof value === 'string' ? value : value == null ? '' : String(value);
|
|
1286
|
+
return (is_attr ? ATTR_SPECIAL : CONTENT_SPECIAL).test(str) ? escape_html(str, is_attr) : str;
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1208
1289
|
/**
|
|
1209
1290
|
* @returns {void}
|
|
1210
1291
|
*/
|
|
@@ -1213,7 +1294,7 @@ export function push_component() {
|
|
|
1213
1294
|
c: null,
|
|
1214
1295
|
p: active_component,
|
|
1215
1296
|
};
|
|
1216
|
-
active_block = component_block(
|
|
1297
|
+
active_block = component_block(noop);
|
|
1217
1298
|
}
|
|
1218
1299
|
|
|
1219
1300
|
/**
|
|
@@ -1268,7 +1349,11 @@ function print_nesting_error(message) {
|
|
|
1268
1349
|
`node_invalid_placement_ssr: ${message}\n\n` +
|
|
1269
1350
|
'This can cause content to shift around as the browser repairs the HTML, and will likely result in a hydration mismatch.';
|
|
1270
1351
|
|
|
1271
|
-
if (seen_warnings
|
|
1352
|
+
if (seen_warnings === null) {
|
|
1353
|
+
seen_warnings = new Set();
|
|
1354
|
+
} else if (seen_warnings.has(message)) {
|
|
1355
|
+
return;
|
|
1356
|
+
}
|
|
1272
1357
|
seen_warnings.add(message);
|
|
1273
1358
|
|
|
1274
1359
|
// eslint-disable-next-line no-console
|
|
@@ -1404,60 +1489,6 @@ export function get_derived(tracked) {
|
|
|
1404
1489
|
return g ? g(tracked.v) : tracked.v;
|
|
1405
1490
|
}
|
|
1406
1491
|
|
|
1407
|
-
/**
|
|
1408
|
-
* @param {any} lazy
|
|
1409
|
-
* @param {number} [index]
|
|
1410
|
-
* @returns {any}
|
|
1411
|
-
*/
|
|
1412
|
-
export function lazy_array_get(lazy, index = 0) {
|
|
1413
|
-
if (is_array(lazy)) {
|
|
1414
|
-
return lazy[index];
|
|
1415
|
-
}
|
|
1416
|
-
var flags = lazy.f;
|
|
1417
|
-
if (flags === TRACKED) {
|
|
1418
|
-
return index === 0
|
|
1419
|
-
? get_tracked(/** @type {Tracked} */ (lazy))
|
|
1420
|
-
: index === 1
|
|
1421
|
-
? lazy
|
|
1422
|
-
: undefined;
|
|
1423
|
-
}
|
|
1424
|
-
if (flags === DERIVED) {
|
|
1425
|
-
return index === 0
|
|
1426
|
-
? get_derived(/** @type {Derived} */ (lazy))
|
|
1427
|
-
: index === 1
|
|
1428
|
-
? lazy
|
|
1429
|
-
: undefined;
|
|
1430
|
-
}
|
|
1431
|
-
return iterable_array_from(lazy, index)[0];
|
|
1432
|
-
}
|
|
1433
|
-
|
|
1434
|
-
/**
|
|
1435
|
-
* @param {any} lazy
|
|
1436
|
-
* @param {number} [index]
|
|
1437
|
-
* @returns {any[]}
|
|
1438
|
-
*/
|
|
1439
|
-
export function lazy_array_rest(lazy, index = 0) {
|
|
1440
|
-
if (is_array(lazy)) {
|
|
1441
|
-
return lazy.slice(index);
|
|
1442
|
-
}
|
|
1443
|
-
var flags = lazy.f;
|
|
1444
|
-
if (flags === TRACKED) {
|
|
1445
|
-
return index === 0
|
|
1446
|
-
? [get_tracked(/** @type {Tracked} */ (lazy)), lazy]
|
|
1447
|
-
: index === 1
|
|
1448
|
-
? [lazy]
|
|
1449
|
-
: [];
|
|
1450
|
-
}
|
|
1451
|
-
if (flags === DERIVED) {
|
|
1452
|
-
return index === 0
|
|
1453
|
-
? [get_derived(/** @type {Derived} */ (lazy)), lazy]
|
|
1454
|
-
: index === 1
|
|
1455
|
-
? [lazy]
|
|
1456
|
-
: [];
|
|
1457
|
-
}
|
|
1458
|
-
return iterable_array_from(lazy, index);
|
|
1459
|
-
}
|
|
1460
|
-
|
|
1461
1492
|
/**
|
|
1462
1493
|
* @param {Derived | Tracked} tracked
|
|
1463
1494
|
* @param {any} value
|
|
@@ -1467,62 +1498,11 @@ export function set(tracked, value) {
|
|
|
1467
1498
|
|
|
1468
1499
|
if (value !== old_value) {
|
|
1469
1500
|
var s = tracked.a.set;
|
|
1470
|
-
tracked.v = s ? s(value, tracked.v) : value;
|
|
1501
|
+
tracked.v = typeof s === 'function' ? s(value, tracked.v) : value;
|
|
1471
1502
|
tracked.c = increment_clock();
|
|
1472
1503
|
}
|
|
1473
1504
|
}
|
|
1474
1505
|
|
|
1475
|
-
/**
|
|
1476
|
-
* @param {any} lazy
|
|
1477
|
-
* @param {any} value
|
|
1478
|
-
* @param {number} [index]
|
|
1479
|
-
* @returns {void}
|
|
1480
|
-
*/
|
|
1481
|
-
export function lazy_array_set(lazy, value, index = 0) {
|
|
1482
|
-
if (is_array(lazy)) {
|
|
1483
|
-
lazy[index] = value;
|
|
1484
|
-
return;
|
|
1485
|
-
}
|
|
1486
|
-
var flags = lazy.f;
|
|
1487
|
-
if (flags === TRACKED || flags === DERIVED) {
|
|
1488
|
-
if (index === 0) {
|
|
1489
|
-
set(/** @type {Derived | Tracked} */ (lazy), value);
|
|
1490
|
-
return;
|
|
1491
|
-
}
|
|
1492
|
-
if (index === 1) {
|
|
1493
|
-
throw_tracked_index_reference_error();
|
|
1494
|
-
}
|
|
1495
|
-
return;
|
|
1496
|
-
}
|
|
1497
|
-
lazy[index] = value;
|
|
1498
|
-
}
|
|
1499
|
-
|
|
1500
|
-
/**
|
|
1501
|
-
* @param {any} lazy
|
|
1502
|
-
* @param {number} [index]
|
|
1503
|
-
* @param {number} [d]
|
|
1504
|
-
* @returns {number}
|
|
1505
|
-
*/
|
|
1506
|
-
export function lazy_array_update(lazy, index = 0, d = 1) {
|
|
1507
|
-
var value = lazy_array_get(lazy, index);
|
|
1508
|
-
var result = d === 1 ? value++ : value--;
|
|
1509
|
-
lazy_array_set(lazy, value, index);
|
|
1510
|
-
return result;
|
|
1511
|
-
}
|
|
1512
|
-
|
|
1513
|
-
/**
|
|
1514
|
-
* @param {any} lazy
|
|
1515
|
-
* @param {number} [index]
|
|
1516
|
-
* @param {number} [d]
|
|
1517
|
-
* @returns {number}
|
|
1518
|
-
*/
|
|
1519
|
-
export function lazy_array_update_pre(lazy, index = 0, d = 1) {
|
|
1520
|
-
var value = lazy_array_get(lazy, index);
|
|
1521
|
-
var new_value = d === 1 ? ++value : --value;
|
|
1522
|
-
lazy_array_set(lazy, new_value, index);
|
|
1523
|
-
return new_value;
|
|
1524
|
-
}
|
|
1525
|
-
|
|
1526
1506
|
/**
|
|
1527
1507
|
* @param {Tracked} tracked
|
|
1528
1508
|
* @param {number} [d]
|
|
@@ -1630,14 +1610,16 @@ export function attr(name, value, is_boolean = false) {
|
|
|
1630
1610
|
}
|
|
1631
1611
|
|
|
1632
1612
|
/**
|
|
1633
|
-
* @param {Record<string, string | number>} styles
|
|
1613
|
+
* @param {Record<string, string | number | null | undefined>} styles
|
|
1634
1614
|
* @returns {string}
|
|
1635
1615
|
*/
|
|
1636
1616
|
function get_styles(styles) {
|
|
1637
1617
|
var result = '';
|
|
1638
1618
|
for (const key in styles) {
|
|
1619
|
+
const raw_value = styles[key];
|
|
1620
|
+
if (raw_value == null) continue;
|
|
1639
1621
|
const css_prop = normalize_css_property_name(key);
|
|
1640
|
-
const value = String(
|
|
1622
|
+
const value = String(raw_value).trim();
|
|
1641
1623
|
result += `${css_prop}: ${value}; `;
|
|
1642
1624
|
}
|
|
1643
1625
|
return result.trim();
|
|
@@ -1645,11 +1627,10 @@ function get_styles(styles) {
|
|
|
1645
1627
|
|
|
1646
1628
|
/**
|
|
1647
1629
|
* @param {Record<string, any>} attrs
|
|
1648
|
-
* @param {string | undefined} css_hash
|
|
1649
|
-
* @param {string} [exclude_prop]
|
|
1630
|
+
* @param {string | undefined} [css_hash]
|
|
1650
1631
|
* @returns {string}
|
|
1651
1632
|
*/
|
|
1652
|
-
export function spread_attrs(attrs, css_hash
|
|
1633
|
+
export function spread_attrs(attrs, css_hash) {
|
|
1653
1634
|
let attr_str = '';
|
|
1654
1635
|
let name;
|
|
1655
1636
|
|
|
@@ -1664,7 +1645,6 @@ export function spread_attrs(attrs, css_hash, exclude_prop) {
|
|
|
1664
1645
|
name === 'children' ||
|
|
1665
1646
|
name === 'innerHTML' ||
|
|
1666
1647
|
name === '#class' ||
|
|
1667
|
-
name === exclude_prop ||
|
|
1668
1648
|
typeof value === 'function' ||
|
|
1669
1649
|
is_tsrx_element(value)
|
|
1670
1650
|
)
|
|
@@ -1707,11 +1687,11 @@ var empty_get_set = { get: undefined, set: undefined };
|
|
|
1707
1687
|
class TrackedValue {
|
|
1708
1688
|
/**
|
|
1709
1689
|
* @param {any} v
|
|
1710
|
-
* @param {{ get?: Function; set?: Function }} a
|
|
1690
|
+
* @param {{ get?: Function; set?: Function | true }} a
|
|
1711
1691
|
* @param {string} hash
|
|
1712
1692
|
*/
|
|
1713
1693
|
constructor(v, a, hash) {
|
|
1714
|
-
/** @type {{ get?: Function; set?: Function }} */
|
|
1694
|
+
/** @type {{ get?: Function; set?: Function | true }} */
|
|
1715
1695
|
this.a = a;
|
|
1716
1696
|
/** @type {AbortController | null} */
|
|
1717
1697
|
this.aa = null;
|
|
@@ -1729,18 +1709,6 @@ class TrackedValue {
|
|
|
1729
1709
|
this.v = v;
|
|
1730
1710
|
}
|
|
1731
1711
|
/** @returns {any} */
|
|
1732
|
-
get [0]() {
|
|
1733
|
-
return throw_tracked_index_value_error();
|
|
1734
|
-
}
|
|
1735
|
-
/** @param {any} v */
|
|
1736
|
-
set [0](v) {
|
|
1737
|
-
throw_tracked_index_value_error();
|
|
1738
|
-
}
|
|
1739
|
-
/** @returns {Tracked} */
|
|
1740
|
-
get [1]() {
|
|
1741
|
-
return throw_tracked_index_reference_error();
|
|
1742
|
-
}
|
|
1743
|
-
/** @returns {any} */
|
|
1744
1712
|
get value() {
|
|
1745
1713
|
return get_tracked(/** @type {Tracked} */ (this));
|
|
1746
1714
|
}
|
|
@@ -1748,25 +1716,25 @@ class TrackedValue {
|
|
|
1748
1716
|
set value(v) {
|
|
1749
1717
|
set(/** @type {Tracked} */ (this), v);
|
|
1750
1718
|
}
|
|
1751
|
-
/**
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1719
|
+
/**
|
|
1720
|
+
* A read-only view: a derived over this value, for a receiver that should
|
|
1721
|
+
* read but not write it. Equivalent to `track(() => tracked.value)`. The
|
|
1722
|
+
* view has no hash of its own: it is not a serialized value.
|
|
1723
|
+
* @returns {Derived}
|
|
1724
|
+
*/
|
|
1725
|
+
readOnly() {
|
|
1726
|
+
return derived(() => get_tracked(/** @type {Tracked} */ (this)));
|
|
1759
1727
|
}
|
|
1760
1728
|
}
|
|
1761
1729
|
|
|
1762
1730
|
class DerivedValue {
|
|
1763
1731
|
/**
|
|
1764
1732
|
* @param {Function} fn
|
|
1765
|
-
* @param {{ get?: Function; set?: Function }} a
|
|
1766
|
-
* @param {string} hash
|
|
1733
|
+
* @param {{ get?: Function; set?: Function | true }} a
|
|
1734
|
+
* @param {string} [hash]
|
|
1767
1735
|
*/
|
|
1768
1736
|
constructor(fn, a, hash) {
|
|
1769
|
-
/** @type {{ get?: Function; set?: Function }} */
|
|
1737
|
+
/** @type {{ get?: Function; set?: Function | true }} */
|
|
1770
1738
|
this.a = a;
|
|
1771
1739
|
// we always should have an active block
|
|
1772
1740
|
/** @type {Block} */
|
|
@@ -1781,24 +1749,12 @@ class DerivedValue {
|
|
|
1781
1749
|
this.f = DERIVED;
|
|
1782
1750
|
/** @type {Function} */
|
|
1783
1751
|
this.fn = fn;
|
|
1784
|
-
/** @type {string} */
|
|
1752
|
+
/** @type {string | undefined} */
|
|
1785
1753
|
this.h = hash;
|
|
1786
1754
|
/** @type {any} */
|
|
1787
1755
|
this.v = UNINITIALIZED;
|
|
1788
1756
|
}
|
|
1789
1757
|
/** @returns {any} */
|
|
1790
|
-
get [0]() {
|
|
1791
|
-
return throw_tracked_index_value_error();
|
|
1792
|
-
}
|
|
1793
|
-
/** @param {any} v */
|
|
1794
|
-
set [0](v) {
|
|
1795
|
-
throw_tracked_index_value_error();
|
|
1796
|
-
}
|
|
1797
|
-
/** @returns {Derived} */
|
|
1798
|
-
get [1]() {
|
|
1799
|
-
return throw_tracked_index_reference_error();
|
|
1800
|
-
}
|
|
1801
|
-
/** @returns {any} */
|
|
1802
1758
|
get value() {
|
|
1803
1759
|
return get_derived(/** @type {Derived} */ (this));
|
|
1804
1760
|
}
|
|
@@ -1806,14 +1762,16 @@ class DerivedValue {
|
|
|
1806
1762
|
set value(v) {
|
|
1807
1763
|
set(/** @type {Derived} */ (this), v);
|
|
1808
1764
|
}
|
|
1809
|
-
/**
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1765
|
+
/**
|
|
1766
|
+
* A read-only view (see `TrackedValue#readOnly`). A derived without a
|
|
1767
|
+
* setter is already read-only and is returned as is; a writable one is
|
|
1768
|
+
* wrapped in a derived that follows it.
|
|
1769
|
+
* @returns {Derived}
|
|
1770
|
+
*/
|
|
1771
|
+
readOnly() {
|
|
1772
|
+
return this.a.set === undefined
|
|
1773
|
+
? /** @type {Derived} */ (this)
|
|
1774
|
+
: derived(() => get_derived(/** @type {Derived} */ (this)));
|
|
1817
1775
|
}
|
|
1818
1776
|
}
|
|
1819
1777
|
|
|
@@ -1821,7 +1779,7 @@ class DerivedValue {
|
|
|
1821
1779
|
* @param {any} v
|
|
1822
1780
|
* @param {string} hash
|
|
1823
1781
|
* @param {(value: any) => any} [get]
|
|
1824
|
-
* @param {(next: any, prev: any) => any} [set]
|
|
1782
|
+
* @param {((next: any, prev: any) => any) | true} [set]
|
|
1825
1783
|
* @returns {Tracked}
|
|
1826
1784
|
*/
|
|
1827
1785
|
function tracked(v, hash, get, set) {
|
|
@@ -1830,29 +1788,11 @@ function tracked(v, hash, get, set) {
|
|
|
1830
1788
|
);
|
|
1831
1789
|
}
|
|
1832
1790
|
|
|
1833
|
-
/**
|
|
1834
|
-
* @param {Record<string, unknown>} obj
|
|
1835
|
-
* @param {string[]} exclude_keys
|
|
1836
|
-
* @returns {Record<string, unknown>}
|
|
1837
|
-
*/
|
|
1838
|
-
export function exclude_from_object(obj, exclude_keys) {
|
|
1839
|
-
/** @type {Record<string, unknown>} */
|
|
1840
|
-
var new_obj = {};
|
|
1841
|
-
|
|
1842
|
-
for (const key of Object.keys(obj)) {
|
|
1843
|
-
if (!exclude_keys.includes(key)) {
|
|
1844
|
-
new_obj[key] = obj[key];
|
|
1845
|
-
}
|
|
1846
|
-
}
|
|
1847
|
-
|
|
1848
|
-
return new_obj;
|
|
1849
|
-
}
|
|
1850
|
-
|
|
1851
1791
|
/**
|
|
1852
1792
|
* @param {any} v
|
|
1853
|
-
* @param {string} hash
|
|
1793
|
+
* @param {string} [hash]
|
|
1854
1794
|
* @param {(value: any) => any} [get]
|
|
1855
|
-
* @param {(next: any, prev: any) => any} [set]
|
|
1795
|
+
* @param {((next: any, prev: any) => any) | true} [set]
|
|
1856
1796
|
* @returns {Derived}
|
|
1857
1797
|
*/
|
|
1858
1798
|
function derived(v, hash, get, set) {
|
|
@@ -1865,7 +1805,7 @@ function derived(v, hash, get, set) {
|
|
|
1865
1805
|
* @param {any} v
|
|
1866
1806
|
* @param {string} hash
|
|
1867
1807
|
* @param {(value: any) => any} [get]
|
|
1868
|
-
* @param {(next: any, prev: any) => any} [set]
|
|
1808
|
+
* @param {((next: any, prev: any) => any) | true} [set]
|
|
1869
1809
|
* @returns {Tracked | Derived}
|
|
1870
1810
|
*/
|
|
1871
1811
|
export function track(v, hash, get, set) {
|
|
@@ -1891,12 +1831,130 @@ export function track(v, hash, get, set) {
|
|
|
1891
1831
|
* @returns {void}
|
|
1892
1832
|
*/
|
|
1893
1833
|
function serialize_track_async_result(output, hash, value, deps) {
|
|
1894
|
-
/** @type {
|
|
1895
|
-
var envelope
|
|
1896
|
-
if (
|
|
1897
|
-
envelope
|
|
1834
|
+
/** @type {string} */
|
|
1835
|
+
var envelope;
|
|
1836
|
+
if (is_plain_data(value, null)) {
|
|
1837
|
+
// plain data: the value travels as raw JSON inside the envelope, so the
|
|
1838
|
+
// client reads it straight off `JSON.parse` with no devalue pass
|
|
1839
|
+
envelope = '{"ok":true,"value":' + JSON.stringify(value);
|
|
1840
|
+
if (deps && deps.length > 0) {
|
|
1841
|
+
envelope += ',"deps":' + JSON.stringify(deps);
|
|
1842
|
+
}
|
|
1843
|
+
envelope += '}';
|
|
1844
|
+
} else {
|
|
1845
|
+
/** @type {{ ok: true, payload: string, deps?: string[] }} */
|
|
1846
|
+
var object = { ok: true, payload: devalue.stringify(value) };
|
|
1847
|
+
if (deps && deps.length > 0) {
|
|
1848
|
+
object.deps = deps;
|
|
1849
|
+
}
|
|
1850
|
+
envelope = JSON.stringify(object);
|
|
1898
1851
|
}
|
|
1899
|
-
|
|
1852
|
+
output.push_serialized_result(
|
|
1853
|
+
'<script id="' +
|
|
1854
|
+
get_track_async_script_id(hash) +
|
|
1855
|
+
'" type="application/json">' +
|
|
1856
|
+
escape_inline_script(envelope) +
|
|
1857
|
+
'</script>',
|
|
1858
|
+
);
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1861
|
+
const default_track_async_serializer = serialize_track_async_result;
|
|
1862
|
+
|
|
1863
|
+
/**
|
|
1864
|
+
* Switch once at registration, keeping the default serializer unchanged and
|
|
1865
|
+
* avoiding a transport lookup for every result. Unused registration code can
|
|
1866
|
+
* be removed from builds that only use the default renderer.
|
|
1867
|
+
* @param {Record<string, (value: any) => any> | undefined} reducers
|
|
1868
|
+
*/
|
|
1869
|
+
export function set_track_async_transport(reducers) {
|
|
1870
|
+
/** @type {typeof serialize_track_async_result} */
|
|
1871
|
+
const serializer =
|
|
1872
|
+
reducers === undefined
|
|
1873
|
+
? default_track_async_serializer
|
|
1874
|
+
: (output, hash, value, deps) => {
|
|
1875
|
+
// Reducers can claim plain objects: devalue must do the only walk.
|
|
1876
|
+
// Embed its JSON directly, avoiding another stringify of the payload
|
|
1877
|
+
// string and another JSON.parse on the client before revival.
|
|
1878
|
+
let envelope = '{"ok":true,"payload":' + devalue.stringify(value, reducers);
|
|
1879
|
+
if (deps && deps.length > 0) envelope += ',"deps":' + JSON.stringify(deps);
|
|
1880
|
+
envelope += '}';
|
|
1881
|
+
output.push_serialized_result(
|
|
1882
|
+
'<script id="' +
|
|
1883
|
+
get_track_async_script_id(hash) +
|
|
1884
|
+
'" type="application/json">' +
|
|
1885
|
+
escape_inline_script(envelope) +
|
|
1886
|
+
'</script>',
|
|
1887
|
+
);
|
|
1888
|
+
};
|
|
1889
|
+
// Keep the function declaration so unused registration leaves exactly the
|
|
1890
|
+
// original renderer in production bundles, without a mutable alias.
|
|
1891
|
+
// @ts-expect-error JavaScript permits reassigning a function declaration.
|
|
1892
|
+
serialize_track_async_result = serializer;
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
/**
|
|
1896
|
+
* Whether a value is a plain data tree that `JSON.stringify` encodes without
|
|
1897
|
+
* loss: strings, finite numbers (not `-0`), booleans, `null`, arrays without
|
|
1898
|
+
* holes and plain objects, every object reachable exactly once. `JSON.parse`
|
|
1899
|
+
* on the client then yields exactly what `devalue.parse` would. Anything else
|
|
1900
|
+
* — `undefined`, `NaN`, `Infinity`, `-0`, bigints, symbols, functions, Dates,
|
|
1901
|
+
* Maps, Sets, class instances, null-prototype objects, symbol keys, cycles
|
|
1902
|
+
* and shared references — keeps its devalue encoding.
|
|
1903
|
+
* @param {unknown} value
|
|
1904
|
+
* @param {Set<object> | null} seen
|
|
1905
|
+
* @returns {boolean}
|
|
1906
|
+
*/
|
|
1907
|
+
function is_plain_data(value, seen) {
|
|
1908
|
+
switch (typeof value) {
|
|
1909
|
+
case 'string':
|
|
1910
|
+
case 'boolean':
|
|
1911
|
+
return true;
|
|
1912
|
+
case 'number':
|
|
1913
|
+
return (
|
|
1914
|
+
value === value &&
|
|
1915
|
+
value !== Infinity &&
|
|
1916
|
+
value !== -Infinity &&
|
|
1917
|
+
(value !== 0 || 1 / value > 0)
|
|
1918
|
+
);
|
|
1919
|
+
case 'object':
|
|
1920
|
+
break;
|
|
1921
|
+
default:
|
|
1922
|
+
return false;
|
|
1923
|
+
}
|
|
1924
|
+
if (value === null) {
|
|
1925
|
+
return true;
|
|
1926
|
+
}
|
|
1927
|
+
var proto = Object.getPrototypeOf(value);
|
|
1928
|
+
var is_list = proto === Array.prototype;
|
|
1929
|
+
if (!is_list && proto !== Object.prototype) {
|
|
1930
|
+
return false;
|
|
1931
|
+
}
|
|
1932
|
+
if (seen === null) {
|
|
1933
|
+
seen = new Set();
|
|
1934
|
+
} else if (seen.has(value)) {
|
|
1935
|
+
return false;
|
|
1936
|
+
}
|
|
1937
|
+
seen.add(value);
|
|
1938
|
+
if (is_list) {
|
|
1939
|
+
var list = /** @type {unknown[]} */ (value);
|
|
1940
|
+
for (var i = 0; i < list.length; i++) {
|
|
1941
|
+
if (!is_plain_data(list[i], seen)) {
|
|
1942
|
+
return false;
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
return true;
|
|
1946
|
+
}
|
|
1947
|
+
if (Object.getOwnPropertySymbols(value).length !== 0) {
|
|
1948
|
+
return false;
|
|
1949
|
+
}
|
|
1950
|
+
var record = /** @type {Record<string, unknown>} */ (value);
|
|
1951
|
+
var keys = Object.keys(record);
|
|
1952
|
+
for (var k = 0; k < keys.length; k++) {
|
|
1953
|
+
if (!is_plain_data(record[keys[k]], seen)) {
|
|
1954
|
+
return false;
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
return true;
|
|
1900
1958
|
}
|
|
1901
1959
|
|
|
1902
1960
|
/**
|
|
@@ -2075,7 +2133,7 @@ function settle_unit_after_catch(catch_block) {
|
|
|
2075
2133
|
* @returns {void}
|
|
2076
2134
|
*/
|
|
2077
2135
|
function push_script_for_hydration(push_fn, hash, envelope) {
|
|
2078
|
-
var serialized_envelope =
|
|
2136
|
+
var serialized_envelope = escape_inline_script(JSON.stringify(envelope));
|
|
2079
2137
|
|
|
2080
2138
|
push_fn(
|
|
2081
2139
|
'<script id="' +
|
|
@@ -2215,20 +2273,25 @@ function run_track_async(t, fn, block, dr, dj) {
|
|
|
2215
2273
|
}
|
|
2216
2274
|
|
|
2217
2275
|
/**
|
|
2218
|
-
*
|
|
2219
|
-
*
|
|
2276
|
+
* The hashes of the compile-time tracked values a trackAsync read, recorded
|
|
2277
|
+
* in its hydration envelope so the client re-subscribes to them. A dependency
|
|
2278
|
+
* without a hash that is itself a derived (a `readOnly()` view, a derived made
|
|
2279
|
+
* outside a compiled call) stands for what it read: its own dependencies are
|
|
2280
|
+
* recorded in its place.
|
|
2220
2281
|
* @param {Dependency | null} head
|
|
2282
|
+
* @param {string[] | null} [hashes]
|
|
2221
2283
|
* @returns {string[] | null}
|
|
2222
2284
|
*/
|
|
2223
|
-
function collect_dep_hashes(head) {
|
|
2224
|
-
/** @type {string[] | null} */
|
|
2225
|
-
var hashes = null;
|
|
2285
|
+
function collect_dep_hashes(head, hashes = null) {
|
|
2226
2286
|
var dep = head;
|
|
2227
2287
|
while (dep !== null) {
|
|
2228
|
-
var
|
|
2288
|
+
var t = /** @type {{ h?: string; f: number; d?: Dependency | null }} */ (dep.t);
|
|
2289
|
+
var h = t.h;
|
|
2229
2290
|
if (h !== undefined) {
|
|
2230
2291
|
if (hashes === null) hashes = [];
|
|
2231
|
-
hashes.push(h);
|
|
2292
|
+
if (!hashes.includes(h)) hashes.push(h);
|
|
2293
|
+
} else if ((t.f & DERIVED) !== 0) {
|
|
2294
|
+
hashes = collect_dep_hashes(t.d ?? null, hashes);
|
|
2232
2295
|
}
|
|
2233
2296
|
dep = dep.n;
|
|
2234
2297
|
}
|
|
@@ -2511,15 +2574,4 @@ export function ripple_map(iterable) {
|
|
|
2511
2574
|
return new Map(iterable);
|
|
2512
2575
|
}
|
|
2513
2576
|
|
|
2514
|
-
/**
|
|
2515
|
-
* Returns the fallback value if the given value is undefined.
|
|
2516
|
-
* @template T
|
|
2517
|
-
* @param {T | undefined} value
|
|
2518
|
-
* @param {T} fallback
|
|
2519
|
-
* @returns {T}
|
|
2520
|
-
*/
|
|
2521
|
-
export function fallback(value, fallback) {
|
|
2522
|
-
return value === undefined ? fallback : value;
|
|
2523
|
-
}
|
|
2524
|
-
|
|
2525
2577
|
export { dynamic_element } from './dynamic.js';
|