@openrewrite/rewrite 8.66.2 → 8.66.4

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.
Files changed (38) hide show
  1. package/dist/java/type.d.ts +6 -3
  2. package/dist/java/type.d.ts.map +1 -1
  3. package/dist/java/type.js +51 -5
  4. package/dist/java/type.js.map +1 -1
  5. package/dist/javascript/add-import.d.ts +18 -2
  6. package/dist/javascript/add-import.d.ts.map +1 -1
  7. package/dist/javascript/add-import.js +49 -15
  8. package/dist/javascript/add-import.js.map +1 -1
  9. package/dist/javascript/format.d.ts +1 -0
  10. package/dist/javascript/format.d.ts.map +1 -1
  11. package/dist/javascript/format.js +45 -2
  12. package/dist/javascript/format.js.map +1 -1
  13. package/dist/javascript/parser.d.ts +2 -1
  14. package/dist/javascript/parser.d.ts.map +1 -1
  15. package/dist/javascript/parser.js +7 -3
  16. package/dist/javascript/parser.js.map +1 -1
  17. package/dist/javascript/remove-import.d.ts +20 -2
  18. package/dist/javascript/remove-import.d.ts.map +1 -1
  19. package/dist/javascript/remove-import.js +121 -11
  20. package/dist/javascript/remove-import.js.map +1 -1
  21. package/dist/javascript/type-mapping.d.ts +17 -0
  22. package/dist/javascript/type-mapping.d.ts.map +1 -1
  23. package/dist/javascript/type-mapping.js +241 -44
  24. package/dist/javascript/type-mapping.js.map +1 -1
  25. package/dist/rpc/rewrite-rpc.js +1 -1
  26. package/dist/rpc/rewrite-rpc.js.map +1 -1
  27. package/dist/rpc/server.js +1 -1
  28. package/dist/rpc/server.js.map +1 -1
  29. package/dist/version.txt +1 -1
  30. package/package.json +1 -1
  31. package/src/java/type.ts +57 -5
  32. package/src/javascript/add-import.ts +55 -15
  33. package/src/javascript/format.ts +44 -3
  34. package/src/javascript/parser.ts +7 -3
  35. package/src/javascript/remove-import.ts +114 -11
  36. package/src/javascript/type-mapping.ts +282 -56
  37. package/src/rpc/rewrite-rpc.ts +1 -1
  38. package/src/rpc/server.ts +1 -1
@@ -24,12 +24,17 @@ class NonDraftableType {
24
24
  }
25
25
 
26
26
  export class JavaScriptTypeMapping {
27
+ // Primary cache: Use type signatures (preferring type.id) as cache keys
28
+ // TypeScript assigns stable IDs to all types, so we don't need secondary caches
27
29
  private readonly typeCache: Map<string | number, Type> = new Map();
30
+ private readonly methodCache: Map<ts.Signature, Type.Method> = new Map();
31
+
28
32
  private readonly regExpSymbol: ts.Symbol | undefined;
29
33
  private readonly stringWrapperType: ts.Type | undefined;
30
34
  private readonly numberWrapperType: ts.Type | undefined;
31
35
  private readonly booleanWrapperType: ts.Type | undefined;
32
36
 
37
+
33
38
  constructor(
34
39
  private readonly checker: ts.TypeChecker
35
40
  ) {
@@ -70,21 +75,120 @@ export class JavaScriptTypeMapping {
70
75
  }
71
76
 
72
77
  private getType(type: ts.Type): Type {
78
+ // Check for error types first - these indicate type-checking failures
79
+ // and should not be processed further
80
+ if (type.flags & ts.TypeFlags.Any) {
81
+ const intrinsicName = (type as any).intrinsicName;
82
+ if (intrinsicName === 'error') {
83
+ return Type.unknownType;
84
+ }
85
+ }
86
+
87
+ // Skip problematic type constructs EARLY - before any caching or recursion
88
+ // These can cause deep recursion and are often computed/structural types
89
+ if (type.flags & ts.TypeFlags.Object) {
90
+ const objectFlags = (type as ts.ObjectType).objectFlags;
91
+ // Always skip mapped types (e.g., { [K in keyof T]: ... })
92
+ // These are structural/computed types that can cause infinite recursion
93
+ if (objectFlags & ts.ObjectFlags.Mapped) {
94
+ return Type.unknownType;
95
+ }
96
+ // Skip instantiated types ONLY if they're not type references
97
+ // Type references like Array<string>, Promise<T> are instantiated but should be mapped
98
+ // Other instantiated types (like object literals) should return unknown
99
+ if (objectFlags & ts.ObjectFlags.Instantiated) {
100
+ const isTypeReference = objectFlags & ts.ObjectFlags.Reference;
101
+ if (!isTypeReference) {
102
+ return Type.unknownType;
103
+ }
104
+ }
105
+ }
106
+ // Always skip conditional types (T extends U ? X : Y)
107
+ if (type.flags & ts.TypeFlags.Conditional) {
108
+ return Type.unknownType;
109
+ }
110
+
111
+ // Check cache using signature (type.id when available)
73
112
  const signature = this.getSignature(type);
74
113
  const existing = this.typeCache.get(signature);
75
114
  if (existing) {
76
115
  return existing;
77
116
  }
78
117
 
118
+ // Get symbol for later use in type detection
119
+ const symbol = type.getSymbol?.();
120
+
121
+ // IMPORTANT: Check if this is a type reference to a parameterized type FIRST
122
+ if (type.flags & ts.TypeFlags.Object) {
123
+ const objectType = type as ts.ObjectType;
124
+ const isTypeReference = objectType.objectFlags & ts.ObjectFlags.Reference;
125
+
126
+ if (isTypeReference) {
127
+ const typeRef = type as ts.TypeReference;
128
+ const hasTypeArgs = typeRef.typeArguments && typeRef.typeArguments.length > 0;
129
+
130
+ if (hasTypeArgs) {
131
+ // This is a parameterized type reference (e.g., RefObject<HTMLButtonElement>)
132
+ // Extract the base class type and type arguments to create a Parameterized type
133
+
134
+ // IMPORTANT: Check if the type arguments are actually type parameters (unsubstituted)
135
+ // This happens when TypeScript expands type aliases but doesn't substitute the type parameters
136
+ // For example, React.Ref<HTMLButtonElement> expands to RefObject<T> | RefCallback<T> | null
137
+ // instead of RefObject<HTMLButtonElement> | RefCallback<HTMLButtonElement> | null
138
+ const hasUnsubstitutedTypeParams = typeRef.typeArguments!.some((arg: any) =>
139
+ (arg as ts.Type).flags & ts.TypeFlags.TypeParameter
140
+ );
141
+
142
+ if (!hasUnsubstitutedTypeParams) {
143
+ // Only create parameterized type if type arguments are actual types, not type parameters
144
+
145
+ if (symbol && (symbol.flags & (ts.SymbolFlags.Class | ts.SymbolFlags.Interface | ts.SymbolFlags.TypeAlias))) {
146
+ const declaredType = this.checker.getDeclaredTypeOfSymbol(symbol);
147
+
148
+ // Get or create the base class type (this gets cached)
149
+ const declaredSig = this.getSignature(declaredType);
150
+ let classType = this.typeCache.get(declaredSig) as Type.Class | undefined;
151
+ if (!classType) {
152
+ classType = this.createEmptyClassType(declaredType);
153
+ this.typeCache.set(declaredSig, classType);
154
+ this.populateClassType(classType, declaredType);
155
+ }
156
+
157
+ // Resolve type arguments
158
+ const typeParameters: Type[] = [];
159
+ for (const typeArg of typeRef.typeArguments!) {
160
+ const resolvedArg = this.getType(typeArg as ts.Type);
161
+ typeParameters.push(resolvedArg);
162
+ }
163
+
164
+ // Create the parameterized type wrapper
165
+ const parameterized = Object.assign(new NonDraftableType(), {
166
+ kind: Type.Kind.Parameterized,
167
+ type: classType,
168
+ typeParameters: typeParameters,
169
+ fullyQualifiedName: classType.fullyQualifiedName,
170
+ toJSON: function () {
171
+ return Type.signature(this);
172
+ }
173
+ }) as Type.Parameterized;
174
+
175
+ // Cache the parameterized type
176
+ this.typeCache.set(signature, parameterized);
177
+ return parameterized;
178
+ }
179
+ }
180
+ }
181
+ }
182
+ }
183
+
79
184
  // Check for class/interface/enum types (including arrays)
80
185
  // Arrays in JavaScript are objects with methods, so we treat them as class types
81
- const symbol = type.getSymbol?.();
82
186
  if (symbol) {
83
187
  // Check for function symbols
84
188
  if (symbol.flags & ts.SymbolFlags.Function) {
85
189
  const callSignatures = type.getCallSignatures();
86
190
  if (callSignatures.length > 0) {
87
- // Create and cache shell first to handle circular references
191
+ // Shell-cache: Create stub, cache it, then populate (prevents cycles)
88
192
  const functionType = this.createEmptyFunctionType();
89
193
  this.typeCache.set(signature, functionType);
90
194
  this.populateFunctionType(functionType, callSignatures[0]);
@@ -96,7 +200,7 @@ export class JavaScriptTypeMapping {
96
200
  if (symbol.flags & (ts.SymbolFlags.FunctionScopedVariable | ts.SymbolFlags.BlockScopedVariable)) {
97
201
  const callSignatures = type.getCallSignatures();
98
202
  if (callSignatures.length > 0) {
99
- // Create and cache shell first to handle circular references
203
+ // Shell-cache: Create stub, cache it, then populate (prevents cycles)
100
204
  const functionType = this.createEmptyFunctionType();
101
205
  this.typeCache.set(signature, functionType);
102
206
  this.populateFunctionType(functionType, callSignatures[0]);
@@ -104,19 +208,60 @@ export class JavaScriptTypeMapping {
104
208
  }
105
209
  }
106
210
 
107
- if (symbol.flags & (ts.SymbolFlags.Class | ts.SymbolFlags.Interface | ts.SymbolFlags.Enum | ts.SymbolFlags.TypeAlias)) {
108
- // Create and cache shell first to handle circular references
211
+ if (symbol.flags & ts.SymbolFlags.ValueModule) {
109
212
  const classType = this.createEmptyClassType(type);
110
213
  this.typeCache.set(signature, classType);
111
214
  this.populateClassType(classType, type);
112
215
  return classType;
113
216
  }
217
+ if (symbol.flags & (ts.SymbolFlags.Class | ts.SymbolFlags.Interface | ts.SymbolFlags.Enum | ts.SymbolFlags.TypeAlias | ts.SymbolFlags.ValueModule)) {
218
+ // Get the declared type from the symbol (analogous to symType = sym.type in Java)
219
+ // This is the base class type without specific type arguments
220
+ const declaredType = this.checker.getDeclaredTypeOfSymbol(symbol);
221
+ const declaredSig = this.getSignature(declaredType);
222
+
223
+ let classType = this.typeCache.get(declaredSig) as Type.Class | undefined;
224
+
225
+ if (!classType) {
226
+ // Shell-cache: Create stub, cache it, then populate (prevents cycles)
227
+ classType = this.createEmptyClassType(declaredType);
228
+ this.typeCache.set(declaredSig, classType);
229
+ this.populateClassType(classType, declaredType);
230
+ }
231
+
232
+ // Return the base class type (parameterized types are handled at the beginning of getType)
233
+ return classType;
234
+ }
235
+
236
+ if (symbol.flags & ts.SymbolFlags.TypeParameter) {
237
+ return this.createGenericTypeVariable(type as ts.TypeParameter, signature);
238
+ }
239
+ }
240
+
241
+ // Note on type aliases with type arguments (e.g., React.Ref<HTMLButtonElement>):
242
+ // TypeScript automatically substitutes type parameters when resolving type aliases.
243
+ // For example, React.Ref<T> = RefCallback<T> | RefObject<T> | null
244
+ // When we encounter Ref<HTMLButtonElement>, TypeScript gives us:
245
+ // RefCallback<HTMLButtonElement> | RefObject<HTMLButtonElement> | null
246
+ // The type parameters are already correctly substituted in the constituent types,
247
+ // so we can just process the resolved type normally (falling through to union handling below).
248
+
249
+ // Check for union types (e.g., string | number)
250
+ if (type.flags & ts.TypeFlags.Union) {
251
+ const unionType = type as ts.UnionType;
252
+ return this.createUnionType(unionType, signature);
253
+ }
254
+
255
+ // Check for intersection types (e.g., A & B)
256
+ if (type.flags & ts.TypeFlags.Intersection) {
257
+ const intersectionType = type as ts.IntersectionType;
258
+ return this.createIntersectionType(intersectionType, signature);
114
259
  }
115
260
 
116
261
  // Check for function types without symbols (anonymous functions, function types)
117
262
  const callSignatures = type.getCallSignatures();
118
- if (callSignatures.length > 0) {
119
- // Function type - create and cache shell first to handle circular references
263
+ if (callSignatures && callSignatures.length > 0) {
264
+ // Shell-cache: Create stub, cache it, then populate (prevents cycles)
120
265
  const functionType = this.createEmptyFunctionType();
121
266
  this.typeCache.set(signature, functionType);
122
267
  this.populateFunctionType(functionType, callSignatures[0]);
@@ -127,11 +272,7 @@ export class JavaScriptTypeMapping {
127
272
  if (type.flags & ts.TypeFlags.Object) {
128
273
  const objectFlags = (type as ts.ObjectType).objectFlags;
129
274
  if (objectFlags & ts.ObjectFlags.Anonymous) {
130
- // Anonymous object type - create and cache shell, then populate
131
- const classType = this.createEmptyClassType(type);
132
- this.typeCache.set(signature, classType);
133
- this.populateClassType(classType, type);
134
- return classType;
275
+ return Type.unknownType;
135
276
  }
136
277
  }
137
278
 
@@ -143,6 +284,7 @@ export class JavaScriptTypeMapping {
143
284
 
144
285
  private getSignature(type: ts.Type): string | number {
145
286
  // Try to use TypeScript's internal id if available
287
+ // TypeScript assigns stable IDs to all types, including parameterized, union, and intersection types
146
288
  if ("id" in type && type.id !== undefined) {
147
289
  return type.id as number;
148
290
  }
@@ -198,6 +340,13 @@ export class JavaScriptTypeMapping {
198
340
  name: string,
199
341
  declaredFormalTypeNames: string[] = []
200
342
  ): Type.Method {
343
+ // Use signature object directly as cache key
344
+ // TypeScript's Compiler API reuses signature objects, giving us ~74% cache hit rate
345
+ const cached = this.methodCache.get(signature);
346
+ if (cached) {
347
+ return cached;
348
+ }
349
+
201
350
  const returnType = signature.getReturnType();
202
351
  const parameters = signature.getParameters();
203
352
  const parameterTypes: Type[] = [];
@@ -210,7 +359,7 @@ export class JavaScriptTypeMapping {
210
359
  }
211
360
 
212
361
  // Create the Type.Method object
213
- return Object.assign(new NonDraftableType(), {
362
+ const method = Object.assign(new NonDraftableType(), {
214
363
  kind: Type.Kind.Method,
215
364
  flags: 0, // FIXME - determine flags
216
365
  declaringType: declaringType,
@@ -226,14 +375,17 @@ export class JavaScriptTypeMapping {
226
375
  return Type.signature(this);
227
376
  }
228
377
  }) as Type.Method;
378
+
379
+ this.methodCache.set(signature, method);
380
+ return method;
229
381
  }
230
382
 
231
383
  private wrapperType(declaringType: (Type.FullyQualified & Type.Primitive) | Type.FullyQualified) {
232
- if (declaringType == Type.Primitive.String && this.stringWrapperType) {
384
+ if (declaringType === Type.Primitive.String && this.stringWrapperType) {
233
385
  return this.getType(this.stringWrapperType) as Type.FullyQualified;
234
- } else if ((declaringType == Type.Primitive.Double || declaringType == Type.Primitive.BigInt) && this.numberWrapperType) {
386
+ } else if ((declaringType === Type.Primitive.Double || declaringType === Type.Primitive.BigInt) && this.numberWrapperType) {
235
387
  return this.getType(this.numberWrapperType) as Type.FullyQualified;
236
- } else if (declaringType == Type.Primitive.Boolean && this.booleanWrapperType) {
388
+ } else if (declaringType === Type.Primitive.Boolean && this.booleanWrapperType) {
237
389
  return this.getType(this.booleanWrapperType) as Type.FullyQualified;
238
390
  } else {
239
391
  // This should not really happen, but we'll fallback to unknown if needed
@@ -361,6 +513,9 @@ export class JavaScriptTypeMapping {
361
513
  } else {
362
514
  declaringType = mappedType as Type.FullyQualified;
363
515
  }
516
+ } else if (mappedType && mappedType.kind === Type.Kind.Parameterized) {
517
+ // For parameterized types (e.g., Array<string>, number[]), use the base class type
518
+ declaringType = (mappedType as Type.Parameterized).type;
364
519
  } else if (mappedType && mappedType.kind === Type.Kind.Primitive) {
365
520
  // Box the primitive to its wrapper type
366
521
  declaringType = this.wrapperType(mappedType as Type.Primitive);
@@ -389,18 +544,18 @@ export class JavaScriptTypeMapping {
389
544
  methodName = node.expression.getText();
390
545
 
391
546
  // Check if this is an import first
392
- const symbol = this.checker.getSymbolAtLocation(node.expression);
547
+ const exprSymbol = this.checker.getSymbolAtLocation(node.expression);
393
548
  let moduleSpecifier: string | undefined;
394
549
  let aliasedSymbol: ts.Symbol | undefined;
395
550
 
396
- if (symbol) {
551
+ if (exprSymbol) {
397
552
  // Check if this is an aliased symbol (i.e., an import)
398
- if (symbol.flags & ts.SymbolFlags.Alias) {
399
- aliasedSymbol = this.checker.getAliasedSymbol(symbol);
553
+ if (exprSymbol.flags & ts.SymbolFlags.Alias) {
554
+ aliasedSymbol = this.checker.getAliasedSymbol(exprSymbol);
400
555
  }
401
556
 
402
557
  // If getAliasedSymbol returns something different, it's an import
403
- if (aliasedSymbol && aliasedSymbol !== symbol) {
558
+ if (aliasedSymbol && aliasedSymbol !== exprSymbol) {
404
559
  // This is definitely an imported symbol
405
560
  const aliasedParentSymbol = (aliasedSymbol as any).parent as ts.Symbol | undefined;
406
561
 
@@ -411,8 +566,8 @@ export class JavaScriptTypeMapping {
411
566
  moduleSpecifier = aliasedParentSymbol.name;
412
567
  } else {
413
568
  // Now find the import declaration to get the module specifier
414
- if (symbol.declarations && symbol.declarations.length > 0) {
415
- let importNode: ts.Node = symbol.declarations[0];
569
+ if (exprSymbol.declarations && exprSymbol.declarations.length > 0) {
570
+ let importNode: ts.Node = exprSymbol.declarations[0];
416
571
 
417
572
  // Traverse up to find the ImportDeclaration
418
573
  while (importNode && !ts.isImportDeclaration(importNode)) {
@@ -744,8 +899,12 @@ export class JavaScriptTypeMapping {
744
899
  // Additional base types are interfaces
745
900
  if (classType.classKind === Type.Class.Kind.Class) {
746
901
  const firstBase = this.getType(baseTypes[0]);
902
+ // Handle both Class and Parameterized (e.g., Component<Props>)
747
903
  if (Type.isClass(firstBase)) {
748
904
  (classType as any).supertype = firstBase;
905
+ } else if (Type.isParameterized(firstBase)) {
906
+ // For parameterized types, use the base class as the supertype
907
+ (classType as any).supertype = (firstBase as Type.Parameterized).type;
749
908
  }
750
909
  // Rest are interfaces
751
910
  for (let i = 1; i < baseTypes.length; i++) {
@@ -829,46 +988,23 @@ export class JavaScriptTypeMapping {
829
988
  }
830
989
 
831
990
  // Check for primitive types
832
- if (type.flags === ts.TypeFlags.Null) {
991
+ // Note: Using bitwise & instead of === for robustness, as TypeScript may assign
992
+ // multiple flags to a single type (e.g., Boolean + Union)
993
+ if (type.flags & ts.TypeFlags.Null) {
833
994
  return Type.Primitive.Null;
834
- } else if (type.flags === ts.TypeFlags.Undefined) {
995
+ } else if (type.flags & ts.TypeFlags.Undefined) {
835
996
  return Type.Primitive.None;
836
- } else if (
837
- type.flags === ts.TypeFlags.Number ||
838
- type.flags === ts.TypeFlags.NumberLiteral ||
839
- type.flags === ts.TypeFlags.NumberLike
840
- ) {
997
+ } else if (type.flags & (ts.TypeFlags.Number | ts.TypeFlags.NumberLiteral | ts.TypeFlags.NumberLike)) {
841
998
  return Type.Primitive.Double;
842
- } else if (
843
- type.flags === ts.TypeFlags.String ||
844
- type.flags === ts.TypeFlags.StringLiteral ||
845
- type.flags === ts.TypeFlags.StringLike
846
- ) {
999
+ } else if (type.flags & (ts.TypeFlags.String | ts.TypeFlags.StringLiteral | ts.TypeFlags.StringLike)) {
847
1000
  return Type.Primitive.String;
848
- } else if (type.flags === ts.TypeFlags.Void) {
1001
+ } else if (type.flags & ts.TypeFlags.Void) {
849
1002
  return Type.Primitive.Void;
850
- } else if (
851
- type.flags === ts.TypeFlags.BigInt ||
852
- type.flags === ts.TypeFlags.BigIntLiteral ||
853
- type.flags === ts.TypeFlags.BigIntLike
854
- ) {
1003
+ } else if (type.flags & (ts.TypeFlags.BigInt | ts.TypeFlags.BigIntLiteral | ts.TypeFlags.BigIntLike)) {
855
1004
  return Type.Primitive.BigInt;
856
- } else if (
857
- (type.symbol !== undefined && type.symbol === this.regExpSymbol) ||
858
- this.checker.typeToString(type) === "RegExp"
859
- ) {
1005
+ } else if (type.symbol !== undefined && type.symbol === this.regExpSymbol) {
860
1006
  return Type.Primitive.String;
861
- }
862
-
863
- /**
864
- * TypeScript may assign multiple flags to a single type (e.g., Boolean + Union).
865
- * Using a bitwise check ensures we detect Boolean even if other flags are set.
866
- */
867
- if (
868
- type.flags & ts.TypeFlags.Boolean ||
869
- type.flags & ts.TypeFlags.BooleanLiteral ||
870
- type.flags & ts.TypeFlags.BooleanLike
871
- ) {
1007
+ } else if (type.flags & (ts.TypeFlags.Boolean | ts.TypeFlags.BooleanLiteral | ts.TypeFlags.BooleanLike)) {
872
1008
  return Type.Primitive.Boolean;
873
1009
  }
874
1010
 
@@ -885,6 +1021,96 @@ export class JavaScriptTypeMapping {
885
1021
  return Type.unknownType;
886
1022
  }
887
1023
 
1024
+ /**
1025
+ * Create a union type from TypeScript union type (e.g., string | number)
1026
+ * Note: Cache check is done in getType() before calling this method
1027
+ */
1028
+ private createUnionType(unionType: ts.UnionType, cacheKey: string | number): Type.Union {
1029
+ // Shell-cache FIRST to prevent infinite recursion (before resolving constituent types)
1030
+ const union = Object.assign(new NonDraftableType(), {
1031
+ kind: Type.Kind.Union,
1032
+ bounds: []
1033
+ }) as Type.Union;
1034
+
1035
+ this.typeCache.set(cacheKey, union);
1036
+
1037
+ // Now map all constituent types (may recursively reference this union)
1038
+ const bounds: Type[] = [];
1039
+ for (const constituentType of unionType.types) {
1040
+ bounds.push(this.getType(constituentType));
1041
+ }
1042
+
1043
+ // Update the bounds in the union we created
1044
+ (union as any).bounds = bounds;
1045
+
1046
+ return union;
1047
+ }
1048
+
1049
+ /**
1050
+ * Create an intersection type from TypeScript intersection type (e.g., A & B)
1051
+ * Note: Cache check is done in getType() before calling this method
1052
+ */
1053
+ private createIntersectionType(intersectionType: ts.IntersectionType, cacheKey: string | number): Type.Intersection {
1054
+ // Shell-cache FIRST to prevent infinite recursion (before resolving constituent types)
1055
+ const intersection = Object.assign(new NonDraftableType(), {
1056
+ kind: Type.Kind.Intersection,
1057
+ bounds: []
1058
+ }) as Type.Intersection;
1059
+
1060
+ this.typeCache.set(cacheKey, intersection);
1061
+
1062
+ // Now map all constituent types (may recursively reference this intersection)
1063
+ const bounds: Type[] = [];
1064
+ for (const constituentType of intersectionType.types) {
1065
+ bounds.push(this.getType(constituentType));
1066
+ }
1067
+
1068
+ // Update the bounds in the intersection we created
1069
+ (intersection as any).bounds = bounds;
1070
+
1071
+ return intersection;
1072
+ }
1073
+
1074
+ /**
1075
+ * Create a generic type variable from a TypeScript type parameter.
1076
+ * Examples: T, K extends string, V extends keyof T
1077
+ * Note: Cache check is done in getType() before calling this method
1078
+ */
1079
+ private createGenericTypeVariable(typeParam: ts.TypeParameter, cacheKey: string | number): Type.GenericTypeVariable {
1080
+ const symbol = typeParam.getSymbol();
1081
+ const name = symbol ? symbol.getName() : '?';
1082
+
1083
+ // Shell-cache: Create stub, cache it, then populate (prevents cycles)
1084
+ const gtv = Object.assign(new NonDraftableType(), {
1085
+ kind: Type.Kind.GenericTypeVariable,
1086
+ name: name,
1087
+ variance: Type.GenericTypeVariable.Variance.Invariant,
1088
+ bounds: []
1089
+ }) as Type.GenericTypeVariable;
1090
+
1091
+ this.typeCache.set(cacheKey, gtv);
1092
+
1093
+ // Get the constraint (upper bound) if it exists
1094
+ const constraint = typeParam.getConstraint();
1095
+ let bounds: Type[] = [];
1096
+ let variance = Type.GenericTypeVariable.Variance.Invariant;
1097
+
1098
+ if (constraint) {
1099
+ const boundType = this.getType(constraint);
1100
+ // Only add bounds if it's not just "object" (the default constraint)
1101
+ if (!(Type.isClass(boundType) && boundType.fullyQualifiedName === 'object')) {
1102
+ bounds = [boundType];
1103
+ variance = Type.GenericTypeVariable.Variance.Covariant;
1104
+ }
1105
+ }
1106
+
1107
+ // Update the variance and bounds
1108
+ (gtv as any).variance = variance;
1109
+ (gtv as any).bounds = bounds;
1110
+
1111
+ return gtv;
1112
+ }
1113
+
888
1114
  /**
889
1115
  * Create an empty function type shell with FQN 𝑓.
890
1116
  * The shell will be populated later to handle circular references.
@@ -85,7 +85,7 @@ export class RewriteRpc {
85
85
  Visit.handle(this.connection, this.localObjects, preparedRecipes, recipeCursors, getObject, getCursor, options.metricsCsv);
86
86
  Generate.handle(this.connection, this.localObjects, preparedRecipes, recipeCursors, getObject, options.metricsCsv);
87
87
  GetObject.handle(this.connection, this.remoteObjects, this.localObjects,
88
- this.localRefs, options?.batchSize || 200, traceGetObject, options.metricsCsv);
88
+ this.localRefs, options?.batchSize || 1000, traceGetObject, options.metricsCsv);
89
89
  GetRecipes.handle(this.connection, registry, options.metricsCsv);
90
90
  GetLanguages.handle(this.connection, options.metricsCsv);
91
91
  PrepareRecipe.handle(this.connection, registry, preparedRecipes, options.metricsCsv);
package/src/rpc/server.ts CHANGED
@@ -46,7 +46,7 @@ async function main() {
46
46
  .option('--log-file <log_path>', 'log file path')
47
47
  .option('--metrics-csv <metrics_csv_path>', 'metrics CSV output path')
48
48
  .option('--trace-rpc-messages', 'trace RPC messages at the protocol level')
49
- .option('--batch-size [size]', 'sets the batch size (default is 200)', s => parseInt(s, 10), 200)
49
+ .option('--batch-size [size]', 'sets the batch size (default is 200)', s => parseInt(s, 10), 1000)
50
50
  .option('--recipe-install-dir <install_dir>', 'Recipe installation directory (default is a temporary directory)')
51
51
  .parse();
52
52