ripple 0.2.44 → 0.2.46
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 +1 -1
- package/src/compiler/phases/1-parse/index.js +83 -0
- package/src/compiler/phases/2-analyze/index.js +48 -9
- package/src/compiler/phases/2-analyze/prune.js +3 -1
- package/src/compiler/phases/3-transform/index.js +136 -43
- package/src/compiler/utils.js +48 -14
- package/src/runtime/array.js +118 -25
- package/src/runtime/index.js +1 -1
- package/src/runtime/internal/client/array.js +16 -16
- package/src/runtime/internal/client/blocks.js +0 -1
- package/src/runtime/internal/client/constants.js +5 -2
- package/src/runtime/internal/client/index.js +4 -0
- package/src/runtime/internal/client/portal.js +3 -3
- package/src/runtime/internal/client/runtime.js +47 -15
- package/tests/array.test.ripple +125 -37
- package/tests/basic.test.ripple +11 -5
package/package.json
CHANGED
|
@@ -38,6 +38,84 @@ function RipplePlugin(config) {
|
|
|
38
38
|
return null;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
// Override getTokenFromCode to handle @ as an identifier prefix
|
|
42
|
+
getTokenFromCode(code) {
|
|
43
|
+
if (code === 64) { // '@' character
|
|
44
|
+
// Look ahead to see if this is followed by a valid identifier character
|
|
45
|
+
if (this.pos + 1 < this.input.length) {
|
|
46
|
+
const nextChar = this.input.charCodeAt(this.pos + 1);
|
|
47
|
+
// Check if the next character can start an identifier
|
|
48
|
+
if ((nextChar >= 65 && nextChar <= 90) || // A-Z
|
|
49
|
+
(nextChar >= 97 && nextChar <= 122) || // a-z
|
|
50
|
+
nextChar === 95 || nextChar === 36) { // _ or $
|
|
51
|
+
|
|
52
|
+
// Check if we're in an expression context
|
|
53
|
+
// In JSX expressions, inside parentheses, assignments, etc.
|
|
54
|
+
// we want to treat @ as an identifier prefix rather than decorator
|
|
55
|
+
const currentType = this.type;
|
|
56
|
+
const inExpression = this.exprAllowed ||
|
|
57
|
+
currentType === tt.braceL || // Inside { }
|
|
58
|
+
currentType === tt.parenL || // Inside ( )
|
|
59
|
+
currentType === tt.eq || // After =
|
|
60
|
+
currentType === tt.comma || // After ,
|
|
61
|
+
currentType === tt.colon || // After :
|
|
62
|
+
currentType === tt.question || // After ?
|
|
63
|
+
currentType === tt.logicalOR || // After ||
|
|
64
|
+
currentType === tt.logicalAND || // After &&
|
|
65
|
+
currentType === tt.dot || // After . (for member expressions like obj.@prop)
|
|
66
|
+
currentType === tt.questionDot; // After ?. (for optional chaining like obj?.@prop)
|
|
67
|
+
|
|
68
|
+
if (inExpression) {
|
|
69
|
+
return this.readAtIdentifier();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return super.getTokenFromCode(code);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Read an @ prefixed identifier
|
|
78
|
+
readAtIdentifier() {
|
|
79
|
+
const start = this.pos;
|
|
80
|
+
this.pos++; // skip '@'
|
|
81
|
+
|
|
82
|
+
// Read the identifier part manually
|
|
83
|
+
let word = '';
|
|
84
|
+
while (this.pos < this.input.length) {
|
|
85
|
+
const ch = this.input.charCodeAt(this.pos);
|
|
86
|
+
if ((ch >= 65 && ch <= 90) || // A-Z
|
|
87
|
+
(ch >= 97 && ch <= 122) || // a-z
|
|
88
|
+
(ch >= 48 && ch <= 57) || // 0-9
|
|
89
|
+
ch === 95 || ch === 36) { // _ or $
|
|
90
|
+
word += this.input[this.pos++];
|
|
91
|
+
} else {
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (word === '') {
|
|
97
|
+
this.raise(start, 'Invalid @ identifier');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Return the full identifier including @
|
|
101
|
+
return this.finishToken(tt.name, '@' + word);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Override parseIdent to mark @ identifiers as tracked
|
|
105
|
+
parseIdent(liberal) {
|
|
106
|
+
const node = super.parseIdent(liberal);
|
|
107
|
+
if (node.name && node.name.startsWith('@')) {
|
|
108
|
+
node.name = node.name.slice(1); // Remove the '@' for internal use
|
|
109
|
+
node.tracked = true;
|
|
110
|
+
node.start++;
|
|
111
|
+
const prev_pos = this.pos;
|
|
112
|
+
this.pos = node.start;
|
|
113
|
+
node.loc.start = this.curPosition();
|
|
114
|
+
this.pos = prev_pos;
|
|
115
|
+
}
|
|
116
|
+
return node;
|
|
117
|
+
}
|
|
118
|
+
|
|
41
119
|
parseExportDefaultDeclaration() {
|
|
42
120
|
// Check if this is "export default component"
|
|
43
121
|
if (this.value === 'component') {
|
|
@@ -159,6 +237,11 @@ function RipplePlugin(config) {
|
|
|
159
237
|
return this.finishNode(node, 'SpreadAttribute');
|
|
160
238
|
} else {
|
|
161
239
|
const id = this.parseIdentNode();
|
|
240
|
+
node.tracked = false;
|
|
241
|
+
if (id.name.startsWith('@')) {
|
|
242
|
+
node.tracked = true;
|
|
243
|
+
id.name = id.name.slice(1);
|
|
244
|
+
}
|
|
162
245
|
this.finishNode(id, 'Identifier');
|
|
163
246
|
node.name = id;
|
|
164
247
|
node.value = id;
|
|
@@ -79,6 +79,10 @@ function visit_function(node, context) {
|
|
|
79
79
|
function_depth: context.state.function_depth + 1,
|
|
80
80
|
expression: null,
|
|
81
81
|
});
|
|
82
|
+
|
|
83
|
+
if (node.metadata.tracked) {
|
|
84
|
+
mark_as_tracked(context.path);
|
|
85
|
+
}
|
|
82
86
|
}
|
|
83
87
|
|
|
84
88
|
function mark_as_tracked(path) {
|
|
@@ -117,11 +121,35 @@ const visitors = {
|
|
|
117
121
|
|
|
118
122
|
if (
|
|
119
123
|
is_reference(node, /** @type {Node} */ (parent)) &&
|
|
120
|
-
|
|
121
|
-
is_tracked_name(node.name) &&
|
|
124
|
+
(is_tracked_name(node) || node.tracked) &&
|
|
122
125
|
binding?.node !== node
|
|
123
126
|
) {
|
|
124
|
-
context.
|
|
127
|
+
mark_as_tracked(context.path);
|
|
128
|
+
if (context.state.metadata?.tracking === false) {
|
|
129
|
+
context.state.metadata.tracking = true;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (
|
|
134
|
+
is_reference(node, /** @type {Node} */ (parent)) &&
|
|
135
|
+
node.tracked &&
|
|
136
|
+
binding?.node !== node
|
|
137
|
+
) {
|
|
138
|
+
if (context.state.metadata?.tracking === false) {
|
|
139
|
+
context.state.metadata.tracking = true;
|
|
140
|
+
}
|
|
141
|
+
binding.transform = {
|
|
142
|
+
read_tracked: (node) => b.call('$.get_tracked', node),
|
|
143
|
+
assign_tracked: (node, value) => b.call('$.set', node, value, b.id('__block')),
|
|
144
|
+
update_tracked: (node) => {
|
|
145
|
+
return b.call(
|
|
146
|
+
node.prefix ? '$.update_pre' : '$.update',
|
|
147
|
+
node.argument,
|
|
148
|
+
b.id('__block'),
|
|
149
|
+
node.operator === '--' && b.literal(-1),
|
|
150
|
+
);
|
|
151
|
+
},
|
|
152
|
+
};
|
|
125
153
|
}
|
|
126
154
|
|
|
127
155
|
context.next();
|
|
@@ -247,7 +275,7 @@ const visitors = {
|
|
|
247
275
|
if (!computed) {
|
|
248
276
|
return node;
|
|
249
277
|
}
|
|
250
|
-
return b.call('$.
|
|
278
|
+
return b.call('$.old_set_property', node, computed, value, b.id('__block'));
|
|
251
279
|
},
|
|
252
280
|
};
|
|
253
281
|
break;
|
|
@@ -264,6 +292,15 @@ const visitors = {
|
|
|
264
292
|
const has_tracked = paths.some(
|
|
265
293
|
(path) => path.node.type === 'Identifier' && is_tracked_name(path.node.name),
|
|
266
294
|
);
|
|
295
|
+
for (const path of paths) {
|
|
296
|
+
if (path.node.tracked) {
|
|
297
|
+
error(
|
|
298
|
+
'Variables cannot be reactively referenced using @',
|
|
299
|
+
state.analysis.module.filename,
|
|
300
|
+
path.node,
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
267
304
|
|
|
268
305
|
if (has_tracked) {
|
|
269
306
|
const tmp = state.scope.generate('tmp');
|
|
@@ -290,7 +327,7 @@ const visitors = {
|
|
|
290
327
|
} else if (metadata.tracking && !metadata.await) {
|
|
291
328
|
if (is_tracked_name(path.node.name) && value.type === 'MemberExpression') {
|
|
292
329
|
return b.call(
|
|
293
|
-
'$.
|
|
330
|
+
'$.old_get_property',
|
|
294
331
|
b.call('$.get_computed', value.object),
|
|
295
332
|
value.property.type === 'Identifier'
|
|
296
333
|
? b.literal(value.property.name)
|
|
@@ -312,7 +349,7 @@ const visitors = {
|
|
|
312
349
|
|
|
313
350
|
if (is_tracked_name(path.node.name) && value.type === 'MemberExpression') {
|
|
314
351
|
return b.call(
|
|
315
|
-
'$.
|
|
352
|
+
'$.old_get_property',
|
|
316
353
|
value.object,
|
|
317
354
|
value.property.type === 'Identifier'
|
|
318
355
|
? b.literal(value.property.name)
|
|
@@ -375,10 +412,10 @@ const visitors = {
|
|
|
375
412
|
};
|
|
376
413
|
} else {
|
|
377
414
|
binding.transform = {
|
|
378
|
-
read: (_) => b.call('$.
|
|
415
|
+
read: (_) => b.call('$.old_get_property', b.id('__props'), b.literal(name)),
|
|
379
416
|
assign: (node, value) => {
|
|
380
417
|
return b.call(
|
|
381
|
-
'$.
|
|
418
|
+
'$.old_set_property',
|
|
382
419
|
b.id('__props'),
|
|
383
420
|
b.literal(name),
|
|
384
421
|
value,
|
|
@@ -387,7 +424,7 @@ const visitors = {
|
|
|
387
424
|
},
|
|
388
425
|
update: (_) =>
|
|
389
426
|
b.call(
|
|
390
|
-
node.prefix ? '$.
|
|
427
|
+
node.prefix ? '$.old_update_property_pre' : '$.old_update_property',
|
|
391
428
|
b.id('__props'),
|
|
392
429
|
b.literal(name),
|
|
393
430
|
b.id('__block'),
|
|
@@ -508,6 +545,8 @@ const visitors = {
|
|
|
508
545
|
|
|
509
546
|
attr.metadata.delegated = delegated_event;
|
|
510
547
|
}
|
|
548
|
+
} else {
|
|
549
|
+
visit(attr.value, state);
|
|
511
550
|
}
|
|
512
551
|
}
|
|
513
552
|
} else if (attr.type === 'AccessorAttribute') {
|
|
@@ -405,7 +405,9 @@ function attribute_matches(node, name, expected_value, operator, case_insensitiv
|
|
|
405
405
|
if (attribute.type === 'SpreadAttribute') return true;
|
|
406
406
|
|
|
407
407
|
if (attribute.type !== 'Attribute') continue;
|
|
408
|
-
|
|
408
|
+
|
|
409
|
+
const lowerCaseName = name.toLowerCase();
|
|
410
|
+
if (![lowerCaseName, `$${lowerCaseName}`].includes(attribute.name.name.toLowerCase())) continue;
|
|
409
411
|
|
|
410
412
|
if (expected_value === null) return true;
|
|
411
413
|
|
|
@@ -17,16 +17,25 @@ import {
|
|
|
17
17
|
is_boolean_attribute,
|
|
18
18
|
is_dom_property,
|
|
19
19
|
is_ripple_import,
|
|
20
|
-
|
|
20
|
+
is_declared_function_within_component,
|
|
21
21
|
is_inside_call_expression,
|
|
22
22
|
is_tracked_computed_property,
|
|
23
23
|
is_value_static,
|
|
24
24
|
is_void_element,
|
|
25
|
+
is_component_level_function,
|
|
25
26
|
} from '../../utils.js';
|
|
26
27
|
import is_reference from 'is-reference';
|
|
27
28
|
import { extract_paths, object } from '../../../utils/ast.js';
|
|
28
29
|
import { render_stylesheets } from './stylesheet.js';
|
|
29
30
|
|
|
31
|
+
function add_ripple_internal_import(context) {
|
|
32
|
+
if (!context.state.to_ts) {
|
|
33
|
+
if (!context.state.imports.has(`import * as $ from 'ripple/internal/client'`)) {
|
|
34
|
+
context.state.imports.add(`import * as $ from 'ripple/internal/client'`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
30
39
|
function visit_function(node, context) {
|
|
31
40
|
if (context.state.to_ts) {
|
|
32
41
|
context.next(context.state);
|
|
@@ -54,13 +63,18 @@ function visit_function(node, context) {
|
|
|
54
63
|
let body = context.visit(node.body, state);
|
|
55
64
|
|
|
56
65
|
if (metadata?.tracked === true) {
|
|
66
|
+
const new_body = [];
|
|
67
|
+
|
|
68
|
+
if (!is_inside_component(context, true) && is_component_level_function(context)) {
|
|
69
|
+
add_ripple_internal_import(context);
|
|
70
|
+
new_body.push(b.var('__block', b.call('$.scope')));
|
|
71
|
+
}
|
|
72
|
+
new_body.push(...body.body);
|
|
73
|
+
|
|
57
74
|
return /** @type {FunctionExpression} */ ({
|
|
58
75
|
...node,
|
|
59
76
|
params: node.params.map((param) => context.visit(param, state)),
|
|
60
|
-
body:
|
|
61
|
-
body.type === 'BlockStatement'
|
|
62
|
-
? { ...body, body: [b.var('__block', b.call('$.scope')), ...body.body] }
|
|
63
|
-
: body,
|
|
77
|
+
body: body.type === 'BlockStatement' ? { ...body, body: new_body } : body,
|
|
64
78
|
});
|
|
65
79
|
}
|
|
66
80
|
|
|
@@ -72,10 +86,17 @@ function build_getter(node, context) {
|
|
|
72
86
|
|
|
73
87
|
for (let i = context.path.length - 1; i >= 0; i -= 1) {
|
|
74
88
|
const binding = state.scope.get(node.name);
|
|
89
|
+
const transform = binding?.transform;
|
|
75
90
|
|
|
76
91
|
// don't transform the declaration itself
|
|
77
|
-
if (node !== binding?.node
|
|
78
|
-
|
|
92
|
+
if (node !== binding?.node) {
|
|
93
|
+
const read_fn = transform?.read || (node.tracked && transform?.read_tracked);
|
|
94
|
+
|
|
95
|
+
if (read_fn) {
|
|
96
|
+
add_ripple_internal_import(context);
|
|
97
|
+
|
|
98
|
+
return read_fn(node, context.state?.metadata?.spread, context.visit);
|
|
99
|
+
}
|
|
79
100
|
}
|
|
80
101
|
}
|
|
81
102
|
|
|
@@ -100,7 +121,7 @@ const visitors = {
|
|
|
100
121
|
const binding = context.state.scope.get(node.name);
|
|
101
122
|
if (
|
|
102
123
|
context.state.metadata?.tracking === false &&
|
|
103
|
-
is_tracked_name(node.name) &&
|
|
124
|
+
(is_tracked_name(node.name) || node.tracked) &&
|
|
104
125
|
binding?.node !== node
|
|
105
126
|
) {
|
|
106
127
|
context.state.metadata.tracking = true;
|
|
@@ -135,6 +156,18 @@ const visitors = {
|
|
|
135
156
|
context.state.metadata.tracking = true;
|
|
136
157
|
}
|
|
137
158
|
|
|
159
|
+
if (
|
|
160
|
+
!context.state.to_ts &&
|
|
161
|
+
callee.type === 'Identifier' &&
|
|
162
|
+
callee.name === 'tracked' &&
|
|
163
|
+
is_ripple_import(callee, context)
|
|
164
|
+
) {
|
|
165
|
+
return {
|
|
166
|
+
...node,
|
|
167
|
+
arguments: [...node.arguments.map((arg) => context.visit(arg)), b.id('__block')],
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
138
171
|
if (
|
|
139
172
|
!is_inside_component(context, true) ||
|
|
140
173
|
context.state.to_ts ||
|
|
@@ -144,7 +177,7 @@ const visitors = {
|
|
|
144
177
|
(is_ripple_import(callee, context) &&
|
|
145
178
|
(callee.type !== 'Identifier' ||
|
|
146
179
|
(callee.name !== 'array' && callee.name !== 'deferred'))) ||
|
|
147
|
-
|
|
180
|
+
is_declared_function_within_component(callee, context)
|
|
148
181
|
) {
|
|
149
182
|
return context.next();
|
|
150
183
|
}
|
|
@@ -199,8 +232,8 @@ const visitors = {
|
|
|
199
232
|
callee.optional ? b.true : undefined,
|
|
200
233
|
node.optional ? b.true : undefined,
|
|
201
234
|
...node.arguments.map((arg) => context.visit(arg)),
|
|
202
|
-
)
|
|
203
|
-
)
|
|
235
|
+
),
|
|
236
|
+
),
|
|
204
237
|
);
|
|
205
238
|
}
|
|
206
239
|
}
|
|
@@ -267,6 +300,18 @@ const visitors = {
|
|
|
267
300
|
MemberExpression(node, context) {
|
|
268
301
|
const parent = context.path.at(-1);
|
|
269
302
|
|
|
303
|
+
if (node.property.type === 'Identifier' && node.property.tracked) {
|
|
304
|
+
add_ripple_internal_import(context);
|
|
305
|
+
|
|
306
|
+
context.state.metadata.tracking = true;
|
|
307
|
+
return b.call(
|
|
308
|
+
'$.get_property',
|
|
309
|
+
context.visit(node.object),
|
|
310
|
+
node.computed ? context.visit(node.property) : b.literal(node.property.name),
|
|
311
|
+
node.optional ? b.true : undefined,
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
|
|
270
315
|
if (parent.type !== 'AssignmentExpression') {
|
|
271
316
|
const object = node.object;
|
|
272
317
|
const property = node.property;
|
|
@@ -286,14 +331,14 @@ const visitors = {
|
|
|
286
331
|
|
|
287
332
|
if (tracked_name) {
|
|
288
333
|
return b.call(
|
|
289
|
-
'$.
|
|
334
|
+
'$.old_get_property',
|
|
290
335
|
context.visit(object),
|
|
291
336
|
property.type === 'Identifier' ? b.literal(property.name) : property,
|
|
292
337
|
node.optional ? b.true : undefined,
|
|
293
338
|
);
|
|
294
339
|
} else {
|
|
295
340
|
return b.call(
|
|
296
|
-
'$.
|
|
341
|
+
'$.old_get_property',
|
|
297
342
|
context.visit(object),
|
|
298
343
|
context.visit(property),
|
|
299
344
|
node.optional ? b.true : undefined,
|
|
@@ -508,9 +553,10 @@ const visitors = {
|
|
|
508
553
|
|
|
509
554
|
if (is_spreading) {
|
|
510
555
|
// For spread attributes, store just the actual value, not the full attribute string
|
|
511
|
-
const actual_value =
|
|
512
|
-
|
|
513
|
-
|
|
556
|
+
const actual_value =
|
|
557
|
+
is_boolean_attribute(name) && value === true
|
|
558
|
+
? b.literal(true)
|
|
559
|
+
: b.literal(value === true ? '' : value);
|
|
514
560
|
spread_attributes.push(b.prop('init', b.literal(name), actual_value));
|
|
515
561
|
} else {
|
|
516
562
|
state.template.push(attr_value);
|
|
@@ -542,9 +588,10 @@ const visitors = {
|
|
|
542
588
|
|
|
543
589
|
if (name === 'value' || name === '$value') {
|
|
544
590
|
const id = state.flush_node();
|
|
545
|
-
const
|
|
591
|
+
const metadata = { tracking: false, await: false };
|
|
592
|
+
const expression = visit(attr.value, { ...state, metadata });
|
|
546
593
|
|
|
547
|
-
if (name === '$value') {
|
|
594
|
+
if (name === '$value' || metadata.tracking) {
|
|
548
595
|
local_updates.push(b.stmt(b.call('$.set_value', id, expression)));
|
|
549
596
|
} else {
|
|
550
597
|
state.init.push(b.stmt(b.call('$.set_value', id, expression)));
|
|
@@ -555,9 +602,10 @@ const visitors = {
|
|
|
555
602
|
|
|
556
603
|
if (name === 'checked' || name === '$checked') {
|
|
557
604
|
const id = state.flush_node();
|
|
558
|
-
const
|
|
605
|
+
const metadata = { tracking: false, await: false };
|
|
606
|
+
const expression = visit(attr.value, { ...state, metadata });
|
|
559
607
|
|
|
560
|
-
if (name === '$checked') {
|
|
608
|
+
if (name === '$checked' || metadata.tracking) {
|
|
561
609
|
local_updates.push(b.stmt(b.call('$.set_checked', id, expression)));
|
|
562
610
|
} else {
|
|
563
611
|
state.init.push(b.stmt(b.call('$.set_checked', id, expression)));
|
|
@@ -567,9 +615,10 @@ const visitors = {
|
|
|
567
615
|
|
|
568
616
|
if (name === 'selected' || name === '$selected') {
|
|
569
617
|
const id = state.flush_node();
|
|
570
|
-
const
|
|
618
|
+
const metadata = { tracking: false, await: false };
|
|
619
|
+
const expression = visit(attr.value, { ...state, metadata });
|
|
571
620
|
|
|
572
|
-
if (name === '$selected') {
|
|
621
|
+
if (name === '$selected' || metadata.tracking) {
|
|
573
622
|
local_updates.push(b.stmt(b.call('$.set_selected', id, expression)));
|
|
574
623
|
} else {
|
|
575
624
|
state.init.push(b.stmt(b.call('$.set_selected', id, expression)));
|
|
@@ -607,7 +656,7 @@ const visitors = {
|
|
|
607
656
|
delegated_assignment = b.array(args);
|
|
608
657
|
} else if (
|
|
609
658
|
handler.type === 'Identifier' &&
|
|
610
|
-
|
|
659
|
+
is_declared_function_within_component(handler, context)
|
|
611
660
|
) {
|
|
612
661
|
delegated_assignment = handler;
|
|
613
662
|
} else {
|
|
@@ -639,11 +688,12 @@ const visitors = {
|
|
|
639
688
|
continue;
|
|
640
689
|
}
|
|
641
690
|
|
|
691
|
+
const metadata = { tracking: false, await: false };
|
|
692
|
+
const expression = visit(attr.value, { ...state, metadata });
|
|
642
693
|
// All other attributes
|
|
643
|
-
if (is_tracked_name(name)) {
|
|
644
|
-
const attribute = name.slice(1);
|
|
694
|
+
if (is_tracked_name(name) || metadata.tracking) {
|
|
695
|
+
const attribute = is_tracked_name(name) ? name.slice(1) : name;
|
|
645
696
|
const id = state.flush_node();
|
|
646
|
-
const expression = visit(attr.value, state);
|
|
647
697
|
|
|
648
698
|
if (is_dom_property(attribute)) {
|
|
649
699
|
local_updates.push(b.stmt(b.assignment('=', b.member(id, attribute), expression)));
|
|
@@ -654,7 +704,6 @@ const visitors = {
|
|
|
654
704
|
}
|
|
655
705
|
} else {
|
|
656
706
|
const id = state.flush_node();
|
|
657
|
-
const expression = visit(attr.value, state);
|
|
658
707
|
|
|
659
708
|
if (is_dom_property(name)) {
|
|
660
709
|
state.init.push(b.stmt(b.assignment('=', b.member(id, name), expression)));
|
|
@@ -682,13 +731,14 @@ const visitors = {
|
|
|
682
731
|
handle_static_attr(class_attribute.name.name, value);
|
|
683
732
|
} else {
|
|
684
733
|
const id = state.flush_node();
|
|
685
|
-
|
|
734
|
+
const metadata = { tracking: false, await: false };
|
|
735
|
+
let expression = visit(class_attribute.value, { ...state, metadata });
|
|
686
736
|
|
|
687
737
|
if (node.metadata.scoped && state.component.css) {
|
|
688
738
|
expression = b.binary('+', b.literal(state.component.css.hash + ' '), expression);
|
|
689
739
|
}
|
|
690
740
|
|
|
691
|
-
if (class_attribute.name.name === '$class') {
|
|
741
|
+
if (class_attribute.name.name === '$class' || metadata.tracking) {
|
|
692
742
|
local_updates.push(b.stmt(b.call('$.set_class', id, expression)));
|
|
693
743
|
} else {
|
|
694
744
|
state.init.push(b.stmt(b.call('$.set_class', id, expression)));
|
|
@@ -880,9 +930,7 @@ const visitors = {
|
|
|
880
930
|
|
|
881
931
|
Fragment(node, context) {
|
|
882
932
|
if (!context.state.to_ts) {
|
|
883
|
-
|
|
884
|
-
context.state.imports.add(`import * as $ from 'ripple/internal/client'`);
|
|
885
|
-
}
|
|
933
|
+
add_ripple_internal_import(context);
|
|
886
934
|
}
|
|
887
935
|
|
|
888
936
|
const metadata = { await: false };
|
|
@@ -906,11 +954,7 @@ const visitors = {
|
|
|
906
954
|
Component(node, context) {
|
|
907
955
|
let prop_statements;
|
|
908
956
|
|
|
909
|
-
|
|
910
|
-
if (!context.state.imports.has(`import * as $ from 'ripple/internal/client'`)) {
|
|
911
|
-
context.state.imports.add(`import * as $ from 'ripple/internal/client'`);
|
|
912
|
-
}
|
|
913
|
-
}
|
|
957
|
+
add_ripple_internal_import(context);
|
|
914
958
|
|
|
915
959
|
const metadata = { await: false };
|
|
916
960
|
|
|
@@ -1000,12 +1044,43 @@ const visitors = {
|
|
|
1000
1044
|
|
|
1001
1045
|
const left = node.left;
|
|
1002
1046
|
|
|
1047
|
+
if (
|
|
1048
|
+
left.type === 'MemberExpression' &&
|
|
1049
|
+
left.property.type === 'Identifier' &&
|
|
1050
|
+
left.property.tracked
|
|
1051
|
+
) {
|
|
1052
|
+
add_ripple_internal_import(context);
|
|
1053
|
+
const operator = node.operator;
|
|
1054
|
+
const right = node.right;
|
|
1055
|
+
|
|
1056
|
+
if (operator !== '=') {
|
|
1057
|
+
context.state.metadata.tracking = true;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
return b.call(
|
|
1061
|
+
'$.set_property',
|
|
1062
|
+
context.visit(left.object),
|
|
1063
|
+
left.computed ? context.visit(left.property) : b.literal(left.property.name),
|
|
1064
|
+
operator === '='
|
|
1065
|
+
? context.visit(right)
|
|
1066
|
+
: b.binary(
|
|
1067
|
+
operator === '+=' ? '+' : operator === '-=' ? '-' : operator === '*=' ? '*' : '/',
|
|
1068
|
+
/** @type {Pattern} */ (context.visit(left)),
|
|
1069
|
+
/** @type {Expression} */ (context.visit(right)),
|
|
1070
|
+
),
|
|
1071
|
+
b.id('__block'),
|
|
1072
|
+
);
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1003
1075
|
if (left.type === 'MemberExpression') {
|
|
1004
1076
|
// need to capture setting length of array to throw a runtime error
|
|
1005
|
-
if (
|
|
1077
|
+
if (
|
|
1078
|
+
left.property.type === 'Identifier' &&
|
|
1079
|
+
(is_tracked_name(left.property.name) || left.property.name === 'length')
|
|
1080
|
+
) {
|
|
1006
1081
|
if (left.property.name !== '$length') {
|
|
1007
1082
|
return b.call(
|
|
1008
|
-
'$.
|
|
1083
|
+
'$.old_set_property',
|
|
1009
1084
|
context.visit(left.object),
|
|
1010
1085
|
left.computed ? context.visit(left.property) : b.literal(left.property.name),
|
|
1011
1086
|
visit_assignment_expression(node, context, build_assignment) ?? context.next(),
|
|
@@ -1038,6 +1113,23 @@ const visitors = {
|
|
|
1038
1113
|
}
|
|
1039
1114
|
const argument = node.argument;
|
|
1040
1115
|
|
|
1116
|
+
if (
|
|
1117
|
+
argument.type === 'MemberExpression' &&
|
|
1118
|
+
argument.property.type === 'Identifier' &&
|
|
1119
|
+
argument.property.tracked
|
|
1120
|
+
) {
|
|
1121
|
+
add_ripple_internal_import(context);
|
|
1122
|
+
context.state.metadata.tracking = true;
|
|
1123
|
+
|
|
1124
|
+
return b.call(
|
|
1125
|
+
node.prefix ? '$.update_pre_property' : '$.update_property',
|
|
1126
|
+
context.visit(argument.object),
|
|
1127
|
+
argument.computed ? context.visit(argument.property) : b.literal(argument.property.name),
|
|
1128
|
+
b.id('__block'),
|
|
1129
|
+
node.operator === '--' ? b.literal(-1) : undefined,
|
|
1130
|
+
);
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1041
1133
|
if (
|
|
1042
1134
|
argument.type === 'MemberExpression' &&
|
|
1043
1135
|
((argument.property.type === 'Identifier' && is_tracked_name(argument.property.name)) ||
|
|
@@ -1045,7 +1137,7 @@ const visitors = {
|
|
|
1045
1137
|
is_tracked_computed_property(argument.object, argument.property, context)))
|
|
1046
1138
|
) {
|
|
1047
1139
|
return b.call(
|
|
1048
|
-
node.prefix ? '$.
|
|
1140
|
+
node.prefix ? '$.old_update_pre_property' : '$.old_update_property',
|
|
1049
1141
|
context.visit(argument.object),
|
|
1050
1142
|
argument.computed ? context.visit(argument.property) : b.literal(argument.property.name),
|
|
1051
1143
|
b.id('__block'),
|
|
@@ -1058,8 +1150,9 @@ const visitors = {
|
|
|
1058
1150
|
const transformers = left && binding?.transform;
|
|
1059
1151
|
|
|
1060
1152
|
if (left === argument) {
|
|
1061
|
-
|
|
1062
|
-
|
|
1153
|
+
const update_fn = transformers?.update || transformers?.update_tracked;
|
|
1154
|
+
if (update_fn) {
|
|
1155
|
+
return update_fn(node);
|
|
1063
1156
|
}
|
|
1064
1157
|
}
|
|
1065
1158
|
|
|
@@ -1303,7 +1396,7 @@ const visitors = {
|
|
|
1303
1396
|
return b.literal(node.quasis[0].value.cooked);
|
|
1304
1397
|
}
|
|
1305
1398
|
|
|
1306
|
-
const expressions = node.expressions.map(expr => context.visit(expr));
|
|
1399
|
+
const expressions = node.expressions.map((expr) => context.visit(expr));
|
|
1307
1400
|
return b.template(node.quasis, expressions);
|
|
1308
1401
|
},
|
|
1309
1402
|
|