ripple 0.2.36 → 0.2.38
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/package.json
CHANGED
|
@@ -15,6 +15,29 @@ import is_reference from 'is-reference';
|
|
|
15
15
|
import { prune_css } from './prune.js';
|
|
16
16
|
import { error } from '../../errors.js';
|
|
17
17
|
|
|
18
|
+
function mark_for_loop_has_template(path) {
|
|
19
|
+
for (let i = path.length - 1; i >= 0; i -= 1) {
|
|
20
|
+
const node = path[i];
|
|
21
|
+
|
|
22
|
+
if (
|
|
23
|
+
node.type === 'Component' ||
|
|
24
|
+
node.type === 'FunctionExpression' ||
|
|
25
|
+
node.type === 'ArrowFunctionExpression' ||
|
|
26
|
+
node.type === 'FunctionDeclaration'
|
|
27
|
+
) {
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
if (
|
|
31
|
+
node.type === 'ForStatement' ||
|
|
32
|
+
node.type === 'ForInStatement' ||
|
|
33
|
+
node.type === 'ForOfStatement'
|
|
34
|
+
) {
|
|
35
|
+
node.metadata.has_template = true;
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
18
41
|
function visit_function(node, context) {
|
|
19
42
|
node.metadata = {
|
|
20
43
|
hoisted: false,
|
|
@@ -407,6 +430,20 @@ const visitors = {
|
|
|
407
430
|
context.next();
|
|
408
431
|
},
|
|
409
432
|
|
|
433
|
+
ForOfStatement(node, context) {
|
|
434
|
+
node.metadata = {
|
|
435
|
+
has_template: false,
|
|
436
|
+
};
|
|
437
|
+
context.next();
|
|
438
|
+
if (!node.metadata.has_template) {
|
|
439
|
+
error(
|
|
440
|
+
'For...of loops must contain a template in their body. Move the for loop into an effect if it does not render anything.',
|
|
441
|
+
context.state.analysis.module.filename,
|
|
442
|
+
node,
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
},
|
|
446
|
+
|
|
410
447
|
ForInStatement(node, context) {
|
|
411
448
|
if (is_inside_component(context)) {
|
|
412
449
|
error(
|
|
@@ -429,13 +466,15 @@ const visitors = {
|
|
|
429
466
|
}
|
|
430
467
|
},
|
|
431
468
|
|
|
432
|
-
Element(node, { state, visit }) {
|
|
469
|
+
Element(node, { state, visit, path }) {
|
|
433
470
|
const is_dom_element =
|
|
434
471
|
node.id.type === 'Identifier' &&
|
|
435
472
|
node.id.name[0].toLowerCase() === node.id.name[0] &&
|
|
436
473
|
node.id.name[0] !== '$';
|
|
437
474
|
const attribute_names = new Set();
|
|
438
475
|
|
|
476
|
+
mark_for_loop_has_template(path);
|
|
477
|
+
|
|
439
478
|
if (is_dom_element) {
|
|
440
479
|
const is_void = is_void_element(node.id.name);
|
|
441
480
|
|
|
@@ -567,6 +606,11 @@ const visitors = {
|
|
|
567
606
|
};
|
|
568
607
|
},
|
|
569
608
|
|
|
609
|
+
Text(node, context) {
|
|
610
|
+
mark_for_loop_has_template(context.path);
|
|
611
|
+
context.next();
|
|
612
|
+
},
|
|
613
|
+
|
|
570
614
|
AwaitExpression(node, context) {
|
|
571
615
|
if (is_inside_component(context)) {
|
|
572
616
|
if (context.state.metadata?.await === false) {
|
|
@@ -328,34 +328,52 @@ const visitors = {
|
|
|
328
328
|
delete declarator.id.typeAnnotation;
|
|
329
329
|
}
|
|
330
330
|
|
|
331
|
-
if (binding !== null && binding.kind === 'tracked'
|
|
331
|
+
if (binding !== null && binding.kind === 'tracked') {
|
|
332
332
|
let expression;
|
|
333
333
|
|
|
334
|
-
if (
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
334
|
+
if (context.state.to_ts) {
|
|
335
|
+
// TypeScript mode: lighter transformation
|
|
336
|
+
if (metadata.tracking && !metadata.await) {
|
|
337
|
+
expression = b.call(
|
|
338
|
+
'$.computed',
|
|
339
|
+
b.thunk(context.visit(declarator.init)),
|
|
340
|
+
b.id('__block'),
|
|
341
|
+
);
|
|
342
|
+
} else {
|
|
343
|
+
expression = b.call(
|
|
344
|
+
'$.tracked',
|
|
345
|
+
declarator.init === null ? undefined : context.visit(declarator.init),
|
|
346
|
+
b.id('__block'),
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
} else {
|
|
350
|
+
// Runtime mode: full transformation
|
|
351
|
+
if (metadata.tracking && metadata.await) {
|
|
352
|
+
expression = b.call(
|
|
353
|
+
b.await(
|
|
339
354
|
b.call(
|
|
340
|
-
'$.
|
|
341
|
-
b.
|
|
342
|
-
|
|
355
|
+
'$.resume_context',
|
|
356
|
+
b.call(
|
|
357
|
+
'$.async_computed',
|
|
358
|
+
b.thunk(context.visit(declarator.init), true),
|
|
359
|
+
b.id('__block'),
|
|
360
|
+
),
|
|
343
361
|
),
|
|
344
362
|
),
|
|
345
|
-
)
|
|
346
|
-
)
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
363
|
+
);
|
|
364
|
+
} else if (metadata.tracking && !metadata.await) {
|
|
365
|
+
expression = b.call(
|
|
366
|
+
'$.computed',
|
|
367
|
+
b.thunk(context.visit(declarator.init)),
|
|
368
|
+
b.id('__block'),
|
|
369
|
+
);
|
|
370
|
+
} else {
|
|
371
|
+
expression = b.call(
|
|
372
|
+
'$.tracked',
|
|
373
|
+
declarator.init === null ? undefined : context.visit(declarator.init),
|
|
374
|
+
b.id('__block'),
|
|
375
|
+
);
|
|
376
|
+
}
|
|
359
377
|
}
|
|
360
378
|
|
|
361
379
|
declarations.push(b.declarator(declarator.id, expression));
|
|
@@ -372,11 +390,32 @@ const visitors = {
|
|
|
372
390
|
delete declarator.id.typeAnnotation;
|
|
373
391
|
}
|
|
374
392
|
|
|
375
|
-
if (!has_tracked
|
|
393
|
+
if (!has_tracked) {
|
|
376
394
|
declarations.push(context.visit(declarator));
|
|
377
395
|
continue;
|
|
378
396
|
}
|
|
379
397
|
|
|
398
|
+
// For TypeScript mode, we still need to transform tracked variables
|
|
399
|
+
// but use a lighter approach that maintains type information
|
|
400
|
+
if (context.state.to_ts) {
|
|
401
|
+
const transformed = declarator.transformed || declarator.id;
|
|
402
|
+
let expression;
|
|
403
|
+
|
|
404
|
+
if (metadata.tracking && !metadata.await) {
|
|
405
|
+
expression = b.call(
|
|
406
|
+
'$.computed',
|
|
407
|
+
b.thunk(context.visit(declarator.init)),
|
|
408
|
+
b.id('__block'),
|
|
409
|
+
);
|
|
410
|
+
} else {
|
|
411
|
+
// Simple tracked variable - always use $.tracked for $ prefixed variables
|
|
412
|
+
expression = b.call('$.tracked', context.visit(declarator.init), b.id('__block'));
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
declarations.push(b.declarator(transformed, expression));
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
418
|
+
|
|
380
419
|
const transformed = declarator.transformed;
|
|
381
420
|
let expression;
|
|
382
421
|
|
package/types/index.d.ts
CHANGED
|
@@ -55,3 +55,27 @@ export class RippleMap<K, V> extends Map<K, V> {
|
|
|
55
55
|
get $size(): number;
|
|
56
56
|
toJSON(): [K, V][];
|
|
57
57
|
}
|
|
58
|
+
|
|
59
|
+
// Compiler-injected runtime symbols (for Ripple component development)
|
|
60
|
+
declare global {
|
|
61
|
+
/**
|
|
62
|
+
* Runtime block context injected by the Ripple compiler.
|
|
63
|
+
* This is automatically available in component scopes and passed to runtime functions.
|
|
64
|
+
*/
|
|
65
|
+
var __block: any;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Ripple runtime namespace - injected by the compiler
|
|
69
|
+
* These functions are available in compiled Ripple components for TypeScript analysis
|
|
70
|
+
*/
|
|
71
|
+
var $: {
|
|
72
|
+
tracked<T>(value: T, block?: any): T;
|
|
73
|
+
tracked_object<T extends Record<string, any>>(obj: T, props: string[], block?: any): T;
|
|
74
|
+
computed<T>(fn: () => T, block?: any): T;
|
|
75
|
+
scope(): any;
|
|
76
|
+
get_tracked(node: any): any;
|
|
77
|
+
get_computed(node: any): any;
|
|
78
|
+
set(node: any, value: any, block?: any): any;
|
|
79
|
+
// Add other runtime functions as needed for TypeScript analysis
|
|
80
|
+
};
|
|
81
|
+
}
|