ripple 0.3.72 → 0.3.76

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 (172) hide show
  1. package/CHANGELOG.md +116 -0
  2. package/package.json +3 -3
  3. package/src/jsx-runtime.d.ts +4 -10
  4. package/src/runtime/dynamic-client.js +33 -0
  5. package/src/runtime/dynamic-server.js +80 -0
  6. package/src/runtime/index-client.js +5 -13
  7. package/src/runtime/index-server.js +2 -0
  8. package/src/runtime/internal/client/blocks.js +6 -27
  9. package/src/runtime/internal/client/composite.js +11 -6
  10. package/src/runtime/internal/client/for.js +80 -5
  11. package/src/runtime/internal/client/index.js +0 -2
  12. package/src/runtime/internal/client/render.js +5 -2
  13. package/src/runtime/internal/client/types.d.ts +0 -10
  14. package/src/runtime/internal/server/index.js +8 -1
  15. package/tests/client/__snapshots__/computed-properties.test.tsrx.snap +8 -0
  16. package/tests/client/__snapshots__/for.test.tsrx.snap +22 -0
  17. package/tests/client/__snapshots__/html.test.tsrx.snap +4 -0
  18. package/tests/client/array/array.copy-within.test.tsrx +19 -19
  19. package/tests/client/array/array.derived.test.tsrx +97 -109
  20. package/tests/client/array/array.iteration.test.tsrx +28 -28
  21. package/tests/client/array/array.mutations.test.tsrx +68 -68
  22. package/tests/client/array/array.static.test.tsrx +82 -92
  23. package/tests/client/array/array.to-methods.test.tsrx +15 -15
  24. package/tests/client/async-suspend.test.tsrx +180 -179
  25. package/tests/client/basic/__snapshots__/basic.attributes.test.tsrx.snap +2 -0
  26. package/tests/client/basic/__snapshots__/basic.rendering.test.tsrx.snap +4 -0
  27. package/tests/client/basic/basic.attributes.test.tsrx +273 -317
  28. package/tests/client/basic/basic.collections.test.tsrx +55 -61
  29. package/tests/client/basic/basic.components.test.tsrx +198 -220
  30. package/tests/client/basic/basic.errors.test.tsrx +70 -76
  31. package/tests/client/basic/basic.events.test.tsrx +80 -85
  32. package/tests/client/basic/basic.get-set.test.tsrx +54 -64
  33. package/tests/client/basic/basic.hmr.test.tsrx +15 -19
  34. package/tests/client/basic/basic.reactivity.test.tsrx +121 -135
  35. package/tests/client/basic/basic.rendering.test.tsrx +273 -178
  36. package/tests/client/basic/basic.styling.test.tsrx +16 -14
  37. package/tests/client/basic/basic.utilities.test.tsrx +8 -10
  38. package/tests/client/boundaries.test.tsrx +18 -18
  39. package/tests/client/compiler/compiler.assignments.test.tsrx +77 -76
  40. package/tests/client/compiler/compiler.attributes.test.tsrx +18 -14
  41. package/tests/client/compiler/compiler.basic.test.tsrx +357 -288
  42. package/tests/client/compiler/compiler.regex.test.tsrx +40 -44
  43. package/tests/client/compiler/compiler.tracked-access.test.tsrx +57 -38
  44. package/tests/client/compiler/compiler.try-in-function.test.tsrx +16 -16
  45. package/tests/client/compiler/compiler.typescript.test.tsrx +4 -3
  46. package/tests/client/composite/composite.dynamic-components.test.tsrx +62 -47
  47. package/tests/client/composite/composite.generics.test.tsrx +165 -167
  48. package/tests/client/composite/composite.props.test.tsrx +66 -74
  49. package/tests/client/composite/composite.reactivity.test.tsrx +132 -166
  50. package/tests/client/composite/composite.render.test.tsrx +92 -101
  51. package/tests/client/computed-properties.test.tsrx +14 -18
  52. package/tests/client/context.test.tsrx +14 -18
  53. package/tests/client/css/global-additional-cases.test.tsrx +493 -439
  54. package/tests/client/css/global-advanced-selectors.test.tsrx +169 -153
  55. package/tests/client/css/global-at-rules.test.tsrx +71 -66
  56. package/tests/client/css/global-basic.test.tsrx +105 -98
  57. package/tests/client/css/global-classes-ids.test.tsrx +128 -114
  58. package/tests/client/css/global-combinators.test.tsrx +83 -78
  59. package/tests/client/css/global-complex-nesting.test.tsrx +134 -120
  60. package/tests/client/css/global-edge-cases.test.tsrx +138 -120
  61. package/tests/client/css/global-keyframes.test.tsrx +108 -96
  62. package/tests/client/css/global-nested.test.tsrx +88 -78
  63. package/tests/client/css/global-pseudo.test.tsrx +104 -98
  64. package/tests/client/css/global-scoping.test.tsrx +145 -125
  65. package/tests/client/css/style-identifier.test.tsrx +65 -72
  66. package/tests/client/date.test.tsrx +83 -83
  67. package/tests/client/dynamic-elements.test.tsrx +318 -299
  68. package/tests/client/events.test.tsrx +252 -266
  69. package/tests/client/for.test.tsrx +120 -127
  70. package/tests/client/head.test.tsrx +74 -48
  71. package/tests/client/html.test.tsrx +37 -49
  72. package/tests/client/input-value.test.tsrx +1125 -1354
  73. package/tests/client/lazy-array.test.tsrx +10 -16
  74. package/tests/client/lazy-destructuring.test.tsrx +169 -221
  75. package/tests/client/map.test.tsrx +39 -41
  76. package/tests/client/media-query.test.tsrx +15 -19
  77. package/tests/client/object.test.tsrx +46 -56
  78. package/tests/client/portal.test.tsrx +31 -37
  79. package/tests/client/ref.test.tsrx +173 -193
  80. package/tests/client/return.test.tsrx +62 -37
  81. package/tests/client/set.test.tsrx +33 -33
  82. package/tests/client/svg.test.tsrx +197 -216
  83. package/tests/client/switch.test.tsrx +201 -191
  84. package/tests/client/track-async-hydration.test.tsrx +14 -18
  85. package/tests/client/tracked-index-access.test.tsrx +18 -28
  86. package/tests/client/try.test.tsrx +494 -619
  87. package/tests/client/tsx.test.tsrx +286 -292
  88. package/tests/client/typescript-generics.test.tsrx +121 -129
  89. package/tests/client/url/url.derived.test.tsrx +21 -25
  90. package/tests/client/url/url.parsing.test.tsrx +35 -35
  91. package/tests/client/url/url.partial-removal.test.tsrx +32 -32
  92. package/tests/client/url/url.reactivity.test.tsrx +68 -72
  93. package/tests/client/url/url.serialization.test.tsrx +8 -8
  94. package/tests/client/url-search-params/url-search-params.derived.test.tsrx +21 -27
  95. package/tests/client/url-search-params/url-search-params.initialization.test.tsrx +16 -16
  96. package/tests/client/url-search-params/url-search-params.iteration.test.tsrx +37 -37
  97. package/tests/client/url-search-params/url-search-params.mutation.test.tsrx +56 -60
  98. package/tests/client/url-search-params/url-search-params.retrieval.test.tsrx +32 -34
  99. package/tests/client/url-search-params/url-search-params.serialization.test.tsrx +9 -9
  100. package/tests/client/url-search-params/url-search-params.tracked-url.test.tsrx +10 -10
  101. package/tests/hydration/compiled/client/basic.js +390 -319
  102. package/tests/hydration/compiled/client/composite.js +52 -44
  103. package/tests/hydration/compiled/client/for.js +734 -604
  104. package/tests/hydration/compiled/client/head.js +183 -103
  105. package/tests/hydration/compiled/client/html.js +93 -86
  106. package/tests/hydration/compiled/client/if-children.js +95 -71
  107. package/tests/hydration/compiled/client/if.js +113 -89
  108. package/tests/hydration/compiled/client/mixed-control-flow.js +225 -209
  109. package/tests/hydration/compiled/client/nested-control-flow.js +94 -98
  110. package/tests/hydration/compiled/client/reactivity.js +26 -24
  111. package/tests/hydration/compiled/client/return.js +8 -42
  112. package/tests/hydration/compiled/client/switch.js +208 -173
  113. package/tests/hydration/compiled/client/track-async-serialization.js +176 -128
  114. package/tests/hydration/compiled/client/try.js +29 -21
  115. package/tests/hydration/compiled/server/basic.js +210 -221
  116. package/tests/hydration/compiled/server/composite.js +13 -14
  117. package/tests/hydration/compiled/server/for.js +427 -444
  118. package/tests/hydration/compiled/server/head.js +199 -189
  119. package/tests/hydration/compiled/server/html.js +33 -41
  120. package/tests/hydration/compiled/server/if-children.js +114 -117
  121. package/tests/hydration/compiled/server/if.js +77 -83
  122. package/tests/hydration/compiled/server/mixed-control-flow.js +145 -150
  123. package/tests/hydration/compiled/server/nested-control-flow.js +10 -0
  124. package/tests/hydration/compiled/server/reactivity.js +24 -22
  125. package/tests/hydration/compiled/server/return.js +6 -18
  126. package/tests/hydration/compiled/server/switch.js +179 -176
  127. package/tests/hydration/compiled/server/track-async-serialization.js +88 -70
  128. package/tests/hydration/compiled/server/try.js +31 -35
  129. package/tests/hydration/components/basic.tsrx +216 -258
  130. package/tests/hydration/components/composite.tsrx +32 -42
  131. package/tests/hydration/components/events.tsrx +81 -101
  132. package/tests/hydration/components/for.tsrx +270 -336
  133. package/tests/hydration/components/head.tsrx +43 -39
  134. package/tests/hydration/components/hmr.tsrx +16 -22
  135. package/tests/hydration/components/html-in-template.tsrx +15 -21
  136. package/tests/hydration/components/html.tsrx +442 -526
  137. package/tests/hydration/components/if-children.tsrx +107 -125
  138. package/tests/hydration/components/if.tsrx +68 -90
  139. package/tests/hydration/components/mixed-control-flow.tsrx +65 -72
  140. package/tests/hydration/components/nested-control-flow.tsrx +202 -216
  141. package/tests/hydration/components/portal.tsrx +33 -41
  142. package/tests/hydration/components/reactivity.tsrx +26 -34
  143. package/tests/hydration/components/return.tsrx +4 -6
  144. package/tests/hydration/components/switch.tsrx +73 -78
  145. package/tests/hydration/components/track-async-serialization.tsrx +83 -93
  146. package/tests/hydration/components/try.tsrx +37 -51
  147. package/tests/hydration/switch.test.js +8 -8
  148. package/tests/server/await.test.tsrx +3 -3
  149. package/tests/server/basic.attributes.test.tsrx +117 -162
  150. package/tests/server/basic.components.test.tsrx +164 -194
  151. package/tests/server/basic.test.tsrx +299 -199
  152. package/tests/server/compiler.test.tsrx +142 -72
  153. package/tests/server/composite.props.test.tsrx +54 -58
  154. package/tests/server/composite.test.tsrx +165 -167
  155. package/tests/server/context.test.tsrx +13 -17
  156. package/tests/server/dynamic-elements.test.tsrx +147 -148
  157. package/tests/server/for.test.tsrx +115 -84
  158. package/tests/server/head.test.tsrx +54 -31
  159. package/tests/server/html-nesting-validation.test.tsrx +16 -8
  160. package/tests/server/if.test.tsrx +49 -59
  161. package/tests/server/lazy-destructuring.test.tsrx +288 -366
  162. package/tests/server/return.test.tsrx +58 -36
  163. package/tests/server/streaming-ssr.test.tsrx +4 -4
  164. package/tests/server/style-identifier.test.tsrx +61 -69
  165. package/tests/server/switch.test.tsrx +89 -97
  166. package/tests/server/track-async-serialization.test.tsrx +85 -103
  167. package/tests/server/try.test.tsrx +275 -360
  168. package/tests/utils/ref-types.test.js +72 -0
  169. package/tests/utils/vite-plugin-config.test.js +41 -74
  170. package/types/index.d.ts +29 -4
  171. package/src/runtime/internal/client/compat.js +0 -40
  172. package/tests/utils/compiler-compat-config.test.js +0 -38
@@ -2,189 +2,187 @@ import { RippleArray, RippleMap } from 'ripple';
2
2
 
3
3
  describe('generics', () => {
4
4
  it('handles advanced generic ambiguity and edge cases', () => {
5
- function App() {
6
- return <>
7
- const maybe = {
8
- factory: function <T>() {
5
+ function App() @{
6
+ const maybe = {
7
+ factory: function <T>() {
8
+ return {
9
+ make: function <U>() {
10
+ return 1;
11
+ },
12
+ };
13
+ },
14
+ };
15
+ const g = maybe?.factory<number>()?.make<boolean>();
16
+ // 8. Comparison operator (ensure '<' here NOT misparsed as generics)
17
+ let x = 10, y = 20;
18
+ const h =
19
+ x < y ? 'lt' : 'ge';
20
+ // 9. Chained comparisons with intervening generics
21
+ class Box<T> {
22
+ value: T;
23
+
24
+ constructor(value: T) {
25
+ this.value = value;
26
+ }
27
+
28
+ open<U>() {
29
+ return new Box<number>(1);
30
+ }
31
+ }
32
+ const limit = 100;
33
+ const i =
34
+ new Box<number>(2).value < limit ? 'ok' : 'no';
35
+ // 11. Generic function call vs Element: Identifier followed by generic args
36
+ function identity<T>(value: T): T {
37
+ return value;
38
+ }
39
+ const j = identity<number>(42);
40
+ // 12. Member + generic call immediately followed by another call
41
+ class Factory {
42
+ create<T>() {
43
+ return (value: T) => value;
44
+ }
45
+ }
46
+ const factory = new Factory();
47
+ const k = factory.create<number>()(123);
48
+ // 13. Multiple generic segments in chain
49
+ function foo<T>() {
50
+ return {
51
+ bar: function <U>() {
9
52
  return {
10
- make: function <U>() {
11
- return 1;
53
+ baz: function <V>() {
54
+ return true;
12
55
  },
13
56
  };
14
57
  },
15
58
  };
16
- const g = maybe?.factory<number>()?.make<boolean>();
17
- // 8. Comparison operator (ensure '<' here NOT misparsed as generics)
18
- let x = 10, y = 20;
19
- const h =
20
- x < y ? 'lt' : 'ge';
21
- // 9. Chained comparisons with intervening generics
22
- class Box<T> {
23
- value: T;
24
-
25
- constructor(value: T) {
26
- this.value = value;
27
- }
59
+ }
60
+ const l = foo<number>().bar<string>().baz<boolean>();
61
+ // 14. Generic with constraint + default
62
+ type Extractor<T extends { id: number } = { id: number }> = (v: T) => number;
63
+ const m: Extractor<{ id: number }> = (v) => v.id;
64
+ // 15. Generic in angle after "new" + trailing call
65
+ class Wrapper<T> {
66
+ value: T;
28
67
 
29
- open<U>() {
30
- return new Box<number>(1);
31
- }
68
+ constructor() {
69
+ this.value = null as unknown as T;
32
70
  }
33
- const limit = 100;
34
- const i =
35
- new Box<number>(2).value < limit ? 'ok' : 'no';
36
- // 10. JSX / Element should still work
37
- <div class="still-works">
38
- <span>{'Test'}</span>
39
- </div>
40
- // 11. Generic function call vs Element: Identifier followed by generic args
41
- function identity<T>(value: T): T {
42
- return value;
43
- }
44
- const j = identity<number>(42);
45
- // 12. Member + generic call immediately followed by another call
46
- class Factory {
47
- create<T>() {
48
- return (value: T) => value;
49
- }
50
- }
51
- const factory = new Factory();
52
- const k = factory.create<number>()(123);
53
- // 13. Multiple generic segments in chain
54
- function foo<T>() {
55
- return {
56
- bar: function <U>() {
57
- return {
58
- baz: function <V>() {
59
- return true;
60
- },
61
- };
62
- },
63
- };
64
- }
65
- const l = foo<number>().bar<string>().baz<boolean>();
66
- // 14. Generic with constraint + default
67
- type Extractor<T extends { id: number } = { id: number }> = (v: T) => number;
68
- const m: Extractor<{ id: number }> = (v) => v.id;
69
- // 15. Generic in angle after "new" + trailing call
70
- class Wrapper<T> {
71
- value: T;
72
-
73
- constructor() {
74
- this.value = null as unknown as T;
75
- }
76
71
 
77
- unwrap<U>() {
78
- return null as unknown as U;
79
- }
80
- }
81
- const n = new Wrapper<number>().unwrap<string>();
82
- // 16. Angle brackets inside type assertion vs generic call
83
- function getUnknown(): unknown {
84
- return new Map<string, number>([['a', 1]]);
85
- }
86
- getUnknown.factory = function <T>() {
87
- return {
88
- make: function <U>() {
89
- return 2;
90
- },
91
- };
72
+ unwrap<U>() {
73
+ return null as unknown as U;
74
+ }
75
+ }
76
+ const n = new Wrapper<number>().unwrap<string>();
77
+ // 16. Angle brackets inside type assertion vs generic call
78
+ function getUnknown(): unknown {
79
+ return new Map<string, number>([['a', 1]]);
80
+ }
81
+ getUnknown.factory = function <T>() {
82
+ return {
83
+ make: function <U>() {
84
+ return 2;
85
+ },
92
86
  };
93
- const raw = getUnknown();
94
- const o = (raw as Map<string, number>).get('a');
95
- // 17. Generic with comma + trailing less-than comparison on next token
96
- class Pair<T1, T2> {
97
- first: T1;
87
+ };
88
+ const raw = getUnknown();
89
+ const o = (raw as Map<string, number>).get('a');
90
+ // 17. Generic with comma + trailing less-than comparison on next token
91
+ class Pair<T1, T2> {
92
+ first: T1;
98
93
 
99
- second: T2;
94
+ second: T2;
100
95
 
101
- constructor() {
102
- this.first = null as unknown as T1;
103
- this.second = null as unknown as T2;
104
- }
105
- }
106
- const p = new Pair<number, string>();
107
- const q =
108
- 1 < 2 ? p : null;
109
- // 18. Nested generics with line breaks resembling JSX indentation
110
- interface Node<T> {
111
- value: T;
112
- }
113
- interface Edge<W> {
114
- weight: W;
115
- }
116
- class Graph<N, E> {
117
- nodes: N[];
96
+ constructor() {
97
+ this.first = null as unknown as T1;
98
+ this.second = null as unknown as T2;
99
+ }
100
+ }
101
+ const p = new Pair<number, string>();
102
+ const q =
103
+ 1 < 2 ? p : null;
104
+ // 18. Nested generics with line breaks resembling JSX indentation
105
+ interface Node<T> {
106
+ value: T;
107
+ }
108
+ interface Edge<W> {
109
+ weight: W;
110
+ }
111
+ class Graph<N, E> {
112
+ nodes: N[];
118
113
 
119
- edges: E[];
114
+ edges: E[];
120
115
 
121
- constructor() {
122
- this.nodes = [];
123
- this.edges = [];
124
- }
125
- }
126
- const r = new Graph<Node<string>, Edge<number>>();
127
- // 19. Ternary containing generics in both branches
128
- let flag = true;
129
- const s = flag ? new Box<number>(1) : new Box<string>('string');
130
- // 20. Generic inside template expression
131
- const t = `length=${new RippleArray<number>().length}`;
132
- // 21. Optional chaining + generic + property access
133
- const registry = new RippleMap<string, number>();
134
- const u = registry.get('id')?.toString();
135
- // 22. Generic call used as callee for another call
136
- function make<T>() {
137
- return (value: T) => value;
138
- }
139
- const v = make<number>()(10);
140
- // 23. Generic followed by tagged template (ensure not confused with JSX)
141
- function tagFn<T>(strings: TemplateStringsArray, ...values) {
142
- return values[0];
143
- }
144
- const tagResult = tagFn`value`;
145
- // 24. Sequence mixing: (a < b) + generic call in same statement
146
- function compute<T>(x: T, y: T): T {
147
- return y;
148
- }
149
- const w = x < y && compute<number>(x, y);
150
- // Additional component focusing on edge crankers
116
+ constructor() {
117
+ this.nodes = [];
118
+ this.edges = [];
119
+ }
120
+ }
121
+ const r = new Graph<Node<string>, Edge<number>>();
122
+ // 19. Ternary containing generics in both branches
123
+ let flag = true;
124
+ const s = flag ? new Box<number>(1) : new Box<string>('string');
125
+ // 20. Generic inside template expression
126
+ const t = `length=${new RippleArray<number>().length}`;
127
+ // 21. Optional chaining + generic + property access
128
+ const registry = new RippleMap<string, number>();
129
+ const u = registry.get('id')?.toString();
130
+ // 22. Generic call used as callee for another call
131
+ function make<T>() {
132
+ return (value: T) => value;
133
+ }
134
+ const v = make<number>()(10);
135
+ // 23. Generic followed by tagged template (ensure not confused with JSX)
136
+ function tagFn<T>(strings: TemplateStringsArray, ...values) {
137
+ return values[0];
138
+ }
139
+ const tagResult = tagFn`value`;
140
+ // 24. Sequence mixing: (a < b) + generic call in same statement
141
+ function compute<T>(x: T, y: T): T {
142
+ return y;
143
+ }
144
+ const w = x < y && compute<number>(x, y);
145
+ // Additional component focusing on edge crankers
151
146
 
152
- // 28. Generic after parenthesized new expression
153
- const aa = (new Box<number>(1)).open<string>();
154
- // 29. Generic chain right after closing paren of IIFE
155
- class Builder<Kind> {
156
- finalize<Result>() {
157
- return {
158
- result: null as unknown as Result,
159
- };
160
- }
161
- }
162
- const builder = new Builder<Number>();
163
- const result = (function () {
164
- return builder;
165
- }() as Builder<Number>).finalize<boolean>();
166
- // 30. Angle bracket start of conditional expression line
167
- function adjust<T>(value: T): T {
168
- return value;
147
+ // 28. Generic after parenthesized new expression
148
+ const aa = (new Box<number>(1)).open<string>();
149
+ // 29. Generic chain right after closing paren of IIFE
150
+ class Builder<Kind> {
151
+ finalize<Result>() {
152
+ return {
153
+ result: null as unknown as Result,
154
+ };
169
155
  }
170
- const val =
171
- new Wrapper<number>().value < 100 ? adjust<number>(10) : adjust<number>(20);
172
- // 32. Generic with comments inside angle list
173
- class Mapper<Key, Value> {
174
- map: Map<Key, Value>;
156
+ }
157
+ const builder = new Builder<Number>();
158
+ const result = (function () {
159
+ return builder;
160
+ }() as Builder<Number>).finalize<boolean>();
161
+ // 30. Angle bracket start of conditional expression line
162
+ function adjust<T>(value: T): T {
163
+ return value;
164
+ }
165
+ const val =
166
+ new Wrapper<number>().value < 100 ? adjust<number>(10) : adjust<number>(20);
167
+ // 32. Generic with comments inside angle list
168
+ class Mapper<Key, Value> {
169
+ map: Map<Key, Value>;
175
170
 
176
- constructor() {
177
- this.map = new Map<Key, Value>();
178
- }
179
- }
180
- const gg = new Mapper<
181
- // key type
182
- string /* value type */,
183
- number
184
- >();
185
- // 33. Map of generic instance as key
186
- const mm = new Map<RippleArray<number>, RippleArray<string>>();
187
- </>;
171
+ constructor() {
172
+ this.map = new Map<Key, Value>();
173
+ }
174
+ }
175
+ const gg = new Mapper<
176
+ // key type
177
+ string /* value type */,
178
+ number
179
+ >();
180
+ // 33. Map of generic instance as key
181
+ const mm = new Map<RippleArray<number>, RippleArray<string>>();
182
+ // 10. JSX / Element should still work
183
+ <div class="still-works">
184
+ <span>{'Test'}</span>
185
+ </div>
188
186
  }
189
187
 
190
188
  render(App);
@@ -2,30 +2,26 @@ import { Context } from 'ripple';
2
2
 
3
3
  describe('Context API', () => {
4
4
  it('handles context override in nested components', async () => {
5
- const MessageContext = Context('default');
5
+ const MessageContext = new Context('default');
6
6
 
7
- function Inner() {
8
- return <>
9
- const msg = MessageContext.get();
10
- <span>{msg}</span>
11
- </>;
7
+ function Inner() @{
8
+ const msg = MessageContext.get();
9
+ <span>{msg}</span>
12
10
  }
13
11
 
14
- function Middle() {
15
- return <>
16
- MessageContext.set('middle');
17
- <div>
18
- <Inner />
19
- </div>
20
- </>;
12
+ function Middle() @{
13
+ MessageContext.set('middle');
14
+ <div>
15
+ <Inner />
16
+ </div>
21
17
  }
22
18
 
23
- function Outer() {
24
- return <>
25
- MessageContext.set('outer');
19
+ function Outer() @{
20
+ MessageContext.set('outer');
21
+ <>
26
22
  <Middle />
27
23
  <Inner />
28
- </>;
24
+ </>
29
25
  }
30
26
 
31
27
  const { body } = await render(Outer);