ripple 0.3.12 → 0.3.13

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