ripple 0.2.215 → 0.3.0
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 +86 -0
- package/package.json +16 -7
- package/src/compiler/errors.js +1 -1
- package/src/compiler/identifier-utils.js +2 -0
- package/src/compiler/index.d.ts +2 -6
- package/src/compiler/phases/1-parse/index.js +171 -233
- package/src/compiler/phases/2-analyze/index.js +216 -16
- package/src/compiler/phases/2-analyze/prune.js +2 -2
- package/src/compiler/phases/3-transform/client/index.js +326 -94
- package/src/compiler/phases/3-transform/segments.js +43 -15
- package/src/compiler/phases/3-transform/server/index.js +71 -21
- package/src/compiler/scope.js +31 -12
- package/src/compiler/source-map-utils.js +4 -6
- package/src/compiler/types/acorn.d.ts +11 -0
- package/src/compiler/types/estree-jsx.d.ts +11 -0
- package/src/compiler/types/estree.d.ts +11 -0
- package/src/compiler/types/import.d.ts +32 -18
- package/src/compiler/types/index.d.ts +75 -23
- package/src/compiler/types/parse.d.ts +7 -10
- package/src/compiler/utils.js +48 -0
- package/src/runtime/array.js +53 -22
- package/src/runtime/date.js +15 -5
- package/src/runtime/index-client.js +41 -7
- package/src/runtime/index-server.js +7 -7
- package/src/runtime/internal/client/bindings.js +2 -2
- package/src/runtime/internal/client/blocks.js +40 -1
- package/src/runtime/internal/client/context.js +8 -0
- package/src/runtime/internal/client/for.js +3 -3
- package/src/runtime/internal/client/index.js +32 -5
- package/src/runtime/internal/client/render.js +20 -8
- package/src/runtime/internal/client/runtime.js +9 -7
- package/src/runtime/internal/client/template.js +1 -1
- package/src/runtime/internal/client/try.js +15 -22
- package/src/runtime/internal/client/utils.js +1 -1
- package/src/runtime/internal/server/context.js +8 -0
- package/src/runtime/internal/server/index.js +99 -6
- package/src/runtime/map.js +7 -7
- package/src/runtime/media-query.js +10 -1
- package/src/runtime/object.js +6 -6
- package/src/runtime/proxy.js +6 -6
- package/src/runtime/set.js +11 -11
- package/src/runtime/url-search-params.js +13 -2
- package/src/runtime/url.js +15 -5
- package/src/utils/builders.js +13 -3
- package/tests/client/array/array.copy-within.test.ripple +11 -11
- package/tests/client/array/array.derived.test.ripple +42 -42
- package/tests/client/array/array.iteration.test.ripple +12 -12
- package/tests/client/array/array.mutations.test.ripple +25 -25
- package/tests/client/array/array.static.test.ripple +103 -106
- package/tests/client/array/array.to-methods.test.ripple +8 -8
- package/tests/client/async-suspend.test.ripple +94 -0
- package/tests/client/basic/basic.attributes.test.ripple +31 -31
- package/tests/client/basic/basic.collections.test.ripple +7 -7
- package/tests/client/basic/basic.components.test.ripple +48 -10
- package/tests/client/basic/basic.errors.test.ripple +111 -30
- 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 +47 -42
- 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.assignments.test.ripple.snap +2 -2
- package/tests/client/compiler/compiler.assignments.test.ripple +21 -21
- package/tests/client/compiler/compiler.basic.test.ripple +223 -82
- package/tests/client/compiler/compiler.tracked-access.test.ripple +8 -9
- package/tests/client/composite/composite.dynamic-components.test.ripple +8 -8
- package/tests/client/composite/composite.generics.test.ripple +4 -4
- package/tests/client/composite/composite.props.test.ripple +9 -9
- package/tests/client/composite/composite.reactivity.test.ripple +32 -26
- package/tests/client/composite/composite.render.test.ripple +13 -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 +4 -4
- package/tests/client/css/style-identifier.test.ripple +49 -41
- package/tests/client/date.test.ripple +40 -40
- package/tests/client/dynamic-elements.test.ripple +165 -30
- package/tests/client/events.test.ripple +25 -25
- package/tests/client/for.test.ripple +76 -8
- package/tests/client/function-overload.test.ripple +0 -1
- package/tests/client/head.test.ripple +7 -7
- package/tests/client/html.test.ripple +2 -2
- package/tests/client/input-value.test.ripple +174 -176
- package/tests/client/map.test.ripple +21 -21
- package/tests/client/media-query.test.ripple +4 -4
- package/tests/client/object.test.ripple +12 -12
- package/tests/client/portal.test.ripple +4 -4
- package/tests/client/ref.test.ripple +5 -5
- package/tests/client/return.test.ripple +17 -17
- package/tests/client/set.test.ripple +16 -16
- package/tests/client/svg.test.ripple +6 -7
- package/tests/client/switch.test.ripple +10 -10
- package/tests/client/tracked-expression.test.ripple +1 -3
- package/tests/client/try.test.ripple +56 -4
- package/tests/client/url/url.derived.test.ripple +10 -9
- package/tests/client/url/url.parsing.test.ripple +10 -10
- package/tests/client/url/url.partial-removal.test.ripple +10 -10
- package/tests/client/url/url.reactivity.test.ripple +17 -17
- package/tests/client/url/url.serialization.test.ripple +4 -4
- package/tests/client/url-search-params/url-search-params.derived.test.ripple +11 -10
- package/tests/client/url-search-params/url-search-params.initialization.test.ripple +5 -7
- package/tests/client/url-search-params/url-search-params.iteration.test.ripple +13 -13
- package/tests/client/url-search-params/url-search-params.mutation.test.ripple +19 -19
- package/tests/client/url-search-params/url-search-params.retrieval.test.ripple +17 -17
- package/tests/client/url-search-params/url-search-params.serialization.test.ripple +5 -5
- package/tests/client/url-search-params/url-search-params.tracked-url.test.ripple +5 -5
- package/tests/hydration/compiled/client/events.js +8 -11
- package/tests/hydration/compiled/client/for.js +20 -23
- package/tests/hydration/compiled/client/head.js +17 -19
- package/tests/hydration/compiled/client/hmr.js +84 -0
- package/tests/hydration/compiled/client/html.js +1 -15
- package/tests/hydration/compiled/client/if-children.js +7 -9
- package/tests/hydration/compiled/client/if.js +5 -7
- package/tests/hydration/compiled/client/mixed-control-flow.js +3 -5
- package/tests/hydration/compiled/client/portal.js +1 -1
- package/tests/hydration/compiled/client/reactivity.js +9 -11
- package/tests/hydration/compiled/client/return.js +11 -13
- package/tests/hydration/compiled/client/switch.js +4 -6
- package/tests/hydration/compiled/server/basic.js +0 -1
- package/tests/hydration/compiled/server/composite.js +0 -3
- package/tests/hydration/compiled/server/events.js +8 -12
- package/tests/hydration/compiled/server/for.js +20 -23
- package/tests/hydration/compiled/server/head.js +17 -19
- package/tests/hydration/compiled/server/hmr.js +107 -0
- package/tests/hydration/compiled/server/html.js +1 -35
- package/tests/hydration/compiled/server/if-children.js +7 -11
- package/tests/hydration/compiled/server/if.js +5 -7
- package/tests/hydration/compiled/server/mixed-control-flow.js +3 -5
- package/tests/hydration/compiled/server/portal.js +1 -9
- package/tests/hydration/compiled/server/reactivity.js +9 -11
- package/tests/hydration/compiled/server/return.js +11 -13
- package/tests/hydration/compiled/server/switch.js +4 -6
- package/tests/hydration/components/events.ripple +8 -9
- package/tests/hydration/components/for.ripple +20 -21
- package/tests/hydration/components/head.ripple +6 -8
- package/tests/hydration/components/hmr.ripple +34 -0
- package/tests/hydration/components/html.ripple +1 -3
- package/tests/hydration/components/if-children.ripple +7 -8
- package/tests/hydration/components/if.ripple +5 -6
- package/tests/hydration/components/mixed-control-flow.ripple +4 -6
- package/tests/hydration/components/portal.ripple +1 -1
- package/tests/hydration/components/reactivity.ripple +9 -10
- package/tests/hydration/components/return.ripple +11 -12
- package/tests/hydration/components/switch.ripple +6 -8
- package/tests/hydration/hmr.test.js +74 -0
- package/tests/server/await.test.ripple +2 -2
- package/tests/server/basic.attributes.test.ripple +19 -21
- package/tests/server/basic.components.test.ripple +13 -7
- package/tests/server/basic.test.ripple +20 -21
- package/tests/server/compiler.test.ripple +5 -5
- package/tests/server/composite.props.test.ripple +6 -7
- package/tests/server/composite.test.ripple +4 -4
- package/tests/server/context.test.ripple +1 -3
- package/tests/server/dynamic-elements.test.ripple +24 -24
- package/tests/server/head.test.ripple +5 -7
- package/tests/server/style-identifier.test.ripple +16 -17
- package/types/index.d.ts +266 -62
- package/types/server.d.ts +6 -6
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { parse, compile, compile_to_volar_mappings } from 'ripple/compiler';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
obfuscate_identifier,
|
|
4
|
+
RIPPLE_NAMESPACE_IDENTIFIER,
|
|
5
|
+
} from 'ripple/compiler/internal/identifier/utils';
|
|
3
6
|
import type * as AST from 'estree';
|
|
4
7
|
|
|
5
8
|
function count_occurrences(string: string, subString: string): number {
|
|
@@ -19,25 +22,25 @@ describe('compiler > basics', () => {
|
|
|
19
22
|
const source = `export component App() {
|
|
20
23
|
<div id="myid" class="myclass">{"Hello World"}</div>
|
|
21
24
|
|
|
22
|
-
<style>#style</style>
|
|
25
|
+
<style>#ripple.style</style>
|
|
23
26
|
}`;
|
|
24
27
|
const style1 = '.myid {color: green }';
|
|
25
28
|
const style2 = '#myid {color: green }';
|
|
26
29
|
const style3 = 'div {color: green }';
|
|
27
30
|
|
|
28
|
-
let input = source.replace('#style', style1);
|
|
31
|
+
let input = source.replace('#ripple.style', style1);
|
|
29
32
|
let ast = parse(input);
|
|
30
33
|
expect(
|
|
31
34
|
((ast.body[0] as AST.ExportNamedDeclaration).declaration as unknown as AST.Component)?.css.source,
|
|
32
35
|
).toEqual(style1);
|
|
33
36
|
|
|
34
|
-
input = source.replace('#style', style2);
|
|
37
|
+
input = source.replace('#ripple.style', style2);
|
|
35
38
|
ast = parse(input);
|
|
36
39
|
expect(
|
|
37
40
|
((ast.body[0] as AST.ExportNamedDeclaration).declaration as unknown as AST.Component)?.css.source,
|
|
38
41
|
).toEqual(style2);
|
|
39
42
|
|
|
40
|
-
input = source.replace('#style', style3);
|
|
43
|
+
input = source.replace('#ripple.style', style3);
|
|
41
44
|
ast = parse(input);
|
|
42
45
|
expect(
|
|
43
46
|
((ast.body[0] as AST.ExportNamedDeclaration).declaration as unknown as AST.Component)?.css.source,
|
|
@@ -197,8 +200,8 @@ describe('compiler > basics', () => {
|
|
|
197
200
|
class Box<T> {
|
|
198
201
|
value: T;
|
|
199
202
|
|
|
200
|
-
method<T>():
|
|
201
|
-
return this.value;
|
|
203
|
+
method<U extends T>(): U {
|
|
204
|
+
return this.value as U;
|
|
202
205
|
}
|
|
203
206
|
|
|
204
207
|
constructor(value: T) {
|
|
@@ -247,91 +250,152 @@ describe('compiler > basics', () => {
|
|
|
247
250
|
expect(js.code).not.toMatch(/_\$_\.template\(`<!><!>`,\s*1,\s*3\)/);
|
|
248
251
|
});
|
|
249
252
|
|
|
250
|
-
it(
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
import {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
253
|
+
// it(
|
|
254
|
+
// 'imports and uses only obfuscated Tracked imports when encountering only shorthand syntax',
|
|
255
|
+
// () => {
|
|
256
|
+
// const source = `
|
|
257
|
+
// import { RippleArray, RippleObject, RippleSet, RippleMap, createRefKey } from 'ripple';
|
|
258
|
+
// component App() {
|
|
259
|
+
// const items = #ripple[1, 2, 3];
|
|
260
|
+
// const obj = #ripple{ a: 1, b: 2, c: 3 };
|
|
261
|
+
// const set = #ripple.set([1, 2, 3]);
|
|
262
|
+
// const map = #ripple.map([['a', 1], ['b', 2], ['c', 3]]);
|
|
263
|
+
|
|
264
|
+
// <div {ref () => {}} />
|
|
265
|
+
// }
|
|
266
|
+
// `;
|
|
267
|
+
// const result = compile_to_volar_mappings(source, 'test.ripple').code;
|
|
268
|
+
|
|
269
|
+
// expect(count_occurrences(result, 'RippleArray')).toBe(1);
|
|
270
|
+
// expect(count_occurrences(result, 'RippleObject')).toBe(1);
|
|
271
|
+
// expect(count_occurrences(result, 'RippleSet')).toBe(1);
|
|
272
|
+
// expect(count_occurrences(result, 'RippleMap')).toBe(1);
|
|
273
|
+
// expect(count_occurrences(result, 'createRefKey')).toBe(1);
|
|
274
|
+
// },
|
|
275
|
+
// );
|
|
276
|
+
|
|
277
|
+
// it(
|
|
278
|
+
// 'adds obfuscated imports and keeps renamed Tracked imports intact when encountering shorthand syntax',
|
|
279
|
+
// () => {
|
|
280
|
+
// const source = `
|
|
281
|
+
// import { RippleArray as TA, RippleObject as TO, RippleSet as TS, RippleMap as TM, createRefKey as crk } from 'ripple';
|
|
282
|
+
// component App() {
|
|
283
|
+
// const items = #ripple[1, 2, 3];
|
|
284
|
+
// const obj = #ripple{ a: 1, b: 2, c: 3 };
|
|
285
|
+
// const set = #ripple.set([1, 2, 3]);
|
|
286
|
+
// const map = #ripple.map([['a', 1], ['b', 2], ['c', 3]]);
|
|
287
|
+
|
|
288
|
+
// <div {ref () => {}} />
|
|
289
|
+
// }
|
|
290
|
+
// `;
|
|
291
|
+
// const result = compile_to_volar_mappings(source, 'test.ripple').code;
|
|
292
|
+
|
|
293
|
+
// expect(count_occurrences(result, obfuscate_identifier('RippleArray'))).toBe(2);
|
|
294
|
+
// expect(count_occurrences(result, 'TA')).toBe(1);
|
|
295
|
+
// expect(count_occurrences(result, obfuscate_identifier('RippleObject'))).toBe(2);
|
|
296
|
+
// expect(count_occurrences(result, 'TO')).toBe(1);
|
|
297
|
+
// expect(count_occurrences(result, obfuscate_identifier('RippleSet'))).toBe(2);
|
|
298
|
+
// expect(count_occurrences(result, 'TS')).toBe(1);
|
|
299
|
+
// expect(count_occurrences(result, obfuscate_identifier('RippleMap'))).toBe(2);
|
|
300
|
+
// expect(count_occurrences(result, 'TM')).toBe(1);
|
|
301
|
+
// expect(count_occurrences(result, obfuscate_identifier('createRefKey'))).toBe(2);
|
|
302
|
+
// expect(count_occurrences(result, 'crk')).toBe(1);
|
|
303
|
+
// },
|
|
304
|
+
// );
|
|
305
|
+
|
|
306
|
+
// it('adds hidden obfuscated imports for shorthand syntax', () => {
|
|
307
|
+
// const source = `
|
|
308
|
+
// component App() {
|
|
309
|
+
// const items = #ripple[1, 2, 3];
|
|
310
|
+
// const obj = #ripple{ a: 1, b: 2, c: 3 };
|
|
311
|
+
// const set = #ripple.set([1, 2, 3]);
|
|
312
|
+
// const map = #ripple.map([['a', 1], ['b', 2], ['c', 3]]);
|
|
313
|
+
|
|
314
|
+
// <div {ref () => {}} />
|
|
315
|
+
// }
|
|
316
|
+
// `;
|
|
317
|
+
// const result = compile_to_volar_mappings(source, 'test.ripple').code;
|
|
318
|
+
|
|
319
|
+
// expect(count_occurrences(result, obfuscate_identifier('RippleArray'))).toBe(2);
|
|
320
|
+
// expect(count_occurrences(result, obfuscate_identifier('RippleObject'))).toBe(2);
|
|
321
|
+
// expect(count_occurrences(result, obfuscate_identifier('RippleSet'))).toBe(2);
|
|
322
|
+
// expect(count_occurrences(result, obfuscate_identifier('RippleMap'))).toBe(2);
|
|
323
|
+
// expect(count_occurrences(result, obfuscate_identifier('createRefKey'))).toBe(2);
|
|
324
|
+
// });
|
|
325
|
+
|
|
326
|
+
it('prints longhand tracked property values in to_ts output while preserving [\'#v\']', () => {
|
|
327
|
+
const source = `
|
|
328
|
+
import { createRefKey } from 'ripple';
|
|
261
329
|
|
|
262
330
|
component App() {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
|
|
331
|
+
let value = #ripple.track('test');
|
|
332
|
+
function inputRef(node) {}
|
|
333
|
+
|
|
334
|
+
const props = {
|
|
335
|
+
id: 'example',
|
|
336
|
+
@value,
|
|
337
|
+
[createRefKey()]: inputRef,
|
|
338
|
+
};
|
|
269
339
|
}
|
|
270
340
|
`;
|
|
271
|
-
const result = compile_to_volar_mappings(source, 'test.ripple').code;
|
|
272
|
-
|
|
273
|
-
expect(count_occurrences(result, 'TrackedArray')).toBe(1);
|
|
274
|
-
expect(count_occurrences(result, 'TrackedObject')).toBe(1);
|
|
275
|
-
expect(count_occurrences(result, 'TrackedSet')).toBe(1);
|
|
276
|
-
expect(count_occurrences(result, 'TrackedMap')).toBe(1);
|
|
277
|
-
expect(count_occurrences(result, 'createRefKey')).toBe(1);
|
|
278
|
-
},
|
|
279
|
-
);
|
|
280
|
-
|
|
281
|
-
it(
|
|
282
|
-
'adds obfuscated imports and keeps renamed Tracked imports intact when encountering shorthand syntax',
|
|
283
|
-
() => {
|
|
284
|
-
const source = `
|
|
285
|
-
import {
|
|
286
|
-
TrackedArray as TA,
|
|
287
|
-
TrackedObject as TO,
|
|
288
|
-
TrackedSet as TS,
|
|
289
|
-
TrackedMap as TM,
|
|
290
|
-
createRefKey as crk,
|
|
291
|
-
} from 'ripple';
|
|
292
341
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
const map = new #Map([['a', 1], ['b', 2], ['c', 3]]);
|
|
342
|
+
const result = compile_to_volar_mappings(source, 'test.ripple').code;
|
|
343
|
+
|
|
344
|
+
expect(result).toMatch(/value:\s*value\??\.\['#v'\]/);
|
|
345
|
+
});
|
|
298
346
|
|
|
299
|
-
|
|
347
|
+
it('rewrites standalone #ripple to the hidden namespace identifier in to_ts output', () => {
|
|
348
|
+
const source = `
|
|
349
|
+
export component App() {
|
|
350
|
+
#ripple
|
|
300
351
|
}
|
|
301
352
|
`;
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
expect(count_occurrences(result, 'TM')).toBe(1);
|
|
312
|
-
expect(count_occurrences(result, obfuscate_identifier('createRefKey'))).toBe(2);
|
|
313
|
-
expect(count_occurrences(result, 'crk')).toBe(1);
|
|
314
|
-
},
|
|
315
|
-
);
|
|
316
|
-
|
|
317
|
-
it('adds hidden obfuscated imports for shorthand syntax', () => {
|
|
353
|
+
|
|
354
|
+
const result = compile_to_volar_mappings(source, 'test.ripple', { loose: true }).code;
|
|
355
|
+
|
|
356
|
+
expect(result).toContain(RIPPLE_NAMESPACE_IDENTIFIER);
|
|
357
|
+
expect(result).toContain(`${RIPPLE_NAMESPACE_IDENTIFIER};`);
|
|
358
|
+
expect(result).not.toContain('#ripple;');
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
it('preserves generic type args in interface extends for Volar mappings', () => {
|
|
318
362
|
const source = `
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
const set = new #Set([1, 2, 3]);
|
|
323
|
-
const map = new #Map([['a', 1], ['b', 2], ['c', 3]]);
|
|
363
|
+
interface PolymorphicProps<T extends keyof HTMLElementTagNameMap> {
|
|
364
|
+
as?: T;
|
|
365
|
+
}
|
|
324
366
|
|
|
325
|
-
|
|
367
|
+
interface Props extends PolymorphicProps<'div'> {
|
|
368
|
+
id: string;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
export component App(props: Props) {
|
|
372
|
+
<div id={props.id} />
|
|
326
373
|
}
|
|
327
374
|
`;
|
|
375
|
+
|
|
328
376
|
const result = compile_to_volar_mappings(source, 'test.ripple').code;
|
|
329
377
|
|
|
330
|
-
expect(
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
378
|
+
expect(result).toContain('extends PolymorphicProps<\'div\'>');
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
it('handles if-else expression statements in Volar mappings', () => {
|
|
382
|
+
const source = `
|
|
383
|
+
export component App() {
|
|
384
|
+
let level = #ripple.track(1);
|
|
385
|
+
|
|
386
|
+
<button
|
|
387
|
+
onClick={() => {
|
|
388
|
+
if (@level === 1) @level = 2;
|
|
389
|
+
else if (@level === 2) @level = 3;
|
|
390
|
+
else @level = 1;
|
|
391
|
+
}}
|
|
392
|
+
>
|
|
393
|
+
{'Toggle'}
|
|
394
|
+
</button>
|
|
395
|
+
}
|
|
396
|
+
`;
|
|
397
|
+
|
|
398
|
+
expect(() => compile_to_volar_mappings(source, 'test.ripple')).not.toThrow();
|
|
335
399
|
});
|
|
336
400
|
|
|
337
401
|
it('should not error on having js below markup in the same scope', () => {
|
|
@@ -357,6 +421,23 @@ export component App() {
|
|
|
357
421
|
expect(() => compile(code, 'test.ripple')).not.toThrow();
|
|
358
422
|
});
|
|
359
423
|
|
|
424
|
+
it('converts nested component children into props in Volar mappings', () => {
|
|
425
|
+
const source = `
|
|
426
|
+
export component App() {
|
|
427
|
+
<ark.div class="host-class" data-value="42">
|
|
428
|
+
component asChild({ children, href, ...rest }: { href: string; [key: string]: any }) {
|
|
429
|
+
<a id="aschild-anchor" {href} {...rest} data-extra="yes">{'Link'}</a>
|
|
430
|
+
}
|
|
431
|
+
</ark.div>
|
|
432
|
+
}
|
|
433
|
+
`;
|
|
434
|
+
const result = compile_to_volar_mappings(source, 'test.ripple').code;
|
|
435
|
+
|
|
436
|
+
expect(result).toContain('<ark.div class="host-class" data-value="42" asChild={');
|
|
437
|
+
expect(result).not.toContain('children={() =>');
|
|
438
|
+
expect(result).not.toContain('function asChild');
|
|
439
|
+
});
|
|
440
|
+
|
|
360
441
|
it('should not error on `this` MemberExpression with a UpdateExpression', () => {
|
|
361
442
|
const code = `
|
|
362
443
|
class Test {
|
|
@@ -374,14 +455,13 @@ export component App() {
|
|
|
374
455
|
expect(() => compile(code, 'test.ripple')).not.toThrow();
|
|
375
456
|
});
|
|
376
457
|
|
|
377
|
-
it('should inject __block for track() calls inside class constructors', () => {
|
|
458
|
+
it('should inject __block for #ripple.track() calls inside class constructors', () => {
|
|
378
459
|
const source = `
|
|
379
|
-
import { track } from 'ripple';
|
|
380
460
|
|
|
381
461
|
class Store {
|
|
382
462
|
constructor() {
|
|
383
|
-
this.count = track(0);
|
|
384
|
-
this.items = #[1, 2, 3];
|
|
463
|
+
this.count = #ripple.track(0);
|
|
464
|
+
this.items = #ripple[1, 2, 3];
|
|
385
465
|
}
|
|
386
466
|
}
|
|
387
467
|
|
|
@@ -397,4 +477,65 @@ export component App() {
|
|
|
397
477
|
expect(code).toContain('__block');
|
|
398
478
|
expect(code).toContain('_$_.scope()');
|
|
399
479
|
});
|
|
480
|
+
|
|
481
|
+
it('parses #ripple.effect and #ripple.untrack calls', () => {
|
|
482
|
+
const source = `
|
|
483
|
+
component App() {
|
|
484
|
+
let count = #ripple.track(0);
|
|
485
|
+
|
|
486
|
+
#ripple.effect(() => {
|
|
487
|
+
const snapshot = #ripple.untrack(() => @count);
|
|
488
|
+
console.log(snapshot);
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
`;
|
|
492
|
+
|
|
493
|
+
const ast = parse(source);
|
|
494
|
+
const ast_json = JSON.stringify(ast);
|
|
495
|
+
|
|
496
|
+
expect(ast_json).toContain('"source_name":"#ripple.effect"');
|
|
497
|
+
expect(ast_json).toContain('"source_name":"#ripple.untrack"');
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
it('collects duplicate declaration parser errors in loose mode', () => {
|
|
501
|
+
const source = `
|
|
502
|
+
export component App() {
|
|
503
|
+
let test = #ripple.track(false);
|
|
504
|
+
let test = 'hey';
|
|
505
|
+
}
|
|
506
|
+
`;
|
|
507
|
+
|
|
508
|
+
expect(() => compile(source, 'test.ripple')).toThrow(
|
|
509
|
+
'Identifier \'test\' has already been declared',
|
|
510
|
+
);
|
|
511
|
+
|
|
512
|
+
const result = compile_to_volar_mappings(source, 'test.ripple', { loose: true });
|
|
513
|
+
|
|
514
|
+
expect(
|
|
515
|
+
result.errors.some(
|
|
516
|
+
(item) => item.message.includes('Identifier \'test\' has already been declared'),
|
|
517
|
+
),
|
|
518
|
+
).toBe(true);
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
it('parses bare #ripple in loose mode for autocomplete recovery', () => {
|
|
522
|
+
const source = `
|
|
523
|
+
export component App() {
|
|
524
|
+
#ripple
|
|
525
|
+
}
|
|
526
|
+
`;
|
|
527
|
+
|
|
528
|
+
expect(() => compile_to_volar_mappings(source, 'test.ripple', { loose: true })).not.toThrow();
|
|
529
|
+
|
|
530
|
+
const result = compile_to_volar_mappings(source, 'test.ripple', { loose: true });
|
|
531
|
+
expect(result.errors).toEqual([]);
|
|
532
|
+
|
|
533
|
+
const ripple_offset = source.indexOf('#ripple');
|
|
534
|
+
const mapping = result.mappings.find(
|
|
535
|
+
(mapping) => mapping.sourceOffsets[0] === ripple_offset &&
|
|
536
|
+
mapping.lengths[0] === '#ripple'.length,
|
|
537
|
+
);
|
|
538
|
+
|
|
539
|
+
expect(mapping?.data.customData.suppressedDiagnostics).toContain(18016);
|
|
540
|
+
});
|
|
400
541
|
});
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { compile } from 'ripple/compiler';
|
|
2
|
-
import { track } from 'ripple';
|
|
3
2
|
|
|
4
3
|
describe('Compiler: Tracked Object Direct Access Checks', () => {
|
|
5
4
|
it('should error on direct access to __v of a tracked object', () => {
|
|
6
5
|
const code = `
|
|
7
6
|
export default component App() {
|
|
8
|
-
let count = track(0);
|
|
7
|
+
let count = #ripple.track(0);
|
|
9
8
|
console.log(count.__v);
|
|
10
9
|
}
|
|
11
10
|
`;
|
|
@@ -17,7 +16,7 @@ describe('Compiler: Tracked Object Direct Access Checks', () => {
|
|
|
17
16
|
it('should error on direct access to "a" (get/set config) of a tracked object', () => {
|
|
18
17
|
const code = `
|
|
19
18
|
export default component App() {
|
|
20
|
-
let myTracked = track(0);
|
|
19
|
+
let myTracked = #ripple.track(0);
|
|
21
20
|
console.log(myTracked.a);
|
|
22
21
|
}
|
|
23
22
|
`;
|
|
@@ -29,7 +28,7 @@ describe('Compiler: Tracked Object Direct Access Checks', () => {
|
|
|
29
28
|
it('should error on direct access to "b" (block) of a tracked object', () => {
|
|
30
29
|
const code = `
|
|
31
30
|
export default component App() {
|
|
32
|
-
let myTracked = track(0);
|
|
31
|
+
let myTracked = #ripple.track(0);
|
|
33
32
|
console.log(myTracked.b);
|
|
34
33
|
}
|
|
35
34
|
`;
|
|
@@ -41,7 +40,7 @@ describe('Compiler: Tracked Object Direct Access Checks', () => {
|
|
|
41
40
|
it('should error on direct access to "c" (clock) of a tracked object', () => {
|
|
42
41
|
const code = `
|
|
43
42
|
export default component App() {
|
|
44
|
-
let myTracked = track(0);
|
|
43
|
+
let myTracked = #ripple.track(0);
|
|
45
44
|
console.log(myTracked.c);
|
|
46
45
|
}
|
|
47
46
|
`;
|
|
@@ -53,7 +52,7 @@ describe('Compiler: Tracked Object Direct Access Checks', () => {
|
|
|
53
52
|
it('should error on direct access to "f" (flags) of a tracked object', () => {
|
|
54
53
|
const code = `
|
|
55
54
|
export default component App() {
|
|
56
|
-
let myTracked = track(0);
|
|
55
|
+
let myTracked = #ripple.track(0);
|
|
57
56
|
console.log(myTracked.f);
|
|
58
57
|
}
|
|
59
58
|
`;
|
|
@@ -65,7 +64,7 @@ describe('Compiler: Tracked Object Direct Access Checks', () => {
|
|
|
65
64
|
it('should compile successfully with correct @ syntax access', () => {
|
|
66
65
|
const code = `
|
|
67
66
|
export default component App() {
|
|
68
|
-
let count = track(0);
|
|
67
|
+
let count = #ripple.track(0);
|
|
69
68
|
console.log(@count);
|
|
70
69
|
}
|
|
71
70
|
`;
|
|
@@ -74,9 +73,9 @@ describe('Compiler: Tracked Object Direct Access Checks', () => {
|
|
|
74
73
|
|
|
75
74
|
it('should compile successfully with correct get() function access', () => {
|
|
76
75
|
const code = `
|
|
77
|
-
|
|
76
|
+
import { get } from 'ripple';
|
|
78
77
|
export default component App() {
|
|
79
|
-
let count = track(0);
|
|
78
|
+
let count = #ripple.track(0);
|
|
80
79
|
console.log(get(count));
|
|
81
80
|
}
|
|
82
81
|
`;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { flushSync } from 'ripple';
|
|
2
2
|
|
|
3
3
|
describe('composite > dynamic components', () => {
|
|
4
|
-
it('supports rendering
|
|
4
|
+
it('supports rendering composite components using <@component> syntax', () => {
|
|
5
5
|
component App() {
|
|
6
6
|
component basic() {
|
|
7
7
|
<div>{'Basic Component'}</div>
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
const tracked_basic = track(() => basic);
|
|
10
|
+
const tracked_basic = #ripple.track(() => basic);
|
|
11
11
|
|
|
12
12
|
<@tracked_basic />
|
|
13
13
|
}
|
|
@@ -24,7 +24,7 @@ describe('composite > dynamic components', () => {
|
|
|
24
24
|
<div>{'Basic Component'}</div>
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
const tracked_basic = track(() => basic);
|
|
27
|
+
const tracked_basic = #ripple.track(() => basic);
|
|
28
28
|
|
|
29
29
|
const obj = {
|
|
30
30
|
tracked_basic,
|
|
@@ -45,15 +45,15 @@ describe('composite > dynamic components', () => {
|
|
|
45
45
|
<div>{'Basic Component'}</div>
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
const tracked_basic = track(() => basic);
|
|
48
|
+
const tracked_basic = #ripple.track(() => basic);
|
|
49
49
|
|
|
50
50
|
const obj = {
|
|
51
51
|
tracked_basic,
|
|
52
52
|
};
|
|
53
53
|
|
|
54
|
-
const
|
|
54
|
+
const ripple_object = #ripple.track(obj);
|
|
55
55
|
|
|
56
|
-
<@
|
|
56
|
+
<@ripple_object.@tracked_basic />
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
render(App);
|
|
@@ -72,7 +72,7 @@ describe('composite > dynamic components', () => {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
component App() {
|
|
75
|
-
let thing = track(() => Child1);
|
|
75
|
+
let thing = #ripple.track(() => Child1);
|
|
76
76
|
|
|
77
77
|
<div id="container">
|
|
78
78
|
<@thing />
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RippleArray, RippleMap } from 'ripple';
|
|
2
2
|
|
|
3
3
|
describe('composite > generics', () => {
|
|
4
4
|
it('handles advanced generic ambiguity and edge cases', () => {
|
|
@@ -143,10 +143,10 @@ describe('composite > generics', () => {
|
|
|
143
143
|
const s = flag ? new Box<number>(1) : new Box<string>('string');
|
|
144
144
|
|
|
145
145
|
// 20. Generic inside template expression
|
|
146
|
-
const t = `length=${new
|
|
146
|
+
const t = `length=${new RippleArray<number>().length}`;
|
|
147
147
|
|
|
148
148
|
// 21. Optional chaining + generic + property access
|
|
149
|
-
const registry = new
|
|
149
|
+
const registry = new RippleMap<string, number>();
|
|
150
150
|
const u = registry.get('id')?.toString();
|
|
151
151
|
|
|
152
152
|
// 22. Generic call used as callee for another call
|
|
@@ -208,7 +208,7 @@ describe('composite > generics', () => {
|
|
|
208
208
|
>();
|
|
209
209
|
|
|
210
210
|
// 33. Map of generic instance as key
|
|
211
|
-
const mm = new Map<
|
|
211
|
+
const mm = new Map<RippleArray<number>, RippleArray<string>>();
|
|
212
212
|
}
|
|
213
213
|
|
|
214
214
|
render(App);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Tracked, Props } from 'ripple';
|
|
2
|
-
import {
|
|
2
|
+
import { flushSync } from 'ripple';
|
|
3
3
|
|
|
4
4
|
describe('composite > props', () => {
|
|
5
5
|
it('correctly handles default prop values', () => {
|
|
@@ -8,7 +8,7 @@ describe('composite > props', () => {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
component App() {
|
|
11
|
-
let foo = track(123);
|
|
11
|
+
let foo = #ripple.track(123);
|
|
12
12
|
|
|
13
13
|
<Child />
|
|
14
14
|
<Child {@foo} />
|
|
@@ -44,7 +44,7 @@ describe('composite > props', () => {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
component App() {
|
|
47
|
-
let foo = track(123);
|
|
47
|
+
let foo = #ripple.track(123);
|
|
48
48
|
|
|
49
49
|
<Child />
|
|
50
50
|
<Child {foo} />
|
|
@@ -62,7 +62,7 @@ describe('composite > props', () => {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
component App() {
|
|
65
|
-
let foo = track(123);
|
|
65
|
+
let foo = #ripple.track(123);
|
|
66
66
|
|
|
67
67
|
<Child />
|
|
68
68
|
<Child {@foo} />
|
|
@@ -78,7 +78,7 @@ describe('composite > props', () => {
|
|
|
78
78
|
const logs: number[] = [];
|
|
79
79
|
|
|
80
80
|
component Counter({ count }: { count: Tracked<number> }) {
|
|
81
|
-
effect(() => {
|
|
81
|
+
#ripple.effect(() => {
|
|
82
82
|
logs.push(@count);
|
|
83
83
|
});
|
|
84
84
|
|
|
@@ -86,7 +86,7 @@ describe('composite > props', () => {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
component App() {
|
|
89
|
-
const count = track(0);
|
|
89
|
+
const count = #ripple.track(0);
|
|
90
90
|
|
|
91
91
|
<div>
|
|
92
92
|
<Counter {count} />
|
|
@@ -107,7 +107,7 @@ describe('composite > props', () => {
|
|
|
107
107
|
|
|
108
108
|
it('correctly retains prop accessors and reactivity when using rest props', () => {
|
|
109
109
|
component Button(props: Props) {
|
|
110
|
-
const [children, rest] = trackSplit(props, ['children']);
|
|
110
|
+
const [children, rest] = #ripple.trackSplit(props, ['children']);
|
|
111
111
|
<button {...@rest}>
|
|
112
112
|
<@children />
|
|
113
113
|
</button>
|
|
@@ -122,14 +122,14 @@ describe('composite > props', () => {
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
component Toggle(props: { pressed: Tracked<boolean> }) {
|
|
125
|
-
const [pressed, rest] = trackSplit(props, ['pressed']);
|
|
125
|
+
const [pressed, rest] = #ripple.trackSplit(props, ['pressed']);
|
|
126
126
|
const onClick = () => (@pressed = !@pressed);
|
|
127
127
|
<Button {...@rest} class={@pressed ? 'on' : 'off'} {onClick}>{'button 1'}</Button>
|
|
128
128
|
<Button class={@pressed ? 'on' : 'off'} {onClick}>{'button 2'}</Button>
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
component App() {
|
|
132
|
-
const pressed = track(true);
|
|
132
|
+
const pressed = #ripple.track(true);
|
|
133
133
|
<Toggle {pressed} />
|
|
134
134
|
}
|
|
135
135
|
|