@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.
- package/dist/java/type.d.ts +6 -3
- package/dist/java/type.d.ts.map +1 -1
- package/dist/java/type.js +51 -5
- package/dist/java/type.js.map +1 -1
- package/dist/javascript/add-import.d.ts +18 -2
- package/dist/javascript/add-import.d.ts.map +1 -1
- package/dist/javascript/add-import.js +49 -15
- package/dist/javascript/add-import.js.map +1 -1
- package/dist/javascript/format.d.ts +1 -0
- package/dist/javascript/format.d.ts.map +1 -1
- package/dist/javascript/format.js +45 -2
- package/dist/javascript/format.js.map +1 -1
- package/dist/javascript/parser.d.ts +2 -1
- package/dist/javascript/parser.d.ts.map +1 -1
- package/dist/javascript/parser.js +7 -3
- package/dist/javascript/parser.js.map +1 -1
- package/dist/javascript/remove-import.d.ts +20 -2
- package/dist/javascript/remove-import.d.ts.map +1 -1
- package/dist/javascript/remove-import.js +121 -11
- package/dist/javascript/remove-import.js.map +1 -1
- package/dist/javascript/type-mapping.d.ts +17 -0
- package/dist/javascript/type-mapping.d.ts.map +1 -1
- package/dist/javascript/type-mapping.js +241 -44
- package/dist/javascript/type-mapping.js.map +1 -1
- package/dist/rpc/rewrite-rpc.js +1 -1
- package/dist/rpc/rewrite-rpc.js.map +1 -1
- package/dist/rpc/server.js +1 -1
- package/dist/rpc/server.js.map +1 -1
- package/dist/version.txt +1 -1
- package/package.json +1 -1
- package/src/java/type.ts +57 -5
- package/src/javascript/add-import.ts +55 -15
- package/src/javascript/format.ts +44 -3
- package/src/javascript/parser.ts +7 -3
- package/src/javascript/remove-import.ts +114 -11
- package/src/javascript/type-mapping.ts +282 -56
- package/src/rpc/rewrite-rpc.ts +1 -1
- 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
|
|
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
|
|
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 &
|
|
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
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
384
|
+
if (declaringType === Type.Primitive.String && this.stringWrapperType) {
|
|
233
385
|
return this.getType(this.stringWrapperType) as Type.FullyQualified;
|
|
234
|
-
} else if ((declaringType
|
|
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
|
|
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
|
|
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 (
|
|
551
|
+
if (exprSymbol) {
|
|
397
552
|
// Check if this is an aliased symbol (i.e., an import)
|
|
398
|
-
if (
|
|
399
|
-
aliasedSymbol = this.checker.getAliasedSymbol(
|
|
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 !==
|
|
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 (
|
|
415
|
-
let importNode: ts.Node =
|
|
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
|
-
|
|
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
|
|
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
|
|
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.
|
package/src/rpc/rewrite-rpc.ts
CHANGED
|
@@ -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 ||
|
|
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),
|
|
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
|
|