@openrewrite/rewrite 8.62.3 → 8.62.5
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/execution.d.ts.map +1 -1
- package/dist/execution.js.map +1 -1
- package/dist/java/rpc.d.ts +1 -0
- package/dist/java/rpc.d.ts.map +1 -1
- package/dist/java/rpc.js +81 -0
- package/dist/java/rpc.js.map +1 -1
- package/dist/java/tree.d.ts +12 -6
- package/dist/java/tree.d.ts.map +1 -1
- package/dist/java/tree.js +12 -92
- package/dist/java/tree.js.map +1 -1
- package/dist/java/type.d.ts +2 -0
- package/dist/java/type.d.ts.map +1 -1
- package/dist/java/type.js +12 -0
- package/dist/java/type.js.map +1 -1
- package/dist/java/visitor.d.ts +12 -4
- package/dist/java/visitor.d.ts.map +1 -1
- package/dist/java/visitor.js +23 -1
- package/dist/java/visitor.js.map +1 -1
- package/dist/javascript/format.d.ts +2 -2
- package/dist/javascript/format.d.ts.map +1 -1
- package/dist/javascript/format.js.map +1 -1
- package/dist/javascript/index.d.ts +3 -0
- package/dist/javascript/index.d.ts.map +1 -1
- package/dist/javascript/index.js +3 -0
- package/dist/javascript/index.js.map +1 -1
- package/dist/javascript/method-matcher.d.ts +16 -0
- package/dist/javascript/method-matcher.d.ts.map +1 -0
- package/dist/javascript/method-matcher.js +222 -0
- package/dist/javascript/method-matcher.js.map +1 -0
- package/dist/javascript/parser.d.ts +1 -1
- package/dist/javascript/parser.d.ts.map +1 -1
- package/dist/javascript/parser.js +27 -5
- package/dist/javascript/parser.js.map +1 -1
- package/dist/javascript/preconditions.d.ts +6 -0
- package/dist/javascript/preconditions.d.ts.map +1 -0
- package/dist/javascript/preconditions.js +58 -0
- package/dist/javascript/preconditions.js.map +1 -0
- package/dist/javascript/print.d.ts +2 -2
- package/dist/javascript/print.d.ts.map +1 -1
- package/dist/javascript/print.js.map +1 -1
- package/dist/javascript/remove-import.d.ts +56 -0
- package/dist/javascript/remove-import.d.ts.map +1 -0
- package/dist/javascript/remove-import.js +715 -0
- package/dist/javascript/remove-import.js.map +1 -0
- package/dist/javascript/rpc.js +3 -18
- package/dist/javascript/rpc.js.map +1 -1
- package/dist/javascript/search/index.d.ts +3 -0
- package/dist/javascript/search/index.d.ts.map +1 -0
- package/dist/javascript/search/index.js +19 -0
- package/dist/javascript/search/index.js.map +1 -0
- package/dist/javascript/search/uses-method.d.ts +8 -0
- package/dist/javascript/search/uses-method.d.ts.map +1 -0
- package/dist/javascript/search/uses-method.js +35 -0
- package/dist/javascript/search/uses-method.js.map +1 -0
- package/dist/javascript/search/uses-type.d.ts +8 -0
- package/dist/javascript/search/uses-type.d.ts.map +1 -0
- package/dist/javascript/search/uses-type.js +71 -0
- package/dist/javascript/search/uses-type.js.map +1 -0
- package/dist/javascript/templating.d.ts +1 -1
- package/dist/javascript/templating.d.ts.map +1 -1
- package/dist/javascript/templating.js +1 -1
- package/dist/javascript/templating.js.map +1 -1
- package/dist/javascript/tree.d.ts +3 -3
- package/dist/javascript/tree.d.ts.map +1 -1
- package/dist/javascript/tree.js +28 -0
- package/dist/javascript/tree.js.map +1 -1
- package/dist/javascript/type-mapping.d.ts +7 -18
- package/dist/javascript/type-mapping.d.ts.map +1 -1
- package/dist/javascript/type-mapping.js +290 -203
- package/dist/javascript/type-mapping.js.map +1 -1
- package/dist/javascript/visitor.d.ts +1 -1
- package/dist/javascript/visitor.d.ts.map +1 -1
- package/dist/javascript/visitor.js +1 -1
- package/dist/javascript/visitor.js.map +1 -1
- package/dist/json/print.js.map +1 -1
- package/dist/json/rpc.js +46 -17
- package/dist/json/rpc.js.map +1 -1
- package/dist/json/visitor.d.ts +2 -2
- package/dist/json/visitor.d.ts.map +1 -1
- package/dist/json/visitor.js.map +1 -1
- package/dist/print.d.ts +1 -0
- package/dist/print.d.ts.map +1 -1
- package/dist/print.js +6 -0
- package/dist/print.js.map +1 -1
- package/dist/rpc/queue.d.ts +15 -6
- package/dist/rpc/queue.d.ts.map +1 -1
- package/dist/rpc/queue.js +37 -13
- package/dist/rpc/queue.js.map +1 -1
- package/dist/rpc/request/generate.d.ts +4 -0
- package/dist/rpc/request/generate.d.ts.map +1 -1
- package/dist/rpc/request/generate.js +9 -4
- package/dist/rpc/request/generate.js.map +1 -1
- package/dist/rpc/request/get-object.d.ts +2 -2
- package/dist/rpc/request/get-object.d.ts.map +1 -1
- package/dist/rpc/request/get-object.js +4 -12
- package/dist/rpc/request/get-object.js.map +1 -1
- package/dist/rpc/request/parse.d.ts.map +1 -1
- package/dist/rpc/request/parse.js.map +1 -1
- package/dist/rpc/request/print.d.ts +1 -1
- package/dist/rpc/request/print.d.ts.map +1 -1
- package/dist/rpc/request/print.js +1 -1
- package/dist/rpc/request/print.js.map +1 -1
- package/dist/rpc/request/visit.d.ts +3 -2
- package/dist/rpc/request/visit.d.ts.map +1 -1
- package/dist/rpc/request/visit.js +5 -4
- package/dist/rpc/request/visit.js.map +1 -1
- package/dist/rpc/rewrite-rpc.d.ts +4 -4
- package/dist/rpc/rewrite-rpc.d.ts.map +1 -1
- package/dist/rpc/rewrite-rpc.js +16 -17
- package/dist/rpc/rewrite-rpc.js.map +1 -1
- package/dist/search/index.d.ts +2 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +18 -0
- package/dist/search/index.js.map +1 -0
- package/dist/search/is-source-file.d.ts +8 -0
- package/dist/search/is-source-file.d.ts.map +1 -0
- package/dist/search/is-source-file.js +70 -0
- package/dist/search/is-source-file.js.map +1 -0
- package/dist/test/rewrite-test.d.ts.map +1 -1
- package/dist/test/rewrite-test.js +3 -0
- package/dist/test/rewrite-test.js.map +1 -1
- package/dist/text/rpc.js +37 -40
- package/dist/text/rpc.js.map +1 -1
- package/dist/util.d.ts +1 -0
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +13 -0
- package/dist/util.js.map +1 -1
- package/dist/version.txt +1 -1
- package/dist/visitor.d.ts +1 -1
- package/dist/visitor.d.ts.map +1 -1
- package/dist/visitor.js +3 -2
- package/dist/visitor.js.map +1 -1
- package/package.json +3 -1
- package/src/execution.ts +0 -2
- package/src/java/rpc.ts +68 -0
- package/src/java/tree.ts +20 -76
- package/src/java/type.ts +14 -0
- package/src/java/visitor.ts +32 -12
- package/src/javascript/format.ts +2 -2
- package/src/javascript/index.ts +4 -0
- package/src/javascript/method-matcher.ts +250 -0
- package/src/javascript/parser.ts +20 -6
- package/src/javascript/preconditions.ts +40 -0
- package/src/javascript/print.ts +3 -3
- package/src/javascript/remove-import.ts +780 -0
- package/src/javascript/rpc.ts +6 -19
- package/src/javascript/search/index.ts +2 -0
- package/src/javascript/search/uses-method.ts +21 -0
- package/src/javascript/search/uses-type.ts +27 -0
- package/src/javascript/templating.ts +4 -3
- package/src/javascript/tree.ts +47 -3
- package/src/javascript/type-mapping.ts +320 -214
- package/src/javascript/visitor.ts +126 -126
- package/src/json/print.ts +1 -1
- package/src/json/rpc.ts +40 -19
- package/src/json/visitor.ts +2 -2
- package/src/print.ts +9 -3
- package/src/rpc/queue.ts +36 -12
- package/src/rpc/request/generate.ts +18 -6
- package/src/rpc/request/get-object.ts +6 -13
- package/src/rpc/request/parse.ts +1 -1
- package/src/rpc/request/print.ts +2 -2
- package/src/rpc/request/visit.ts +6 -5
- package/src/rpc/rewrite-rpc.ts +22 -21
- package/src/search/index.ts +1 -0
- package/src/search/is-source-file.ts +26 -0
- package/src/test/rewrite-test.ts +5 -2
- package/src/text/rpc.ts +33 -37
- package/src/util.ts +19 -4
- package/src/visitor.ts +3 -3
|
@@ -22,20 +22,12 @@ class NonDraftableType {
|
|
|
22
22
|
[immerable] = false;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
const builtInTypes = new Set([
|
|
26
|
-
'Array', 'Object', 'Function', 'String', 'Number', 'Boolean',
|
|
27
|
-
'Date', 'RegExp', 'Error', 'Promise', 'Map', 'Set', 'WeakMap',
|
|
28
|
-
'WeakSet', 'Symbol', 'BigInt', 'HTMLElement', 'Document',
|
|
29
|
-
'Window', 'Console', 'JSON', 'Math', 'Reflect', 'Proxy'
|
|
30
|
-
]);
|
|
31
|
-
|
|
32
25
|
export class JavaScriptTypeMapping {
|
|
33
26
|
private readonly typeCache: Map<string | number, Type> = new Map();
|
|
34
27
|
private readonly regExpSymbol: ts.Symbol | undefined;
|
|
35
28
|
|
|
36
29
|
constructor(
|
|
37
|
-
private readonly checker: ts.TypeChecker
|
|
38
|
-
private readonly projectRoot: string = process.cwd()
|
|
30
|
+
private readonly checker: ts.TypeChecker
|
|
39
31
|
) {
|
|
40
32
|
this.regExpSymbol = checker.resolveName(
|
|
41
33
|
"RegExp",
|
|
@@ -62,15 +54,8 @@ export class JavaScriptTypeMapping {
|
|
|
62
54
|
return existing;
|
|
63
55
|
}
|
|
64
56
|
|
|
65
|
-
// Check
|
|
66
|
-
//
|
|
67
|
-
if (this.checker.isArrayType(type)) {
|
|
68
|
-
const arrayType = this.createArrayType(type as ts.TypeReference);
|
|
69
|
-
this.typeCache.set(signature, arrayType);
|
|
70
|
-
return arrayType;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Check for class/interface/enum types (but not arrays)
|
|
57
|
+
// Check for class/interface/enum types (including arrays)
|
|
58
|
+
// Arrays in JavaScript are objects with methods, so we treat them as class types
|
|
74
59
|
const symbol = type.getSymbol?.();
|
|
75
60
|
if (symbol) {
|
|
76
61
|
if (symbol.flags & (ts.SymbolFlags.Class | ts.SymbolFlags.Interface | ts.SymbolFlags.Enum | ts.SymbolFlags.TypeAlias)) {
|
|
@@ -129,7 +114,7 @@ export class JavaScriptTypeMapping {
|
|
|
129
114
|
|
|
130
115
|
primitiveType(node: ts.Node): Type.Primitive {
|
|
131
116
|
const type = this.type(node);
|
|
132
|
-
if (Type.isClass(type) && type.fullyQualifiedName === '
|
|
117
|
+
if (Type.isClass(type) && type.fullyQualifiedName === 'RegExp') {
|
|
133
118
|
return Type.Primitive.String;
|
|
134
119
|
}
|
|
135
120
|
return Type.isPrimitive(type) ? type : Type.Primitive.None;
|
|
@@ -147,7 +132,47 @@ export class JavaScriptTypeMapping {
|
|
|
147
132
|
return undefined;
|
|
148
133
|
}
|
|
149
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Helper to create a Type.Method object from common parameters
|
|
137
|
+
*/
|
|
138
|
+
private createMethodType(
|
|
139
|
+
signature: ts.Signature,
|
|
140
|
+
node: ts.Node,
|
|
141
|
+
declaringType: Type.FullyQualified,
|
|
142
|
+
name: string,
|
|
143
|
+
declaredFormalTypeNames: string[] = []
|
|
144
|
+
): Type.Method {
|
|
145
|
+
const returnType = signature.getReturnType();
|
|
146
|
+
const parameters = signature.getParameters();
|
|
147
|
+
const parameterTypes: Type[] = [];
|
|
148
|
+
const parameterNames: string[] = [];
|
|
149
|
+
|
|
150
|
+
for (const param of parameters) {
|
|
151
|
+
parameterNames.push(param.getName());
|
|
152
|
+
const paramType = this.checker.getTypeOfSymbolAtLocation(param, node);
|
|
153
|
+
parameterTypes.push(this.getType(paramType));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Create the Type.Method object
|
|
157
|
+
return Object.assign(new NonDraftableType(), {
|
|
158
|
+
kind: Type.Kind.Method,
|
|
159
|
+
declaringType: declaringType,
|
|
160
|
+
name: name,
|
|
161
|
+
returnType: this.getType(returnType),
|
|
162
|
+
parameterNames: parameterNames,
|
|
163
|
+
parameterTypes: parameterTypes,
|
|
164
|
+
thrownExceptions: [], // JavaScript doesn't have checked exceptions
|
|
165
|
+
annotations: [],
|
|
166
|
+
defaultValue: undefined,
|
|
167
|
+
declaredFormalTypeNames: declaredFormalTypeNames,
|
|
168
|
+
toJSON: function () {
|
|
169
|
+
return Type.signature(this);
|
|
170
|
+
}
|
|
171
|
+
}) as Type.Method;
|
|
172
|
+
}
|
|
173
|
+
|
|
150
174
|
methodType(node: ts.Node): Type.Method | undefined {
|
|
175
|
+
|
|
151
176
|
let signature: ts.Signature | undefined;
|
|
152
177
|
let methodName: string;
|
|
153
178
|
let declaringType: Type.FullyQualified;
|
|
@@ -161,7 +186,68 @@ export class JavaScriptTypeMapping {
|
|
|
161
186
|
return undefined;
|
|
162
187
|
}
|
|
163
188
|
|
|
164
|
-
|
|
189
|
+
let symbol = this.checker.getSymbolAtLocation(node.expression);
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
if (!symbol && ts.isPropertyAccessExpression(node.expression)) {
|
|
193
|
+
// For property access expressions where we couldn't get a symbol,
|
|
194
|
+
// try to get the symbol from the signature's declaration
|
|
195
|
+
const declaration = signature?.getDeclaration();
|
|
196
|
+
if (declaration) {
|
|
197
|
+
symbol = this.checker.getSymbolAtLocation(declaration);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// If still no symbol but we have a signature, we can proceed with limited info
|
|
201
|
+
if (!symbol && signature) {
|
|
202
|
+
// For cases like util.isArray where the module is 'any' type
|
|
203
|
+
// We'll construct a basic method type from the signature
|
|
204
|
+
methodName = node.expression.name.getText();
|
|
205
|
+
|
|
206
|
+
// When there's no symbol but we have a signature, we need to work harder
|
|
207
|
+
// to find the declaring type. This happens with CommonJS require() calls
|
|
208
|
+
// where the module is typed as 'any' but methods still have signatures
|
|
209
|
+
|
|
210
|
+
// Try to trace back through the AST to find the require() call
|
|
211
|
+
let inferredDeclaringType: Type.FullyQualified | undefined;
|
|
212
|
+
const objExpr = node.expression.expression;
|
|
213
|
+
|
|
214
|
+
if (ts.isIdentifier(objExpr)) {
|
|
215
|
+
// Look for the variable declaration that assigns the require() result
|
|
216
|
+
const objSymbol = this.checker.getSymbolAtLocation(objExpr);
|
|
217
|
+
|
|
218
|
+
if (objSymbol && objSymbol.valueDeclaration) {
|
|
219
|
+
const valueDecl = objSymbol.valueDeclaration;
|
|
220
|
+
if (ts.isVariableDeclaration(valueDecl) && valueDecl.initializer) {
|
|
221
|
+
// Check if it's a require() call
|
|
222
|
+
if (ts.isCallExpression(valueDecl.initializer)) {
|
|
223
|
+
const callExpr = valueDecl.initializer;
|
|
224
|
+
if (ts.isIdentifier(callExpr.expression) &&
|
|
225
|
+
callExpr.expression.getText() === 'require' &&
|
|
226
|
+
callExpr.arguments.length > 0) {
|
|
227
|
+
// Extract the module name from require('module-name')
|
|
228
|
+
const moduleArg = callExpr.arguments[0];
|
|
229
|
+
if (ts.isStringLiteral(moduleArg)) {
|
|
230
|
+
const moduleName = moduleArg.text;
|
|
231
|
+
|
|
232
|
+
inferredDeclaringType = {
|
|
233
|
+
kind: Type.Kind.Class,
|
|
234
|
+
fullyQualifiedName: moduleName
|
|
235
|
+
} as Type.FullyQualified;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Use the inferred type or fall back to unknown
|
|
244
|
+
declaringType = inferredDeclaringType || Type.unknownType as Type.FullyQualified;
|
|
245
|
+
|
|
246
|
+
// Create the method type using the helper
|
|
247
|
+
return this.createMethodType(signature, node, declaringType, methodName);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
165
251
|
if (!symbol) {
|
|
166
252
|
return undefined;
|
|
167
253
|
}
|
|
@@ -169,63 +255,164 @@ export class JavaScriptTypeMapping {
|
|
|
169
255
|
// Get the method name
|
|
170
256
|
if (ts.isPropertyAccessExpression(node.expression)) {
|
|
171
257
|
methodName = node.expression.name.getText();
|
|
258
|
+
|
|
259
|
+
// Check if the object is an imported symbol
|
|
260
|
+
const objSymbol = this.checker.getSymbolAtLocation(node.expression.expression);
|
|
261
|
+
let isImport = false;
|
|
262
|
+
if (objSymbol) {
|
|
263
|
+
// Only call getAliasedSymbol if the symbol is actually an alias
|
|
264
|
+
if (objSymbol.flags & ts.SymbolFlags.Alias) {
|
|
265
|
+
const aliasedSymbol = this.checker.getAliasedSymbol(objSymbol);
|
|
266
|
+
isImport = aliasedSymbol && aliasedSymbol !== objSymbol;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
172
270
|
const exprType = this.checker.getTypeAtLocation(node.expression.expression);
|
|
173
271
|
const mappedType = this.getType(exprType);
|
|
174
272
|
|
|
175
|
-
//
|
|
176
|
-
if (
|
|
177
|
-
//
|
|
273
|
+
// Handle different types
|
|
274
|
+
if (mappedType && mappedType.kind === Type.Kind.Class) {
|
|
275
|
+
// Update the declaring type with the corrected FQN
|
|
276
|
+
if (isImport && objSymbol) {
|
|
277
|
+
const importName = objSymbol.getName();
|
|
278
|
+
const origFqn = (mappedType as Type.Class).fullyQualifiedName;
|
|
279
|
+
const lastDot = origFqn.lastIndexOf('.');
|
|
280
|
+
if (lastDot > 0) {
|
|
281
|
+
const typeName = origFqn.substring(lastDot + 1);
|
|
282
|
+
declaringType = {
|
|
283
|
+
kind: Type.Kind.Class,
|
|
284
|
+
fullyQualifiedName: `${importName}.${typeName}`
|
|
285
|
+
} as Type.FullyQualified;
|
|
286
|
+
} else {
|
|
287
|
+
declaringType = mappedType as Type.FullyQualified;
|
|
288
|
+
}
|
|
289
|
+
} else {
|
|
290
|
+
declaringType = mappedType as Type.FullyQualified;
|
|
291
|
+
}
|
|
292
|
+
} else {
|
|
293
|
+
// Handle primitive types and other non-class types
|
|
294
|
+
if (mappedType) {
|
|
295
|
+
if ((mappedType as any).keyword === 'String') {
|
|
296
|
+
declaringType = {
|
|
297
|
+
kind: Type.Kind.Class,
|
|
298
|
+
fullyQualifiedName: 'String'
|
|
299
|
+
} as Type.FullyQualified;
|
|
300
|
+
} else if ((mappedType as any).keyword === 'Number') {
|
|
301
|
+
declaringType = {
|
|
302
|
+
kind: Type.Kind.Class,
|
|
303
|
+
fullyQualifiedName: 'Number'
|
|
304
|
+
} as Type.FullyQualified;
|
|
305
|
+
} else {
|
|
306
|
+
// Fallback for other types
|
|
307
|
+
declaringType = mappedType as Type.FullyQualified;
|
|
308
|
+
}
|
|
309
|
+
} else {
|
|
310
|
+
// Default to unknown if we can't determine the type
|
|
311
|
+
declaringType = Type.unknownType as Type.FullyQualified;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// For string methods like 'hello'.split(), ensure we have a proper declaring type for primitives
|
|
316
|
+
if (!isImport && declaringType === Type.unknownType) {
|
|
317
|
+
// If the expression type is a primitive string, use String as declaring type
|
|
178
318
|
const typeString = this.checker.typeToString(exprType);
|
|
179
319
|
if (typeString === 'string' || exprType.flags & ts.TypeFlags.String || exprType.flags & ts.TypeFlags.StringLiteral) {
|
|
180
320
|
declaringType = {
|
|
181
321
|
kind: Type.Kind.Class,
|
|
182
|
-
fullyQualifiedName: '
|
|
322
|
+
fullyQualifiedName: 'string'
|
|
183
323
|
} as Type.FullyQualified;
|
|
184
324
|
} else if (typeString === 'number' || exprType.flags & ts.TypeFlags.Number || exprType.flags & ts.TypeFlags.NumberLiteral) {
|
|
185
325
|
declaringType = {
|
|
186
326
|
kind: Type.Kind.Class,
|
|
187
|
-
fullyQualifiedName: '
|
|
327
|
+
fullyQualifiedName: 'number'
|
|
188
328
|
} as Type.FullyQualified;
|
|
189
329
|
} else {
|
|
190
330
|
// Fallback for other primitive types or unknown
|
|
191
331
|
declaringType = Type.unknownType as Type.FullyQualified;
|
|
192
332
|
}
|
|
193
|
-
} else {
|
|
194
|
-
declaringType = mappedType as Type.FullyQualified;
|
|
195
333
|
}
|
|
334
|
+
|
|
196
335
|
} else if (ts.isIdentifier(node.expression)) {
|
|
197
336
|
methodName = node.expression.getText();
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
if (
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
337
|
+
|
|
338
|
+
// Check if this is an import first
|
|
339
|
+
const symbol = this.checker.getSymbolAtLocation(node.expression);
|
|
340
|
+
let moduleSpecifier: string | undefined;
|
|
341
|
+
|
|
342
|
+
if (symbol) {
|
|
343
|
+
// Check if this is an aliased symbol (i.e., an import)
|
|
344
|
+
let aliasedSymbol: ts.Symbol | undefined;
|
|
345
|
+
if (symbol.flags & ts.SymbolFlags.Alias) {
|
|
346
|
+
aliasedSymbol = this.checker.getAliasedSymbol(symbol);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// If getAliasedSymbol returns something different, it's an import
|
|
350
|
+
if (aliasedSymbol && aliasedSymbol !== symbol) {
|
|
351
|
+
// This is definitely an imported symbol
|
|
352
|
+
// Now find the import declaration to get the module specifier
|
|
353
|
+
if (symbol.declarations && symbol.declarations.length > 0) {
|
|
354
|
+
let importNode: ts.Node = symbol.declarations[0];
|
|
355
|
+
|
|
356
|
+
// Traverse up to find the ImportDeclaration
|
|
357
|
+
while (importNode && !ts.isImportDeclaration(importNode)) {
|
|
358
|
+
importNode = importNode.parent;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
if (importNode && ts.isImportDeclaration(importNode)) {
|
|
362
|
+
const importDeclNode = importNode as ts.ImportDeclaration;
|
|
363
|
+
if (ts.isStringLiteral(importDeclNode.moduleSpecifier)) {
|
|
364
|
+
moduleSpecifier = importDeclNode.moduleSpecifier.text;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (moduleSpecifier) {
|
|
372
|
+
// This is an imported function - use the module specifier as declaring type
|
|
373
|
+
if (moduleSpecifier.startsWith('node:')) {
|
|
374
|
+
// Node.js built-in module
|
|
212
375
|
declaringType = {
|
|
213
376
|
kind: Type.Kind.Class,
|
|
214
|
-
fullyQualifiedName:
|
|
377
|
+
fullyQualifiedName: 'node'
|
|
215
378
|
} as Type.FullyQualified;
|
|
379
|
+
methodName = moduleSpecifier.substring(5); // Remove 'node:' prefix
|
|
216
380
|
} else {
|
|
217
|
-
//
|
|
218
|
-
|
|
219
|
-
|
|
381
|
+
// Regular module import
|
|
382
|
+
declaringType = {
|
|
383
|
+
kind: Type.Kind.Class,
|
|
384
|
+
fullyQualifiedName: moduleSpecifier
|
|
385
|
+
} as Type.FullyQualified;
|
|
386
|
+
methodName = '<default>';
|
|
220
387
|
}
|
|
221
388
|
} else {
|
|
222
|
-
//
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
389
|
+
// Fall back to the original logic for non-imported functions
|
|
390
|
+
const exprType = this.checker.getTypeAtLocation(node.expression);
|
|
391
|
+
const funcType = this.getType(exprType);
|
|
392
|
+
|
|
393
|
+
if (funcType && funcType.kind === Type.Kind.Class) {
|
|
394
|
+
const fqn = (funcType as Type.Class).fullyQualifiedName;
|
|
395
|
+
const lastDot = fqn.lastIndexOf('.');
|
|
396
|
+
|
|
397
|
+
if (lastDot > 0) {
|
|
398
|
+
// For functions from modules, use the module part as declaring type
|
|
399
|
+
declaringType = {
|
|
400
|
+
kind: Type.Kind.Class,
|
|
401
|
+
fullyQualifiedName: fqn.substring(0, lastDot)
|
|
402
|
+
} as Type.FullyQualified;
|
|
403
|
+
} else {
|
|
404
|
+
// No dots in the name - the type IS the module itself
|
|
405
|
+
declaringType = funcType as Type.FullyQualified;
|
|
406
|
+
}
|
|
227
407
|
} else {
|
|
228
|
-
|
|
408
|
+
// Try to use the symbol's parent or module
|
|
409
|
+
const parent = (symbol as any).parent;
|
|
410
|
+
if (parent) {
|
|
411
|
+
const parentType = this.checker.getDeclaredTypeOfSymbol(parent);
|
|
412
|
+
declaringType = this.getType(parentType) as Type.FullyQualified;
|
|
413
|
+
} else {
|
|
414
|
+
declaringType = Type.unknownType as Type.FullyQualified;
|
|
415
|
+
}
|
|
229
416
|
}
|
|
230
417
|
}
|
|
231
418
|
} else {
|
|
@@ -290,57 +477,16 @@ export class JavaScriptTypeMapping {
|
|
|
290
477
|
return undefined;
|
|
291
478
|
}
|
|
292
479
|
|
|
293
|
-
//
|
|
294
|
-
|
|
295
|
-
const parameters = signature.getParameters();
|
|
296
|
-
const parameterTypes: Type[] = [];
|
|
297
|
-
const parameterNames: string[] = [];
|
|
298
|
-
|
|
299
|
-
for (const param of parameters) {
|
|
300
|
-
parameterNames.push(param.getName());
|
|
301
|
-
const paramType = this.checker.getTypeOfSymbolAtLocation(param, node);
|
|
302
|
-
parameterTypes.push(this.getType(paramType));
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
// Create the Type.Method object
|
|
306
|
-
return Object.assign(new NonDraftableType(), {
|
|
307
|
-
kind: Type.Kind.Method,
|
|
308
|
-
declaringType: declaringType,
|
|
309
|
-
name: methodName,
|
|
310
|
-
returnType: this.getType(returnType),
|
|
311
|
-
parameterNames: parameterNames,
|
|
312
|
-
parameterTypes: parameterTypes,
|
|
313
|
-
thrownExceptions: [], // JavaScript doesn't have checked exceptions
|
|
314
|
-
annotations: [],
|
|
315
|
-
defaultValue: undefined,
|
|
316
|
-
declaredFormalTypeNames: declaredFormalTypeNames,
|
|
317
|
-
toJSON: function () {
|
|
318
|
-
return Type.signature(this);
|
|
319
|
-
}
|
|
320
|
-
}) as Type.Method;
|
|
480
|
+
// Create the method type using the helper
|
|
481
|
+
return this.createMethodType(signature, node, declaringType, methodName, declaredFormalTypeNames);
|
|
321
482
|
}
|
|
322
483
|
|
|
323
|
-
/**
|
|
324
|
-
* Create a JavaType.Array from a TypeScript array type
|
|
325
|
-
*/
|
|
326
|
-
private createArrayType(type: ts.TypeReference): Type.Array {
|
|
327
|
-
// Get the element type (type argument of Array<T>)
|
|
328
|
-
const typeArgs = this.checker.getTypeArguments(type);
|
|
329
|
-
const elemType = typeArgs.length > 0 ? this.getType(typeArgs[0]) : Type.unknownType;
|
|
330
|
-
|
|
331
|
-
return Object.assign(new NonDraftableType(), {
|
|
332
|
-
kind: Type.Kind.Array,
|
|
333
|
-
elemType: elemType,
|
|
334
|
-
annotations: [],
|
|
335
|
-
toJSON: function () {
|
|
336
|
-
return Type.signature(this);
|
|
337
|
-
}
|
|
338
|
-
}) as Type.Array;
|
|
339
|
-
}
|
|
340
484
|
|
|
341
485
|
/**
|
|
342
486
|
* Get the fully qualified name for a TypeScript type.
|
|
343
|
-
*
|
|
487
|
+
* Uses TypeScript's built-in resolution which properly handles things like:
|
|
488
|
+
* - React.Component (not @types/react.Component)
|
|
489
|
+
* - _.LoDashStatic (not @types/lodash.LoDashStatic)
|
|
344
490
|
*/
|
|
345
491
|
private getFullyQualifiedName(type: ts.Type): string {
|
|
346
492
|
const symbol = type.getSymbol?.();
|
|
@@ -348,140 +494,100 @@ export class JavaScriptTypeMapping {
|
|
|
348
494
|
return "unknown";
|
|
349
495
|
}
|
|
350
496
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
if (
|
|
354
|
-
|
|
355
|
-
if (
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
// Check if this is a test file (snowflake ID as filename)
|
|
365
|
-
// Test files are generated with numeric IDs like "672087069480189952.ts"
|
|
366
|
-
if (/^\d+\.(ts|tsx|js|jsx)$/.test(fileName)) {
|
|
367
|
-
// For test files, just return the type name without module prefix
|
|
368
|
-
return typeName;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
// Check if this is from TypeScript's lib files (lib.d.ts, lib.dom.d.ts, etc.)
|
|
372
|
-
if (fileName.includes("/typescript/lib/lib.") || fileName.includes("\\typescript\\lib\\lib.")) {
|
|
373
|
-
return `lib.${typeName}`;
|
|
374
|
-
}
|
|
497
|
+
// First, check if this symbol is an import/alias
|
|
498
|
+
// For imported types, we want to use the module specifier instead of the file path
|
|
499
|
+
if (symbol.flags & ts.SymbolFlags.Alias) {
|
|
500
|
+
const aliasedSymbol = this.checker.getAliasedSymbol(symbol);
|
|
501
|
+
if (aliasedSymbol && aliasedSymbol !== symbol && symbol.declarations && symbol.declarations.length > 0) {
|
|
502
|
+
// Try to find the import declaration to get the module specifier
|
|
503
|
+
let importNode: ts.Node | undefined = symbol.declarations[0];
|
|
504
|
+
|
|
505
|
+
// Traverse up to find the ImportDeclaration or ImportSpecifier
|
|
506
|
+
while (importNode && importNode.parent && !ts.isImportDeclaration(importNode) && !ts.isImportSpecifier(importNode)) {
|
|
507
|
+
importNode = importNode.parent;
|
|
508
|
+
}
|
|
375
509
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
// For default exports from Node modules, we want the module to be the "class"
|
|
390
|
-
// But we still need to include the type name for proper identification
|
|
391
|
-
if (typeName === "default" || typeName === modulePath) {
|
|
392
|
-
// This is likely the default export, just use the module name
|
|
393
|
-
return `node.${modulePath}`;
|
|
394
|
-
}
|
|
395
|
-
// For named exports, include both module and type name
|
|
396
|
-
if (modulePath.includes('/')) {
|
|
397
|
-
return `node.${modulePath.replace(/\//g, '.')}.${typeName}`;
|
|
510
|
+
let moduleSpecifier: string | undefined;
|
|
511
|
+
|
|
512
|
+
if (importNode && ts.isImportSpecifier(importNode)) {
|
|
513
|
+
// Named import like: import { ClipLoader } from 'react-spinners'
|
|
514
|
+
// ImportSpecifier -> NamedImports -> ImportClause -> ImportDeclaration
|
|
515
|
+
const namedImports = importNode.parent; // NamedImports
|
|
516
|
+
if (namedImports && ts.isNamedImports(namedImports)) {
|
|
517
|
+
const importClause = namedImports.parent; // ImportClause
|
|
518
|
+
if (importClause && ts.isImportClause(importClause)) {
|
|
519
|
+
const importDecl = importClause.parent; // ImportDeclaration
|
|
520
|
+
if (importDecl && ts.isImportDeclaration(importDecl) && ts.isStringLiteral(importDecl.moduleSpecifier)) {
|
|
521
|
+
moduleSpecifier = importDecl.moduleSpecifier.text;
|
|
522
|
+
}
|
|
398
523
|
}
|
|
399
|
-
return `node.${modulePath}.${typeName}`;
|
|
400
524
|
}
|
|
401
|
-
|
|
402
|
-
|
|
525
|
+
} else if (importNode && ts.isImportDeclaration(importNode)) {
|
|
526
|
+
// Default or namespace import
|
|
527
|
+
if (ts.isStringLiteral(importNode.moduleSpecifier)) {
|
|
528
|
+
moduleSpecifier = importNode.moduleSpecifier.text;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
if (moduleSpecifier) {
|
|
533
|
+
// Build the fully qualified name from module specifier + symbol name
|
|
534
|
+
const symbolName = symbol.getName();
|
|
535
|
+
return `${moduleSpecifier}.${symbolName}`;
|
|
403
536
|
}
|
|
404
|
-
return `${packageName}.${typeName}`;
|
|
405
537
|
}
|
|
406
538
|
}
|
|
407
539
|
|
|
408
|
-
//
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
540
|
+
// Fall back to TypeScript's built-in getFullyQualifiedName
|
|
541
|
+
// This returns names with quotes that we need to clean up
|
|
542
|
+
// e.g., '"React"."Component"' -> 'React.Component'
|
|
543
|
+
const tsQualifiedName = this.checker.getFullyQualifiedName(symbol);
|
|
544
|
+
let cleanedName = tsQualifiedName.replace(/"/g, '');
|
|
545
|
+
|
|
546
|
+
// Check if this is a file path from node_modules (happens with some packages)
|
|
547
|
+
// TypeScript sometimes returns full paths instead of module names
|
|
548
|
+
if (cleanedName.includes('node_modules/')) {
|
|
549
|
+
// Extract the module name from the path
|
|
550
|
+
// Example: /private/var/.../node_modules/react-spinners/src/index.ClipLoader
|
|
551
|
+
// Should become: react-spinners.ClipLoader
|
|
552
|
+
const nodeModulesIndex = cleanedName.indexOf('node_modules/');
|
|
553
|
+
const afterNodeModules = cleanedName.substring(nodeModulesIndex + 'node_modules/'.length);
|
|
554
|
+
|
|
555
|
+
// Split by '/' to get parts of the path
|
|
556
|
+
const pathParts = afterNodeModules.split('/');
|
|
557
|
+
|
|
558
|
+
if (pathParts.length > 0) {
|
|
559
|
+
// First part is the package name (might be scoped like @types)
|
|
560
|
+
let packageName = pathParts[0];
|
|
561
|
+
|
|
562
|
+
// Handle scoped packages
|
|
563
|
+
if (packageName.startsWith('@') && pathParts.length > 1) {
|
|
564
|
+
packageName = `${packageName}/${pathParts[1]}`;
|
|
565
|
+
}
|
|
423
566
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
567
|
+
// Find the symbol name (everything after the last dot in the original cleaned name)
|
|
568
|
+
const lastDotIndex = cleanedName.lastIndexOf('.');
|
|
569
|
+
if (lastDotIndex > 0) {
|
|
570
|
+
const symbolName = cleanedName.substring(lastDotIndex + 1);
|
|
571
|
+
cleanedName = `${packageName}.${symbolName}`;
|
|
572
|
+
} else {
|
|
573
|
+
cleanedName = packageName;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
433
576
|
}
|
|
434
577
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
// Convert backslashes to forward slashes (for Windows)
|
|
439
|
-
relativePath = relativePath.replace(/\\/g, '/');
|
|
440
|
-
|
|
441
|
-
return relativePath;
|
|
578
|
+
return cleanedName.endsWith('Constructor') ?
|
|
579
|
+
cleanedName.substring(0, cleanedName.length - 'Constructor'.length) :
|
|
580
|
+
cleanedName;
|
|
442
581
|
}
|
|
443
582
|
|
|
583
|
+
|
|
444
584
|
/**
|
|
445
585
|
* Create an empty JavaType.Class shell from a TypeScript type.
|
|
446
586
|
* The shell will be populated later to handle circular references.
|
|
447
587
|
*/
|
|
448
588
|
private createEmptyClassType(type: ts.Type): Type.Class {
|
|
449
|
-
// Use our
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
// If getFullyQualifiedName returned unknown, fall back to TypeScript's method
|
|
453
|
-
if (fullyQualifiedName === "unknown") {
|
|
454
|
-
const symbol = type.symbol;
|
|
455
|
-
fullyQualifiedName = symbol ? this.checker.getFullyQualifiedName(symbol) : `<anonymous>${this.checker.typeToString(type)}`;
|
|
456
|
-
|
|
457
|
-
// Fix FQN for types from @types packages
|
|
458
|
-
// TypeScript returns "_.LoDashStatic" but we want "@types/lodash.LoDashStatic"
|
|
459
|
-
if (symbol && symbol.declarations && symbol.declarations.length > 0) {
|
|
460
|
-
const sourceFile = symbol.declarations[0].getSourceFile();
|
|
461
|
-
const fileName = sourceFile.fileName;
|
|
462
|
-
// Check if this is from @types package
|
|
463
|
-
const typesMatch = fileName.match(/node_modules\/@types\/([^/]+)/);
|
|
464
|
-
if (typesMatch) {
|
|
465
|
-
const packageName = typesMatch[1];
|
|
466
|
-
// Special handling for @types/node - use "node" prefix instead
|
|
467
|
-
if (packageName === "node") {
|
|
468
|
-
// Extract the module name from the file path if possible
|
|
469
|
-
const nodeMatch = fileName.match(/node_modules\/@types\/node\/([^.]+)\.d\.ts/);
|
|
470
|
-
if (nodeMatch) {
|
|
471
|
-
const modulePath = nodeMatch[1];
|
|
472
|
-
// Replace the module specifier with node.module
|
|
473
|
-
fullyQualifiedName = fullyQualifiedName.replace(/^[^.]+\./, `node.${modulePath}.`);
|
|
474
|
-
} else {
|
|
475
|
-
// Fallback: just use "node" prefix
|
|
476
|
-
fullyQualifiedName = fullyQualifiedName.replace(/^[^.]+\./, `node.`);
|
|
477
|
-
}
|
|
478
|
-
} else {
|
|
479
|
-
// Replace the module specifier part with @types/package
|
|
480
|
-
fullyQualifiedName = fullyQualifiedName.replace(/^[^.]+\./, `@types/${packageName}.`);
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
}
|
|
589
|
+
// Use our getFullyQualifiedName method which uses TypeScript's built-in resolution
|
|
590
|
+
const fullyQualifiedName = this.getFullyQualifiedName(type);
|
|
485
591
|
|
|
486
592
|
// Determine the class kind based on symbol flags
|
|
487
593
|
let classKind = Type.Class.Kind.Interface; // Default to interface
|