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