ripple 0.3.3 → 0.3.4
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 +72 -0
- package/package.json +2 -2
- package/src/compiler/identifier-utils.js +1 -8
- package/src/compiler/phases/1-parse/index.js +101 -195
- package/src/compiler/phases/2-analyze/index.js +82 -174
- package/src/compiler/phases/2-analyze/prune.js +2 -2
- package/src/compiler/phases/3-transform/client/index.js +169 -261
- package/src/compiler/phases/3-transform/server/index.js +185 -42
- package/src/compiler/types/index.d.ts +14 -33
- package/src/compiler/utils.js +32 -20
- package/src/runtime/index-client.js +0 -17
- package/src/runtime/internal/client/bindings.js +118 -7
- package/src/runtime/internal/client/render.js +5 -1
- package/src/runtime/internal/client/runtime.js +1 -1
- package/src/runtime/internal/client/types.d.ts +4 -0
- package/tests/client/array/array.copy-within.test.ripple +7 -7
- package/tests/client/array/array.derived.test.ripple +24 -24
- package/tests/client/array/array.iteration.test.ripple +7 -7
- package/tests/client/array/array.mutations.test.ripple +17 -17
- package/tests/client/array/array.to-methods.test.ripple +4 -4
- package/tests/client/async-suspend.test.ripple +3 -3
- package/tests/client/basic/basic.attributes.test.ripple +31 -31
- package/tests/client/basic/basic.collections.test.ripple +6 -6
- package/tests/client/basic/basic.components.test.ripple +8 -8
- package/tests/client/basic/basic.errors.test.ripple +31 -34
- package/tests/client/basic/basic.events.test.ripple +11 -11
- package/tests/client/basic/basic.get-set.test.ripple +18 -18
- package/tests/client/basic/basic.reactivity.test.ripple +36 -36
- package/tests/client/basic/basic.rendering.test.ripple +7 -7
- package/tests/client/basic/basic.utilities.test.ripple +4 -4
- package/tests/client/boundaries.test.ripple +7 -7
- package/tests/client/compiler/__snapshots__/compiler.typescript.test.ripple.snap +24 -0
- package/tests/client/compiler/compiler.assignments.test.ripple +12 -10
- package/tests/client/compiler/compiler.basic.test.ripple +57 -58
- package/tests/client/compiler/compiler.tracked-access.test.ripple +14 -8
- package/tests/client/compiler/compiler.typescript.test.ripple +31 -0
- package/tests/client/composite/composite.dynamic-components.test.ripple +6 -6
- package/tests/client/composite/composite.props.test.ripple +9 -9
- package/tests/client/composite/composite.reactivity.test.ripple +23 -23
- package/tests/client/composite/composite.render.test.ripple +52 -4
- package/tests/client/computed-properties.test.ripple +3 -3
- package/tests/client/context.test.ripple +3 -3
- package/tests/client/css/global-additional-cases.test.ripple +5 -2
- package/tests/client/css/style-identifier.test.ripple +40 -49
- package/tests/client/date.test.ripple +39 -39
- package/tests/client/dynamic-elements.test.ripple +37 -37
- package/tests/client/events.test.ripple +25 -25
- package/tests/client/for.test.ripple +8 -8
- package/tests/client/head.test.ripple +7 -7
- package/tests/client/html.test.ripple +2 -2
- package/tests/client/input-value.test.ripple +376 -177
- package/tests/client/lazy-destructuring.test.ripple +185 -0
- package/tests/client/map.test.ripple +20 -20
- package/tests/client/media-query.test.ripple +4 -4
- package/tests/client/object.test.ripple +5 -5
- package/tests/client/portal.test.ripple +4 -4
- package/tests/client/ref.test.ripple +3 -3
- package/tests/client/return.test.ripple +17 -17
- package/tests/client/set.test.ripple +10 -10
- package/tests/client/svg.test.ripple +6 -5
- package/tests/client/switch.test.ripple +10 -10
- package/tests/client/tracked-expression.test.ripple +3 -1
- package/tests/client/try.test.ripple +4 -4
- package/tests/client/url/url.derived.test.ripple +6 -7
- package/tests/client/url/url.parsing.test.ripple +9 -9
- package/tests/client/url/url.partial-removal.test.ripple +9 -9
- package/tests/client/url/url.reactivity.test.ripple +16 -16
- package/tests/client/url/url.serialization.test.ripple +3 -3
- package/tests/client/url-search-params/url-search-params.derived.test.ripple +7 -8
- package/tests/client/url-search-params/url-search-params.initialization.test.ripple +6 -4
- package/tests/client/url-search-params/url-search-params.iteration.test.ripple +12 -12
- package/tests/client/url-search-params/url-search-params.mutation.test.ripple +18 -18
- package/tests/client/url-search-params/url-search-params.retrieval.test.ripple +16 -16
- package/tests/client/url-search-params/url-search-params.serialization.test.ripple +4 -4
- package/tests/client/url-search-params/url-search-params.tracked-url.test.ripple +3 -3
- package/tests/hydration/build-components.js +4 -10
- package/tests/hydration/compiled/client/basic.js +4 -4
- package/tests/hydration/compiled/client/events.js +2 -0
- package/tests/hydration/compiled/client/for.js +2 -0
- package/tests/hydration/compiled/client/head.js +13 -11
- package/tests/hydration/compiled/client/hmr.js +4 -2
- package/tests/hydration/compiled/client/html.js +82 -95
- package/tests/hydration/compiled/client/if-children.js +8 -9
- package/tests/hydration/compiled/client/if.js +2 -0
- package/tests/hydration/compiled/client/mixed-control-flow.js +4 -2
- package/tests/hydration/compiled/client/portal.js +1 -1
- package/tests/hydration/compiled/client/reactivity.js +2 -0
- package/tests/hydration/compiled/client/return.js +2 -0
- package/tests/hydration/compiled/client/switch.js +2 -0
- package/tests/hydration/compiled/server/composite.js +2 -2
- package/tests/hydration/compiled/server/events.js +2 -0
- package/tests/hydration/compiled/server/for.js +2 -0
- package/tests/hydration/compiled/server/head.js +13 -11
- package/tests/hydration/compiled/server/hmr.js +2 -0
- package/tests/hydration/compiled/server/html.js +2 -0
- package/tests/hydration/compiled/server/if-children.js +2 -0
- package/tests/hydration/compiled/server/if.js +2 -0
- package/tests/hydration/compiled/server/mixed-control-flow.js +2 -0
- package/tests/hydration/compiled/server/portal.js +1 -1
- package/tests/hydration/compiled/server/reactivity.js +2 -0
- package/tests/hydration/compiled/server/return.js +2 -0
- package/tests/hydration/compiled/server/switch.js +2 -0
- package/tests/hydration/components/composite.ripple +1 -1
- package/tests/hydration/components/events.ripple +10 -8
- package/tests/hydration/components/for.ripple +22 -20
- package/tests/hydration/components/head.ripple +8 -6
- package/tests/hydration/components/hmr.ripple +3 -1
- package/tests/hydration/components/html.ripple +3 -1
- package/tests/hydration/components/if-children.ripple +9 -7
- package/tests/hydration/components/if.ripple +7 -5
- package/tests/hydration/components/mixed-control-flow.ripple +5 -3
- package/tests/hydration/components/portal.ripple +2 -2
- package/tests/hydration/components/reactivity.ripple +11 -9
- package/tests/hydration/components/return.ripple +13 -11
- package/tests/hydration/components/switch.ripple +6 -4
- package/tests/server/__snapshots__/compiler.test.ripple.snap +22 -0
- package/tests/server/await.test.ripple +2 -2
- package/tests/server/basic.attributes.test.ripple +21 -19
- package/tests/server/basic.components.test.ripple +5 -4
- package/tests/server/basic.test.ripple +21 -20
- package/tests/server/compiler.test.ripple +36 -5
- package/tests/server/composite.props.test.ripple +7 -6
- package/tests/server/context.test.ripple +3 -1
- package/tests/server/dynamic-elements.test.ripple +24 -24
- package/tests/server/head.test.ripple +7 -5
- package/tests/server/style-identifier.test.ripple +95 -16
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { track } from 'ripple';
|
|
2
|
+
|
|
1
3
|
export component MixedControlFlowStatic() {
|
|
2
4
|
const rows = [
|
|
3
5
|
{ id: 1, kind: 'a', enabled: true },
|
|
@@ -29,9 +31,9 @@ export component MixedControlFlowStatic() {
|
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
export component MixedControlFlowReactive() {
|
|
32
|
-
let show =
|
|
33
|
-
let mode =
|
|
34
|
-
let items =
|
|
34
|
+
let show = track(true);
|
|
35
|
+
let mode = track<'a' | 'b'>('a');
|
|
36
|
+
let items = track([
|
|
35
37
|
{ id: 1, label: 'One' },
|
|
36
38
|
{ id: 2, label: 'Two' },
|
|
37
39
|
]);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Portal components for hydration testing
|
|
2
|
-
import { Portal } from 'ripple';
|
|
2
|
+
import { Portal, track } from 'ripple';
|
|
3
3
|
|
|
4
4
|
// Simple portal with static content
|
|
5
5
|
export component SimplePortal() {
|
|
@@ -13,7 +13,7 @@ export component SimplePortal() {
|
|
|
13
13
|
|
|
14
14
|
// Portal with conditional rendering
|
|
15
15
|
export component ConditionalPortal() {
|
|
16
|
-
let show =
|
|
16
|
+
let show = track(true);
|
|
17
17
|
|
|
18
18
|
<div class="container">
|
|
19
19
|
<button class="toggle" onClick={() => (@show = !@show)}>{'Toggle'}</button>
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import { track } from 'ripple';
|
|
2
|
+
|
|
1
3
|
// Reactive components for hydration testing
|
|
2
4
|
|
|
3
5
|
export component TrackedState() {
|
|
4
|
-
let count =
|
|
6
|
+
let count = track(0);
|
|
5
7
|
<div class="count">{@count}</div>
|
|
6
8
|
}
|
|
7
9
|
|
|
8
10
|
export component CounterWithInitial(props: { initial: number }) {
|
|
9
|
-
let count =
|
|
11
|
+
let count = track(props.initial);
|
|
10
12
|
<div>
|
|
11
13
|
<span class="count">{@count}</span>
|
|
12
14
|
</div>
|
|
@@ -17,24 +19,24 @@ export component CounterWrapper() {
|
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
export component ComputedValues() {
|
|
20
|
-
let a =
|
|
21
|
-
let b =
|
|
22
|
+
let a = track(2);
|
|
23
|
+
let b = track(3);
|
|
22
24
|
const sum = () => @a + @b;
|
|
23
25
|
<div class="sum">{sum()}</div>
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
export component MultipleTracked() {
|
|
27
|
-
let x =
|
|
28
|
-
let y =
|
|
29
|
-
let z =
|
|
29
|
+
let x = track(10);
|
|
30
|
+
let y = track(20);
|
|
31
|
+
let z = track(30);
|
|
30
32
|
<div class="x">{@x}</div>
|
|
31
33
|
<div class="y">{@y}</div>
|
|
32
34
|
<div class="z">{@z}</div>
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
export component DerivedState() {
|
|
36
|
-
let firstName =
|
|
37
|
-
let lastName =
|
|
38
|
+
let firstName = track('John');
|
|
39
|
+
let lastName = track('Doe');
|
|
38
40
|
const fullName = () => `${@firstName} ${@lastName}`;
|
|
39
41
|
<div class="name">{fullName()}</div>
|
|
40
42
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { track } from 'ripple';
|
|
2
|
+
|
|
1
3
|
// Return statement components for hydration testing
|
|
2
4
|
|
|
3
5
|
// Basic return - skips content after direct return
|
|
@@ -264,7 +266,7 @@ export component ReturnWithElseBothReturn() {
|
|
|
264
266
|
|
|
265
267
|
// Reactive return - starts true, can toggle to false
|
|
266
268
|
export component ReactiveReturnTrueToFalse() {
|
|
267
|
-
let condition =
|
|
269
|
+
let condition = track(true);
|
|
268
270
|
|
|
269
271
|
<button
|
|
270
272
|
class="toggle"
|
|
@@ -283,7 +285,7 @@ export component ReactiveReturnTrueToFalse() {
|
|
|
283
285
|
|
|
284
286
|
// Reactive return - starts false, can toggle to true
|
|
285
287
|
export component ReactiveReturnFalseToTrue() {
|
|
286
|
-
let condition =
|
|
288
|
+
let condition = track(false);
|
|
287
289
|
|
|
288
290
|
<button
|
|
289
291
|
class="toggle"
|
|
@@ -303,7 +305,7 @@ export component ReactiveReturnFalseToTrue() {
|
|
|
303
305
|
// Reactive nested return - only inner condition (b) is tracked
|
|
304
306
|
export component ReactiveNestedReturn() {
|
|
305
307
|
let a = true;
|
|
306
|
-
let b =
|
|
308
|
+
let b = track(true);
|
|
307
309
|
|
|
308
310
|
<button
|
|
309
311
|
class="toggle"
|
|
@@ -396,7 +398,7 @@ export component MultipleSiblingReturns() {
|
|
|
396
398
|
|
|
397
399
|
// Reactive sibling returns - cycles first -> second -> fallback
|
|
398
400
|
export component ReactiveSiblingReturns() {
|
|
399
|
-
let mode =
|
|
401
|
+
let mode = track('first');
|
|
400
402
|
|
|
401
403
|
<button
|
|
402
404
|
class="toggle"
|
|
@@ -428,8 +430,8 @@ export component ReactiveSiblingReturns() {
|
|
|
428
430
|
|
|
429
431
|
// Reactive nested returns with tracked outer and inner conditions
|
|
430
432
|
export component ReactiveOuterInnerReturns() {
|
|
431
|
-
let a =
|
|
432
|
-
let b =
|
|
433
|
+
let a = track(true);
|
|
434
|
+
let b = track(true);
|
|
433
435
|
|
|
434
436
|
<button
|
|
435
437
|
class="toggle-a"
|
|
@@ -462,7 +464,7 @@ export component ReactiveOuterInnerReturns() {
|
|
|
462
464
|
|
|
463
465
|
// Reactive else-if return chain that transitions between return and non-return states
|
|
464
466
|
export component ReactiveElseIfReturns() {
|
|
465
|
-
let status =
|
|
467
|
+
let status = track(0);
|
|
466
468
|
|
|
467
469
|
<button
|
|
468
470
|
class="toggle"
|
|
@@ -487,10 +489,10 @@ export component ReactiveElseIfReturns() {
|
|
|
487
489
|
|
|
488
490
|
// Deeply nested independent return guards with multiple root-level siblings
|
|
489
491
|
export component ReactiveDeepNestedIndependentReturns() {
|
|
490
|
-
let c1 =
|
|
491
|
-
let c2 =
|
|
492
|
-
let c3 =
|
|
493
|
-
let c4 =
|
|
492
|
+
let c1 = track(false);
|
|
493
|
+
let c2 = track(false);
|
|
494
|
+
let c3 = track(false);
|
|
495
|
+
let c4 = track(false);
|
|
494
496
|
|
|
495
497
|
<button
|
|
496
498
|
class="toggle-c1"
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { track } from 'ripple';
|
|
2
|
+
|
|
1
3
|
export component SwitchStatic() {
|
|
2
4
|
const status: string = 'success';
|
|
3
5
|
switch (status) {
|
|
@@ -13,7 +15,7 @@ export component SwitchStatic() {
|
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
export component SwitchReactive() {
|
|
16
|
-
let status =
|
|
18
|
+
let status = track<'a' | 'b' | 'c'>('a');
|
|
17
19
|
<button
|
|
18
20
|
class="toggle"
|
|
19
21
|
onClick={() => {
|
|
@@ -49,7 +51,7 @@ export component SwitchFallthrough() {
|
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
export component SwitchNumericLevels() {
|
|
52
|
-
let level =
|
|
54
|
+
let level = track<1 | 2 | 3>(1);
|
|
53
55
|
<button
|
|
54
56
|
class="level-toggle"
|
|
55
57
|
onClick={() => {
|
|
@@ -74,7 +76,7 @@ export component SwitchNumericLevels() {
|
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
export component SwitchBlockScoped() {
|
|
77
|
-
let level =
|
|
79
|
+
let level = track<1 | 2 | 3>(1);
|
|
78
80
|
<button
|
|
79
81
|
class="block-toggle"
|
|
80
82
|
onClick={() => {
|
|
@@ -102,7 +104,7 @@ export component SwitchBlockScoped() {
|
|
|
102
104
|
}
|
|
103
105
|
|
|
104
106
|
export component SwitchNoBreak() {
|
|
105
|
-
let level =
|
|
107
|
+
let level = track<1 | 2 | 3>(1);
|
|
106
108
|
<button
|
|
107
109
|
class="nobreak-toggle"
|
|
108
110
|
onClick={() => {
|
|
@@ -96,6 +96,28 @@ export async function App(__output) {
|
|
|
96
96
|
App.async = true;"
|
|
97
97
|
`;
|
|
98
98
|
|
|
99
|
+
exports[`compiler typescript tests > removes class TypeScript syntax from JS output 1`] = `
|
|
100
|
+
"import * as _$_ from 'ripple/internal/server';
|
|
101
|
+
|
|
102
|
+
class PrintEvent {
|
|
103
|
+
text;
|
|
104
|
+
|
|
105
|
+
constructor(text) {
|
|
106
|
+
this.text = text;
|
|
107
|
+
}
|
|
108
|
+
}"
|
|
109
|
+
`;
|
|
110
|
+
|
|
111
|
+
exports[`compiler typescript tests > removes class extends type arguments from JS output 1`] = `
|
|
112
|
+
"import * as _$_ from 'ripple/internal/server';
|
|
113
|
+
|
|
114
|
+
class StringMap extends Map {
|
|
115
|
+
constructor() {
|
|
116
|
+
super();
|
|
117
|
+
}
|
|
118
|
+
}"
|
|
119
|
+
`;
|
|
120
|
+
|
|
99
121
|
exports[`compiler typescript tests > removes type assertions from function parameters and leaves default values 1`] = `
|
|
100
122
|
"import * as _$_ from 'ripple/internal/server';
|
|
101
123
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { set,
|
|
1
|
+
import { get, set, track } from 'ripple';
|
|
2
2
|
|
|
3
3
|
describe('await in control flow', () => {
|
|
4
4
|
it('all tests are commented out for now as await in control flow is not yet supported', () => {
|
|
@@ -8,7 +8,7 @@ describe('await in control flow', () => {
|
|
|
8
8
|
// it('should handle await inside if statement', async () => {
|
|
9
9
|
// component App() {
|
|
10
10
|
// let condition = true;
|
|
11
|
-
// let data =
|
|
11
|
+
// let data = track('loading');
|
|
12
12
|
|
|
13
13
|
// if (condition) {
|
|
14
14
|
// await new Promise((resolve) => setTimeout(() => {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { RippleObject, track } from 'ripple';
|
|
2
|
+
|
|
1
3
|
describe('basic server > attribute rendering', () => {
|
|
2
4
|
it('render static attributes', async () => {
|
|
3
5
|
component Basic() {
|
|
@@ -17,7 +19,7 @@ describe('basic server > attribute rendering', () => {
|
|
|
17
19
|
|
|
18
20
|
it('render dynamic class attribute', async () => {
|
|
19
21
|
component Basic() {
|
|
20
|
-
let active =
|
|
22
|
+
let active = track(false);
|
|
21
23
|
|
|
22
24
|
<div class={@active ? 'active' : 'inactive'}>{'Dynamic Class'}</div>
|
|
23
25
|
|
|
@@ -87,7 +89,7 @@ describe('basic server > attribute rendering', () => {
|
|
|
87
89
|
|
|
88
90
|
it('render dynamic class object', async () => {
|
|
89
91
|
component Basic() {
|
|
90
|
-
let active =
|
|
92
|
+
let active = track(false);
|
|
91
93
|
|
|
92
94
|
<div class={{ active: @active, inactive: !@active }}>{'Dynamic Class'}</div>
|
|
93
95
|
|
|
@@ -114,7 +116,7 @@ describe('basic server > attribute rendering', () => {
|
|
|
114
116
|
'applies scoped ripple class to multiple elements with dynamic class expressions',
|
|
115
117
|
async () => {
|
|
116
118
|
component Basic() {
|
|
117
|
-
let selected =
|
|
119
|
+
let selected = track(1);
|
|
118
120
|
|
|
119
121
|
<div class={@selected === 0 ? 'selected' : ''}>{`div 1`}</div>
|
|
120
122
|
<div class={@selected === 0 ? 'selected' : ''}>{`div 2`}</div>
|
|
@@ -145,7 +147,7 @@ describe('basic server > attribute rendering', () => {
|
|
|
145
147
|
|
|
146
148
|
it('render dynamic id attribute', async () => {
|
|
147
149
|
component Basic() {
|
|
148
|
-
let count =
|
|
150
|
+
let count = track(0);
|
|
149
151
|
|
|
150
152
|
<div id={`item-${@count}`}>{'Dynamic ID'}</div>
|
|
151
153
|
}
|
|
@@ -160,7 +162,7 @@ describe('basic server > attribute rendering', () => {
|
|
|
160
162
|
|
|
161
163
|
it('render dynamic style attribute', async () => {
|
|
162
164
|
component Basic() {
|
|
163
|
-
let color =
|
|
165
|
+
let color = track('red');
|
|
164
166
|
|
|
165
167
|
<div style={`color: ${@color}; font-weight: bold;`}>{'Dynamic Style'}</div>
|
|
166
168
|
}
|
|
@@ -176,7 +178,7 @@ describe('basic server > attribute rendering', () => {
|
|
|
176
178
|
|
|
177
179
|
it('render style attribute as dynamic object', async () => {
|
|
178
180
|
component Basic() {
|
|
179
|
-
let color =
|
|
181
|
+
let color = track('red');
|
|
180
182
|
|
|
181
183
|
<div style={{ color: @color, fontWeight: 'bold' }}>{'Dynamic Style'}</div>
|
|
182
184
|
}
|
|
@@ -192,7 +194,7 @@ describe('basic server > attribute rendering', () => {
|
|
|
192
194
|
|
|
193
195
|
it('render tracked variable as style attribute', async () => {
|
|
194
196
|
component Basic() {
|
|
195
|
-
let style =
|
|
197
|
+
let style = track({ color: 'red', fontWeight: 'bold' });
|
|
196
198
|
|
|
197
199
|
<div {@style}>{'Dynamic Style'}</div>
|
|
198
200
|
}
|
|
@@ -208,7 +210,7 @@ describe('basic server > attribute rendering', () => {
|
|
|
208
210
|
|
|
209
211
|
it('render tracked object as style attribute', async () => {
|
|
210
212
|
component Basic() {
|
|
211
|
-
let style =
|
|
213
|
+
let style = new RippleObject({ color: 'red', fontWeight: 'bold' });
|
|
212
214
|
|
|
213
215
|
<div style={{ color: style.color, fontWeight: style.fontWeight }}>{'Dynamic Style'}</div>
|
|
214
216
|
}
|
|
@@ -275,8 +277,8 @@ describe('basic server > attribute rendering', () => {
|
|
|
275
277
|
|
|
276
278
|
it('render dynamic boolean attributes as false', async () => {
|
|
277
279
|
component Basic() {
|
|
278
|
-
let disabled =
|
|
279
|
-
let checked =
|
|
280
|
+
let disabled = track(false);
|
|
281
|
+
let checked = track(false);
|
|
280
282
|
|
|
281
283
|
<input type="checkbox" {@disabled} {@checked} />
|
|
282
284
|
}
|
|
@@ -310,8 +312,8 @@ describe('basic server > attribute rendering', () => {
|
|
|
310
312
|
|
|
311
313
|
it('render dynamic boolean attributes as true', async () => {
|
|
312
314
|
component Basic() {
|
|
313
|
-
let disabled =
|
|
314
|
-
let checked =
|
|
315
|
+
let disabled = track(true);
|
|
316
|
+
let checked = track(true);
|
|
315
317
|
|
|
316
318
|
<input type="checkbox" {@disabled} {@checked} />
|
|
317
319
|
}
|
|
@@ -345,8 +347,8 @@ describe('basic server > attribute rendering', () => {
|
|
|
345
347
|
|
|
346
348
|
it('render multiple dynamic attributes', async () => {
|
|
347
349
|
component Basic() {
|
|
348
|
-
let theme =
|
|
349
|
-
let size =
|
|
350
|
+
let theme = track('light');
|
|
351
|
+
let size = track('medium');
|
|
350
352
|
|
|
351
353
|
<div class={`theme-${@theme} size-${@size}`} data-theme={@theme} data-size={@size}>
|
|
352
354
|
{'Multiple Dynamic Attributes'}
|
|
@@ -365,8 +367,8 @@ describe('basic server > attribute rendering', () => {
|
|
|
365
367
|
|
|
366
368
|
it('render conditional attributes', async () => {
|
|
367
369
|
component Basic() {
|
|
368
|
-
let showTitle =
|
|
369
|
-
let showAria =
|
|
370
|
+
let showTitle = track(false);
|
|
371
|
+
let showAria = track(false);
|
|
370
372
|
|
|
371
373
|
<div
|
|
372
374
|
title={@showTitle ? 'This is a title' : undefined}
|
|
@@ -387,7 +389,7 @@ describe('basic server > attribute rendering', () => {
|
|
|
387
389
|
|
|
388
390
|
it('render spread attributes', async () => {
|
|
389
391
|
component Basic() {
|
|
390
|
-
let attrs =
|
|
392
|
+
let attrs = track<TestAttributes>(
|
|
391
393
|
{
|
|
392
394
|
class: 'initial',
|
|
393
395
|
id: 'test-1',
|
|
@@ -409,12 +411,12 @@ describe('basic server > attribute rendering', () => {
|
|
|
409
411
|
|
|
410
412
|
it('renders with reactive attributes with nested reactive attributes', async () => {
|
|
411
413
|
component Basic() {
|
|
412
|
-
let value =
|
|
414
|
+
let value = track('parent-class');
|
|
413
415
|
|
|
414
416
|
<p class={@value}>{'Colored parent value'}</p>
|
|
415
417
|
|
|
416
418
|
<div>
|
|
417
|
-
let nested =
|
|
419
|
+
let nested = track('nested-class');
|
|
418
420
|
|
|
419
421
|
<p class={@nested}>{'Colored nested value'}</p>
|
|
420
422
|
</div>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { track } from 'ripple';
|
|
1
2
|
import type {
|
|
2
3
|
Tracked,
|
|
3
4
|
PropsWithChildren,
|
|
@@ -106,7 +107,7 @@ describe('basic server > components & composition', () => {
|
|
|
106
107
|
}
|
|
107
108
|
|
|
108
109
|
component Basic() {
|
|
109
|
-
let clicked =
|
|
110
|
+
let clicked = track(false);
|
|
110
111
|
|
|
111
112
|
<Card
|
|
112
113
|
title="Test Card"
|
|
@@ -143,8 +144,8 @@ describe('basic server > components & composition', () => {
|
|
|
143
144
|
}
|
|
144
145
|
|
|
145
146
|
component Basic() {
|
|
146
|
-
let message =
|
|
147
|
-
let number =
|
|
147
|
+
let message = track('Hello');
|
|
148
|
+
let number = track(1);
|
|
148
149
|
|
|
149
150
|
<ChildComponent text={message} count={number} />
|
|
150
151
|
<button
|
|
@@ -231,7 +232,7 @@ describe('basic server > components & composition', () => {
|
|
|
231
232
|
}
|
|
232
233
|
|
|
233
234
|
component App() {
|
|
234
|
-
let Content =
|
|
235
|
+
let Content = track(() => Noop);
|
|
235
236
|
<@Content />
|
|
236
237
|
}
|
|
237
238
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { track } from 'ripple';
|
|
1
2
|
import type { Tracked, PropsNoChildren } from 'ripple';
|
|
2
3
|
|
|
3
4
|
describe('basic client', () => {
|
|
@@ -14,7 +15,7 @@ describe('basic client', () => {
|
|
|
14
15
|
|
|
15
16
|
it('renders tracked state updates', async () => {
|
|
16
17
|
component Counter() {
|
|
17
|
-
const count =
|
|
18
|
+
const count = track(0);
|
|
18
19
|
|
|
19
20
|
@count++;
|
|
20
21
|
@count = @count + 5;
|
|
@@ -37,8 +38,8 @@ describe('basic client', () => {
|
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
component Parent() {
|
|
40
|
-
const count =
|
|
41
|
-
let Dynamic =
|
|
41
|
+
const count = track(10);
|
|
42
|
+
let Dynamic = track(() => Child);
|
|
42
43
|
|
|
43
44
|
<@Dynamic {count} class={{ test: true }} />
|
|
44
45
|
}
|
|
@@ -50,7 +51,7 @@ describe('basic client', () => {
|
|
|
50
51
|
|
|
51
52
|
it('renders tracked object properties', async () => {
|
|
52
53
|
component ObjCounter() {
|
|
53
|
-
const obj = { count:
|
|
54
|
+
const obj = { count: track(2) };
|
|
54
55
|
|
|
55
56
|
obj.@count += 3;
|
|
56
57
|
obj.@count = obj.@count + 1;
|
|
@@ -65,9 +66,9 @@ describe('basic client', () => {
|
|
|
65
66
|
|
|
66
67
|
it('renders spread props with tracked values', async () => {
|
|
67
68
|
component SpreadProps() {
|
|
68
|
-
const id =
|
|
69
|
-
const isActive =
|
|
70
|
-
const styles =
|
|
69
|
+
const id = track('unique-id');
|
|
70
|
+
const isActive = track(true);
|
|
71
|
+
const styles = track({ color: 'red', fontSize: '16px' });
|
|
71
72
|
|
|
72
73
|
<div {...{ id: @id, class: { active: @isActive }, style: @styles }}>{'Spread Props'}</div>
|
|
73
74
|
}
|
|
@@ -81,8 +82,8 @@ describe('basic client', () => {
|
|
|
81
82
|
|
|
82
83
|
it('handles AssignExpressions with tracked values or properties correctly', async () => {
|
|
83
84
|
component Assignments() {
|
|
84
|
-
const count =
|
|
85
|
-
const obj = { value:
|
|
85
|
+
const count = track(0);
|
|
86
|
+
const obj = { value: track(5) };
|
|
86
87
|
|
|
87
88
|
@count += 10;
|
|
88
89
|
obj.@value *= 2;
|
|
@@ -98,9 +99,9 @@ describe('basic client', () => {
|
|
|
98
99
|
|
|
99
100
|
it(`handles derived changes via tracked dependencies' changes`, async () => {
|
|
100
101
|
component Derived() {
|
|
101
|
-
let base =
|
|
102
|
-
let multiplier =
|
|
103
|
-
const derived =
|
|
102
|
+
let base = track(5);
|
|
103
|
+
let multiplier = track(3);
|
|
104
|
+
const derived = track(() => @base * @multiplier);
|
|
104
105
|
|
|
105
106
|
<div>{@derived}</div>
|
|
106
107
|
|
|
@@ -117,10 +118,10 @@ describe('basic client', () => {
|
|
|
117
118
|
|
|
118
119
|
it(`handles derived changes based on another derived's dependencies' changes`, async () => {
|
|
119
120
|
component NestedDerived() {
|
|
120
|
-
let a =
|
|
121
|
-
let b =
|
|
122
|
-
const sum =
|
|
123
|
-
const product =
|
|
121
|
+
let a = track(2);
|
|
122
|
+
let b = track(3);
|
|
123
|
+
const sum = track(() => @a + @b);
|
|
124
|
+
const product = track(() => @sum * 2);
|
|
124
125
|
|
|
125
126
|
<div>{@product}</div>
|
|
126
127
|
|
|
@@ -137,19 +138,19 @@ describe('basic client', () => {
|
|
|
137
138
|
|
|
138
139
|
it('handles lexical scopes correctly', async () => {
|
|
139
140
|
component LexicalScopes() {
|
|
140
|
-
let x =
|
|
141
|
+
let x = track(1);
|
|
141
142
|
<div>{@x}</div>
|
|
142
143
|
|
|
143
144
|
<div>
|
|
144
|
-
let x =
|
|
145
|
+
let x = track(10);
|
|
145
146
|
{@x}
|
|
146
147
|
</div>
|
|
147
148
|
|
|
148
149
|
<div>
|
|
149
|
-
let x =
|
|
150
|
+
let x = track(12);
|
|
150
151
|
{@x}
|
|
151
152
|
<span>
|
|
152
|
-
let x =
|
|
153
|
+
let x = track(15);
|
|
153
154
|
{@x}
|
|
154
155
|
</span>
|
|
155
156
|
</div>
|
|
@@ -41,6 +41,37 @@ function getString(e: string = 'test') {
|
|
|
41
41
|
expect(result.js.code).toMatchSnapshot();
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
+
it('removes class TypeScript syntax from JS output', () => {
|
|
45
|
+
const source = `interface BaseEvent {}
|
|
46
|
+
|
|
47
|
+
class PrintEvent implements BaseEvent {
|
|
48
|
+
text: string;
|
|
49
|
+
|
|
50
|
+
constructor(text: string) {
|
|
51
|
+
this.text = text;
|
|
52
|
+
}
|
|
53
|
+
}`;
|
|
54
|
+
|
|
55
|
+
const result = compile(source, 'test.ripple', { mode: 'server' });
|
|
56
|
+
|
|
57
|
+
expect(result.js.code).not.toContain('implements');
|
|
58
|
+
expect(result.js.code).toMatchSnapshot();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('removes class extends type arguments from JS output', () => {
|
|
62
|
+
const source = `class StringMap extends Map<string, string> {
|
|
63
|
+
constructor() {
|
|
64
|
+
super();
|
|
65
|
+
}
|
|
66
|
+
}`;
|
|
67
|
+
|
|
68
|
+
const result = compile(source, 'test.ripple', { mode: 'server' });
|
|
69
|
+
|
|
70
|
+
expect(result.js.code).not.toContain('Map<string, string>');
|
|
71
|
+
expect(result.js.code).toContain('class StringMap extends Map');
|
|
72
|
+
expect(result.js.code).toMatchSnapshot();
|
|
73
|
+
});
|
|
74
|
+
|
|
44
75
|
it('throws error for interpolating children as text in SSR mode', () => {
|
|
45
76
|
const source = `
|
|
46
77
|
export component Layout({ children }) {
|
|
@@ -67,7 +98,7 @@ export component Layout(props) {
|
|
|
67
98
|
describe('compiler server block tests', () => {
|
|
68
99
|
it('compiles server block with with only supported types', () => {
|
|
69
100
|
const source = `
|
|
70
|
-
#
|
|
101
|
+
#server {
|
|
71
102
|
function something() {
|
|
72
103
|
return 'unexported function';
|
|
73
104
|
}
|
|
@@ -105,7 +136,7 @@ describe('compiler server block tests', () => {
|
|
|
105
136
|
|
|
106
137
|
it('throws error for unsupported exported object pattern in server block', () => {
|
|
107
138
|
const source = `
|
|
108
|
-
#
|
|
139
|
+
#server {
|
|
109
140
|
const obj = { fn1: () => {}, fn2: () => {} };
|
|
110
141
|
|
|
111
142
|
export const { fn1, fn2 } = obj;
|
|
@@ -116,7 +147,7 @@ describe('compiler server block tests', () => {
|
|
|
116
147
|
|
|
117
148
|
it('throws error for unsupported exported array pattern in server block', () => {
|
|
118
149
|
const source = `
|
|
119
|
-
#
|
|
150
|
+
#server {
|
|
120
151
|
const arr = [() => {}, () => {}];
|
|
121
152
|
|
|
122
153
|
export const [fnarr1, fnarr2] = arr;
|
|
@@ -127,7 +158,7 @@ describe('compiler server block tests', () => {
|
|
|
127
158
|
|
|
128
159
|
it('throws error for unsupported exported member expression via object in server block', () => {
|
|
129
160
|
const source = `
|
|
130
|
-
#
|
|
161
|
+
#server {
|
|
131
162
|
const obj = { fn1: () => {}, fn2: () => {} };
|
|
132
163
|
|
|
133
164
|
export const objProp = obj.fn1;
|
|
@@ -138,7 +169,7 @@ describe('compiler server block tests', () => {
|
|
|
138
169
|
|
|
139
170
|
it('throws error for unsupported exported member expression via array in server block', () => {
|
|
140
171
|
const source = `
|
|
141
|
-
#
|
|
172
|
+
#server {
|
|
142
173
|
const arr = [() => {}, () => {}];
|
|
143
174
|
|
|
144
175
|
export const arrIndex0 = arr[0];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { track, trackSplit } from 'ripple';
|
|
1
2
|
import type { Tracked, Props } from 'ripple';
|
|
2
3
|
|
|
3
4
|
describe('composite > props', () => {
|
|
@@ -7,7 +8,7 @@ describe('composite > props', () => {
|
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
component App() {
|
|
10
|
-
let foo =
|
|
11
|
+
let foo = track(123);
|
|
11
12
|
|
|
12
13
|
<Child />
|
|
13
14
|
<Child {@foo} />
|
|
@@ -45,7 +46,7 @@ describe('composite > props', () => {
|
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
component App() {
|
|
48
|
-
let foo =
|
|
49
|
+
let foo = track(123);
|
|
49
50
|
|
|
50
51
|
<Child />
|
|
51
52
|
<Child {foo} />
|
|
@@ -64,7 +65,7 @@ describe('composite > props', () => {
|
|
|
64
65
|
}
|
|
65
66
|
|
|
66
67
|
component App() {
|
|
67
|
-
let foo =
|
|
68
|
+
let foo = track(123);
|
|
68
69
|
|
|
69
70
|
<Child />
|
|
70
71
|
<Child {@foo} />
|
|
@@ -79,7 +80,7 @@ describe('composite > props', () => {
|
|
|
79
80
|
|
|
80
81
|
it('correctly retains prop accessors and reactivity when using rest props', async () => {
|
|
81
82
|
component Button(props: Props) {
|
|
82
|
-
const [children, rest] =
|
|
83
|
+
const [children, rest] = trackSplit(props, ['children']);
|
|
83
84
|
<button {...@rest}>
|
|
84
85
|
<@children />
|
|
85
86
|
</button>
|
|
@@ -94,14 +95,14 @@ describe('composite > props', () => {
|
|
|
94
95
|
}
|
|
95
96
|
|
|
96
97
|
component Toggle(props: { pressed: Tracked<boolean> }) {
|
|
97
|
-
const [pressed, rest] =
|
|
98
|
+
const [pressed, rest] = trackSplit(props, ['pressed']);
|
|
98
99
|
const onClick = () => (@pressed = !@pressed);
|
|
99
100
|
<Button {...@rest} class={@pressed ? 'on' : 'off'} {onClick}>{'button 1'}</Button>
|
|
100
101
|
<Button class={@pressed ? 'on' : 'off'} {onClick}>{'button 2'}</Button>
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
component App() {
|
|
104
|
-
const pressed =
|
|
105
|
+
const pressed = track(true);
|
|
105
106
|
<Toggle {pressed} />
|
|
106
107
|
}
|
|
107
108
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { Context } from 'ripple';
|
|
2
|
+
|
|
1
3
|
describe('Context API', () => {
|
|
2
4
|
it('handles context override in nested components', async () => {
|
|
3
|
-
const MessageContext =
|
|
5
|
+
const MessageContext = Context('default');
|
|
4
6
|
|
|
5
7
|
component Inner() {
|
|
6
8
|
const msg = MessageContext.get();
|