ripple 0.2.183 → 0.2.185

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.
@@ -1,13 +1,13 @@
1
- /** @import { CustomMappingData, PluginActionOverrides } from 'ripple/compiler'; */
2
- /** @import { DocumentHighlightKind } from 'vscode-languageserver-types'; */
1
+ /**
2
+ @import { CustomMappingData, PluginActionOverrides } from 'ripple/compiler';
3
+ @import { DocumentHighlightKind } from 'vscode-languageserver-types';
4
+ @import * as AST from 'estree';
5
+ @import * as ESTreeJSX from 'estree-jsx';
6
+ @import {MappingData, CodeMapping, VolarMappingsResult} from 'ripple/compiler';
7
+ @import {CodeMapping as VolarCodeMapping} from '@volar/language-core';
8
+ */
3
9
 
4
10
  /**
5
- * @typedef {import('estree').Position} Position
6
- * @typedef {{start: Position, end: Position}} Location
7
- * @typedef {import('@volar/language-core').CodeMapping} VolarCodeMapping
8
- * @typedef {import('ripple/compiler').MappingData} MappingData
9
- * @typedef {import('ripple/compiler').CodeMapping} CodeMapping
10
- * @typedef {import('ripple/compiler').VolarMappingsResult} VolarMappingsResult
11
11
  * @typedef {{
12
12
  * start: number,
13
13
  * end: number,
@@ -61,7 +61,7 @@ function loc_to_offset(line, column, line_offsets) {
61
61
 
62
62
  /**
63
63
  * Extract CSS source regions from style elements in the AST
64
- * @param {any} ast - The parsed AST
64
+ * @param {AST.Node} ast - The parsed AST
65
65
  * @param {string} source - Original source code
66
66
  * @param {number[]} source_line_offsets
67
67
  * @returns {CssSourceRegion[]}
@@ -74,10 +74,14 @@ function extractCssSourceRegions(ast, source, source_line_offsets) {
74
74
  Element(node) {
75
75
  // Check if this is a style element with CSS content
76
76
  if (node.id?.name === 'style' && node.css) {
77
- const openLoc = node.openingElement.loc;
77
+ const openLoc = /** @type {ESTreeJSX.JSXOpeningElement & AST.NodeWithLocation} */ (
78
+ node.openingElement
79
+ ).loc;
78
80
  const cssStart = loc_to_offset(openLoc.end.line, openLoc.end.column, source_line_offsets);
79
81
 
80
- const closeLoc = node.closingElement.loc;
82
+ const closeLoc = /** @type {ESTreeJSX.JSXClosingElement & AST.NodeWithLocation} */ (
83
+ node.closingElement
84
+ ).loc;
81
85
  const cssEnd = loc_to_offset(
82
86
  closeLoc.start.line,
83
87
  closeLoc.start.column,
@@ -102,8 +106,8 @@ function extractCssSourceRegions(ast, source, source_line_offsets) {
102
106
 
103
107
  /**
104
108
  * Create Volar mappings by walking the transformed AST
105
- * @param {any} ast - The transformed AST
106
- * @param {any} ast_from_source - The original AST from source
109
+ * @param {AST.Node} ast - The transformed AST
110
+ * @param {AST.Node} ast_from_source - The original AST from source
107
111
  * @param {string} source - Original source code
108
112
  * @param {string} generated_code - Generated code (returned in output, not used for searching)
109
113
  * @param {object} esrap_source_map - Esrap source map for accurate position lookup
@@ -147,17 +151,18 @@ export function convert_source_map_to_mappings(
147
151
  // All tokens must have source/generated text and loc property for accurate positioning
148
152
  /**
149
153
  * @type {Array<{
150
- * source: string,
154
+ * source: string | null | undefined,
151
155
  * generated: string,
152
156
  * is_full_import_statement?: boolean,
153
- * loc: Location,
154
- * end_loc?: Location,
157
+ * loc: AST.SourceLocation,
158
+ * end_loc?: AST.SourceLocation,
155
159
  * metadata?: PluginActionOverrides
156
160
  * }>}
157
161
  */
158
162
  const tokens = [];
159
163
 
160
164
  // We have to visit everything in generated order to maintain correct indices
165
+
161
166
  walk(ast, null, {
162
167
  _(node, { visit }) {
163
168
  // Collect key node types: Identifiers, Literals, and JSX Elements
@@ -231,7 +236,11 @@ export function convert_source_map_to_mappings(
231
236
  } else if (node.type === 'ImportSpecifier') {
232
237
  // If local and imported are the same, only visit local to avoid duplicates
233
238
  // Otherwise visit both in order
234
- if (node.imported && node.local && node.imported.name !== node.local.name) {
239
+ if (
240
+ node.imported &&
241
+ node.local &&
242
+ /** @type {AST.Identifier} */ (node.imported).name !== node.local.name
243
+ ) {
235
244
  visit(node.imported);
236
245
  visit(node.local);
237
246
  } else if (node.local) {
@@ -250,7 +259,12 @@ export function convert_source_map_to_mappings(
250
259
  } else if (node.type === 'ExportSpecifier') {
251
260
  // If local and exported are the same, only visit local to avoid duplicates
252
261
  // Otherwise visit both in order
253
- if (node.local && node.exported && node.local.name !== node.exported.name) {
262
+ if (
263
+ node.local &&
264
+ node.exported &&
265
+ /** @type {AST.Identifier} */ (node.local).name !==
266
+ /** @type {AST.Identifier} */ (node.exported).name
267
+ ) {
254
268
  visit(node.local);
255
269
  visit(node.exported);
256
270
  } else if (node.local) {
@@ -271,7 +285,7 @@ export function convert_source_map_to_mappings(
271
285
  } else if (node.type === 'ExportDefaultDeclaration') {
272
286
  // Visit the declaration
273
287
  if (node.declaration) {
274
- visit(node.declaration);
288
+ visit(/** @type {AST.Node} */ (node.declaration));
275
289
  }
276
290
  return;
277
291
  } else if (node.type === 'ExportAllDeclaration') {
@@ -357,7 +371,7 @@ export function convert_source_map_to_mappings(
357
371
  // 2. Visit children in order
358
372
  if (node.children) {
359
373
  for (const child of node.children) {
360
- visit(child);
374
+ visit(/** @type {AST.Node} */ (child));
361
375
  }
362
376
  }
363
377
 
@@ -366,7 +380,9 @@ export function convert_source_map_to_mappings(
366
380
  !node.openingElement?.selfClosing &&
367
381
  node.closingElement?.name?.type === 'JSXIdentifier'
368
382
  ) {
369
- const closingNameNode = node.closingElement.name;
383
+ const closingNameNode = /** @type {ESTreeJSX.JSXIdentifier & AST.NodeWithLocation} */ (
384
+ node.closingElement.name
385
+ );
370
386
  if (closingNameNode.metadata?.is_capitalized) {
371
387
  tokens.push({
372
388
  source: closingNameNode.metadata.original_name,
@@ -390,24 +406,25 @@ export function convert_source_map_to_mappings(
390
406
  ) {
391
407
  // Add function/component keyword token
392
408
  if (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression') {
409
+ const node_fn = /** @type (typeof node) & AST.NodeWithLocation */ (node);
393
410
  const source_keyword = node.metadata?.was_component ? 'component' : 'function';
394
411
  // Add token for the keyword - esrap already mapped it via context.write('function', node)
395
412
  tokens.push({
396
413
  source: source_keyword,
397
414
  generated: 'function',
398
415
  loc: {
399
- start: { line: node.loc.start.line, column: node.loc.start.column },
416
+ start: { line: node_fn.loc.start.line, column: node_fn.loc.start.column },
400
417
  end: {
401
- line: node.loc.start.line,
402
- column: node.loc.start.column + source_keyword.length,
418
+ line: node_fn.loc.start.line,
419
+ column: node_fn.loc.start.column + source_keyword.length,
403
420
  },
404
421
  },
405
422
  });
406
423
  }
407
424
 
408
425
  // Visit in source order: id, params, body
409
- if (node.id) {
410
- visit(node.id);
426
+ if (/** @type {AST.FunctionDeclaration | AST.FunctionExpression} */ (node).id) {
427
+ visit(/** @type {AST.FunctionDeclaration | AST.FunctionExpression} */ (node).id);
411
428
  }
412
429
  if (node.params) {
413
430
  for (const param of node.params) {
@@ -478,8 +495,8 @@ export function convert_source_map_to_mappings(
478
495
  visit(node.right);
479
496
  }
480
497
  // Ripple-specific: index variable
481
- if (node.index) {
482
- visit(node.index);
498
+ if (/** @type {AST.ForOfStatement} */ (node).index) {
499
+ visit(/** @type {AST.ForOfStatement} */ (node).index);
483
500
  }
484
501
  if (node.body) {
485
502
  visit(node.body);
@@ -511,14 +528,17 @@ export function convert_source_map_to_mappings(
511
528
  if (node.pending) {
512
529
  // Add a special token for the 'pending' keyword with customData
513
530
  // to suppress TypeScript diagnostics and provide custom hover/definition
531
+ const pending = /** @type {(typeof node.pending) & AST.NodeWithLocation} */ (
532
+ node.pending
533
+ );
514
534
  const pendingKeywordLoc = {
515
535
  start: {
516
- line: node.pending.loc.start.line,
517
- column: node.pending.loc.start.column - 'pending '.length,
536
+ line: pending.loc.start.line,
537
+ column: pending.loc.start.column - 'pending '.length,
518
538
  },
519
539
  end: {
520
- line: node.pending.loc.start.line,
521
- column: node.pending.loc.start.column - 1,
540
+ line: pending.loc.start.line,
541
+ column: pending.loc.start.column - 1,
522
542
  },
523
543
  };
524
544
  tokens.push({
@@ -764,8 +784,8 @@ export function convert_source_map_to_mappings(
764
784
  if (node.argument) {
765
785
  visit(node.argument);
766
786
  // Visit type annotation if present (for RestElement)
767
- if (node.argument.typeAnnotation) {
768
- visit(node.argument.typeAnnotation);
787
+ if (/** @type {AST.Pattern} */ (node.argument).typeAnnotation) {
788
+ visit(/** @type {AST.Pattern} */ (node.argument).typeAnnotation);
769
789
  }
770
790
  }
771
791
  // RestElement itself can have typeAnnotation
@@ -828,7 +848,7 @@ export function convert_source_map_to_mappings(
828
848
  // Visit children in order
829
849
  if (node.children) {
830
850
  for (const child of node.children) {
831
- visit(child);
851
+ visit(/** @type {AST.Node} */ (child));
832
852
  }
833
853
  }
834
854
  return;
@@ -956,10 +976,11 @@ export function convert_source_map_to_mappings(
956
976
  if (node.typeName) {
957
977
  visit(node.typeName);
958
978
  }
959
- // Check both typeParameters and typeArguments (different parsers use different names)
960
- if (node.typeParameters) {
961
- visit(node.typeParameters);
962
- }
979
+
980
+ // typeParameters and typeArguments (different parsers use different names)
981
+ // tsTypeParameters is a bug in the estree-typescript
982
+ // but we fixed in the analyzer to typeArguments.
983
+
963
984
  if (node.typeArguments) {
964
985
  visit(node.typeArguments);
965
986
  }
@@ -1004,8 +1025,13 @@ export function convert_source_map_to_mappings(
1004
1025
  for (const param of node.parameters) {
1005
1026
  visit(param);
1006
1027
  // Visit type annotation on the parameter
1007
- if (param.typeAnnotation) {
1008
- visit(param.typeAnnotation);
1028
+ if (
1029
+ /** @type {Exclude<AST.Parameter, AST.TSParameterProperty>} */ (param).typeAnnotation
1030
+ ) {
1031
+ visit(
1032
+ /** @type {Exclude<AST.Parameter, AST.TSParameterProperty>} */ (param)
1033
+ .typeAnnotation,
1034
+ );
1009
1035
  }
1010
1036
  }
1011
1037
  }
@@ -1042,8 +1068,13 @@ export function convert_source_map_to_mappings(
1042
1068
  for (const param of node.parameters) {
1043
1069
  visit(param);
1044
1070
  // Visit type annotation on the parameter
1045
- if (param.typeAnnotation) {
1046
- visit(param.typeAnnotation);
1071
+ if (
1072
+ /** @type {Exclude<AST.Parameter, AST.TSParameterProperty>} */ (param).typeAnnotation
1073
+ ) {
1074
+ visit(
1075
+ /** @type {Exclude<AST.Parameter, AST.TSParameterProperty>} */ (param)
1076
+ .typeAnnotation,
1077
+ );
1047
1078
  }
1048
1079
  }
1049
1080
  }
@@ -1057,8 +1088,13 @@ export function convert_source_map_to_mappings(
1057
1088
  for (const param of node.parameters) {
1058
1089
  visit(param);
1059
1090
  // Visit type annotation on the parameter
1060
- if (param.typeAnnotation) {
1061
- visit(param.typeAnnotation);
1091
+ if (
1092
+ /** @type {Exclude<AST.Parameter, AST.TSParameterProperty>} */ (param).typeAnnotation
1093
+ ) {
1094
+ visit(
1095
+ /** @type {Exclude<AST.Parameter, AST.TSParameterProperty>} */ (param)
1096
+ .typeAnnotation,
1097
+ );
1062
1098
  }
1063
1099
  }
1064
1100
  }
@@ -1078,8 +1114,13 @@ export function convert_source_map_to_mappings(
1078
1114
  for (const param of node.parameters) {
1079
1115
  visit(param);
1080
1116
  // Visit type annotation on the parameter
1081
- if (param.typeAnnotation) {
1082
- visit(param.typeAnnotation);
1117
+ if (
1118
+ /** @type {Exclude<AST.Parameter, AST.TSParameterProperty>} */ (param).typeAnnotation
1119
+ ) {
1120
+ visit(
1121
+ /** @type {Exclude<AST.Parameter, AST.TSParameterProperty>} */ (param)
1122
+ .typeAnnotation,
1123
+ );
1083
1124
  }
1084
1125
  }
1085
1126
  }
@@ -1170,6 +1211,9 @@ export function convert_source_map_to_mappings(
1170
1211
  if (node.exprName) {
1171
1212
  visit(node.exprName);
1172
1213
  }
1214
+ if (node.typeArguments) {
1215
+ visit(node.typeArguments);
1216
+ }
1173
1217
  return;
1174
1218
  } else if (node.type === 'TSInterfaceDeclaration') {
1175
1219
  // Interface declaration
@@ -1327,7 +1371,7 @@ export function convert_source_map_to_mappings(
1327
1371
  });
1328
1372
 
1329
1373
  for (const token of tokens) {
1330
- const source_text = token.source;
1374
+ const source_text = token.source ?? '';
1331
1375
  const gen_text = token.generated;
1332
1376
 
1333
1377
  const source_start = loc_to_offset(
@@ -1344,7 +1388,7 @@ export function convert_source_map_to_mappings(
1344
1388
  let gen_start;
1345
1389
 
1346
1390
  if (token.is_full_import_statement) {
1347
- const end_loc = /** @type {Location} */ (token.end_loc).end;
1391
+ const end_loc = /** @type {AST.SourceLocation} */ (token.end_loc).end;
1348
1392
  const source_end = loc_to_offset(end_loc.line, end_loc.column, source_line_offsets);
1349
1393
 
1350
1394
  // Look up where import keyword and source literal map to in generated code
@@ -16,6 +16,7 @@ import { walk } from 'zimmerframe';
16
16
  import ts from 'esrap/languages/ts';
17
17
  import path from 'node:path';
18
18
  import { print } from 'esrap';
19
+ import is_reference from 'is-reference';
19
20
  import {
20
21
  determine_namespace_for_children,
21
22
  escape_html,
@@ -30,17 +31,6 @@ import { is_event_attribute } from '../../../../utils/events.js';
30
31
  import { render_stylesheets } from '../stylesheet.js';
31
32
  import { createHash } from 'node:crypto';
32
33
 
33
- /**
34
- * @param {TransformServerContext} context
35
- */
36
- function add_ripple_internal_import(context) {
37
- if (!context.state.to_ts) {
38
- if (!context.state.imports.has(`import * as _$_ from 'ripple/internal/server'`)) {
39
- context.state.imports.add(`import * as _$_ from 'ripple/internal/server'`);
40
- }
41
- }
42
- }
43
-
44
34
  /**
45
35
  * @param {AST.Node[]} children
46
36
  * @param {TransformServerContext} context
@@ -110,8 +100,31 @@ const visitors = {
110
100
  }
111
101
  },
112
102
 
103
+ Identifier(node, context) {
104
+ const parent = /** @type {AST.Node} */ (context.path.at(-1));
105
+
106
+ if (is_reference(node, parent) && node.tracked) {
107
+ const is_right_side_of_assignment =
108
+ parent.type === 'AssignmentExpression' && parent.right === node;
109
+ if (
110
+ (parent.type !== 'AssignmentExpression' && parent.type !== 'UpdateExpression') ||
111
+ is_right_side_of_assignment
112
+ ) {
113
+ return b.call('_$_.get', node);
114
+ }
115
+ }
116
+ },
117
+
113
118
  Component(node, context) {
114
- add_ripple_internal_import(context);
119
+ if (node.params.length > 0) {
120
+ let props_param = node.params[0];
121
+
122
+ if (props_param.type === 'Identifier') {
123
+ delete props_param.typeAnnotation;
124
+ } else if (props_param.type === 'ObjectPattern') {
125
+ delete props_param.typeAnnotation;
126
+ }
127
+ }
115
128
 
116
129
  const metadata = { await: false };
117
130
  const body_statements = [
@@ -608,23 +621,32 @@ const visitors = {
608
621
  if (!is_inside_component(context)) {
609
622
  return context.next();
610
623
  }
624
+
611
625
  const cases = [];
626
+
612
627
  for (const switch_case of node.cases) {
613
- const consequent_scope =
614
- context.state.scopes.get(switch_case.consequent) || context.state.scope;
615
- const consequent = b.block(
616
- transform_body(switch_case.consequent, {
617
- ...context,
618
- state: { ...context.state, scope: consequent_scope },
619
- }),
620
- );
628
+ const case_body = [];
629
+
630
+ if (switch_case.consequent.length !== 0) {
631
+ const consequent_scope =
632
+ context.state.scopes.get(switch_case.consequent) || context.state.scope;
633
+ const consequent = b.block(
634
+ transform_body(switch_case.consequent, {
635
+ ...context,
636
+ state: { ...context.state, scope: consequent_scope },
637
+ }),
638
+ );
639
+ case_body.push(...consequent.body);
640
+ }
641
+
621
642
  cases.push(
622
643
  b.switch_case(
623
644
  switch_case.test ? /** @type {AST.Expression} */ (context.visit(switch_case.test)) : null,
624
- consequent.body,
645
+ case_body,
625
646
  ),
626
647
  );
627
648
  }
649
+
628
650
  context.state.init?.push(
629
651
  b.switch(/** @type {AST.Expression} */ (context.visit(node.discriminant)), cases),
630
652
  );
@@ -698,17 +720,91 @@ const visitors = {
698
720
  AssignmentExpression(node, context) {
699
721
  const left = node.left;
700
722
 
723
+ if (
724
+ left.type === 'MemberExpression' &&
725
+ (left.tracked || (left.property.type === 'Identifier' && left.property.tracked))
726
+ ) {
727
+ const operator = node.operator;
728
+ const right = node.right;
729
+
730
+ return b.call(
731
+ '_$_.set_property',
732
+ /** @type {AST.Expression} */ (context.visit(left.object)),
733
+ left.computed
734
+ ? /** @type {AST.Expression} */ (context.visit(left.property))
735
+ : b.literal(/** @type {AST.Identifier} */ (left.property).name),
736
+ operator === '='
737
+ ? /** @type {AST.Expression} */ (context.visit(right))
738
+ : b.binary(
739
+ operator === '+=' ? '+' : operator === '-=' ? '-' : operator === '*=' ? '*' : '/',
740
+ b.call(
741
+ '_$_.get_property',
742
+ /** @type {AST.Expression} */ (context.visit(left.object)),
743
+ left.computed
744
+ ? /** @type {AST.Expression} */ (context.visit(left.property))
745
+ : b.literal(/** @type {AST.Identifier} */ (left.property).name),
746
+ undefined,
747
+ ),
748
+ /** @type {AST.Expression} */ (context.visit(right)),
749
+ ),
750
+ );
751
+ }
752
+
701
753
  if (left.type === 'Identifier' && left.tracked) {
754
+ const operator = node.operator;
755
+ const right = node.right;
756
+
757
+ return b.call(
758
+ '_$_.set',
759
+ /** @type {AST.Expression} */ (context.visit(left)),
760
+ operator === '='
761
+ ? /** @type {AST.Expression} */ (context.visit(right))
762
+ : b.binary(
763
+ operator === '+=' ? '+' : operator === '-=' ? '-' : operator === '*=' ? '*' : '/',
764
+ b.call('_$_.get', left),
765
+ /** @type {AST.Expression} */ (context.visit(right)),
766
+ ),
767
+ );
768
+ }
769
+
770
+ return context.next();
771
+ },
772
+
773
+ UpdateExpression(node, context) {
774
+ const argument = node.argument;
775
+
776
+ if (
777
+ argument.type === 'MemberExpression' &&
778
+ (argument.tracked || (argument.property.type === 'Identifier' && argument.property.tracked))
779
+ ) {
702
780
  return b.call(
703
- 'set',
781
+ node.prefix ? '_$_.update_pre_property' : '_$_.update_property',
704
782
  /** @type {AST.Expression} */
705
- (context.visit(left, { ...context.state, metadata: { tracking: false } })),
783
+ (context.visit(argument.object, { ...context.state, metadata: { tracking: false } })),
784
+ argument.computed
785
+ ? /** @type {AST.Expression} */ (context.visit(argument.property))
786
+ : b.literal(/** @type {AST.Identifier} */ (argument.property).name),
787
+ node.operator === '--' ? b.literal(-1) : undefined,
788
+ );
789
+ }
790
+
791
+ if (argument.type === 'Identifier' && argument.tracked) {
792
+ return b.call(
793
+ node.prefix ? '_$_.update_pre' : '_$_.update',
706
794
  /** @type {AST.Expression} */
707
- (context.visit(node.right)),
795
+ (context.visit(argument)),
796
+ node.operator === '--' ? b.literal(-1) : undefined,
708
797
  );
709
798
  }
710
799
 
711
- return context.next();
800
+ if (argument.type === 'TrackedExpression') {
801
+ return b.call(
802
+ node.prefix ? '_$_.update_pre' : '_$_.update',
803
+ /** @type {AST.Expression} */
804
+ (context.visit(argument.argument)),
805
+ node.operator === '--' ? b.literal(-1) : undefined,
806
+ );
807
+ }
712
808
  },
713
809
 
714
810
  ServerIdentifier(node, context) {
@@ -832,6 +928,10 @@ const visitors = {
832
928
  return b.await(/** @type {AST.AwaitExpression} */ (context.visit(node.argument)));
833
929
  },
834
930
 
931
+ TrackedExpression(node, context) {
932
+ return b.call('_$_.get', /** @type {AST.Expression} */ (context.visit(node.argument)));
933
+ },
934
+
835
935
  TrackedObjectExpression(node, context) {
836
936
  // For SSR, we just evaluate the object as-is since there's no reactivity
837
937
  return b.object(
@@ -852,20 +952,14 @@ const visitors = {
852
952
  },
853
953
 
854
954
  MemberExpression(node, context) {
855
- const parent = context.path.at(-1);
856
-
857
955
  if (node.tracked || (node.property.type === 'Identifier' && node.property.tracked)) {
858
956
  return b.call(
859
- 'get',
860
- b.member(
861
- /** @type {AST.Expression} */
862
- (context.visit(node.object)),
863
- node.computed
864
- ? /** @type {AST.Expression} */ (context.visit(node.property))
865
- : node.property,
866
- node.computed,
867
- node.optional,
868
- ),
957
+ '_$_.get_property',
958
+ /** @type {AST.Expression} */ (context.visit(node.object)),
959
+ node.computed
960
+ ? /** @type {AST.Expression} */ (context.visit(node.property))
961
+ : b.literal(/** @type {AST.Identifier} */ (node.property).name),
962
+ node.optional ? b.true : undefined,
869
963
  );
870
964
  }
871
965
 
@@ -877,7 +971,7 @@ const visitors = {
877
971
  let expression = /** @type {AST.Expression} */ (visit(node.expression, { ...state, metadata }));
878
972
 
879
973
  if (expression.type === 'Identifier' && expression.tracked) {
880
- expression = b.call('get', expression);
974
+ expression = b.call('_$_.get', expression);
881
975
  }
882
976
 
883
977
  if (expression.type === 'Literal') {
@@ -975,6 +1069,8 @@ export function transform_server(filename, source, analysis, minify_css) {
975
1069
  metadata: {},
976
1070
  };
977
1071
 
1072
+ state.imports.add(`import * as _$_ from 'ripple/internal/server'`);
1073
+
978
1074
  const program = walk(analysis.ast, { ...state }, visitors);
979
1075
 
980
1076
  const css = render_stylesheets(state.stylesheets, minify_css);
@@ -993,17 +1089,11 @@ export function transform_server(filename, source, analysis, minify_css) {
993
1089
  }
994
1090
 
995
1091
  // Add async property to component functions
996
-
997
1092
  for (const import_node of state.imports) {
998
1093
  /** @type {AST.Program} */ (program).body.unshift(b.stmt(b.id(import_node)));
999
1094
  }
1000
1095
 
1001
- // ESRap unfortunately hard codes the type from '@typescript-eslint/types'
1002
- // Our types from 'estree' are incompatible
1003
- // So we'll just give it what it wants with an unknown cast.
1004
- // Functionally, none of the properties that are different between the two types
1005
- // are used by the printer, so this is safe.
1006
- const js = print(/** @type {TSESTree.Node} */ (/** @type {unknown} */ (program)), ts(), {
1096
+ const js = print(program, /** @type {Visitors<AST.Node, TransformServerState>} */ (ts()), {
1007
1097
  sourceMapContent: source,
1008
1098
  sourceMapSource: path.basename(filename),
1009
1099
  });
@@ -1,5 +1,12 @@
1
- /** @import { Binding, ScopeInterface, ScopeRoot as ScopeRootInterface } from '#compiler' */
2
- /** @import * as AST from 'estree' */
1
+ /**
2
+ @import {
3
+ Binding,
4
+ ScopeInterface,
5
+ ScopeRoot as ScopeRootInterface,
6
+ Context
7
+ } from '#compiler';
8
+ @import * as AST from 'estree';
9
+ */
3
10
 
4
11
  import is_reference from 'is-reference';
5
12
  import { extract_identifiers, object, unwrap_pattern } from '../utils/ast.js';
@@ -45,7 +52,7 @@ export function create_scopes(ast, root, parent) {
45
52
  /**
46
53
  * Create a block scope
47
54
  * @param {AST.Node} node - AST node
48
- * @param {{ state: any, next: Function }} context - Visitor context
55
+ * @param {Context<AST.Node, State>} context - Visitor context
49
56
  */
50
57
  const create_block_scope = (node, { state, next }) => {
51
58
  const scope = state.scope.child(true);
@@ -60,7 +67,7 @@ export function create_scopes(ast, root, parent) {
60
67
  next({ scope });
61
68
  };
62
69
 
63
- walk(/** @type {AST.Node} */ (ast), state, {
70
+ walk(ast, state, {
64
71
  // references
65
72
  Identifier(node, { path, state }) {
66
73
  const parent = path.at(-1);
@@ -95,12 +102,6 @@ export function create_scopes(ast, root, parent) {
95
102
  }
96
103
  },
97
104
 
98
- /**
99
- * @param {AST.Component} node
100
- * @param {Object} context
101
- * @param {any} context.state
102
- * @param {Function} context.next
103
- */
104
105
  Component(node, { state, next }) {
105
106
  const scope = state.scope.child();
106
107
  scopes.set(node, scope);
@@ -114,12 +115,6 @@ export function create_scopes(ast, root, parent) {
114
115
  next({ scope });
115
116
  },
116
117
 
117
- /**
118
- * @param {AST.Element} node
119
- * @param {Object} context
120
- * @param {any} context.state
121
- * @param {Function} context.next
122
- */
123
118
  Element(node, { state, next }) {
124
119
  const scope = state.scope.child();
125
120
  scopes.set(node, scope);