ripple 0.3.72 → 0.3.74
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +66 -0
- package/package.json +3 -3
- package/src/jsx-runtime.d.ts +2 -8
- package/src/runtime/index-client.js +3 -13
- package/src/runtime/internal/client/blocks.js +3 -25
- package/src/runtime/internal/client/for.js +80 -5
- package/src/runtime/internal/client/index.js +0 -2
- package/src/runtime/internal/client/types.d.ts +0 -10
- package/tests/client/__snapshots__/computed-properties.test.tsrx.snap +8 -0
- package/tests/client/__snapshots__/for.test.tsrx.snap +22 -0
- package/tests/client/__snapshots__/html.test.tsrx.snap +4 -0
- package/tests/client/array/array.copy-within.test.tsrx +19 -19
- package/tests/client/array/array.derived.test.tsrx +97 -109
- package/tests/client/array/array.iteration.test.tsrx +28 -28
- package/tests/client/array/array.mutations.test.tsrx +68 -68
- package/tests/client/array/array.static.test.tsrx +82 -92
- package/tests/client/array/array.to-methods.test.tsrx +15 -15
- package/tests/client/async-suspend.test.tsrx +180 -179
- package/tests/client/basic/__snapshots__/basic.attributes.test.tsrx.snap +2 -0
- package/tests/client/basic/__snapshots__/basic.rendering.test.tsrx.snap +4 -0
- package/tests/client/basic/basic.attributes.test.tsrx +273 -317
- package/tests/client/basic/basic.collections.test.tsrx +55 -61
- package/tests/client/basic/basic.components.test.tsrx +196 -218
- package/tests/client/basic/basic.errors.test.tsrx +70 -76
- package/tests/client/basic/basic.events.test.tsrx +80 -85
- package/tests/client/basic/basic.get-set.test.tsrx +54 -64
- package/tests/client/basic/basic.hmr.test.tsrx +15 -19
- package/tests/client/basic/basic.reactivity.test.tsrx +121 -135
- package/tests/client/basic/basic.rendering.test.tsrx +273 -178
- package/tests/client/basic/basic.utilities.test.tsrx +8 -10
- package/tests/client/boundaries.test.tsrx +18 -18
- package/tests/client/compiler/compiler.assignments.test.tsrx +77 -76
- package/tests/client/compiler/compiler.attributes.test.tsrx +18 -14
- package/tests/client/compiler/compiler.basic.test.tsrx +357 -288
- package/tests/client/compiler/compiler.regex.test.tsrx +40 -44
- package/tests/client/compiler/compiler.tracked-access.test.tsrx +57 -38
- package/tests/client/compiler/compiler.try-in-function.test.tsrx +16 -16
- package/tests/client/compiler/compiler.typescript.test.tsrx +4 -3
- package/tests/client/composite/composite.dynamic-components.test.tsrx +41 -44
- package/tests/client/composite/composite.generics.test.tsrx +165 -167
- package/tests/client/composite/composite.props.test.tsrx +66 -74
- package/tests/client/composite/composite.reactivity.test.tsrx +132 -166
- package/tests/client/composite/composite.render.test.tsrx +92 -101
- package/tests/client/computed-properties.test.tsrx +14 -18
- package/tests/client/context.test.tsrx +14 -18
- package/tests/client/css/global-additional-cases.test.tsrx +491 -437
- package/tests/client/css/global-advanced-selectors.test.tsrx +169 -153
- package/tests/client/css/global-at-rules.test.tsrx +71 -66
- package/tests/client/css/global-basic.test.tsrx +105 -98
- package/tests/client/css/global-classes-ids.test.tsrx +128 -114
- package/tests/client/css/global-combinators.test.tsrx +83 -78
- package/tests/client/css/global-complex-nesting.test.tsrx +134 -120
- package/tests/client/css/global-edge-cases.test.tsrx +138 -120
- package/tests/client/css/global-keyframes.test.tsrx +108 -96
- package/tests/client/css/global-nested.test.tsrx +88 -78
- package/tests/client/css/global-pseudo.test.tsrx +104 -98
- package/tests/client/css/global-scoping.test.tsrx +145 -125
- package/tests/client/css/style-identifier.test.tsrx +62 -69
- package/tests/client/date.test.tsrx +83 -83
- package/tests/client/dynamic-elements.test.tsrx +227 -283
- package/tests/client/events.test.tsrx +252 -266
- package/tests/client/for.test.tsrx +120 -127
- package/tests/client/head.test.tsrx +40 -48
- package/tests/client/html.test.tsrx +37 -49
- package/tests/client/input-value.test.tsrx +1125 -1354
- package/tests/client/lazy-array.test.tsrx +10 -16
- package/tests/client/lazy-destructuring.test.tsrx +169 -221
- package/tests/client/map.test.tsrx +39 -41
- package/tests/client/media-query.test.tsrx +15 -19
- package/tests/client/object.test.tsrx +46 -56
- package/tests/client/portal.test.tsrx +31 -37
- package/tests/client/ref.test.tsrx +173 -193
- package/tests/client/return.test.tsrx +62 -37
- package/tests/client/set.test.tsrx +33 -33
- package/tests/client/svg.test.tsrx +195 -215
- package/tests/client/switch.test.tsrx +201 -191
- package/tests/client/track-async-hydration.test.tsrx +14 -18
- package/tests/client/tracked-index-access.test.tsrx +18 -28
- package/tests/client/try.test.tsrx +494 -619
- package/tests/client/tsx.test.tsrx +286 -292
- package/tests/client/typescript-generics.test.tsrx +121 -129
- package/tests/client/url/url.derived.test.tsrx +21 -25
- package/tests/client/url/url.parsing.test.tsrx +35 -35
- package/tests/client/url/url.partial-removal.test.tsrx +32 -32
- package/tests/client/url/url.reactivity.test.tsrx +68 -72
- package/tests/client/url/url.serialization.test.tsrx +8 -8
- package/tests/client/url-search-params/url-search-params.derived.test.tsrx +21 -27
- package/tests/client/url-search-params/url-search-params.initialization.test.tsrx +16 -16
- package/tests/client/url-search-params/url-search-params.iteration.test.tsrx +37 -37
- package/tests/client/url-search-params/url-search-params.mutation.test.tsrx +56 -60
- package/tests/client/url-search-params/url-search-params.retrieval.test.tsrx +32 -34
- package/tests/client/url-search-params/url-search-params.serialization.test.tsrx +9 -9
- package/tests/client/url-search-params/url-search-params.tracked-url.test.tsrx +10 -10
- package/tests/hydration/compiled/client/basic.js +390 -319
- package/tests/hydration/compiled/client/composite.js +52 -44
- package/tests/hydration/compiled/client/for.js +734 -604
- package/tests/hydration/compiled/client/head.js +183 -103
- package/tests/hydration/compiled/client/html.js +93 -86
- package/tests/hydration/compiled/client/if-children.js +95 -71
- package/tests/hydration/compiled/client/if.js +113 -89
- package/tests/hydration/compiled/client/mixed-control-flow.js +225 -209
- package/tests/hydration/compiled/client/nested-control-flow.js +94 -98
- package/tests/hydration/compiled/client/reactivity.js +26 -24
- package/tests/hydration/compiled/client/return.js +8 -42
- package/tests/hydration/compiled/client/switch.js +208 -173
- package/tests/hydration/compiled/client/track-async-serialization.js +176 -128
- package/tests/hydration/compiled/client/try.js +29 -21
- package/tests/hydration/compiled/server/basic.js +210 -221
- package/tests/hydration/compiled/server/composite.js +13 -14
- package/tests/hydration/compiled/server/for.js +427 -444
- package/tests/hydration/compiled/server/head.js +199 -189
- package/tests/hydration/compiled/server/html.js +33 -41
- package/tests/hydration/compiled/server/if-children.js +114 -117
- package/tests/hydration/compiled/server/if.js +77 -83
- package/tests/hydration/compiled/server/mixed-control-flow.js +145 -150
- package/tests/hydration/compiled/server/nested-control-flow.js +10 -0
- package/tests/hydration/compiled/server/reactivity.js +24 -22
- package/tests/hydration/compiled/server/return.js +6 -18
- package/tests/hydration/compiled/server/switch.js +179 -176
- package/tests/hydration/compiled/server/track-async-serialization.js +88 -70
- package/tests/hydration/compiled/server/try.js +31 -35
- package/tests/hydration/components/basic.tsrx +216 -258
- package/tests/hydration/components/composite.tsrx +32 -42
- package/tests/hydration/components/events.tsrx +81 -101
- package/tests/hydration/components/for.tsrx +270 -336
- package/tests/hydration/components/head.tsrx +43 -39
- package/tests/hydration/components/hmr.tsrx +16 -22
- package/tests/hydration/components/html-in-template.tsrx +15 -21
- package/tests/hydration/components/html.tsrx +442 -526
- package/tests/hydration/components/if-children.tsrx +107 -125
- package/tests/hydration/components/if.tsrx +68 -90
- package/tests/hydration/components/mixed-control-flow.tsrx +65 -72
- package/tests/hydration/components/nested-control-flow.tsrx +202 -216
- package/tests/hydration/components/portal.tsrx +33 -41
- package/tests/hydration/components/reactivity.tsrx +26 -34
- package/tests/hydration/components/return.tsrx +4 -6
- package/tests/hydration/components/switch.tsrx +73 -78
- package/tests/hydration/components/track-async-serialization.tsrx +83 -93
- package/tests/hydration/components/try.tsrx +37 -51
- package/tests/hydration/switch.test.js +8 -8
- package/tests/server/await.test.tsrx +3 -3
- package/tests/server/basic.attributes.test.tsrx +117 -162
- package/tests/server/basic.components.test.tsrx +163 -193
- package/tests/server/basic.test.tsrx +298 -198
- package/tests/server/compiler.test.tsrx +142 -72
- package/tests/server/composite.props.test.tsrx +54 -58
- package/tests/server/composite.test.tsrx +165 -167
- package/tests/server/context.test.tsrx +13 -17
- package/tests/server/dynamic-elements.test.tsrx +103 -135
- package/tests/server/for.test.tsrx +115 -84
- package/tests/server/head.test.tsrx +31 -31
- package/tests/server/html-nesting-validation.test.tsrx +16 -8
- package/tests/server/if.test.tsrx +49 -59
- package/tests/server/lazy-destructuring.test.tsrx +288 -366
- package/tests/server/return.test.tsrx +58 -36
- package/tests/server/streaming-ssr.test.tsrx +4 -4
- package/tests/server/style-identifier.test.tsrx +58 -66
- package/tests/server/switch.test.tsrx +89 -97
- package/tests/server/track-async-serialization.test.tsrx +85 -103
- package/tests/server/try.test.tsrx +275 -360
- package/tests/utils/ref-types.test.js +72 -0
- package/tests/utils/vite-plugin-config.test.js +41 -74
- package/types/index.d.ts +1 -0
- package/src/runtime/internal/client/compat.js +0 -40
- package/tests/utils/compiler-compat-config.test.js +0 -38
|
@@ -3,8 +3,8 @@ import { flushSync, track } from 'ripple';
|
|
|
3
3
|
|
|
4
4
|
describe('basic client > rendering & text', () => {
|
|
5
5
|
it('renders static text', () => {
|
|
6
|
-
function Basic() {
|
|
7
|
-
|
|
6
|
+
function Basic() @{
|
|
7
|
+
<div>{'Hello World'}</div>
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
expect(container).toBeDefined();
|
|
@@ -14,11 +14,9 @@ describe('basic client > rendering & text', () => {
|
|
|
14
14
|
});
|
|
15
15
|
|
|
16
16
|
it('renders semi-dynamic text', () => {
|
|
17
|
-
function Basic() {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
<div>{message}</div>
|
|
21
|
-
</>;
|
|
17
|
+
function Basic() @{
|
|
18
|
+
let message = 'Hello World';
|
|
19
|
+
<div>{message}</div>
|
|
22
20
|
}
|
|
23
21
|
|
|
24
22
|
render(Basic);
|
|
@@ -27,11 +25,9 @@ describe('basic client > rendering & text', () => {
|
|
|
27
25
|
});
|
|
28
26
|
|
|
29
27
|
it('renders string interpolation without creating HTML', () => {
|
|
30
|
-
function Basic() {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
<div>{markup}</div>
|
|
34
|
-
</>;
|
|
28
|
+
function Basic() @{
|
|
29
|
+
let markup = '<span>Not HTML</span>';
|
|
30
|
+
<div>{markup}</div>
|
|
35
31
|
}
|
|
36
32
|
|
|
37
33
|
render(Basic);
|
|
@@ -42,32 +38,35 @@ describe('basic client > rendering & text', () => {
|
|
|
42
38
|
expect(div.querySelector('span')).toBeNull();
|
|
43
39
|
});
|
|
44
40
|
|
|
45
|
-
it('renders direct
|
|
46
|
-
function Basic() {
|
|
47
|
-
|
|
48
|
-
<div class="entities">
|
|
49
|
-
<div class="backslash">
|
|
50
|
-
<pre class="multiline">
|
|
51
|
-
|
|
52
|
-
|
|
41
|
+
it('renders direct JSX text children as text', () => {
|
|
42
|
+
function Basic() @{
|
|
43
|
+
<>
|
|
44
|
+
<div class="entities">Rock & "Roll"</div>
|
|
45
|
+
<div class="backslash">line break</div>
|
|
46
|
+
<pre class="multiline">
|
|
47
|
+
first
|
|
48
|
+
second
|
|
49
|
+
</pre>
|
|
50
|
+
</>
|
|
53
51
|
}
|
|
54
52
|
|
|
55
53
|
render(Basic);
|
|
56
54
|
|
|
57
55
|
expect(container.querySelector('.entities').textContent).toBe('Rock & "Roll"');
|
|
58
|
-
expect(container.querySelector('.backslash').textContent).toBe('line
|
|
56
|
+
expect(container.querySelector('.backslash').textContent).toBe('line break');
|
|
59
57
|
expect(container.querySelector('.multiline').textContent).toBe('first\nsecond');
|
|
60
58
|
});
|
|
61
59
|
|
|
62
|
-
it('does not render
|
|
60
|
+
it('does not render JavaScript statements outside returned component templates', () => {
|
|
63
61
|
function Basic() {
|
|
64
62
|
const ready = true;
|
|
65
63
|
|
|
66
64
|
if (ready) {
|
|
67
|
-
|
|
65
|
+
const leaked = 'should not render';
|
|
66
|
+
void leaked;
|
|
68
67
|
}
|
|
69
68
|
|
|
70
|
-
return <>
|
|
69
|
+
return <>Hello world</>;
|
|
71
70
|
}
|
|
72
71
|
|
|
73
72
|
render(Basic);
|
|
@@ -77,14 +76,12 @@ second"</pre>
|
|
|
77
76
|
});
|
|
78
77
|
|
|
79
78
|
it('renders primitive component return branches', () => {
|
|
80
|
-
function Basic() {
|
|
79
|
+
function Basic() @{
|
|
81
80
|
const ready = false;
|
|
82
|
-
|
|
83
81
|
if (!ready) {
|
|
84
82
|
return 'Waiting';
|
|
85
83
|
}
|
|
86
|
-
|
|
87
|
-
return <>"Ready"</>;
|
|
84
|
+
<>Ready</>
|
|
88
85
|
}
|
|
89
86
|
|
|
90
87
|
render(Basic);
|
|
@@ -122,10 +119,127 @@ second"</pre>
|
|
|
122
119
|
expect(container.textContent).toBe('');
|
|
123
120
|
});
|
|
124
121
|
|
|
125
|
-
it('does not
|
|
122
|
+
it('does not stringify adjacent call-containing expression children', () => {
|
|
123
|
+
function child(label: string) @{
|
|
124
|
+
<span>{label}</span>
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function empty() {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const Constructed = function Constructed(label: string) {
|
|
132
|
+
return child(label);
|
|
133
|
+
} as unknown as {
|
|
134
|
+
new (label: string): ReturnType<typeof child>;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const factory = child;
|
|
138
|
+
|
|
139
|
+
function tag(_strings: TemplateStringsArray) {
|
|
140
|
+
return child('tagged');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const lookup = {
|
|
144
|
+
member: child('member'),
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
function getKey(): keyof typeof lookup {
|
|
148
|
+
return 'member';
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function touch() {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
let assigned;
|
|
156
|
+
|
|
157
|
+
function Basic() @{
|
|
158
|
+
<>
|
|
159
|
+
<div>
|
|
160
|
+
{'call:'}
|
|
161
|
+
{child('call')}
|
|
162
|
+
</div>
|
|
163
|
+
<div>
|
|
164
|
+
{'new:'}
|
|
165
|
+
{new Constructed('new')}
|
|
166
|
+
</div>
|
|
167
|
+
<div>
|
|
168
|
+
{'chain:'}
|
|
169
|
+
{factory?.('chain')}
|
|
170
|
+
</div>
|
|
171
|
+
<div>
|
|
172
|
+
{'ts-wrapper:'}
|
|
173
|
+
{child('ts-wrapper')!}
|
|
174
|
+
</div>
|
|
175
|
+
<div>
|
|
176
|
+
{'array:'}
|
|
177
|
+
{[child('array')]}
|
|
178
|
+
</div>
|
|
179
|
+
<div>
|
|
180
|
+
{'assignment:'}
|
|
181
|
+
{assigned = child('assignment')}
|
|
182
|
+
</div>
|
|
183
|
+
<div>
|
|
184
|
+
{'logical:'}
|
|
185
|
+
{true && child('logical')}
|
|
186
|
+
</div>
|
|
187
|
+
<div>
|
|
188
|
+
{'conditional:'}
|
|
189
|
+
{true ? child('conditional') : ''}
|
|
190
|
+
</div>
|
|
191
|
+
<div>
|
|
192
|
+
{'member:'}
|
|
193
|
+
{lookup[getKey()]}
|
|
194
|
+
</div>
|
|
195
|
+
<div>
|
|
196
|
+
{'object:'}
|
|
197
|
+
{{
|
|
198
|
+
[Symbol.for('ripple.element')]: true,
|
|
199
|
+
render() {
|
|
200
|
+
return child('object');
|
|
201
|
+
},
|
|
202
|
+
}}
|
|
203
|
+
</div>
|
|
204
|
+
<div>
|
|
205
|
+
{'sequence:'}
|
|
206
|
+
{(touch(), child('sequence'))}
|
|
207
|
+
</div>
|
|
208
|
+
<div>
|
|
209
|
+
{'tagged:'}
|
|
210
|
+
{tag`tagged`}
|
|
211
|
+
</div>
|
|
212
|
+
<div>
|
|
213
|
+
{'unary:'}
|
|
214
|
+
{void empty()}
|
|
215
|
+
</div>
|
|
216
|
+
</>
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
render(Basic);
|
|
220
|
+
|
|
221
|
+
expect([...container.querySelectorAll('div')].map((div) => div.textContent)).toEqual([
|
|
222
|
+
'call:call',
|
|
223
|
+
'new:new',
|
|
224
|
+
'chain:chain',
|
|
225
|
+
'ts-wrapper:ts-wrapper',
|
|
226
|
+
'array:array',
|
|
227
|
+
'assignment:assignment',
|
|
228
|
+
'logical:logical',
|
|
229
|
+
'conditional:conditional',
|
|
230
|
+
'member:member',
|
|
231
|
+
'object:object',
|
|
232
|
+
'sequence:sequence',
|
|
233
|
+
'tagged:tagged',
|
|
234
|
+
'unary:',
|
|
235
|
+
]);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it('does not render unreachable statements after an ASI return', () => {
|
|
126
239
|
function Basic() {
|
|
127
240
|
return;
|
|
128
|
-
|
|
241
|
+
const leaked = 'should not render';
|
|
242
|
+
void leaked;
|
|
129
243
|
}
|
|
130
244
|
|
|
131
245
|
render(Basic);
|
|
@@ -133,14 +247,14 @@ second"</pre>
|
|
|
133
247
|
expect(container.textContent).toBe('');
|
|
134
248
|
});
|
|
135
249
|
|
|
136
|
-
it('renders bare
|
|
137
|
-
function App() {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
250
|
+
it('renders bare JSX text in if-else branches', () => {
|
|
251
|
+
function App() @{
|
|
252
|
+
let condition = false;
|
|
253
|
+
@if (condition) {
|
|
254
|
+
<>Hello Ripple</>
|
|
255
|
+
} @else {
|
|
256
|
+
<>Hello React</>
|
|
257
|
+
}
|
|
144
258
|
}
|
|
145
259
|
|
|
146
260
|
render(App);
|
|
@@ -149,18 +263,16 @@ second"</pre>
|
|
|
149
263
|
});
|
|
150
264
|
|
|
151
265
|
it('renders dynamic text', () => {
|
|
152
|
-
function Basic() {
|
|
153
|
-
|
|
154
|
-
|
|
266
|
+
function Basic() @{
|
|
267
|
+
let &[message] = track('Hello World');
|
|
268
|
+
<>
|
|
155
269
|
<button
|
|
156
270
|
onClick={() => {
|
|
157
271
|
message = 'Hello Ripple';
|
|
158
272
|
}}
|
|
159
|
-
>
|
|
160
|
-
{'Change Text'}
|
|
161
|
-
</button>
|
|
273
|
+
>{'Change Text'}</button>
|
|
162
274
|
<div>{message}</div>
|
|
163
|
-
|
|
275
|
+
</>
|
|
164
276
|
}
|
|
165
277
|
|
|
166
278
|
render(Basic);
|
|
@@ -174,8 +286,8 @@ second"</pre>
|
|
|
174
286
|
});
|
|
175
287
|
|
|
176
288
|
it('renders empty string literal', () => {
|
|
177
|
-
function Basic() {
|
|
178
|
-
|
|
289
|
+
function Basic() @{
|
|
290
|
+
<div>{''}</div>
|
|
179
291
|
}
|
|
180
292
|
|
|
181
293
|
render(Basic);
|
|
@@ -183,8 +295,8 @@ second"</pre>
|
|
|
183
295
|
});
|
|
184
296
|
|
|
185
297
|
it('renders empty template literal', () => {
|
|
186
|
-
function Basic() {
|
|
187
|
-
|
|
298
|
+
function Basic() @{
|
|
299
|
+
<div>{``}</div>
|
|
188
300
|
}
|
|
189
301
|
|
|
190
302
|
render(Basic);
|
|
@@ -192,22 +304,22 @@ second"</pre>
|
|
|
192
304
|
});
|
|
193
305
|
|
|
194
306
|
it('renders tick template literal for nested children', () => {
|
|
195
|
-
function Child({ level, children }: { level: number; children: any }) {
|
|
196
|
-
|
|
197
|
-
if (level == 1) {
|
|
307
|
+
function Child({ level, children }: { level: number; children: any }) @{
|
|
308
|
+
<>
|
|
309
|
+
@if (level == 1) {
|
|
198
310
|
<h1>{children}</h1>
|
|
199
311
|
}
|
|
200
|
-
if (level == 2) {
|
|
312
|
+
@if (level == 2) {
|
|
201
313
|
<h2>{children}</h2>
|
|
202
314
|
}
|
|
203
|
-
if (level == 3) {
|
|
315
|
+
@if (level == 3) {
|
|
204
316
|
<h3>{children}</h3>
|
|
205
317
|
}
|
|
206
|
-
|
|
318
|
+
</>
|
|
207
319
|
}
|
|
208
320
|
|
|
209
|
-
function App() {
|
|
210
|
-
|
|
321
|
+
function App() @{
|
|
322
|
+
<Child level={1}>{`Heading 1`}</Child>
|
|
211
323
|
}
|
|
212
324
|
|
|
213
325
|
render(App);
|
|
@@ -215,14 +327,14 @@ second"</pre>
|
|
|
215
327
|
});
|
|
216
328
|
|
|
217
329
|
it('renders simple JS expression logic correctly', () => {
|
|
218
|
-
function Example() {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
330
|
+
function Example() @{
|
|
331
|
+
let test: Record<number, string> = {};
|
|
332
|
+
let counter = 0;
|
|
333
|
+
test[counter++] = 'Test';
|
|
334
|
+
<>
|
|
223
335
|
<div>{JSON.stringify(test)}</div>
|
|
224
336
|
<div>{JSON.stringify(counter)}</div>
|
|
225
|
-
|
|
337
|
+
</>
|
|
226
338
|
}
|
|
227
339
|
render(Example);
|
|
228
340
|
|
|
@@ -230,31 +342,29 @@ second"</pre>
|
|
|
230
342
|
});
|
|
231
343
|
|
|
232
344
|
it('renders with mixed static and dynamic content', () => {
|
|
233
|
-
function Basic() {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
<
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
</div>
|
|
257
|
-
</>;
|
|
345
|
+
function Basic() @{
|
|
346
|
+
let &[name] = track('World');
|
|
347
|
+
let &[count] = track(0);
|
|
348
|
+
const staticMessage = 'Welcome to Ripple!';
|
|
349
|
+
<div class="mixed-content">
|
|
350
|
+
<h1>{staticMessage}</h1>
|
|
351
|
+
<p class="greeting">
|
|
352
|
+
{'Hello, ' + name + '!'}
|
|
353
|
+
</p>
|
|
354
|
+
<p class="notifications">
|
|
355
|
+
{'You have ' + count + ' notifications'}
|
|
356
|
+
</p>
|
|
357
|
+
<button
|
|
358
|
+
onClick={() => {
|
|
359
|
+
count++;
|
|
360
|
+
}}
|
|
361
|
+
>{'Add Notification'}</button>
|
|
362
|
+
<button
|
|
363
|
+
onClick={() => {
|
|
364
|
+
name = name === 'World' ? 'User' : 'World';
|
|
365
|
+
}}
|
|
366
|
+
>{'Toggle Name'}</button>
|
|
367
|
+
</div>
|
|
258
368
|
}
|
|
259
369
|
|
|
260
370
|
render(Basic);
|
|
@@ -278,16 +388,16 @@ second"</pre>
|
|
|
278
388
|
});
|
|
279
389
|
|
|
280
390
|
it('basic operations', () => {
|
|
281
|
-
function App() {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
391
|
+
function App() @{
|
|
392
|
+
let &[count] = track(0);
|
|
393
|
+
const a = count++;
|
|
394
|
+
const b = ++count;
|
|
395
|
+
<>
|
|
286
396
|
<div>{a}</div>
|
|
287
397
|
<div>{b}</div>
|
|
288
398
|
<div>{5}</div>
|
|
289
399
|
<div>{count}</div>
|
|
290
|
-
|
|
400
|
+
</>
|
|
291
401
|
}
|
|
292
402
|
|
|
293
403
|
render(App);
|
|
@@ -295,36 +405,32 @@ second"</pre>
|
|
|
295
405
|
});
|
|
296
406
|
|
|
297
407
|
it('renders with conditional rendering using if statements', () => {
|
|
298
|
-
function Basic() {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
408
|
+
function Basic() @{
|
|
409
|
+
let &[showContent] = track(false);
|
|
410
|
+
let &[userRole] = track('guest');
|
|
411
|
+
<>
|
|
302
412
|
<button
|
|
303
413
|
onClick={() => {
|
|
304
414
|
showContent = !showContent;
|
|
305
415
|
}}
|
|
306
|
-
>
|
|
307
|
-
{'Toggle Content'}
|
|
308
|
-
</button>
|
|
416
|
+
>{'Toggle Content'}</button>
|
|
309
417
|
<button
|
|
310
418
|
onClick={() => {
|
|
311
419
|
userRole = userRole === 'guest' ? 'admin' : 'guest';
|
|
312
420
|
}}
|
|
313
|
-
>
|
|
314
|
-
{'Toggle Role'}
|
|
315
|
-
</button>
|
|
421
|
+
>{'Toggle Role'}</button>
|
|
316
422
|
<div class="content">
|
|
317
|
-
if (showContent) {
|
|
318
|
-
if (userRole === 'admin') {
|
|
423
|
+
@if (showContent) {
|
|
424
|
+
@if (userRole === 'admin') {
|
|
319
425
|
<div class="admin-content">{'Admin content'}</div>
|
|
320
|
-
} else {
|
|
426
|
+
} @else {
|
|
321
427
|
<div class="user-content">{'User content'}</div>
|
|
322
428
|
}
|
|
323
|
-
} else {
|
|
429
|
+
} @else {
|
|
324
430
|
<div class="no-content">{'No content'}</div>
|
|
325
431
|
}
|
|
326
432
|
</div>
|
|
327
|
-
|
|
433
|
+
</>
|
|
328
434
|
}
|
|
329
435
|
|
|
330
436
|
render(Basic);
|
|
@@ -352,14 +458,9 @@ second"</pre>
|
|
|
352
458
|
});
|
|
353
459
|
|
|
354
460
|
it('should handle lexical scopes correctly', () => {
|
|
355
|
-
function App() {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
let sectionData = 'Nested scope variable';
|
|
359
|
-
|
|
360
|
-
{sectionData}
|
|
361
|
-
</section>
|
|
362
|
-
</>;
|
|
461
|
+
function App() @{
|
|
462
|
+
let sectionData = 'Nested scope variable';
|
|
463
|
+
<section>{sectionData}</section>
|
|
363
464
|
}
|
|
364
465
|
|
|
365
466
|
render(App);
|
|
@@ -367,48 +468,48 @@ second"</pre>
|
|
|
367
468
|
});
|
|
368
469
|
|
|
369
470
|
it('runs nested JavaScript blocks inside component-local callables', () => {
|
|
370
|
-
function App() {
|
|
371
|
-
|
|
372
|
-
function
|
|
373
|
-
|
|
374
|
-
|
|
471
|
+
function App() @{
|
|
472
|
+
function readFunction() {
|
|
473
|
+
const label = 'function outer';
|
|
474
|
+
let result = '';
|
|
475
|
+
|
|
476
|
+
{
|
|
477
|
+
const label = 'function inner';
|
|
478
|
+
result = label;
|
|
479
|
+
}
|
|
375
480
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
481
|
+
return `${result} / ${label}`;
|
|
482
|
+
}
|
|
483
|
+
const readArrow = () => {
|
|
484
|
+
const offset = 5;
|
|
485
|
+
let value = offset;
|
|
380
486
|
|
|
381
|
-
|
|
487
|
+
{
|
|
488
|
+
const offset = 17;
|
|
489
|
+
value += offset;
|
|
382
490
|
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
491
|
+
|
|
492
|
+
return value;
|
|
493
|
+
};
|
|
494
|
+
class Reader {
|
|
495
|
+
read() {
|
|
496
|
+
const label = 'method outer';
|
|
497
|
+
let result = '';
|
|
386
498
|
|
|
387
499
|
{
|
|
388
|
-
const
|
|
389
|
-
|
|
500
|
+
const label = 'method inner';
|
|
501
|
+
result = label;
|
|
390
502
|
}
|
|
391
503
|
|
|
392
|
-
return
|
|
393
|
-
};
|
|
394
|
-
class Reader {
|
|
395
|
-
read() {
|
|
396
|
-
const label = 'method outer';
|
|
397
|
-
let result = '';
|
|
398
|
-
|
|
399
|
-
{
|
|
400
|
-
const label = 'method inner';
|
|
401
|
-
result = label;
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
return `${result} / ${label}`;
|
|
405
|
-
}
|
|
504
|
+
return `${result} / ${label}`;
|
|
406
505
|
}
|
|
407
|
-
|
|
506
|
+
}
|
|
507
|
+
const reader = new Reader();
|
|
508
|
+
<>
|
|
408
509
|
<div class="block-function">{readFunction()}</div>
|
|
409
510
|
<div class="block-arrow">{readArrow()}</div>
|
|
410
511
|
<div class="block-method">{reader.read()}</div>
|
|
411
|
-
|
|
512
|
+
</>
|
|
412
513
|
}
|
|
413
514
|
|
|
414
515
|
render(App);
|
|
@@ -423,27 +524,23 @@ second"</pre>
|
|
|
423
524
|
});
|
|
424
525
|
|
|
425
526
|
it('should handle consecutive text nodes without duplication', () => {
|
|
426
|
-
function App() {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
</div>
|
|
440
|
-
</>;
|
|
441
|
-
},
|
|
442
|
-
};
|
|
527
|
+
function App() @{
|
|
528
|
+
const Something = conditional('a');
|
|
529
|
+
function conditional(item: 'a') {
|
|
530
|
+
let hello = 'Hello';
|
|
531
|
+
const obj = {
|
|
532
|
+
a: function A() @{
|
|
533
|
+
<div>
|
|
534
|
+
{'a'}
|
|
535
|
+
{' '}
|
|
536
|
+
{hello}
|
|
537
|
+
</div>
|
|
538
|
+
},
|
|
539
|
+
};
|
|
443
540
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
541
|
+
return obj[item];
|
|
542
|
+
}
|
|
543
|
+
<Something />
|
|
447
544
|
}
|
|
448
545
|
|
|
449
546
|
render(App);
|
|
@@ -452,16 +549,14 @@ second"</pre>
|
|
|
452
549
|
});
|
|
453
550
|
|
|
454
551
|
it('should handle multiple consecutive text expressions', () => {
|
|
455
|
-
function App() {
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
</div>
|
|
464
|
-
</>;
|
|
552
|
+
function App() @{
|
|
553
|
+
let name = 'World';
|
|
554
|
+
<div>
|
|
555
|
+
{'Hello'}
|
|
556
|
+
{' '}
|
|
557
|
+
{name}
|
|
558
|
+
{'!'}
|
|
559
|
+
</div>
|
|
465
560
|
}
|
|
466
561
|
|
|
467
562
|
render(App);
|
|
@@ -5,17 +5,15 @@ describe('basic client > utilities', () => {
|
|
|
5
5
|
let resolve: () => void;
|
|
6
6
|
const promise = new Promise<void>((res) => (resolve = res));
|
|
7
7
|
|
|
8
|
-
function Basic() {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
tick().then(() => resolve());
|
|
15
|
-
});
|
|
8
|
+
function Basic() @{
|
|
9
|
+
let &[value] = track(0);
|
|
10
|
+
effect(() => {
|
|
11
|
+
untrack(() => {
|
|
12
|
+
value++;
|
|
13
|
+
tick().then(() => resolve());
|
|
16
14
|
});
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
});
|
|
16
|
+
<p>{value}</p>
|
|
19
17
|
}
|
|
20
18
|
render(Basic);
|
|
21
19
|
|