ripple 0.3.11 → 0.3.13
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 +43 -0
- package/package.json +8 -2
- package/src/compiler/phases/1-parse/index.js +73 -30
- package/src/compiler/phases/2-analyze/index.js +28 -58
- package/src/compiler/phases/3-transform/client/index.js +127 -164
- package/src/compiler/phases/3-transform/segments.js +4 -8
- package/src/compiler/phases/3-transform/server/index.js +210 -360
- package/src/compiler/types/import.d.ts +0 -12
- package/src/compiler/types/index.d.ts +12 -5
- package/src/compiler/types/parse.d.ts +2 -0
- package/src/compiler/utils.js +39 -44
- package/src/helpers.d.ts +2 -0
- package/src/runtime/index-client.js +15 -13
- package/src/runtime/index-server.js +18 -11
- package/src/runtime/internal/client/blocks.js +19 -23
- package/src/runtime/internal/client/constants.js +20 -9
- package/src/runtime/internal/client/index.js +14 -4
- package/src/runtime/internal/client/runtime.js +435 -173
- package/src/runtime/internal/client/try.js +334 -156
- package/src/runtime/internal/client/types.d.ts +26 -0
- package/src/runtime/internal/server/blocks.js +183 -0
- package/src/runtime/internal/server/constants.js +7 -0
- package/src/runtime/internal/server/index.js +780 -148
- package/src/runtime/internal/server/types.d.ts +35 -0
- package/src/server/index.js +1 -1
- package/src/utils/async.js +35 -0
- package/src/utils/builders.js +3 -1
- package/tests/client/__snapshots__/computed-properties.test.rsrx.snap +49 -0
- package/tests/client/__snapshots__/for.test.rsrx.snap +319 -0
- package/tests/client/__snapshots__/html.test.rsrx.snap +40 -0
- package/tests/client/_etc.test.rsrx +7 -0
- package/tests/client/array/{array.static.test.ripple → array.static.test.rsrx} +18 -20
- package/tests/client/async-suspend.test.rsrx +662 -0
- package/tests/client/basic/__snapshots__/basic.attributes.test.rsrx.snap +60 -0
- package/tests/client/basic/__snapshots__/basic.rendering.test.rsrx.snap +59 -0
- package/tests/client/basic/{basic.errors.test.ripple → basic.errors.test.rsrx} +2 -2
- package/tests/client/compiler/__snapshots__/compiler.assignments.test.rsrx.snap +12 -0
- package/tests/client/compiler/__snapshots__/compiler.typescript.test.rsrx.snap +46 -0
- package/tests/client/compiler/{compiler.try-in-function.test.ripple → compiler.try-in-function.test.rsrx} +8 -6
- package/tests/client/composite/__snapshots__/composite.render.test.rsrx.snap +37 -0
- package/tests/client/{function-overload.test.ripple → function-overload.test.rsrx} +1 -1
- package/tests/client/try.test.rsrx +1702 -0
- package/tests/hydration/build-components.js +5 -3
- package/tests/hydration/compiled/client/head.js +11 -11
- package/tests/hydration/compiled/client/mixed-control-flow.js +55 -70
- package/tests/hydration/compiled/client/nested-control-flow.js +72 -88
- package/tests/hydration/compiled/client/try.js +42 -54
- package/tests/hydration/compiled/server/basic.js +491 -369
- package/tests/hydration/compiled/server/composite.js +153 -128
- package/tests/hydration/compiled/server/events.js +166 -145
- package/tests/hydration/compiled/server/for.js +821 -677
- package/tests/hydration/compiled/server/head.js +200 -165
- package/tests/hydration/compiled/server/hmr.js +62 -54
- package/tests/hydration/compiled/server/html-in-template.js +64 -55
- package/tests/hydration/compiled/server/html.js +1477 -1360
- package/tests/hydration/compiled/server/if-children.js +448 -408
- package/tests/hydration/compiled/server/if.js +204 -171
- package/tests/hydration/compiled/server/mixed-control-flow.js +237 -195
- package/tests/hydration/compiled/server/nested-control-flow.js +533 -467
- package/tests/hydration/compiled/server/portal.js +94 -107
- package/tests/hydration/compiled/server/reactivity.js +87 -64
- package/tests/hydration/compiled/server/return.js +1424 -1174
- package/tests/hydration/compiled/server/switch.js +268 -238
- package/tests/hydration/compiled/server/try.js +98 -87
- package/tests/hydration/components/{mixed-control-flow.ripple → mixed-control-flow.rsrx} +2 -2
- package/tests/hydration/components/{try.ripple → try.rsrx} +4 -2
- package/tests/hydration/mixed-control-flow.test.js +14 -0
- package/tests/hydration/nested-control-flow.test.js +50 -48
- package/tests/hydration/try.test.js +25 -0
- package/tests/server/__snapshots__/compiler.test.ripple.snap +0 -32
- package/tests/server/__snapshots__/compiler.test.rsrx.snap +95 -0
- package/tests/server/{compiler.test.ripple → compiler.test.rsrx} +0 -17
- package/tests/server/{html-nesting-validation.test.ripple → html-nesting-validation.test.rsrx} +3 -3
- package/tests/server/streaming-ssr.test.rsrx +115 -0
- package/tests/server/try.test.rsrx +503 -0
- package/tests/utils/compiler-compat-config.test.js +3 -3
- package/tests/utils/vite-plugin-config.test.js +1 -1
- package/tests/utils/vite-plugin-hmr.test.js +5 -5
- package/tsconfig.json +4 -0
- package/types/index.d.ts +13 -23
- package/types/server.d.ts +43 -16
- package/tests/client/_etc.test.ripple +0 -5
- package/tests/client/async-suspend.test.ripple +0 -94
- package/tests/client/try.test.ripple +0 -196
- package/tests/server/streaming-ssr.test.ripple +0 -68
- package/tests/server/try.test.ripple +0 -82
- /package/tests/client/array/{array.copy-within.test.ripple → array.copy-within.test.rsrx} +0 -0
- /package/tests/client/array/{array.derived.test.ripple → array.derived.test.rsrx} +0 -0
- /package/tests/client/array/{array.iteration.test.ripple → array.iteration.test.rsrx} +0 -0
- /package/tests/client/array/{array.mutations.test.ripple → array.mutations.test.rsrx} +0 -0
- /package/tests/client/array/{array.to-methods.test.ripple → array.to-methods.test.rsrx} +0 -0
- /package/tests/client/basic/{basic.attributes.test.ripple → basic.attributes.test.rsrx} +0 -0
- /package/tests/client/basic/{basic.collections.test.ripple → basic.collections.test.rsrx} +0 -0
- /package/tests/client/basic/{basic.components.test.ripple → basic.components.test.rsrx} +0 -0
- /package/tests/client/basic/{basic.events.test.ripple → basic.events.test.rsrx} +0 -0
- /package/tests/client/basic/{basic.get-set.test.ripple → basic.get-set.test.rsrx} +0 -0
- /package/tests/client/basic/{basic.hmr.test.ripple → basic.hmr.test.rsrx} +0 -0
- /package/tests/client/basic/{basic.reactivity.test.ripple → basic.reactivity.test.rsrx} +0 -0
- /package/tests/client/basic/{basic.rendering.test.ripple → basic.rendering.test.rsrx} +0 -0
- /package/tests/client/basic/{basic.styling.test.ripple → basic.styling.test.rsrx} +0 -0
- /package/tests/client/basic/{basic.utilities.test.ripple → basic.utilities.test.rsrx} +0 -0
- /package/tests/client/{boundaries.test.ripple → boundaries.test.rsrx} +0 -0
- /package/tests/client/compiler/{compiler.assignments.test.ripple → compiler.assignments.test.rsrx} +0 -0
- /package/tests/client/compiler/{compiler.attributes.test.ripple → compiler.attributes.test.rsrx} +0 -0
- /package/tests/client/compiler/{compiler.basic.test.ripple → compiler.basic.test.rsrx} +0 -0
- /package/tests/client/compiler/{compiler.regex.test.ripple → compiler.regex.test.rsrx} +0 -0
- /package/tests/client/compiler/{compiler.tracked-access.test.ripple → compiler.tracked-access.test.rsrx} +0 -0
- /package/tests/client/compiler/{compiler.typescript.test.ripple → compiler.typescript.test.rsrx} +0 -0
- /package/tests/client/composite/{composite.dynamic-components.test.ripple → composite.dynamic-components.test.rsrx} +0 -0
- /package/tests/client/composite/{composite.generics.test.ripple → composite.generics.test.rsrx} +0 -0
- /package/tests/client/composite/{composite.props.test.ripple → composite.props.test.rsrx} +0 -0
- /package/tests/client/composite/{composite.reactivity.test.ripple → composite.reactivity.test.rsrx} +0 -0
- /package/tests/client/composite/{composite.render.test.ripple → composite.render.test.rsrx} +0 -0
- /package/tests/client/{computed-properties.test.ripple → computed-properties.test.rsrx} +0 -0
- /package/tests/client/{context.test.ripple → context.test.rsrx} +0 -0
- /package/tests/client/css/{global-additional-cases.test.ripple → global-additional-cases.test.rsrx} +0 -0
- /package/tests/client/css/{global-advanced-selectors.test.ripple → global-advanced-selectors.test.rsrx} +0 -0
- /package/tests/client/css/{global-at-rules.test.ripple → global-at-rules.test.rsrx} +0 -0
- /package/tests/client/css/{global-basic.test.ripple → global-basic.test.rsrx} +0 -0
- /package/tests/client/css/{global-classes-ids.test.ripple → global-classes-ids.test.rsrx} +0 -0
- /package/tests/client/css/{global-combinators.test.ripple → global-combinators.test.rsrx} +0 -0
- /package/tests/client/css/{global-complex-nesting.test.ripple → global-complex-nesting.test.rsrx} +0 -0
- /package/tests/client/css/{global-edge-cases.test.ripple → global-edge-cases.test.rsrx} +0 -0
- /package/tests/client/css/{global-keyframes.test.ripple → global-keyframes.test.rsrx} +0 -0
- /package/tests/client/css/{global-nested.test.ripple → global-nested.test.rsrx} +0 -0
- /package/tests/client/css/{global-pseudo.test.ripple → global-pseudo.test.rsrx} +0 -0
- /package/tests/client/css/{global-scoping.test.ripple → global-scoping.test.rsrx} +0 -0
- /package/tests/client/css/{style-identifier.test.ripple → style-identifier.test.rsrx} +0 -0
- /package/tests/client/{date.test.ripple → date.test.rsrx} +0 -0
- /package/tests/client/{dynamic-elements.test.ripple → dynamic-elements.test.rsrx} +0 -0
- /package/tests/client/{events.test.ripple → events.test.rsrx} +0 -0
- /package/tests/client/{for.test.ripple → for.test.rsrx} +0 -0
- /package/tests/client/{function-overload-import.ripple → function-overload-import.rsrx} +0 -0
- /package/tests/client/{head.test.ripple → head.test.rsrx} +0 -0
- /package/tests/client/{html.test.ripple → html.test.rsrx} +0 -0
- /package/tests/client/{input-value.test.ripple → input-value.test.rsrx} +0 -0
- /package/tests/client/{lazy-destructuring.test.ripple → lazy-destructuring.test.rsrx} +0 -0
- /package/tests/client/{map.test.ripple → map.test.rsrx} +0 -0
- /package/tests/client/{media-query.test.ripple → media-query.test.rsrx} +0 -0
- /package/tests/client/{object.test.ripple → object.test.rsrx} +0 -0
- /package/tests/client/{portal.test.ripple → portal.test.rsrx} +0 -0
- /package/tests/client/{ref.test.ripple → ref.test.rsrx} +0 -0
- /package/tests/client/{return.test.ripple → return.test.rsrx} +0 -0
- /package/tests/client/{set.test.ripple → set.test.rsrx} +0 -0
- /package/tests/client/{svg.test.ripple → svg.test.rsrx} +0 -0
- /package/tests/client/{switch.test.ripple → switch.test.rsrx} +0 -0
- /package/tests/client/{tsx.test.ripple → tsx.test.rsrx} +0 -0
- /package/tests/client/{typescript-generics.test.ripple → typescript-generics.test.rsrx} +0 -0
- /package/tests/client/url/{url.derived.test.ripple → url.derived.test.rsrx} +0 -0
- /package/tests/client/url/{url.parsing.test.ripple → url.parsing.test.rsrx} +0 -0
- /package/tests/client/url/{url.partial-removal.test.ripple → url.partial-removal.test.rsrx} +0 -0
- /package/tests/client/url/{url.reactivity.test.ripple → url.reactivity.test.rsrx} +0 -0
- /package/tests/client/url/{url.serialization.test.ripple → url.serialization.test.rsrx} +0 -0
- /package/tests/client/url-search-params/{url-search-params.derived.test.ripple → url-search-params.derived.test.rsrx} +0 -0
- /package/tests/client/url-search-params/{url-search-params.initialization.test.ripple → url-search-params.initialization.test.rsrx} +0 -0
- /package/tests/client/url-search-params/{url-search-params.iteration.test.ripple → url-search-params.iteration.test.rsrx} +0 -0
- /package/tests/client/url-search-params/{url-search-params.mutation.test.ripple → url-search-params.mutation.test.rsrx} +0 -0
- /package/tests/client/url-search-params/{url-search-params.retrieval.test.ripple → url-search-params.retrieval.test.rsrx} +0 -0
- /package/tests/client/url-search-params/{url-search-params.serialization.test.ripple → url-search-params.serialization.test.rsrx} +0 -0
- /package/tests/client/url-search-params/{url-search-params.tracked-url.test.ripple → url-search-params.tracked-url.test.rsrx} +0 -0
- /package/tests/hydration/components/{basic.ripple → basic.rsrx} +0 -0
- /package/tests/hydration/components/{composite.ripple → composite.rsrx} +0 -0
- /package/tests/hydration/components/{events.ripple → events.rsrx} +0 -0
- /package/tests/hydration/components/{for.ripple → for.rsrx} +0 -0
- /package/tests/hydration/components/{head.ripple → head.rsrx} +0 -0
- /package/tests/hydration/components/{hmr.ripple → hmr.rsrx} +0 -0
- /package/tests/hydration/components/{html-in-template.ripple → html-in-template.rsrx} +0 -0
- /package/tests/hydration/components/{html.ripple → html.rsrx} +0 -0
- /package/tests/hydration/components/{if-children.ripple → if-children.rsrx} +0 -0
- /package/tests/hydration/components/{if.ripple → if.rsrx} +0 -0
- /package/tests/hydration/components/{nested-control-flow.ripple → nested-control-flow.rsrx} +0 -0
- /package/tests/hydration/components/{portal.ripple → portal.rsrx} +0 -0
- /package/tests/hydration/components/{reactivity.ripple → reactivity.rsrx} +0 -0
- /package/tests/hydration/components/{return.ripple → return.rsrx} +0 -0
- /package/tests/hydration/components/{switch.ripple → switch.rsrx} +0 -0
- /package/tests/server/{await.test.ripple → await.test.rsrx} +0 -0
- /package/tests/server/{basic.attributes.test.ripple → basic.attributes.test.rsrx} +0 -0
- /package/tests/server/{basic.components.test.ripple → basic.components.test.rsrx} +0 -0
- /package/tests/server/{basic.test.ripple → basic.test.rsrx} +0 -0
- /package/tests/server/{composite.props.test.ripple → composite.props.test.rsrx} +0 -0
- /package/tests/server/{composite.test.ripple → composite.test.rsrx} +0 -0
- /package/tests/server/{context.test.ripple → context.test.rsrx} +0 -0
- /package/tests/server/{dynamic-elements.test.ripple → dynamic-elements.test.rsrx} +0 -0
- /package/tests/server/{for.test.ripple → for.test.rsrx} +0 -0
- /package/tests/server/{head.test.ripple → head.test.rsrx} +0 -0
- /package/tests/server/{if.test.ripple → if.test.rsrx} +0 -0
- /package/tests/server/{lazy-destructuring.test.ripple → lazy-destructuring.test.rsrx} +0 -0
- /package/tests/server/{return.test.ripple → return.test.rsrx} +0 -0
- /package/tests/server/{style-identifier.test.ripple → style-identifier.test.rsrx} +0 -0
- /package/tests/server/{switch.test.ripple → switch.test.rsrx} +0 -0
|
@@ -1,17 +1,40 @@
|
|
|
1
1
|
/**
|
|
2
|
-
@import { Component, Dependency, Derived, Tracked } from '#server';
|
|
3
|
-
@import {
|
|
2
|
+
@import { Component, Dependency, Derived, Tracked, Block, TryBlockWithCatch } from '#server';
|
|
3
|
+
@import { NestedArray } from '#helpers';
|
|
4
|
+
@import { Props } from '#public';
|
|
5
|
+
@import { RenderResult, BaseRenderOptions, RenderStreamResult, Stream, StreamSink } from 'ripple/server';
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Export-only Types
|
|
9
|
+
/**
|
|
10
|
+
@typedef {Output} OutputInterface;
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
// Internal Types
|
|
14
|
+
/**
|
|
15
|
+
@typedef {(props?: Props) => void} RenderComponent
|
|
16
|
+
@typedef {{
|
|
17
|
+
tag: string;
|
|
18
|
+
parent: undefined | ElementContext;
|
|
19
|
+
filename: undefined | string;
|
|
20
|
+
line: number;
|
|
21
|
+
column: number;
|
|
22
|
+
}} ElementContext;
|
|
23
|
+
@typedef {{
|
|
24
|
+
cancel: () => void,
|
|
25
|
+
}} RegisteredAsyncOperation;
|
|
4
26
|
*/
|
|
5
27
|
|
|
6
|
-
import { Readable } from 'stream';
|
|
7
|
-
import { DERIVED, UNINITIALIZED, TRACKED } from '../client/constants.js';
|
|
8
28
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
29
|
+
DERIVED,
|
|
30
|
+
UNINITIALIZED,
|
|
31
|
+
TRACKED,
|
|
32
|
+
SUSPENSE_PENDING,
|
|
33
|
+
SUSPENSE_REJECTED,
|
|
34
|
+
ASYNC_DERIVED_READ_THROWN,
|
|
35
|
+
DERIVED_UPDATED,
|
|
36
|
+
} from '../client/constants.js';
|
|
37
|
+
import { is_ripple_object, array_slice } from '../client/utils.js';
|
|
15
38
|
import { escape } from '../../../utils/escaping.js';
|
|
16
39
|
import { is_boolean_attribute } from '../../../compiler/utils.js';
|
|
17
40
|
import { clsx } from 'clsx';
|
|
@@ -22,47 +45,122 @@ import {
|
|
|
22
45
|
is_tag_valid_with_parent,
|
|
23
46
|
is_tag_valid_with_ancestor,
|
|
24
47
|
} from '../../../html-tree-validation.js';
|
|
48
|
+
import { get_async_track_result } from '../../../utils/async.js';
|
|
49
|
+
import {
|
|
50
|
+
cancel_async_operations,
|
|
51
|
+
component_block,
|
|
52
|
+
get_closest_catch_block,
|
|
53
|
+
try_block,
|
|
54
|
+
} from './blocks.js';
|
|
55
|
+
import { COMPONENT_BLOCK, TRY_BLOCK } from './constants.js';
|
|
25
56
|
|
|
26
57
|
export { escape };
|
|
27
58
|
export { register_component_css as register_css } from './css-registry.js';
|
|
28
59
|
export { hash } from '../../../utils/hashing.js';
|
|
29
60
|
export { context } from './context.js';
|
|
61
|
+
export { try_block, component_block, regular_block } from './blocks.js';
|
|
30
62
|
export { array_slice };
|
|
31
63
|
export { ripple_element, normalize_children };
|
|
32
64
|
|
|
65
|
+
export function noop() {}
|
|
66
|
+
|
|
33
67
|
/**
|
|
34
|
-
* @param {Output} output
|
|
35
68
|
* @param {any} value
|
|
36
69
|
* @returns {void}
|
|
37
70
|
*/
|
|
38
|
-
export function render_expression(
|
|
39
|
-
|
|
71
|
+
export function render_expression(value) {
|
|
72
|
+
output_push(BLOCK_OPEN);
|
|
40
73
|
|
|
41
74
|
if (is_ripple_element(value)) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (result && typeof result.then === 'function') {
|
|
45
|
-
return result.then(() => {
|
|
46
|
-
output.push(BLOCK_CLOSE);
|
|
47
|
-
});
|
|
48
|
-
}
|
|
75
|
+
value.render({});
|
|
49
76
|
} else {
|
|
50
|
-
|
|
77
|
+
output_push(escape(value ?? ''));
|
|
51
78
|
}
|
|
52
79
|
|
|
53
|
-
|
|
80
|
+
output_push(BLOCK_CLOSE);
|
|
54
81
|
}
|
|
55
82
|
|
|
56
|
-
/**
|
|
57
|
-
|
|
83
|
+
/**
|
|
84
|
+
* @returns {Stream}
|
|
85
|
+
*/
|
|
86
|
+
export function create_ssr_stream() {
|
|
87
|
+
/** @type {ReadableStreamDefaultController<Uint8Array> | null} */
|
|
88
|
+
var c = null;
|
|
89
|
+
/** @type {ReadableStream<Uint8Array>} */
|
|
90
|
+
var stream = new ReadableStream({
|
|
91
|
+
start(controller) {
|
|
92
|
+
// this runs synchronously
|
|
93
|
+
c = controller;
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
var encoder = new TextEncoder();
|
|
97
|
+
var is_closed = false;
|
|
98
|
+
var controller = /** @type {ReadableStreamDefaultController<Uint8Array>} */ (
|
|
99
|
+
/** @type {unknown} */ (c)
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
var close = controller.close;
|
|
103
|
+
var error = controller.error;
|
|
104
|
+
|
|
105
|
+
controller.close = function (...args) {
|
|
106
|
+
is_closed = true;
|
|
107
|
+
close.call(controller, ...args);
|
|
108
|
+
};
|
|
58
109
|
|
|
59
|
-
|
|
60
|
-
|
|
110
|
+
controller.error = function (...args) {
|
|
111
|
+
is_closed = true;
|
|
112
|
+
error.call(controller, ...args);
|
|
113
|
+
};
|
|
61
114
|
|
|
115
|
+
return {
|
|
116
|
+
controller,
|
|
117
|
+
textEncoder: encoder,
|
|
118
|
+
stream,
|
|
119
|
+
sink: {
|
|
120
|
+
push(chunk) {
|
|
121
|
+
if (is_closed) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
controller.enqueue(encoder.encode(chunk));
|
|
125
|
+
},
|
|
126
|
+
close() {
|
|
127
|
+
controller.close();
|
|
128
|
+
},
|
|
129
|
+
error(reason) {
|
|
130
|
+
controller.error(reason);
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** @type {null | Component} */
|
|
137
|
+
export let active_component = null;
|
|
138
|
+
/** @type {null | Block} */
|
|
139
|
+
export let active_block = null;
|
|
140
|
+
export let tracking = false;
|
|
62
141
|
/** @type {null | Dependency} */
|
|
63
142
|
let active_dependency = null;
|
|
143
|
+
let inside_async_track = false;
|
|
144
|
+
/** @type {ElementContext | undefined} */
|
|
145
|
+
let current_element;
|
|
146
|
+
/** @type {Set<string>} */
|
|
147
|
+
let seen_warnings = new Set();
|
|
64
148
|
|
|
65
|
-
|
|
149
|
+
/**
|
|
150
|
+
* @returns {void}
|
|
151
|
+
*/
|
|
152
|
+
export function reset_state() {
|
|
153
|
+
active_component = null;
|
|
154
|
+
active_block = null;
|
|
155
|
+
active_dependency = null;
|
|
156
|
+
inside_async_track = false;
|
|
157
|
+
tracking = false;
|
|
158
|
+
seen_warnings = new Set();
|
|
159
|
+
current_element = undefined;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** @type {number} */
|
|
163
|
+
let clock = 0;
|
|
66
164
|
|
|
67
165
|
/**
|
|
68
166
|
* @returns {number}
|
|
@@ -71,6 +169,13 @@ function increment_clock() {
|
|
|
71
169
|
return ++clock;
|
|
72
170
|
}
|
|
73
171
|
|
|
172
|
+
/**
|
|
173
|
+
* @param {Block} block
|
|
174
|
+
*/
|
|
175
|
+
export function set_active_block(block) {
|
|
176
|
+
active_block = block;
|
|
177
|
+
}
|
|
178
|
+
|
|
74
179
|
/**
|
|
75
180
|
* @param {Tracked | Derived} tracked
|
|
76
181
|
* @returns {Dependency}
|
|
@@ -169,6 +274,15 @@ function update_derived(computed) {
|
|
|
169
274
|
}
|
|
170
275
|
}
|
|
171
276
|
|
|
277
|
+
/**
|
|
278
|
+
* @param {Tracked} computed
|
|
279
|
+
* @param {any} value
|
|
280
|
+
*/
|
|
281
|
+
function update_tracked_value_clock(computed, value) {
|
|
282
|
+
computed.v = value;
|
|
283
|
+
computed.c = increment_clock();
|
|
284
|
+
}
|
|
285
|
+
|
|
172
286
|
/**
|
|
173
287
|
* @param {Derived} computed
|
|
174
288
|
*/
|
|
@@ -178,15 +292,29 @@ function run_derived(computed) {
|
|
|
178
292
|
var previous_component = active_component;
|
|
179
293
|
|
|
180
294
|
try {
|
|
181
|
-
active_component = computed.co;
|
|
182
295
|
tracking = true;
|
|
183
296
|
active_dependency = null;
|
|
297
|
+
active_component = computed.co;
|
|
184
298
|
|
|
185
299
|
var value = computed.fn();
|
|
186
300
|
|
|
187
301
|
computed.d = active_dependency;
|
|
188
302
|
|
|
189
303
|
return value;
|
|
304
|
+
} catch (error) {
|
|
305
|
+
computed.d = active_dependency;
|
|
306
|
+
if (error === ASYNC_DERIVED_READ_THROWN) {
|
|
307
|
+
// Check if any dependency is rejected — if so, propagate rejection
|
|
308
|
+
var dep = active_dependency;
|
|
309
|
+
while (dep !== null) {
|
|
310
|
+
if (dep.t.v === SUSPENSE_REJECTED) {
|
|
311
|
+
return SUSPENSE_REJECTED;
|
|
312
|
+
}
|
|
313
|
+
dep = dep.n;
|
|
314
|
+
}
|
|
315
|
+
return SUSPENSE_PENDING;
|
|
316
|
+
}
|
|
317
|
+
throw error;
|
|
190
318
|
} finally {
|
|
191
319
|
tracking = previous_tracking;
|
|
192
320
|
active_dependency = previous_dependency;
|
|
@@ -207,27 +335,79 @@ const replacements = {
|
|
|
207
335
|
]),
|
|
208
336
|
};
|
|
209
337
|
|
|
210
|
-
class Output {
|
|
211
|
-
|
|
212
|
-
|
|
338
|
+
export class Output {
|
|
339
|
+
/** @type {Output} */
|
|
340
|
+
#root;
|
|
341
|
+
/** @type {NestedArray<string>} */
|
|
342
|
+
#head = [];
|
|
343
|
+
/** @type {NestedArray<string>} */
|
|
344
|
+
#body = [];
|
|
213
345
|
/** @type {Set<string>} */
|
|
214
|
-
css = new Set();
|
|
215
|
-
/** @type {
|
|
216
|
-
promises = [];
|
|
217
|
-
/** @type {Output | null} */
|
|
346
|
+
#css = new Set();
|
|
347
|
+
/** @type {null | Output} */
|
|
218
348
|
#parent = null;
|
|
219
|
-
/** @type {
|
|
220
|
-
#
|
|
349
|
+
/** @type {StreamSink | null} */
|
|
350
|
+
#streamOutput = null;
|
|
351
|
+
#stream_started = false;
|
|
352
|
+
#stream_finished = false;
|
|
353
|
+
/** @type {null | number} */
|
|
354
|
+
#pending_count = null;
|
|
355
|
+
/** @type {null | Promise<void>} */
|
|
356
|
+
#promise = null;
|
|
357
|
+
/** @type {null | (() => void)} */
|
|
358
|
+
#promise_resolve = null;
|
|
359
|
+
/** @type {null | ((reason?: any) => void)} */
|
|
360
|
+
#promise_reject = null;
|
|
361
|
+
#is_root = false;
|
|
362
|
+
#sync_run = false;
|
|
363
|
+
/** @type {Set<RegisteredAsyncOperation>} */
|
|
364
|
+
#async_operations = new Set();
|
|
221
365
|
/** @type {null | 'head'} */
|
|
222
366
|
target = null;
|
|
223
367
|
|
|
368
|
+
get root() {
|
|
369
|
+
return this.#root;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
get body() {
|
|
373
|
+
return this.#body;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
get head() {
|
|
377
|
+
return this.#head;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
get css() {
|
|
381
|
+
return this.#css;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
get promise() {
|
|
385
|
+
if (this.#is_root) {
|
|
386
|
+
return /** @type {Promise<void>} */ (this.#promise);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
throw new Error('getPromise() can only be called on the root Output');
|
|
390
|
+
}
|
|
391
|
+
|
|
224
392
|
/**
|
|
225
393
|
* @param {Output | null} parent
|
|
226
|
-
* @param {import('stream').Readable | null} stream
|
|
227
394
|
*/
|
|
228
|
-
constructor(parent
|
|
229
|
-
|
|
230
|
-
|
|
395
|
+
constructor(parent) {
|
|
396
|
+
if (!parent) {
|
|
397
|
+
this.#root = this;
|
|
398
|
+
this.#is_root = true;
|
|
399
|
+
this.#promise = new Promise((resolve, reject) => {
|
|
400
|
+
this.#promise_resolve = resolve;
|
|
401
|
+
this.#promise_reject = reject;
|
|
402
|
+
});
|
|
403
|
+
this.#pending_count = 1;
|
|
404
|
+
this.#sync_run = true;
|
|
405
|
+
} else {
|
|
406
|
+
this.#root = parent.root;
|
|
407
|
+
this.#parent = parent;
|
|
408
|
+
this.#parent.body.push(this.body);
|
|
409
|
+
this.#parent.head.push(this.head);
|
|
410
|
+
}
|
|
231
411
|
}
|
|
232
412
|
|
|
233
413
|
/**
|
|
@@ -235,16 +415,28 @@ class Output {
|
|
|
235
415
|
* @returns {void}
|
|
236
416
|
*/
|
|
237
417
|
push(str) {
|
|
238
|
-
if (this.
|
|
239
|
-
|
|
418
|
+
if (this.isStreamMode() && !this.isSyncRun()) {
|
|
419
|
+
// TODO - we need to wrap the resulting block output into something that
|
|
420
|
+
// the client-side can understand and append them appropriately,
|
|
421
|
+
// or actually, first append and hydrate when the full block is finished
|
|
422
|
+
// without waiting for the all blocks to finish streaming to make hydration faster
|
|
423
|
+
/** @type {StreamSink} */
|
|
424
|
+
(this.#root.#streamOutput).push(str);
|
|
240
425
|
return;
|
|
241
426
|
}
|
|
242
427
|
|
|
243
|
-
if (this
|
|
244
|
-
this.#
|
|
245
|
-
|
|
246
|
-
this.body += str;
|
|
428
|
+
if (this.target === 'head') {
|
|
429
|
+
this.#head.push(str);
|
|
430
|
+
return;
|
|
247
431
|
}
|
|
432
|
+
|
|
433
|
+
this.#body.push(str);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
clear() {
|
|
437
|
+
this.#head.length = 0;
|
|
438
|
+
this.#body.length = 0;
|
|
439
|
+
this.#css.clear();
|
|
248
440
|
}
|
|
249
441
|
|
|
250
442
|
/**
|
|
@@ -252,113 +444,261 @@ class Output {
|
|
|
252
444
|
* @returns {void}
|
|
253
445
|
*/
|
|
254
446
|
register_css(hash) {
|
|
255
|
-
this.
|
|
447
|
+
if (this.isStreamMode() && !this.isSyncRun()) {
|
|
448
|
+
// TODO - when we're in the streaming mode and finished the sync render,
|
|
449
|
+
// We should wrap the css into something that the client-side can understand
|
|
450
|
+
// and append them into the head immediately
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
this.#css.add(hash);
|
|
256
454
|
}
|
|
257
|
-
}
|
|
258
455
|
|
|
259
|
-
/**
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
456
|
+
/**
|
|
457
|
+
* @param {RegisteredAsyncOperation} operation
|
|
458
|
+
* @return {void}
|
|
459
|
+
*/
|
|
460
|
+
registerAsync(operation) {
|
|
461
|
+
this.#async_operations.add(operation);
|
|
462
|
+
this.#root._incrementPending();
|
|
463
|
+
}
|
|
265
464
|
|
|
266
|
-
|
|
267
|
-
|
|
465
|
+
/**
|
|
466
|
+
* @param {RegisteredAsyncOperation} operation
|
|
467
|
+
* @returns {void}
|
|
468
|
+
*/
|
|
469
|
+
resolveAsync(operation) {
|
|
470
|
+
this.#async_operations.delete(operation);
|
|
471
|
+
this.#root._decrementPending();
|
|
472
|
+
}
|
|
268
473
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
474
|
+
cancelAsyncOperations() {
|
|
475
|
+
for (const operation of this.#async_operations) {
|
|
476
|
+
operation.cancel();
|
|
477
|
+
this.#async_operations.delete(operation);
|
|
478
|
+
this.clear();
|
|
479
|
+
this.#root._decrementPending();
|
|
274
480
|
}
|
|
275
|
-
|
|
276
|
-
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
_incrementPending() {
|
|
484
|
+
if (this.#is_root) {
|
|
485
|
+
/** @type {number} */ (this.#pending_count)++;
|
|
486
|
+
return;
|
|
277
487
|
}
|
|
488
|
+
throw new Error('_incrementPending() is an internal method.');
|
|
489
|
+
}
|
|
278
490
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
491
|
+
_decrementPending() {
|
|
492
|
+
if (this.#is_root) {
|
|
493
|
+
/** @type {number} */ (this.#pending_count)--;
|
|
494
|
+
|
|
495
|
+
if (this.#pending_count === 0) {
|
|
496
|
+
this.#promise_resolve?.();
|
|
497
|
+
}
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
throw new Error('_decrementPending() is an internal method.');
|
|
286
501
|
}
|
|
287
|
-
return { head, body, css };
|
|
288
|
-
}
|
|
289
502
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
503
|
+
_finishSyncRun() {
|
|
504
|
+
if (this.#is_root) {
|
|
505
|
+
this.#sync_run = false;
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
throw new Error('_finishSyncRun() is an internal method.');
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* @param {StreamSink} stream
|
|
514
|
+
*/
|
|
515
|
+
_setStream(stream) {
|
|
516
|
+
if (this.#is_root) {
|
|
517
|
+
this.#streamOutput = stream;
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
throw new Error('_setStream() is an internal method.');
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
_startStream() {
|
|
525
|
+
if (this.#is_root) {
|
|
526
|
+
this.#stream_started = true;
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
throw new Error('_startStream() is an internal method.');
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
_closeStream() {
|
|
534
|
+
if (this.#is_root) {
|
|
535
|
+
if (this.#streamOutput && this.#stream_started && !this.#stream_finished) {
|
|
536
|
+
this.#stream_finished = true;
|
|
537
|
+
this.#streamOutput.close();
|
|
538
|
+
}
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
throw new Error('_closeStream() is an internal method.');
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* @param {unknown} reason
|
|
547
|
+
* @returns {void}
|
|
548
|
+
*/
|
|
549
|
+
_errorStream(reason) {
|
|
550
|
+
if (this.#is_root) {
|
|
551
|
+
if (this.#streamOutput && this.#stream_started && !this.#stream_finished) {
|
|
552
|
+
this.#stream_finished = true;
|
|
553
|
+
this.#streamOutput.error(reason);
|
|
554
|
+
}
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
throw new Error('_errorStream() is an internal method.');
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
isStreamMode() {
|
|
562
|
+
return this.#root.#streamOutput !== null;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
isSyncRun() {
|
|
566
|
+
return this.#root.#sync_run;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
branch() {
|
|
570
|
+
return new Output(this);
|
|
571
|
+
}
|
|
298
572
|
}
|
|
573
|
+
|
|
299
574
|
/**
|
|
300
|
-
*
|
|
301
|
-
* @param {
|
|
302
|
-
* @
|
|
303
|
-
* @param {Output} output
|
|
575
|
+
* @param {RenderComponent} component
|
|
576
|
+
* @param {BaseRenderOptions} [passed_in_options]
|
|
577
|
+
* @returns {Promise<RenderResult | RenderStreamResult>}
|
|
304
578
|
*/
|
|
305
|
-
async function
|
|
579
|
+
export async function render(component, passed_in_options = {}) {
|
|
580
|
+
/** @type {BaseRenderOptions} */
|
|
581
|
+
var options = {
|
|
582
|
+
...(passed_in_options.stream ? { closeStream: true } : {}),
|
|
583
|
+
...passed_in_options,
|
|
584
|
+
};
|
|
585
|
+
/** @type {Error | null } */
|
|
586
|
+
var top_level_error = null;
|
|
587
|
+
var head = '';
|
|
588
|
+
var body = '';
|
|
589
|
+
var css = new Set();
|
|
590
|
+
/** @type {Block | null} */
|
|
591
|
+
var root_block = null;
|
|
592
|
+
|
|
306
593
|
// Reset dev-mode element tracking state at the start of each render
|
|
307
|
-
|
|
594
|
+
reset_state();
|
|
595
|
+
|
|
596
|
+
try_block(
|
|
597
|
+
// since there is no `active_block` yet, the usual automatic block run will be skipped
|
|
598
|
+
() => {
|
|
599
|
+
// this will run only once and immediately when we call the `try_block`
|
|
600
|
+
root_block = /** @type {Block} */ (active_block);
|
|
601
|
+
const output = root_block.o;
|
|
602
|
+
if (options.stream) {
|
|
603
|
+
output._setStream(options.stream);
|
|
604
|
+
}
|
|
605
|
+
component({});
|
|
606
|
+
output._decrementPending();
|
|
607
|
+
output._finishSyncRun();
|
|
608
|
+
|
|
609
|
+
if (output.isStreamMode()) {
|
|
610
|
+
sync_buffers_to_string(output);
|
|
611
|
+
output._startStream();
|
|
612
|
+
output.push(head);
|
|
613
|
+
output.push(body);
|
|
614
|
+
// TODO - how do we handle css?, in needs to be inside the head
|
|
615
|
+
// We probably can allocate a buffer inside the head for this
|
|
616
|
+
// We should have the same order of insertion as for the full async render
|
|
617
|
+
}
|
|
618
|
+
},
|
|
619
|
+
(error) => {
|
|
620
|
+
// TODO - allow a global error template in ripple.config.ts
|
|
621
|
+
// We're not going to send the error in the stream stream.error()
|
|
622
|
+
// as we should send sent the error template
|
|
623
|
+
|
|
624
|
+
// store the error to be returned
|
|
625
|
+
top_level_error = error;
|
|
626
|
+
console.error(error);
|
|
627
|
+
},
|
|
628
|
+
() => {
|
|
629
|
+
// TODO - allow a global pending in ripple.config.ts
|
|
630
|
+
// pending would be implemented as part of the streaming rendering support
|
|
631
|
+
},
|
|
632
|
+
);
|
|
633
|
+
|
|
634
|
+
await /** @type {Block} */ (/** @type {unknown} */ (root_block)).o.promise;
|
|
635
|
+
reset_state();
|
|
636
|
+
|
|
637
|
+
const output = /** @type {Block} */ (/** @type {unknown} */ (root_block)).o;
|
|
638
|
+
if (output.isStreamMode() && options.closeStream) {
|
|
639
|
+
output._closeStream();
|
|
640
|
+
}
|
|
308
641
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
642
|
+
if (!output.isStreamMode()) {
|
|
643
|
+
sync_buffers_to_string(output);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
return options.stream
|
|
647
|
+
? { stream: options.stream, topLevelError: top_level_error }
|
|
648
|
+
: { head, body, css, topLevelError: top_level_error };
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* @param {Output} output
|
|
652
|
+
* @returns {void}
|
|
653
|
+
*/
|
|
654
|
+
function sync_buffers_to_string(output) {
|
|
655
|
+
head = /** @type {string[]} */ (output.head).flat(Infinity).join('');
|
|
656
|
+
body = BLOCK_OPEN + /** @type {string[]} */ (output.body).flat(Infinity).join('') + BLOCK_CLOSE;
|
|
657
|
+
css = output.css;
|
|
324
658
|
}
|
|
325
659
|
}
|
|
660
|
+
|
|
326
661
|
/**
|
|
327
662
|
* @returns {void}
|
|
328
663
|
*/
|
|
329
664
|
export function push_component() {
|
|
330
|
-
|
|
665
|
+
active_component = {
|
|
331
666
|
c: null,
|
|
332
667
|
p: active_component,
|
|
333
668
|
};
|
|
334
|
-
|
|
669
|
+
active_block = component_block(() => {});
|
|
335
670
|
}
|
|
336
671
|
|
|
337
672
|
/**
|
|
338
673
|
* @returns {void}
|
|
339
674
|
*/
|
|
340
675
|
export function pop_component() {
|
|
341
|
-
|
|
342
|
-
|
|
676
|
+
active_component = /** @type {Component} */ (active_component).p;
|
|
677
|
+
active_block = /** @type {Block} */ (active_block).p;
|
|
343
678
|
}
|
|
344
679
|
|
|
345
680
|
/**
|
|
346
|
-
* @
|
|
347
|
-
*
|
|
348
|
-
* parent: undefined | ElementContext;
|
|
349
|
-
* filename: undefined | string;
|
|
350
|
-
* line: number;
|
|
351
|
-
* column: number;
|
|
352
|
-
* }} ElementContext
|
|
681
|
+
* @param {string} str
|
|
682
|
+
* @returns {void}
|
|
353
683
|
*/
|
|
684
|
+
export function output_push(str) {
|
|
685
|
+
/** @type {Block} */ (active_block).o.push(str);
|
|
686
|
+
}
|
|
354
687
|
|
|
355
|
-
/**
|
|
356
|
-
|
|
688
|
+
/**
|
|
689
|
+
* @param {Output['target']} target
|
|
690
|
+
*/
|
|
691
|
+
export function set_output_target(target) {
|
|
692
|
+
/** @type {Block} */ (active_block).o.target = target;
|
|
693
|
+
}
|
|
357
694
|
|
|
358
695
|
/**
|
|
359
|
-
* @
|
|
696
|
+
* @param {string} hash
|
|
697
|
+
* @returns {void}
|
|
360
698
|
*/
|
|
361
|
-
|
|
699
|
+
export function output_register_css(hash) {
|
|
700
|
+
/** @type {Block} */ (active_block).o.register_css(hash);
|
|
701
|
+
}
|
|
362
702
|
|
|
363
703
|
/**
|
|
364
704
|
* @param {string} message
|
|
@@ -427,34 +767,6 @@ export function pop_element() {
|
|
|
427
767
|
}
|
|
428
768
|
}
|
|
429
769
|
|
|
430
|
-
/**
|
|
431
|
-
* Resets the dev-mode element tracking state.
|
|
432
|
-
* Called automatically at the start/end of each render to prevent
|
|
433
|
-
* state from leaking between renders (e.g., if a render throws).
|
|
434
|
-
* Also exported for testing purposes.
|
|
435
|
-
* @returns {void}
|
|
436
|
-
*/
|
|
437
|
-
export function reset_element_state() {
|
|
438
|
-
seen_warnings = new Set();
|
|
439
|
-
current_element = undefined;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
/**
|
|
443
|
-
* @param {() => any} fn
|
|
444
|
-
* @returns {Promise<void>}
|
|
445
|
-
*/
|
|
446
|
-
export async function async(fn) {
|
|
447
|
-
await fn();
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
/**
|
|
451
|
-
* @returns {boolean}
|
|
452
|
-
*/
|
|
453
|
-
export function aborted() {
|
|
454
|
-
// For SSR, we don't abort rendering
|
|
455
|
-
return false;
|
|
456
|
-
}
|
|
457
|
-
|
|
458
770
|
/**
|
|
459
771
|
* @param {any} tracked
|
|
460
772
|
* @returns {any}
|
|
@@ -473,6 +785,24 @@ export function get(tracked) {
|
|
|
473
785
|
register_dependency(tracked);
|
|
474
786
|
}
|
|
475
787
|
|
|
788
|
+
if (tracked.v === SUSPENSE_PENDING || tracked.v === SUSPENSE_REJECTED) {
|
|
789
|
+
var is_try_block = false;
|
|
790
|
+
if (
|
|
791
|
+
!inside_async_track &&
|
|
792
|
+
(!active_block ||
|
|
793
|
+
active_block.f & COMPONENT_BLOCK ||
|
|
794
|
+
(is_try_block = (active_block.f & TRY_BLOCK) !== 0))
|
|
795
|
+
) {
|
|
796
|
+
throw new Error(
|
|
797
|
+
`Reads on pending tracked or derived values directly inside ${is_try_block ? 'try' : 'component'} body are prohibited. Use trackPending() test for safe access or create another derived instead.`,
|
|
798
|
+
);
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
// this will be caught by the run_block and the block will be re-run
|
|
802
|
+
// once the async tracked dependency's promise resolves
|
|
803
|
+
throw ASYNC_DERIVED_READ_THROWN;
|
|
804
|
+
}
|
|
805
|
+
|
|
476
806
|
var g = tracked.a.get;
|
|
477
807
|
return g ? g(tracked.v) : tracked.v;
|
|
478
808
|
}
|
|
@@ -639,6 +969,7 @@ export function spread_attrs(attrs, css_hash) {
|
|
|
639
969
|
|
|
640
970
|
var empty_get_set = { get: undefined, set: undefined };
|
|
641
971
|
|
|
972
|
+
/** @type {Tracked} */
|
|
642
973
|
class TrackedValue {
|
|
643
974
|
/**
|
|
644
975
|
* @param {any} v
|
|
@@ -646,6 +977,8 @@ class TrackedValue {
|
|
|
646
977
|
*/
|
|
647
978
|
constructor(v, a) {
|
|
648
979
|
this.a = a;
|
|
980
|
+
this.aa = null;
|
|
981
|
+
this.ap = null;
|
|
649
982
|
this.c = 0;
|
|
650
983
|
this.f = TRACKED;
|
|
651
984
|
this.v = v;
|
|
@@ -676,6 +1009,7 @@ class TrackedValue {
|
|
|
676
1009
|
}
|
|
677
1010
|
}
|
|
678
1011
|
|
|
1012
|
+
/** @type {Derived} */
|
|
679
1013
|
class DerivedValue {
|
|
680
1014
|
/**
|
|
681
1015
|
* @param {Function} fn
|
|
@@ -683,11 +1017,13 @@ class DerivedValue {
|
|
|
683
1017
|
*/
|
|
684
1018
|
constructor(fn, a) {
|
|
685
1019
|
this.a = a;
|
|
1020
|
+
// we always should have an active block
|
|
1021
|
+
// even in async we rerun blocks so we can rely on this
|
|
1022
|
+
this.b = /** @type {Block} */ (active_block);
|
|
686
1023
|
this.c = 0;
|
|
687
1024
|
this.co = active_component;
|
|
688
|
-
/** @type {null | import('#server').Dependency} */
|
|
689
1025
|
this.d = null;
|
|
690
|
-
this.f =
|
|
1026
|
+
this.f = DERIVED;
|
|
691
1027
|
this.fn = fn;
|
|
692
1028
|
this.v = UNINITIALIZED;
|
|
693
1029
|
}
|
|
@@ -745,6 +1081,16 @@ export function exclude_from_object(obj, exclude_keys) {
|
|
|
745
1081
|
return new_obj;
|
|
746
1082
|
}
|
|
747
1083
|
|
|
1084
|
+
/**
|
|
1085
|
+
* @param {any} v
|
|
1086
|
+
* @param {(value: any) => any} [get]
|
|
1087
|
+
* @param {(next: any, prev: any) => any} [set]
|
|
1088
|
+
* @returns {Derived}
|
|
1089
|
+
*/
|
|
1090
|
+
function derived(v, get, set) {
|
|
1091
|
+
return /** @type {Derived} */ (new DerivedValue(v, get || set ? { get, set } : empty_get_set));
|
|
1092
|
+
}
|
|
1093
|
+
|
|
748
1094
|
/**
|
|
749
1095
|
* @param {any} v
|
|
750
1096
|
* @param {(value: any) => any} [get]
|
|
@@ -759,12 +1105,298 @@ export function track(v, get, set) {
|
|
|
759
1105
|
}
|
|
760
1106
|
|
|
761
1107
|
if (typeof v === 'function') {
|
|
762
|
-
return
|
|
1108
|
+
return derived(v, get, set);
|
|
763
1109
|
}
|
|
764
1110
|
|
|
765
1111
|
return tracked(v, get, set);
|
|
766
1112
|
}
|
|
767
1113
|
|
|
1114
|
+
/**
|
|
1115
|
+
* Runs the async tracked function, handling sync results, async results,
|
|
1116
|
+
* and chained cases where fn() reads a pending dependency.
|
|
1117
|
+
* @param {Tracked} t
|
|
1118
|
+
* @param {() => any} fn
|
|
1119
|
+
* @param {Block} block
|
|
1120
|
+
* @param {((value?: any) => void) | null} dr
|
|
1121
|
+
* @param {((reason?: any) => void) | null} dj
|
|
1122
|
+
*/
|
|
1123
|
+
function run_track_async(t, fn, block, dr, dj) {
|
|
1124
|
+
var previous_tracking = tracking;
|
|
1125
|
+
var previous_dependency = active_dependency;
|
|
1126
|
+
var previous_inside = inside_async_track;
|
|
1127
|
+
tracking = true;
|
|
1128
|
+
active_dependency = null;
|
|
1129
|
+
inside_async_track = true;
|
|
1130
|
+
|
|
1131
|
+
var result;
|
|
1132
|
+
/** @type {Dependency | null} */
|
|
1133
|
+
var caught_dep = null;
|
|
1134
|
+
var caught = false;
|
|
1135
|
+
|
|
1136
|
+
try {
|
|
1137
|
+
result = fn();
|
|
1138
|
+
} catch (error) {
|
|
1139
|
+
caught_dep = active_dependency;
|
|
1140
|
+
caught = true;
|
|
1141
|
+
|
|
1142
|
+
if (error !== ASYNC_DERIVED_READ_THROWN) {
|
|
1143
|
+
throw error;
|
|
1144
|
+
}
|
|
1145
|
+
} finally {
|
|
1146
|
+
tracking = previous_tracking;
|
|
1147
|
+
active_dependency = previous_dependency;
|
|
1148
|
+
inside_async_track = previous_inside;
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
if (caught) {
|
|
1152
|
+
// Chained case: fn() read a pending tracked/derived dependency
|
|
1153
|
+
// Check if any dependency is rejected
|
|
1154
|
+
var dep = /** @type {Dependency | null} */ (caught_dep);
|
|
1155
|
+
while (dep !== null) {
|
|
1156
|
+
if (dep.t.v === SUSPENSE_REJECTED) {
|
|
1157
|
+
update_tracked_value_clock(t, SUSPENSE_REJECTED);
|
|
1158
|
+
if (dj) {
|
|
1159
|
+
dj(new Error('Upstream dependency rejected'));
|
|
1160
|
+
}
|
|
1161
|
+
return;
|
|
1162
|
+
}
|
|
1163
|
+
dep = dep.n;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
// Create synthetic promise if first time (for downstream chaining)
|
|
1167
|
+
if (!dr) {
|
|
1168
|
+
t.ap = new Promise((resolve, reject) => {
|
|
1169
|
+
dr = resolve;
|
|
1170
|
+
dj = reject;
|
|
1171
|
+
});
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
// Find the pending dependency with a promise and chain on it
|
|
1175
|
+
dep = /** @type {Dependency | null} */ (caught_dep);
|
|
1176
|
+
while (dep !== null) {
|
|
1177
|
+
var dep_tracked = /** @type {Tracked} */ (dep.t);
|
|
1178
|
+
if ((dep_tracked.f & TRACKED) !== 0 && dep_tracked.v === SUSPENSE_PENDING && dep_tracked.ap) {
|
|
1179
|
+
/** @type {PromiseLike<any>} */ (dep_tracked.ap).then(
|
|
1180
|
+
() => run_track_async(t, fn, block, dr, dj),
|
|
1181
|
+
(error) => {
|
|
1182
|
+
update_tracked_value_clock(t, SUSPENSE_REJECTED);
|
|
1183
|
+
if (dj) {
|
|
1184
|
+
dj(error);
|
|
1185
|
+
}
|
|
1186
|
+
route_error_to_catch_block(get_closest_catch_block(block), error);
|
|
1187
|
+
},
|
|
1188
|
+
);
|
|
1189
|
+
return;
|
|
1190
|
+
}
|
|
1191
|
+
dep = dep.n;
|
|
1192
|
+
}
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
// Handle the result
|
|
1197
|
+
var async_result = get_async_track_result(result);
|
|
1198
|
+
|
|
1199
|
+
if (async_result === null) {
|
|
1200
|
+
// Sync result
|
|
1201
|
+
update_tracked_value_clock(t, result);
|
|
1202
|
+
if (dr) {
|
|
1203
|
+
dr(result);
|
|
1204
|
+
}
|
|
1205
|
+
return;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
t.aa = async_result.abort_controller;
|
|
1209
|
+
|
|
1210
|
+
if (!dr) {
|
|
1211
|
+
// First run, no chaining — set real promise directly
|
|
1212
|
+
t.ap = async_result.promise;
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
async_result.promise.then(
|
|
1216
|
+
(resolved) => {
|
|
1217
|
+
update_tracked_value_clock(t, resolved);
|
|
1218
|
+
if (dr) {
|
|
1219
|
+
dr(resolved);
|
|
1220
|
+
}
|
|
1221
|
+
},
|
|
1222
|
+
(error) => {
|
|
1223
|
+
update_tracked_value_clock(t, SUSPENSE_REJECTED);
|
|
1224
|
+
if (dj) {
|
|
1225
|
+
dj(error);
|
|
1226
|
+
}
|
|
1227
|
+
route_error_to_catch_block(get_closest_catch_block(block), error);
|
|
1228
|
+
},
|
|
1229
|
+
);
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
/**
|
|
1233
|
+
* @param {any} v
|
|
1234
|
+
* @returns {Tracked | void}
|
|
1235
|
+
*/
|
|
1236
|
+
export function track_async(v) {
|
|
1237
|
+
if (is_ripple_object(v)) {
|
|
1238
|
+
return v;
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
if (typeof v !== 'function') {
|
|
1242
|
+
throw new TypeError(
|
|
1243
|
+
'trackAsync() only accepts function arguments that return a promise or an object with a promise property',
|
|
1244
|
+
);
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
var t = tracked(SUSPENSE_PENDING);
|
|
1248
|
+
var block = /** @type {Block} */ (active_block);
|
|
1249
|
+
run_track_async(t, v, block, null, null);
|
|
1250
|
+
return t;
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
/**
|
|
1254
|
+
* @param {(Derived | Tracked) | (() => any)} tracked
|
|
1255
|
+
* @returns {boolean}
|
|
1256
|
+
*/
|
|
1257
|
+
export function is_tracked_pending(tracked) {
|
|
1258
|
+
try {
|
|
1259
|
+
if (typeof tracked === 'function') {
|
|
1260
|
+
tracked();
|
|
1261
|
+
} else {
|
|
1262
|
+
get(tracked);
|
|
1263
|
+
}
|
|
1264
|
+
return false;
|
|
1265
|
+
} catch (error) {
|
|
1266
|
+
if (error === ASYNC_DERIVED_READ_THROWN) {
|
|
1267
|
+
return true;
|
|
1268
|
+
}
|
|
1269
|
+
throw error;
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
/**
|
|
1274
|
+
* @param {Tracked | Derived} tracked
|
|
1275
|
+
* @return {any}
|
|
1276
|
+
*/
|
|
1277
|
+
export function peek_tracked(tracked) {
|
|
1278
|
+
if (!is_ripple_object(tracked)) {
|
|
1279
|
+
return tracked;
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
return tracked.v;
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
/**
|
|
1286
|
+
* Routes an error to the nearest catch boundary: clears output, cancels
|
|
1287
|
+
* pending async work, and invokes the catch handler if one exists.
|
|
1288
|
+
* @param {TryBlockWithCatch} catch_block
|
|
1289
|
+
* @param {any} error
|
|
1290
|
+
*/
|
|
1291
|
+
function route_error_to_catch_block(catch_block, error) {
|
|
1292
|
+
// cancel async should also clear the output
|
|
1293
|
+
// for this block and all its children
|
|
1294
|
+
cancel_async_operations(catch_block);
|
|
1295
|
+
reset_state();
|
|
1296
|
+
set_active_block(catch_block);
|
|
1297
|
+
catch_block.s.c(error);
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
/**
|
|
1301
|
+
* @param {Block} block
|
|
1302
|
+
* @returns {void}
|
|
1303
|
+
*/
|
|
1304
|
+
function register_block_rerun(block) {
|
|
1305
|
+
// Find the pending dependency with a promise in the dependency chain.
|
|
1306
|
+
var dep_entry = active_dependency;
|
|
1307
|
+
// tracked async must exist as otherwise we wouldn't have thrown the ASYNC_DERIVED_READ_THROWN
|
|
1308
|
+
/** @type {Tracked | null} */
|
|
1309
|
+
var t = null;
|
|
1310
|
+
while (dep_entry !== null) {
|
|
1311
|
+
var d = /** @type {Tracked} */ (dep_entry.t);
|
|
1312
|
+
if ((d.f & TRACKED) !== 0 && d.v === SUSPENSE_PENDING && d.ap) {
|
|
1313
|
+
t = d;
|
|
1314
|
+
break;
|
|
1315
|
+
}
|
|
1316
|
+
dep_entry = dep_entry.n;
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
var cancelled = false;
|
|
1320
|
+
var try_catch_block = get_closest_catch_block(block);
|
|
1321
|
+
var operation = {
|
|
1322
|
+
cancel: () => {
|
|
1323
|
+
cancelled = true;
|
|
1324
|
+
if (t && t.aa) {
|
|
1325
|
+
t.aa.abort(DERIVED_UPDATED);
|
|
1326
|
+
t.aa = null;
|
|
1327
|
+
t.ap = null;
|
|
1328
|
+
}
|
|
1329
|
+
},
|
|
1330
|
+
};
|
|
1331
|
+
|
|
1332
|
+
try_catch_block.o.registerAsync(operation);
|
|
1333
|
+
/** @type {PromiseLike<any>} */ (/** @type {Tracked} */ (t).ap).then(
|
|
1334
|
+
() => {
|
|
1335
|
+
if (cancelled) {
|
|
1336
|
+
return;
|
|
1337
|
+
}
|
|
1338
|
+
reset_state();
|
|
1339
|
+
try {
|
|
1340
|
+
run_block(block);
|
|
1341
|
+
try_catch_block.o.resolveAsync(operation);
|
|
1342
|
+
} catch (error) {
|
|
1343
|
+
route_error_to_catch_block(try_catch_block, error);
|
|
1344
|
+
}
|
|
1345
|
+
},
|
|
1346
|
+
(error) => {
|
|
1347
|
+
if (cancelled) {
|
|
1348
|
+
return;
|
|
1349
|
+
}
|
|
1350
|
+
route_error_to_catch_block(try_catch_block, error);
|
|
1351
|
+
},
|
|
1352
|
+
);
|
|
1353
|
+
// clear all output buffers as we'll rerun the block rendering
|
|
1354
|
+
block.o.clear();
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
/**
|
|
1358
|
+
* @param {Block} block
|
|
1359
|
+
*/
|
|
1360
|
+
export function run_block(block) {
|
|
1361
|
+
var previous_block = active_block;
|
|
1362
|
+
var previous_component = active_component;
|
|
1363
|
+
var previous_tracking = tracking;
|
|
1364
|
+
var previous_dependency = active_dependency;
|
|
1365
|
+
var previous_element = current_element;
|
|
1366
|
+
try {
|
|
1367
|
+
active_block = block;
|
|
1368
|
+
active_component = block.co;
|
|
1369
|
+
tracking = true;
|
|
1370
|
+
active_dependency = null;
|
|
1371
|
+
block.fn(block.o);
|
|
1372
|
+
} catch (error) {
|
|
1373
|
+
var output = block.o;
|
|
1374
|
+
if (error === ASYNC_DERIVED_READ_THROWN) {
|
|
1375
|
+
// regardless of the render mode (stream, etc.)
|
|
1376
|
+
// we need to rerun the block when the dependency's promise resolves
|
|
1377
|
+
register_block_rerun(block);
|
|
1378
|
+
|
|
1379
|
+
if (output.isStreamMode() && output.isSyncRun()) {
|
|
1380
|
+
// rethrowing so that the pending block catches it
|
|
1381
|
+
// we should only render fallback/pending in the streaming mode
|
|
1382
|
+
// when in the synchronous phase
|
|
1383
|
+
throw error;
|
|
1384
|
+
}
|
|
1385
|
+
} else {
|
|
1386
|
+
// always re-throw real errors
|
|
1387
|
+
// during sync, try_block's catch handles it;
|
|
1388
|
+
// during async, the register_block_rerun() try/catch handles it
|
|
1389
|
+
throw error;
|
|
1390
|
+
}
|
|
1391
|
+
} finally {
|
|
1392
|
+
active_block = previous_block;
|
|
1393
|
+
active_component = previous_component;
|
|
1394
|
+
tracking = previous_tracking;
|
|
1395
|
+
active_dependency = previous_dependency;
|
|
1396
|
+
current_element = previous_element;
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
|
|
768
1400
|
/**
|
|
769
1401
|
* @param {any} _
|
|
770
1402
|
* @param {ConstructorParameters<typeof URL>} params
|