ripple 0.2.66 → 0.2.68

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 an elegant TypeScript UI framework",
4
4
  "license": "MIT",
5
5
  "author": "Dominic Gannaway",
6
- "version": "0.2.66",
6
+ "version": "0.2.68",
7
7
  "type": "module",
8
8
  "module": "src/runtime/index.js",
9
9
  "main": "src/runtime/index.js",
@@ -87,6 +87,10 @@ const visitors = {
87
87
  next(scope !== undefined && scope !== state.scope ? { ...state, scope } : state);
88
88
  },
89
89
 
90
+ Program(_, context) {
91
+ return context.next({ ...context.state, function_depth: 0, expression: null });
92
+ },
93
+
90
94
  Identifier(node, context) {
91
95
  const binding = context.state.scope.get(node.name);
92
96
  const parent = context.path.at(-1);
@@ -133,6 +137,25 @@ const visitors = {
133
137
  },
134
138
 
135
139
  CallExpression(node, context) {
140
+ const callee = node.callee;
141
+
142
+ if (
143
+ context.state.function_depth === 0 &&
144
+ ((callee.type === 'Identifier' && callee.name === 'track') ||
145
+ (callee.type === 'MemberExpression' &&
146
+ callee.object.type === 'Identifier' &&
147
+ callee.property.type === 'Identifier' &&
148
+ callee.property.name === 'track' &&
149
+ !callee.computed)) &&
150
+ is_ripple_import(callee, context)
151
+ ) {
152
+ error(
153
+ '`track` can only be used within a reactive context, such as a component, function or class that is used or created from a component',
154
+ context.state.analysis.module.filename,
155
+ node,
156
+ );
157
+ }
158
+
136
159
  if (context.state.metadata?.tracking === false) {
137
160
  context.state.metadata.tracking = true;
138
161
  }
@@ -145,27 +168,20 @@ const visitors = {
145
168
  },
146
169
 
147
170
  VariableDeclaration(node, context) {
148
- const { state, visit, path } = context;
171
+ const { state, visit } = context;
149
172
 
150
173
  for (const declarator of node.declarations) {
151
174
  if (is_inside_component(context) && node.kind === 'var') {
152
175
  error(
153
- 'var declarations are not allowed in components, use let or const instead',
176
+ '`var` declarations are not allowed in components, use let or const instead',
154
177
  state.analysis.module.filename,
155
178
  declarator,
156
179
  );
157
180
  }
158
181
  const metadata = { tracking: false, await: false };
159
- const parent = path.at(-1);
160
- const init_is_untracked =
161
- declarator.init !== null &&
162
- declarator.init.type === 'CallExpression' &&
163
- is_ripple_import(declarator.init.callee, context) &&
164
- declarator.init.callee.type === 'Identifier' &&
165
- (declarator.init.callee.name === 'untrack' || declarator.init.callee.name === 'deferred');
166
182
 
167
183
  if (declarator.id.type === 'Identifier') {
168
- visit(declarator, state);
184
+ visit(declarator, state);
169
185
  } else {
170
186
  const paths = extract_paths(declarator.id);
171
187
 
@@ -234,7 +250,7 @@ const visitors = {
234
250
  }
235
251
  const elements = [];
236
252
 
237
- context.next({ ...context.state, elements });
253
+ context.next({ ...context.state, elements, function_depth: context.state.function_depth + 1 });
238
254
 
239
255
  const css = node.css;
240
256
 
@@ -29,8 +29,8 @@ import { is_event_attribute, is_passive_event } from '../../../utils/events.js';
29
29
 
30
30
  function add_ripple_internal_import(context) {
31
31
  if (!context.state.to_ts) {
32
- if (!context.state.imports.has(`import * as $ from 'ripple/internal/client'`)) {
33
- context.state.imports.add(`import * as $ from 'ripple/internal/client'`);
32
+ if (!context.state.imports.has(`import * as _$_ from 'ripple/internal/client'`)) {
33
+ context.state.imports.add(`import * as _$_ from 'ripple/internal/client'`);
34
34
  }
35
35
  }
36
36
  }
@@ -66,7 +66,7 @@ function visit_function(node, context) {
66
66
 
67
67
  if (!is_inside_component(context, true) && is_component_level_function(context)) {
68
68
  add_ripple_internal_import(context);
69
- new_body.push(b.var('__block', b.call('$.scope')));
69
+ new_body.push(b.var('__block', b.call('_$_.scope')));
70
70
  }
71
71
  if (body.type === 'BlockStatement') {
72
72
  new_body.push(...body.body);
@@ -135,7 +135,7 @@ const visitors = {
135
135
  context.state.metadata.tracking = true;
136
136
  }
137
137
  if (node.tracked) {
138
- return b.call('$.get', build_getter(node, context));
138
+ return b.call('_$_.get', build_getter(node, context));
139
139
  }
140
140
  }
141
141
 
@@ -167,8 +167,12 @@ const visitors = {
167
167
 
168
168
  if (
169
169
  !context.state.to_ts &&
170
- callee.type === 'Identifier' &&
171
- callee.name === 'track' &&
170
+ ((callee.type === 'Identifier' && callee.name === 'track') ||
171
+ (callee.type === 'MemberExpression' &&
172
+ callee.object.type === 'Identifier' &&
173
+ callee.property.type === 'Identifier' &&
174
+ callee.property.name === 'track' &&
175
+ !callee.computed)) &&
172
176
  is_ripple_import(callee, context)
173
177
  ) {
174
178
  if (node.arguments.length === 0) {
@@ -186,9 +190,6 @@ const visitors = {
186
190
  (parent?.type === 'MemberExpression' && parent.property === node) ||
187
191
  is_inside_call_expression(context) ||
188
192
  !context.path.some((node) => node.type === 'Component') ||
189
- (is_ripple_import(callee, context) &&
190
- (callee.type !== 'Identifier' ||
191
- (callee.name !== 'array' && callee.name !== 'deferred'))) ||
192
193
  is_declared_function_within_component(callee, context)
193
194
  ) {
194
195
  return context.next();
@@ -200,11 +201,11 @@ const visitors = {
200
201
 
201
202
  if (callee.computed) {
202
203
  return b.call(
203
- '$.with_scope',
204
+ '_$_.with_scope',
204
205
  b.id('__block'),
205
206
  b.thunk(
206
207
  b.call(
207
- '$.call_property',
208
+ '_$_.call_property',
208
209
  context.visit(callee.object),
209
210
  context.visit(property),
210
211
  callee.optional ? b.true : undefined,
@@ -217,7 +218,7 @@ const visitors = {
217
218
  }
218
219
 
219
220
  return b.call(
220
- '$.with_scope',
221
+ '_$_.with_scope',
221
222
  b.id('__block'),
222
223
  b.thunk(
223
224
  {
@@ -269,7 +270,7 @@ const visitors = {
269
270
  }
270
271
 
271
272
  return b.call(
272
- '$.with_scope',
273
+ '_$_.with_scope',
273
274
  b.id('__block'),
274
275
  b.thunk({
275
276
  ...node,
@@ -290,7 +291,7 @@ const visitors = {
290
291
  add_ripple_internal_import(context);
291
292
 
292
293
  return b.call(
293
- '$.get_property',
294
+ '_$_.get_property',
294
295
  context.visit(node.object),
295
296
  node.computed ? context.visit(node.property) : b.literal(node.property.name),
296
297
  node.optional ? b.true : undefined,
@@ -324,6 +325,13 @@ const visitors = {
324
325
  }
325
326
  },
326
327
 
328
+ PropertyDefinition(node, context) {
329
+ if (!context.state.to_ts) {
330
+ delete node.typeAnnotation;
331
+ }
332
+ return context.next();
333
+ },
334
+
327
335
  VariableDeclaration(node, context) {
328
336
  const declarations = [];
329
337
 
@@ -344,13 +352,13 @@ const visitors = {
344
352
  // TypeScript mode: lighter transformation
345
353
  if (metadata.tracking && !metadata.await) {
346
354
  expression = b.call(
347
- '$.derived',
355
+ '_$_.derived',
348
356
  b.thunk(context.visit(declarator.init)),
349
357
  b.id('__block'),
350
358
  );
351
359
  } else {
352
360
  expression = b.call(
353
- '$.tracked',
361
+ '_$_.tracked',
354
362
  declarator.init === null ? undefined : context.visit(declarator.init),
355
363
  b.id('__block'),
356
364
  );
@@ -362,9 +370,9 @@ const visitors = {
362
370
  expression = b.call(
363
371
  b.await(
364
372
  b.call(
365
- '$.resume_context',
373
+ '_$_.resume_context',
366
374
  b.call(
367
- '$.async_computed',
375
+ '_$_.async_computed',
368
376
  b.thunk(context.visit(declarator.init), true),
369
377
  b.id('__block'),
370
378
  ),
@@ -373,13 +381,13 @@ const visitors = {
373
381
  );
374
382
  } else if (metadata.tracking && !metadata.await) {
375
383
  expression = b.call(
376
- '$.derived',
384
+ '_$_.derived',
377
385
  b.thunk(context.visit(declarator.init)),
378
386
  b.id('__block'),
379
387
  );
380
388
  } else {
381
389
  expression = b.call(
382
- '$.tracked',
390
+ '_$_.tracked',
383
391
  declarator.init === null ? undefined : context.visit(declarator.init),
384
392
  b.id('__block'),
385
393
  );
@@ -474,9 +482,9 @@ const visitors = {
474
482
  const expression = visit(attr.value, { ...state, metadata });
475
483
 
476
484
  if (name === '$value' || metadata.tracking) {
477
- local_updates.push(b.stmt(b.call('$.set_value', id, expression)));
485
+ local_updates.push(b.stmt(b.call('_$_.set_value', id, expression)));
478
486
  } else {
479
- state.init.push(b.stmt(b.call('$.set_value', id, expression)));
487
+ state.init.push(b.stmt(b.call('_$_.set_value', id, expression)));
480
488
  }
481
489
 
482
490
  continue;
@@ -488,9 +496,9 @@ const visitors = {
488
496
  const expression = visit(attr.value, { ...state, metadata });
489
497
 
490
498
  if (name === '$checked' || metadata.tracking) {
491
- local_updates.push(b.stmt(b.call('$.set_checked', id, expression)));
499
+ local_updates.push(b.stmt(b.call('_$_.set_checked', id, expression)));
492
500
  } else {
493
- state.init.push(b.stmt(b.call('$.set_checked', id, expression)));
501
+ state.init.push(b.stmt(b.call('_$_.set_checked', id, expression)));
494
502
  }
495
503
  continue;
496
504
  }
@@ -501,9 +509,9 @@ const visitors = {
501
509
  const expression = visit(attr.value, { ...state, metadata });
502
510
 
503
511
  if (name === '$selected' || metadata.tracking) {
504
- local_updates.push(b.stmt(b.call('$.set_selected', id, expression)));
512
+ local_updates.push(b.stmt(b.call('_$_.set_selected', id, expression)));
505
513
  } else {
506
- state.init.push(b.stmt(b.call('$.set_selected', id, expression)));
514
+ state.init.push(b.stmt(b.call('_$_.set_selected', id, expression)));
507
515
  }
508
516
  continue;
509
517
  }
@@ -556,7 +564,7 @@ const visitors = {
556
564
  state.init.push(
557
565
  b.stmt(
558
566
  b.call(
559
- '$.event',
567
+ '_$_.event',
560
568
  b.literal(event_name),
561
569
  id,
562
570
  handler,
@@ -581,7 +589,7 @@ const visitors = {
581
589
  local_updates.push(b.stmt(b.assignment('=', b.member(id, attribute), expression)));
582
590
  } else {
583
591
  local_updates.push(
584
- b.stmt(b.call('$.set_attribute', id, b.literal(attribute), expression)),
592
+ b.stmt(b.call('_$_.set_attribute', id, b.literal(attribute), expression)),
585
593
  );
586
594
  }
587
595
  } else {
@@ -590,7 +598,9 @@ const visitors = {
590
598
  if (is_dom_property(name)) {
591
599
  state.init.push(b.stmt(b.assignment('=', b.member(id, name), expression)));
592
600
  } else {
593
- state.init.push(b.stmt(b.call('$.set_attribute', id, b.literal(name), expression)));
601
+ state.init.push(
602
+ b.stmt(b.call('_$_.set_attribute', id, b.literal(name), expression)),
603
+ );
594
604
  }
595
605
  }
596
606
  }
@@ -598,7 +608,7 @@ const visitors = {
598
608
  spread_attributes.push(b.spread(visit(attr.argument, state)));
599
609
  } else if (attr.type === 'RefAttribute') {
600
610
  const id = state.flush_node();
601
- state.init.push(b.stmt(b.call('$.ref', id, b.thunk(visit(attr.argument, state)))));
611
+ state.init.push(b.stmt(b.call('_$_.ref', id, b.thunk(visit(attr.argument, state)))));
602
612
  }
603
613
  }
604
614
 
@@ -619,11 +629,12 @@ const visitors = {
619
629
  if (node.metadata.scoped && state.component.css) {
620
630
  expression = b.binary('+', b.literal(state.component.css.hash + ' '), expression);
621
631
  }
632
+ const is_html = context.state.metadata.namespace === 'html' && node.id.name !== 'svg'
622
633
 
623
- if (class_attribute.name.name === '$class' || metadata.tracking) {
624
- local_updates.push(b.stmt(b.call('$.set_class', id, expression)));
634
+ if (metadata.tracking) {
635
+ local_updates.push(b.stmt(b.call('_$_.set_class', id, expression, is_html)));
625
636
  } else {
626
- state.init.push(b.stmt(b.call('$.set_class', id, expression)));
637
+ state.init.push(b.stmt(b.call('_$_.set_class', id, expression, is_html)));
627
638
  }
628
639
  }
629
640
  } else if (node.metadata.scoped && state.component.css) {
@@ -637,7 +648,7 @@ const visitors = {
637
648
  if (spread_attributes !== null && spread_attributes.length > 0) {
638
649
  const id = state.flush_node();
639
650
  state.init.push(
640
- b.stmt(b.call('$.render_spread', id, b.thunk(b.object(spread_attributes)))),
651
+ b.stmt(b.call('_$_.render_spread', id, b.thunk(b.object(spread_attributes)))),
641
652
  );
642
653
  }
643
654
 
@@ -661,7 +672,7 @@ const visitors = {
661
672
 
662
673
  if (update.length > 0) {
663
674
  if (state.scope.parent.declarations.size > 0) {
664
- state.init.push(b.stmt(b.call('$.render', b.thunk(b.block(update), !!update.async))));
675
+ state.init.push(b.stmt(b.call('_$_.render', b.thunk(b.block(update), !!update.async))));
665
676
  } else {
666
677
  state.update.push(...update);
667
678
  }
@@ -703,7 +714,7 @@ const visitors = {
703
714
  ),
704
715
  );
705
716
  } else if (attr.type === 'RefAttribute') {
706
- props.push(b.prop('init', b.call('$.ref_prop'), visit(attr.argument, state), true));
717
+ props.push(b.prop('init', b.call('_$_.ref_prop'), visit(attr.argument, state), true));
707
718
  } else if (attr.type === 'AccessorAttribute') {
708
719
  let get_expr;
709
720
 
@@ -784,14 +795,14 @@ const visitors = {
784
795
  b.call(
785
796
  node.id,
786
797
  id,
787
- b.call('$.spread_props', b.thunk(b.object(props)), b.id('__block')),
788
- b.id('$.active_block'),
798
+ b.call('_$_.spread_props', b.thunk(b.object(props)), b.id('__block')),
799
+ b.id('_$_.active_block'),
789
800
  ),
790
801
  ),
791
802
  );
792
803
  } else {
793
804
  state.init.push(
794
- b.stmt(b.call(visit(node.id, state), id, b.object(props), b.id('$.active_block'))),
805
+ b.stmt(b.call(visit(node.id, state), id, b.object(props), b.id('_$_.active_block'))),
795
806
  );
796
807
  }
797
808
  }
@@ -814,7 +825,7 @@ const visitors = {
814
825
  [b.id('__anchor'), ...node.params.map((param) => context.visit(param, context.state))],
815
826
  b.block(
816
827
  metadata.await
817
- ? [b.stmt(b.call('$.async', b.thunk(b.block(body_statements), true)))]
828
+ ? [b.stmt(b.call('_$_.async', b.thunk(b.block(body_statements), true)))]
818
829
  : body_statements,
819
830
  ),
820
831
  );
@@ -852,12 +863,12 @@ const visitors = {
852
863
  }
853
864
 
854
865
  const body_statements = [
855
- b.stmt(b.call('$.push_component')),
866
+ b.stmt(b.call('_$_.push_component')),
856
867
  ...transform_body(node.body, {
857
868
  ...context,
858
869
  state: { ...context.state, component: node, metadata },
859
870
  }),
860
- b.stmt(b.call('$.pop_component')),
871
+ b.stmt(b.call('_$_.pop_component')),
861
872
  ];
862
873
 
863
874
  if (node.css !== null && node.css) {
@@ -872,7 +883,7 @@ const visitors = {
872
883
  b.block([
873
884
  ...(prop_statements ?? []),
874
885
  ...(metadata.await
875
- ? [b.stmt(b.call('$.async', b.thunk(b.block(body_statements), true)))]
886
+ ? [b.stmt(b.call('_$_.async', b.thunk(b.block(body_statements), true)))]
876
887
  : body_statements),
877
888
  ]),
878
889
  );
@@ -899,7 +910,7 @@ const visitors = {
899
910
  }
900
911
 
901
912
  return b.call(
902
- '$.set_property',
913
+ '_$_.set_property',
903
914
  context.visit(left.object, { ...context.state, metadata: { tracking: false } }),
904
915
  left.computed ? context.visit(left.property) : b.literal(left.property.name),
905
916
  operator === '='
@@ -919,7 +930,7 @@ const visitors = {
919
930
  const right = node.right;
920
931
 
921
932
  return b.call(
922
- '$.set',
933
+ '_$_.set',
923
934
  context.visit(left, { ...context.state, metadata: { tracking: null } }),
924
935
  operator === '='
925
936
  ? context.visit(right)
@@ -953,7 +964,7 @@ const visitors = {
953
964
  context.state.metadata.tracking = true;
954
965
 
955
966
  return b.call(
956
- node.prefix ? '$.update_pre_property' : '$.update_property',
967
+ node.prefix ? '_$_.update_pre_property' : '_$_.update_property',
957
968
  context.visit(argument.object, { ...context.state, metadata: { tracking: false } }),
958
969
  argument.computed ? context.visit(argument.property) : b.literal(argument.property.name),
959
970
  b.id('__block'),
@@ -963,7 +974,7 @@ const visitors = {
963
974
 
964
975
  if (argument.type === 'Identifier' && argument.tracked) {
965
976
  return b.call(
966
- node.prefix ? '$.update_pre' : '$.update',
977
+ node.prefix ? '_$_.update_pre' : '_$_.update',
967
978
  context.visit(argument, { ...context.state, metadata: { tracking: null } }),
968
979
  b.id('__block'),
969
980
  node.operator === '--' ? b.literal(-1) : undefined,
@@ -1003,7 +1014,7 @@ const visitors = {
1003
1014
  context.state.init.push(
1004
1015
  b.stmt(
1005
1016
  b.call(
1006
- '$.for',
1017
+ '_$_.for',
1007
1018
  id,
1008
1019
  b.thunk(context.visit(node.right)),
1009
1020
  b.arrow(
@@ -1063,7 +1074,7 @@ const visitors = {
1063
1074
  statements.push(
1064
1075
  b.stmt(
1065
1076
  b.call(
1066
- '$.if',
1077
+ '_$_.if',
1067
1078
  id,
1068
1079
  b.arrow(
1069
1080
  [b.id('__render')],
@@ -1112,13 +1123,13 @@ const visitors = {
1112
1123
  });
1113
1124
 
1114
1125
  if (metadata.pending) {
1115
- body = [b.stmt(b.call('$.async', b.thunk(b.block(body), true)))];
1126
+ body = [b.stmt(b.call('_$_.async', b.thunk(b.block(body), true)))];
1116
1127
  }
1117
1128
 
1118
1129
  context.state.init.push(
1119
1130
  b.stmt(
1120
1131
  b.call(
1121
- '$.try',
1132
+ '_$_.try',
1122
1133
  id,
1123
1134
  b.arrow([b.id('__anchor')], b.block(body)),
1124
1135
  node.handler === null
@@ -1144,7 +1155,7 @@ const visitors = {
1144
1155
  context.state.metadata.await = true;
1145
1156
  }
1146
1157
 
1147
- return b.call(b.await(b.call('$.maybe_tracked', context.visit(node.argument))));
1158
+ return b.call(b.await(b.call('_$_.maybe_tracked', context.visit(node.argument))));
1148
1159
  },
1149
1160
 
1150
1161
  BinaryExpression(node, context) {
@@ -1152,7 +1163,9 @@ const visitors = {
1152
1163
  },
1153
1164
 
1154
1165
  TemplateLiteral(node, context) {
1155
- if (node.expressions.length === 0) {
1166
+ const parent = context.path.at(-1);
1167
+
1168
+ if (node.expressions.length === 0 && parent?.type !== 'TaggedTemplateExpression') {
1156
1169
  return b.literal(node.quasis[0].value.cooked);
1157
1170
  }
1158
1171
 
@@ -1474,12 +1487,13 @@ function transform_children(children, context) {
1474
1487
  node.type === 'DebuggerStatement' ||
1475
1488
  node.type === 'ClassDeclaration' ||
1476
1489
  node.type === 'TSTypeAliasDeclaration' ||
1490
+ node.type === 'TSInterfaceDeclaration' ||
1477
1491
  node.type === 'Component'
1478
1492
  ) {
1479
1493
  const metadata = { await: false };
1480
1494
  state.init.push(visit(node, { ...state, metadata }));
1481
1495
  if (metadata.await) {
1482
- state.init.push(b.if(b.call('$.aborted'), b.return(null)));
1496
+ state.init.push(b.if(b.call('_$_.aborted'), b.return(null)));
1483
1497
  if (state.metadata?.await === false) {
1484
1498
  state.metadata.await = true;
1485
1499
  }
@@ -1498,13 +1512,13 @@ function transform_children(children, context) {
1498
1512
  return cached;
1499
1513
  } else if (current_prev !== null) {
1500
1514
  const id = get_id(node);
1501
- state.setup.push(b.var(id, b.call('$.sibling', current_prev())));
1515
+ state.setup.push(b.var(id, b.call('_$_.sibling', current_prev())));
1502
1516
  cached = id;
1503
1517
  return id;
1504
1518
  } else if (initial !== null) {
1505
1519
  if (is_fragment) {
1506
1520
  const id = get_id(node);
1507
- state.setup.push(b.var(id, b.call('$.child_frag', initial)));
1521
+ state.setup.push(b.var(id, b.call('_$_.child_frag', initial)));
1508
1522
  cached = id;
1509
1523
  return id;
1510
1524
  }
@@ -1515,7 +1529,7 @@ function transform_children(children, context) {
1515
1529
  }
1516
1530
 
1517
1531
  const id = get_id(node);
1518
- state.setup.push(b.var(id, b.call('$.child', state.flush_node())));
1532
+ state.setup.push(b.var(id, b.call('_$_.child', state.flush_node())));
1519
1533
  cached = id;
1520
1534
  return id;
1521
1535
  } else {
@@ -1534,7 +1548,7 @@ function transform_children(children, context) {
1534
1548
  if (metadata.tracking) {
1535
1549
  state.template.push(' ');
1536
1550
  const id = flush_node();
1537
- state.update.push(b.stmt(b.call('$.set_text', id, expression)));
1551
+ state.update.push(b.stmt(b.call('_$_.set_text', id, expression)));
1538
1552
  if (metadata.await) {
1539
1553
  state.update.async = true;
1540
1554
  }
@@ -1546,7 +1560,7 @@ function transform_children(children, context) {
1546
1560
  state.template.push(' ');
1547
1561
  state.init.push(
1548
1562
  b.stmt(
1549
- b.assignment('=', b.member(b.call('$.child', id), b.id('nodeValue')), expression),
1563
+ b.assignment('=', b.member(b.call('_$_.child', id), b.id('nodeValue')), expression),
1550
1564
  ),
1551
1565
  );
1552
1566
  }
@@ -1554,7 +1568,7 @@ function transform_children(children, context) {
1554
1568
  // Handle Text nodes in fragments
1555
1569
  state.template.push(' ');
1556
1570
  const id = flush_node();
1557
- state.update.push(b.stmt(b.call('$.set_text', id, expression)));
1571
+ state.update.push(b.stmt(b.call('_$_.set_text', id, expression)));
1558
1572
  if (metadata.await) {
1559
1573
  state.update.async = true;
1560
1574
  }
@@ -1579,9 +1593,9 @@ function transform_children(children, context) {
1579
1593
 
1580
1594
  if (root && initial !== null && template_id !== null) {
1581
1595
  const flags = is_fragment ? b.literal(TEMPLATE_FRAGMENT) : b.literal(0);
1582
- state.final.push(b.stmt(b.call('$.append', b.id('__anchor'), initial)));
1596
+ state.final.push(b.stmt(b.call('_$_.append', b.id('__anchor'), initial)));
1583
1597
  state.hoisted.push(
1584
- b.var(template_id, b.call('$.template', join_template(state.template), flags)),
1598
+ b.var(template_id, b.call('_$_.template', join_template(state.template), flags)),
1585
1599
  );
1586
1600
  }
1587
1601
  }
@@ -1600,7 +1614,7 @@ function transform_body(body, { visit, state }) {
1600
1614
  transform_children(body, { visit, state: body_state, root: true });
1601
1615
 
1602
1616
  if (body_state.update.length > 0) {
1603
- body_state.init.push(b.stmt(b.call('$.render', b.thunk(b.block(body_state.update)))));
1617
+ body_state.init.push(b.stmt(b.call('_$_.render', b.thunk(b.block(body_state.update)))));
1604
1618
  }
1605
1619
 
1606
1620
  return [...body_state.setup, ...body_state.init, ...body_state.final];
@@ -1636,7 +1650,7 @@ export function transform(filename, source, analysis, to_ts) {
1636
1650
  if (state.events.size > 0) {
1637
1651
  program.body.push(
1638
1652
  b.stmt(
1639
- b.call('$.delegate', b.array(Array.from(state.events).map((name) => b.literal(name)))),
1653
+ b.call('_$_.delegate', b.array(Array.from(state.events).map((name) => b.literal(name)))),
1640
1654
  ),
1641
1655
  );
1642
1656
  }
@@ -262,7 +262,7 @@ export class Scope {
262
262
  * @param {Identifier} node
263
263
  * @param {Binding['kind']} kind
264
264
  * @param {DeclarationKind} declaration_kind
265
- * @param {null | Expression | FunctionDeclaration | ClassDeclaration | ImportDeclaration | AST.EachBlock | AST.SnippetBlock} initial
265
+ * @param {null | Expression | FunctionDeclaration | ClassDeclaration | ImportDeclaration} initial
266
266
  * @returns {Binding}
267
267
  */
268
268
  declare(node, kind, declaration_kind, initial = null) {
@@ -276,9 +276,12 @@ export class Scope {
276
276
  }
277
277
  }
278
278
 
279
+ if (node.name === '_$_') {
280
+ throw new Error('Cannot declare a variable named "_$_" as it is a reserved identifier');
281
+ }
282
+
279
283
  if (this.declarations.has(node.name)) {
280
- // This also errors on var/function types, but that's arguably a good thing
281
- e.declaration_duplicate(node, node.name);
284
+ throw new Error(`'${node.name}' has already been declared in the current scope`);
282
285
  }
283
286
 
284
287
  /** @type {Binding} */
@@ -418,6 +418,18 @@ export function is_ripple_import(callee, context) {
418
418
  if (callee.type === 'Identifier') {
419
419
  const binding = context.state.scope.get(callee.name);
420
420
 
421
+ return (
422
+ binding?.declaration_kind === 'import' &&
423
+ binding.initial.source.type === 'Literal' &&
424
+ binding.initial.source.value === 'ripple'
425
+ );
426
+ } else if (
427
+ callee.type === 'MemberExpression' &&
428
+ callee.object.type === 'Identifier' &&
429
+ !callee.computed
430
+ ) {
431
+ const binding = context.state.scope.get(callee.object.name);
432
+
421
433
  return (
422
434
  binding?.declaration_kind === 'import' &&
423
435
  binding.initial.source.type === 'Literal' &&
package/src/utils/ast.js CHANGED
@@ -101,7 +101,7 @@ function _extract_paths(assignments = [], param, expression, update_expression,
101
101
  }
102
102
  }
103
103
 
104
- return b.call('$.exclude_from_object', expression(object), b.array(props));
104
+ return b.call('_$_.exclude_from_object', expression(object), b.array(props));
105
105
  };
106
106
 
107
107
  if (prop.argument.type === 'Identifier') {
@@ -202,7 +202,7 @@ function _extract_paths(assignments = [], param, expression, update_expression,
202
202
  }
203
203
 
204
204
  export function build_fallback(expression, fallback) {
205
- return b.call('$.fallback', expression, fallback);
205
+ return b.call('_$_.fallback', expression, fallback);
206
206
  }
207
207
 
208
208
  /**
@@ -65,7 +65,7 @@ describe('compiler success tests', () => {
65
65
  });
66
66
 
67
67
 
68
- /*it('renders without crashing using < character', () => {
68
+ it('renders without crashing using < character', () => {
69
69
  component App() {
70
70
  function bar() {
71
71
  for (let i = 0; i < 10; i++) {
@@ -80,7 +80,7 @@ describe('compiler success tests', () => {
80
80
  }
81
81
 
82
82
  render(App);
83
- });*/
83
+ });
84
84
 
85
85
  it('render lexical blocks without crashing', () => {
86
86
  component App() {
@@ -240,4 +240,44 @@ describe('compiler success tests', () => {
240
240
 
241
241
  render(App);
242
242
  });
243
+
244
+ it('should not fail with random TS syntax', () => {
245
+ function tagFn() {
246
+ return null;
247
+ }
248
+
249
+ function Wrapper() {
250
+ return {
251
+ unwrap: function<T>() {
252
+ return null as unknown as T;
253
+ }
254
+ }
255
+ }
256
+
257
+ component App() {
258
+ let x: number[] = [] as number[];
259
+
260
+ const n = new Wrapper<number>().unwrap<string>();
261
+
262
+ const tagResult = tagFn`value`;
263
+
264
+ interface Node<T> {
265
+ value: T;
266
+ }
267
+
268
+ class Box<T> {
269
+ value: T;
270
+
271
+ method<T>(): T {
272
+ return this.value;
273
+ }
274
+ }
275
+
276
+ let flag = true;
277
+
278
+ const s = flag ? new Box<number>() : new Box<string>();
279
+ }
280
+
281
+ render(App);
282
+ });
243
283
  });