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.
Files changed (217) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/package.json +11 -30
  3. package/src/compiler/types/import.d.ts +0 -12
  4. package/src/helpers.d.ts +2 -0
  5. package/src/runtime/array.js +38 -38
  6. package/src/runtime/create-subscriber.js +2 -2
  7. package/src/runtime/index-client.js +15 -13
  8. package/src/runtime/index-server.js +18 -11
  9. package/src/runtime/internal/client/bindings.js +4 -6
  10. package/src/runtime/internal/client/blocks.js +19 -23
  11. package/src/runtime/internal/client/constants.js +20 -9
  12. package/src/runtime/internal/client/events.js +8 -3
  13. package/src/runtime/internal/client/hmr.js +5 -17
  14. package/src/runtime/internal/client/index.js +14 -4
  15. package/src/runtime/internal/client/runtime.js +436 -173
  16. package/src/runtime/internal/client/try.js +334 -156
  17. package/src/runtime/internal/client/types.d.ts +26 -0
  18. package/src/runtime/internal/server/blocks.js +181 -0
  19. package/src/runtime/internal/server/constants.js +7 -0
  20. package/src/runtime/internal/server/index.js +774 -150
  21. package/src/runtime/internal/server/types.d.ts +35 -0
  22. package/src/runtime/media-query.js +34 -33
  23. package/src/runtime/object.js +7 -10
  24. package/src/runtime/proxy.js +2 -3
  25. package/src/runtime/reactive-value.js +23 -21
  26. package/src/server/index.js +1 -1
  27. package/src/utils/ast.js +1 -1
  28. package/src/utils/async.js +35 -0
  29. package/src/utils/attributes.js +43 -0
  30. package/src/utils/builders.js +5 -3
  31. package/tests/client/__snapshots__/computed-properties.test.rsrx.snap +49 -0
  32. package/tests/client/__snapshots__/for.test.rsrx.snap +319 -0
  33. package/tests/client/__snapshots__/html.test.rsrx.snap +40 -0
  34. package/tests/client/_etc.test.rsrx +7 -0
  35. package/tests/client/array/{array.static.test.ripple → array.static.test.rsrx} +18 -20
  36. package/tests/client/async-suspend.test.rsrx +662 -0
  37. package/tests/client/basic/__snapshots__/basic.attributes.test.rsrx.snap +60 -0
  38. package/tests/client/basic/__snapshots__/basic.rendering.test.rsrx.snap +59 -0
  39. package/tests/client/basic/{basic.errors.test.ripple → basic.errors.test.rsrx} +3 -3
  40. package/tests/client/basic/{basic.styling.test.ripple → basic.styling.test.rsrx} +1 -1
  41. package/tests/client/compiler/__snapshots__/compiler.assignments.test.rsrx.snap +12 -0
  42. package/tests/client/compiler/__snapshots__/compiler.typescript.test.rsrx.snap +46 -0
  43. package/tests/client/compiler/{compiler.assignments.test.ripple → compiler.assignments.test.rsrx} +1 -1
  44. package/tests/client/compiler/{compiler.attributes.test.ripple → compiler.attributes.test.rsrx} +1 -1
  45. package/tests/client/compiler/{compiler.basic.test.ripple → compiler.basic.test.rsrx} +13 -13
  46. package/tests/client/compiler/{compiler.tracked-access.test.ripple → compiler.tracked-access.test.rsrx} +1 -1
  47. package/tests/client/compiler/{compiler.try-in-function.test.ripple → compiler.try-in-function.test.rsrx} +9 -7
  48. package/tests/client/compiler/{compiler.typescript.test.ripple → compiler.typescript.test.rsrx} +1 -1
  49. package/tests/client/composite/__snapshots__/composite.render.test.rsrx.snap +37 -0
  50. package/tests/client/css/{global-additional-cases.test.ripple → global-additional-cases.test.rsrx} +1 -1
  51. package/tests/client/css/{global-advanced-selectors.test.ripple → global-advanced-selectors.test.rsrx} +1 -1
  52. package/tests/client/css/{global-at-rules.test.ripple → global-at-rules.test.rsrx} +1 -1
  53. package/tests/client/css/{global-basic.test.ripple → global-basic.test.rsrx} +1 -1
  54. package/tests/client/css/{global-classes-ids.test.ripple → global-classes-ids.test.rsrx} +1 -1
  55. package/tests/client/css/{global-combinators.test.ripple → global-combinators.test.rsrx} +1 -1
  56. package/tests/client/css/{global-complex-nesting.test.ripple → global-complex-nesting.test.rsrx} +1 -1
  57. package/tests/client/css/{global-edge-cases.test.ripple → global-edge-cases.test.rsrx} +1 -1
  58. package/tests/client/css/{global-keyframes.test.ripple → global-keyframes.test.rsrx} +1 -1
  59. package/tests/client/css/{global-nested.test.ripple → global-nested.test.rsrx} +1 -1
  60. package/tests/client/css/{global-pseudo.test.ripple → global-pseudo.test.rsrx} +1 -1
  61. package/tests/client/css/{global-scoping.test.ripple → global-scoping.test.rsrx} +1 -1
  62. package/tests/client/css/{style-identifier.test.ripple → style-identifier.test.rsrx} +1 -1
  63. package/tests/client/{function-overload.test.ripple → function-overload.test.rsrx} +1 -1
  64. package/tests/client/{return.test.ripple → return.test.rsrx} +1 -1
  65. package/tests/client/try.test.rsrx +1702 -0
  66. package/tests/hydration/build-components.js +6 -4
  67. package/tests/hydration/compiled/client/head.js +11 -11
  68. package/tests/hydration/compiled/client/mixed-control-flow.js +55 -70
  69. package/tests/hydration/compiled/client/nested-control-flow.js +72 -88
  70. package/tests/hydration/compiled/client/try.js +42 -54
  71. package/tests/hydration/compiled/server/basic.js +491 -369
  72. package/tests/hydration/compiled/server/composite.js +153 -128
  73. package/tests/hydration/compiled/server/events.js +166 -145
  74. package/tests/hydration/compiled/server/for.js +821 -677
  75. package/tests/hydration/compiled/server/head.js +200 -165
  76. package/tests/hydration/compiled/server/hmr.js +62 -54
  77. package/tests/hydration/compiled/server/html-in-template.js +64 -55
  78. package/tests/hydration/compiled/server/html.js +1477 -1360
  79. package/tests/hydration/compiled/server/if-children.js +448 -408
  80. package/tests/hydration/compiled/server/if.js +204 -171
  81. package/tests/hydration/compiled/server/mixed-control-flow.js +237 -195
  82. package/tests/hydration/compiled/server/nested-control-flow.js +533 -467
  83. package/tests/hydration/compiled/server/portal.js +94 -107
  84. package/tests/hydration/compiled/server/reactivity.js +87 -64
  85. package/tests/hydration/compiled/server/return.js +1424 -1174
  86. package/tests/hydration/compiled/server/switch.js +268 -238
  87. package/tests/hydration/compiled/server/try.js +98 -87
  88. package/tests/hydration/components/{mixed-control-flow.ripple → mixed-control-flow.rsrx} +2 -2
  89. package/tests/hydration/components/{try.ripple → try.rsrx} +4 -2
  90. package/tests/hydration/mixed-control-flow.test.js +14 -0
  91. package/tests/hydration/nested-control-flow.test.js +50 -48
  92. package/tests/hydration/try.test.js +25 -0
  93. package/tests/server/__snapshots__/compiler.test.ripple.snap +0 -32
  94. package/tests/server/__snapshots__/compiler.test.rsrx.snap +95 -0
  95. package/tests/server/{compiler.test.ripple → compiler.test.rsrx} +0 -17
  96. package/tests/server/{html-nesting-validation.test.ripple → html-nesting-validation.test.rsrx} +3 -3
  97. package/tests/server/streaming-ssr.test.rsrx +115 -0
  98. package/tests/server/{style-identifier.test.ripple → style-identifier.test.rsrx} +1 -1
  99. package/tests/server/try.test.rsrx +503 -0
  100. package/tests/setup-server.js +1 -1
  101. package/tests/utils/compiler-compat-config.test.js +4 -4
  102. package/tests/utils/vite-plugin-config.test.js +1 -1
  103. package/tests/utils/vite-plugin-hmr.test.js +5 -5
  104. package/tsconfig.json +2 -0
  105. package/types/index.d.ts +13 -23
  106. package/types/server.d.ts +43 -16
  107. package/src/compiler/comment-utils.js +0 -91
  108. package/src/compiler/errors.js +0 -77
  109. package/src/compiler/identifier-utils.js +0 -80
  110. package/src/compiler/index.d.ts +0 -127
  111. package/src/compiler/index.js +0 -89
  112. package/src/compiler/phases/1-parse/index.js +0 -2964
  113. package/src/compiler/phases/1-parse/style.js +0 -704
  114. package/src/compiler/phases/2-analyze/css-analyze.js +0 -160
  115. package/src/compiler/phases/2-analyze/index.js +0 -2238
  116. package/src/compiler/phases/2-analyze/prune.js +0 -1131
  117. package/src/compiler/phases/2-analyze/validation.js +0 -168
  118. package/src/compiler/phases/3-transform/client/index.js +0 -5301
  119. package/src/compiler/phases/3-transform/segments.js +0 -2129
  120. package/src/compiler/phases/3-transform/server/index.js +0 -1899
  121. package/src/compiler/phases/3-transform/stylesheet.js +0 -545
  122. package/src/compiler/scope.js +0 -476
  123. package/src/compiler/source-map-utils.js +0 -358
  124. package/src/compiler/types/acorn.d.ts +0 -11
  125. package/src/compiler/types/estree-jsx.d.ts +0 -11
  126. package/src/compiler/types/estree.d.ts +0 -11
  127. package/src/compiler/types/index.d.ts +0 -1404
  128. package/src/compiler/types/parse.d.ts +0 -1721
  129. package/src/compiler/utils.js +0 -1263
  130. package/tests/client/_etc.test.ripple +0 -5
  131. package/tests/client/async-suspend.test.ripple +0 -94
  132. package/tests/client/try.test.ripple +0 -196
  133. package/tests/server/streaming-ssr.test.ripple +0 -68
  134. package/tests/server/try.test.ripple +0 -82
  135. /package/tests/client/array/{array.copy-within.test.ripple → array.copy-within.test.rsrx} +0 -0
  136. /package/tests/client/array/{array.derived.test.ripple → array.derived.test.rsrx} +0 -0
  137. /package/tests/client/array/{array.iteration.test.ripple → array.iteration.test.rsrx} +0 -0
  138. /package/tests/client/array/{array.mutations.test.ripple → array.mutations.test.rsrx} +0 -0
  139. /package/tests/client/array/{array.to-methods.test.ripple → array.to-methods.test.rsrx} +0 -0
  140. /package/tests/client/basic/{basic.attributes.test.ripple → basic.attributes.test.rsrx} +0 -0
  141. /package/tests/client/basic/{basic.collections.test.ripple → basic.collections.test.rsrx} +0 -0
  142. /package/tests/client/basic/{basic.components.test.ripple → basic.components.test.rsrx} +0 -0
  143. /package/tests/client/basic/{basic.events.test.ripple → basic.events.test.rsrx} +0 -0
  144. /package/tests/client/basic/{basic.get-set.test.ripple → basic.get-set.test.rsrx} +0 -0
  145. /package/tests/client/basic/{basic.hmr.test.ripple → basic.hmr.test.rsrx} +0 -0
  146. /package/tests/client/basic/{basic.reactivity.test.ripple → basic.reactivity.test.rsrx} +0 -0
  147. /package/tests/client/basic/{basic.rendering.test.ripple → basic.rendering.test.rsrx} +0 -0
  148. /package/tests/client/basic/{basic.utilities.test.ripple → basic.utilities.test.rsrx} +0 -0
  149. /package/tests/client/{boundaries.test.ripple → boundaries.test.rsrx} +0 -0
  150. /package/tests/client/compiler/{compiler.regex.test.ripple → compiler.regex.test.rsrx} +0 -0
  151. /package/tests/client/composite/{composite.dynamic-components.test.ripple → composite.dynamic-components.test.rsrx} +0 -0
  152. /package/tests/client/composite/{composite.generics.test.ripple → composite.generics.test.rsrx} +0 -0
  153. /package/tests/client/composite/{composite.props.test.ripple → composite.props.test.rsrx} +0 -0
  154. /package/tests/client/composite/{composite.reactivity.test.ripple → composite.reactivity.test.rsrx} +0 -0
  155. /package/tests/client/composite/{composite.render.test.ripple → composite.render.test.rsrx} +0 -0
  156. /package/tests/client/{computed-properties.test.ripple → computed-properties.test.rsrx} +0 -0
  157. /package/tests/client/{context.test.ripple → context.test.rsrx} +0 -0
  158. /package/tests/client/{date.test.ripple → date.test.rsrx} +0 -0
  159. /package/tests/client/{dynamic-elements.test.ripple → dynamic-elements.test.rsrx} +0 -0
  160. /package/tests/client/{events.test.ripple → events.test.rsrx} +0 -0
  161. /package/tests/client/{for.test.ripple → for.test.rsrx} +0 -0
  162. /package/tests/client/{function-overload-import.ripple → function-overload-import.rsrx} +0 -0
  163. /package/tests/client/{head.test.ripple → head.test.rsrx} +0 -0
  164. /package/tests/client/{html.test.ripple → html.test.rsrx} +0 -0
  165. /package/tests/client/{input-value.test.ripple → input-value.test.rsrx} +0 -0
  166. /package/tests/client/{lazy-destructuring.test.ripple → lazy-destructuring.test.rsrx} +0 -0
  167. /package/tests/client/{map.test.ripple → map.test.rsrx} +0 -0
  168. /package/tests/client/{media-query.test.ripple → media-query.test.rsrx} +0 -0
  169. /package/tests/client/{object.test.ripple → object.test.rsrx} +0 -0
  170. /package/tests/client/{portal.test.ripple → portal.test.rsrx} +0 -0
  171. /package/tests/client/{ref.test.ripple → ref.test.rsrx} +0 -0
  172. /package/tests/client/{set.test.ripple → set.test.rsrx} +0 -0
  173. /package/tests/client/{svg.test.ripple → svg.test.rsrx} +0 -0
  174. /package/tests/client/{switch.test.ripple → switch.test.rsrx} +0 -0
  175. /package/tests/client/{tsx.test.ripple → tsx.test.rsrx} +0 -0
  176. /package/tests/client/{typescript-generics.test.ripple → typescript-generics.test.rsrx} +0 -0
  177. /package/tests/client/url/{url.derived.test.ripple → url.derived.test.rsrx} +0 -0
  178. /package/tests/client/url/{url.parsing.test.ripple → url.parsing.test.rsrx} +0 -0
  179. /package/tests/client/url/{url.partial-removal.test.ripple → url.partial-removal.test.rsrx} +0 -0
  180. /package/tests/client/url/{url.reactivity.test.ripple → url.reactivity.test.rsrx} +0 -0
  181. /package/tests/client/url/{url.serialization.test.ripple → url.serialization.test.rsrx} +0 -0
  182. /package/tests/client/url-search-params/{url-search-params.derived.test.ripple → url-search-params.derived.test.rsrx} +0 -0
  183. /package/tests/client/url-search-params/{url-search-params.initialization.test.ripple → url-search-params.initialization.test.rsrx} +0 -0
  184. /package/tests/client/url-search-params/{url-search-params.iteration.test.ripple → url-search-params.iteration.test.rsrx} +0 -0
  185. /package/tests/client/url-search-params/{url-search-params.mutation.test.ripple → url-search-params.mutation.test.rsrx} +0 -0
  186. /package/tests/client/url-search-params/{url-search-params.retrieval.test.ripple → url-search-params.retrieval.test.rsrx} +0 -0
  187. /package/tests/client/url-search-params/{url-search-params.serialization.test.ripple → url-search-params.serialization.test.rsrx} +0 -0
  188. /package/tests/client/url-search-params/{url-search-params.tracked-url.test.ripple → url-search-params.tracked-url.test.rsrx} +0 -0
  189. /package/tests/hydration/components/{basic.ripple → basic.rsrx} +0 -0
  190. /package/tests/hydration/components/{composite.ripple → composite.rsrx} +0 -0
  191. /package/tests/hydration/components/{events.ripple → events.rsrx} +0 -0
  192. /package/tests/hydration/components/{for.ripple → for.rsrx} +0 -0
  193. /package/tests/hydration/components/{head.ripple → head.rsrx} +0 -0
  194. /package/tests/hydration/components/{hmr.ripple → hmr.rsrx} +0 -0
  195. /package/tests/hydration/components/{html-in-template.ripple → html-in-template.rsrx} +0 -0
  196. /package/tests/hydration/components/{html.ripple → html.rsrx} +0 -0
  197. /package/tests/hydration/components/{if-children.ripple → if-children.rsrx} +0 -0
  198. /package/tests/hydration/components/{if.ripple → if.rsrx} +0 -0
  199. /package/tests/hydration/components/{nested-control-flow.ripple → nested-control-flow.rsrx} +0 -0
  200. /package/tests/hydration/components/{portal.ripple → portal.rsrx} +0 -0
  201. /package/tests/hydration/components/{reactivity.ripple → reactivity.rsrx} +0 -0
  202. /package/tests/hydration/components/{return.ripple → return.rsrx} +0 -0
  203. /package/tests/hydration/components/{switch.ripple → switch.rsrx} +0 -0
  204. /package/tests/server/{await.test.ripple → await.test.rsrx} +0 -0
  205. /package/tests/server/{basic.attributes.test.ripple → basic.attributes.test.rsrx} +0 -0
  206. /package/tests/server/{basic.components.test.ripple → basic.components.test.rsrx} +0 -0
  207. /package/tests/server/{basic.test.ripple → basic.test.rsrx} +0 -0
  208. /package/tests/server/{composite.props.test.ripple → composite.props.test.rsrx} +0 -0
  209. /package/tests/server/{composite.test.ripple → composite.test.rsrx} +0 -0
  210. /package/tests/server/{context.test.ripple → context.test.rsrx} +0 -0
  211. /package/tests/server/{dynamic-elements.test.ripple → dynamic-elements.test.rsrx} +0 -0
  212. /package/tests/server/{for.test.ripple → for.test.rsrx} +0 -0
  213. /package/tests/server/{head.test.ripple → head.test.rsrx} +0 -0
  214. /package/tests/server/{if.test.ripple → if.test.rsrx} +0 -0
  215. /package/tests/server/{lazy-destructuring.test.ripple → lazy-destructuring.test.rsrx} +0 -0
  216. /package/tests/server/{return.test.ripple → return.test.rsrx} +0 -0
  217. /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 { SSRComponent } from 'ripple/server';
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
- is_ripple_object,
10
- get_descriptor,
11
- define_property,
12
- is_array,
13
- array_slice,
14
- } from '../client/utils.js';
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 '../../../compiler/utils.js';
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(output, value) {
39
- output.push(BLOCK_OPEN);
59
+ export function render_expression(value) {
60
+ output_push(BLOCK_OPEN);
40
61
 
41
62
  if (is_ripple_element(value)) {
42
- var result = value.render(output, {});
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
- output.push(escape(value ?? ''));
65
+ output_push(escape(value ?? ''));
51
66
  }
52
67
 
53
- output.push(BLOCK_CLOSE);
68
+ output_push(BLOCK_CLOSE);
54
69
  }
55
70
 
56
- /** @type {null | Component} */
57
- export let active_component = null;
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
- /** @type {number} */
60
- let clock = 0;
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
- export let tracking = false;
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
- head = '';
212
- body = '';
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 {Promise<any>[]} */
216
- promises = [];
217
- /** @type {Output | null} */
334
+ #css = new Set();
335
+ /** @type {null | Output} */
218
336
  #parent = null;
219
- /** @type {import('stream').Readable | null} */
220
- #stream = null;
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, stream = null) {
229
- this.#parent = parent;
230
- this.#stream = stream;
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.target === 'head') {
239
- this.head += str;
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.#stream) {
244
- this.#stream.push(str);
245
- } else {
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.css.add(hash);
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
- /** @type {import('ripple/server').render} */
260
- export async function render(component) {
261
- const output = new Output(null, null);
262
- let head = '';
263
- let body = '';
264
- let css = /** @type {Set<string>} */ (new Set());
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
- // Reset dev-mode element tracking state at the start of each render
267
- reset_element_state();
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
- try {
270
- if (component.async) {
271
- await component(output, {});
272
- } else {
273
- component(output, {});
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
- if (output.promises.length > 0) {
276
- await Promise.all(output.promises);
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
- head = output.head;
280
- body = BLOCK_OPEN + output.body + BLOCK_CLOSE;
281
- css = output.css;
282
- } catch (error) {
283
- console.log(error);
284
- } finally {
285
- reset_element_state();
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
- /** @type {import('ripple/server').renderToStream} */
291
- export function renderToStream(component) {
292
- const stream = new Readable({
293
- read() {},
294
- });
295
- const output = new Output(null, stream);
296
- render_in_chunks(component, stream, output);
297
- return stream;
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 {SSRComponent} component
302
- * @param {Readable} stream
303
- * @param {Output} output
563
+ * @param {RenderComponent} component
564
+ * @param {BaseRenderOptions} [passed_in_options]
565
+ * @returns {Promise<RenderResult | RenderStreamResult>}
304
566
  */
305
- async function render_in_chunks(component, stream, output) {
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
- reset_element_state();
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
- try {
310
- if (component.async) {
311
- await component(output, {});
312
- } else {
313
- component(output, {});
314
- }
315
- if (output.promises.length > 0) {
316
- await Promise.all(output.promises);
317
- }
318
- stream.push(null);
319
- } catch (error) {
320
- console.error(error);
321
- stream.emit('error', error);
322
- } finally {
323
- reset_element_state();
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
- var component = {
654
+ active_component = {
331
655
  c: null,
332
656
  p: active_component,
333
657
  };
334
- active_component = component;
658
+ active_block = component_block(() => {});
335
659
  }
336
660
 
337
661
  /**
338
662
  * @returns {void}
339
663
  */
340
664
  export function pop_component() {
341
- var component = /** @type {Component} */ (active_component);
342
- active_component = component.p;
665
+ active_component = /** @type {Component} */ (active_component).p;
666
+ active_block = /** @type {Block} */ (active_block).p;
343
667
  }
344
668
 
345
669
  /**
346
- * @typedef {{
347
- * tag: string;
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
- /** @type {ElementContext | undefined} */
356
- let current_element;
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
- * @type {Set<string>}
685
+ * @param {string} hash
686
+ * @returns {void}
360
687
  */
361
- let seen_warnings = new Set();
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 {null | import('#server').Dependency} */
1016
+ /** @type {Dependency | null} */
689
1017
  this.d = null;
690
- this.f = TRACKED | DERIVED;
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 /** @type {Derived} */ (new DerivedValue(v, get || set ? { get, set } : empty_get_set));
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