ripple 0.2.42 → 0.2.44

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
@@ -3,7 +3,7 @@
3
3
  "description": "Ripple is a TypeScript UI framework for the web",
4
4
  "license": "MIT",
5
5
  "author": "Dominic Gannaway",
6
- "version": "0.2.42",
6
+ "version": "0.2.44",
7
7
  "type": "module",
8
8
  "module": "src/runtime/index.js",
9
9
  "main": "src/runtime/index.js",
@@ -139,15 +139,14 @@ function RipplePlugin(config) {
139
139
  }
140
140
 
141
141
  if (this.eat(tt.braceL)) {
142
- if (this.type.label === '@') {
142
+ if (this.value === 'ref') {
143
143
  this.next();
144
- if (this.value !== 'use') {
145
- this.unexpected();
144
+ if (this.type === tt.braceR) {
145
+ this.raise(this.start, '"ref" is a Ripple keyword and must be used in the form {ref fn}');
146
146
  }
147
- this.next();
148
147
  node.argument = this.parseMaybeAssign();
149
148
  this.expect(tt.braceR);
150
- return this.finishNode(node, 'UseAttribute');
149
+ return this.finishNode(node, 'RefAttribute');
151
150
  } else if (this.type === tt.ellipsis) {
152
151
  this.expect(tt.ellipsis);
153
152
  node.argument = this.parseMaybeAssign();
@@ -150,40 +150,57 @@ const visitors = {
150
150
  }
151
151
 
152
152
  // Handle array methods that access the array
153
- if (
154
- callee.type === 'MemberExpression' &&
155
- !callee.optional &&
156
- callee.property.type === 'Identifier'
157
- ) {
158
- const name = callee.property.name;
159
- if (
160
- // TODO support the missing array methods
161
- name === 'reduce' ||
162
- name === 'map' ||
163
- name === 'forEach' ||
164
- name === 'join' ||
165
- name === 'includes' ||
166
- name === 'indexOf' ||
167
- name === 'lastIndexOf' ||
168
- name === 'filter' ||
169
- name === 'every' ||
170
- name === 'some' ||
171
- name === 'toSpliced' ||
172
- name === 'toSorted' ||
173
- name === 'toString' ||
174
- name === 'values' ||
175
- name === 'entries'
176
- ) {
153
+ if (callee.type === 'MemberExpression') {
154
+ const property = callee.property;
155
+
156
+ if (property.type === 'Identifier' && !callee.optional) {
157
+ const name = property.name;
158
+ if (
159
+ // TODO support the missing array methods
160
+ name === 'reduce' ||
161
+ name === 'map' ||
162
+ name === 'forEach' ||
163
+ name === 'join' ||
164
+ name === 'includes' ||
165
+ name === 'indexOf' ||
166
+ name === 'lastIndexOf' ||
167
+ name === 'filter' ||
168
+ name === 'every' ||
169
+ name === 'some' ||
170
+ name === 'toSpliced' ||
171
+ name === 'toSorted' ||
172
+ name === 'toString' ||
173
+ name === 'values' ||
174
+ name === 'entries'
175
+ ) {
176
+ return b.call(
177
+ '$.with_scope',
178
+ b.id('__block'),
179
+ b.thunk(
180
+ b.call(
181
+ '$.array_' + name,
182
+ context.visit(callee.object),
183
+ ...node.arguments.map((arg) => context.visit(arg)),
184
+ ),
185
+ ),
186
+ );
187
+ }
188
+ }
189
+
190
+ if (callee.computed) {
177
191
  return b.call(
178
192
  '$.with_scope',
179
193
  b.id('__block'),
180
194
  b.thunk(
181
195
  b.call(
182
- '$.array_' + name,
196
+ '$.call_property',
183
197
  context.visit(callee.object),
198
+ context.visit(property),
199
+ callee.optional ? b.true : undefined,
200
+ node.optional ? b.true : undefined,
184
201
  ...node.arguments.map((arg) => context.visit(arg)),
185
- ),
186
- ),
202
+ )
203
+ )
187
204
  );
188
205
  }
189
206
  }
@@ -213,6 +230,13 @@ const visitors = {
213
230
  context.next();
214
231
  },
215
232
 
233
+ TSMappedType(_, context) {
234
+ if (!context.state.to_ts) {
235
+ return b.empty;
236
+ }
237
+ context.next();
238
+ },
239
+
216
240
  NewExpression(node, context) {
217
241
  const callee = node.callee;
218
242
  const parent = context.path.at(-1);
@@ -483,7 +507,11 @@ const visitors = {
483
507
  );
484
508
 
485
509
  if (is_spreading) {
486
- spread_attributes.push(b.prop('init', b.literal(name), attr_value));
510
+ // For spread attributes, store just the actual value, not the full attribute string
511
+ const actual_value = is_boolean_attribute(name) && value === true
512
+ ? b.literal(true)
513
+ : b.literal(value === true ? '' : value);
514
+ spread_attributes.push(b.prop('init', b.literal(name), actual_value));
487
515
  } else {
488
516
  state.template.push(attr_value);
489
517
  }
@@ -637,9 +665,9 @@ const visitors = {
637
665
  }
638
666
  } else if (attr.type === 'SpreadAttribute') {
639
667
  spread_attributes.push(b.spread(b.call('$.spread_object', visit(attr.argument, state))));
640
- } else if (attr.type === 'UseAttribute') {
668
+ } else if (attr.type === 'RefAttribute') {
641
669
  const id = state.flush_node();
642
- state.init.push(b.stmt(b.call('$.use', id, b.thunk(visit(attr.argument, state)))));
670
+ state.init.push(b.stmt(b.call('$.ref', id, b.thunk(visit(attr.argument, state)))));
643
671
  }
644
672
  }
645
673
 
@@ -742,8 +770,8 @@ const visitors = {
742
770
  ),
743
771
  ),
744
772
  );
745
- } else if (attr.type === 'UseAttribute') {
746
- props.push(b.prop('init', b.call('$.use_prop'), visit(attr.argument, state), true));
773
+ } else if (attr.type === 'RefAttribute') {
774
+ props.push(b.prop('init', b.call('$.ref_prop'), visit(attr.argument, state), true));
747
775
  } else if (attr.type === 'AccessorAttribute') {
748
776
  // # means it's an accessor to the runtime
749
777
  tracked.push(b.literal('#' + attr.name.name));
@@ -973,7 +1001,8 @@ const visitors = {
973
1001
  const left = node.left;
974
1002
 
975
1003
  if (left.type === 'MemberExpression') {
976
- if (left.property.type === 'Identifier' && is_tracked_name(left.property.name)) {
1004
+ // need to capture setting length of array to throw a runtime error
1005
+ if (left.property.type === 'Identifier' && (is_tracked_name(left.property.name) || left.property.name === 'length')) {
977
1006
  if (left.property.name !== '$length') {
978
1007
  return b.call(
979
1008
  '$.set_property',
@@ -1269,6 +1298,15 @@ const visitors = {
1269
1298
  return b.binary(node.operator, context.visit(node.left), context.visit(node.right));
1270
1299
  },
1271
1300
 
1301
+ TemplateLiteral(node, context) {
1302
+ if (node.expressions.length === 0) {
1303
+ return b.literal(node.quasis[0].value.cooked);
1304
+ }
1305
+
1306
+ const expressions = node.expressions.map(expr => context.visit(expr));
1307
+ return b.template(node.quasis, expressions);
1308
+ },
1309
+
1272
1310
  RenderFragment(node, context) {
1273
1311
  const identifer = node.expression.callee;
1274
1312
 
@@ -1375,12 +1413,12 @@ function transform_ts_child(node, context) {
1375
1413
  const children = [];
1376
1414
  let has_children_props = false;
1377
1415
 
1378
- // Filter out UseAttributes and handle them separately
1379
- const use_attributes = [];
1416
+ // Filter out RefAttributes and handle them separately
1417
+ const ref_attributes = [];
1380
1418
  const attributes = node.attributes
1381
1419
  .filter((attr) => {
1382
- if (attr.type === 'UseAttribute') {
1383
- use_attributes.push(attr);
1420
+ if (attr.type === 'RefAttribute') {
1421
+ ref_attributes.push(attr);
1384
1422
  return false;
1385
1423
  }
1386
1424
  return true;
@@ -1404,10 +1442,10 @@ function transform_ts_child(node, context) {
1404
1442
  }
1405
1443
  });
1406
1444
 
1407
- // Add UseAttribute references separately for sourcemap purposes
1408
- for (const use_attr of use_attributes) {
1445
+ // Add RefAttribute references separately for sourcemap purposes
1446
+ for (const ref_attr of ref_attributes) {
1409
1447
  const metadata = { await: false };
1410
- const argument = visit(use_attr.argument, { ...state, metadata });
1448
+ const argument = visit(ref_attr.argument, { ...state, metadata });
1411
1449
  state.init.push(b.stmt(argument));
1412
1450
  }
1413
1451
 
@@ -61,8 +61,8 @@ export function convert_source_map_to_mappings(source_map, source, generated_cod
61
61
  );
62
62
  const source_content = source.substring(source_offset, source_offset + segment_length);
63
63
 
64
- // Skip mappings for UseAttribute syntax to avoid overlapping sourcemaps
65
- if (source_content.includes('{@use ') || source_content.match(/\{\s*@use\s+/)) {
64
+ // Skip mappings for RefAttribute syntax to avoid overlapping sourcemaps
65
+ if (source_content.includes('{ref ') || source_content.match(/\{\s*ref\s+/)) {
66
66
  continue;
67
67
  }
68
68