@openrewrite/rewrite 8.62.2 → 8.62.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/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.map +1 -1
- package/dist/java/tree.js +0 -87
- package/dist/java/tree.js.map +1 -1
- package/dist/java/visitor.d.ts +4 -4
- package/dist/java/visitor.d.ts.map +1 -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/parser.d.ts +1 -1
- package/dist/javascript/parser.d.ts.map +1 -1
- package/dist/javascript/parser.js +26 -4
- package/dist/javascript/parser.js.map +1 -1
- 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/rpc.js +1 -16
- package/dist/javascript/rpc.js.map +1 -1
- package/dist/javascript/type-mapping.d.ts +4 -19
- package/dist/javascript/type-mapping.d.ts.map +1 -1
- package/dist/javascript/type-mapping.js +228 -163
- 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.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 +2 -2
- package/dist/print.d.ts.map +1 -1
- package/dist/print.js +4 -2
- 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 +3 -4
- package/dist/rpc/request/print.d.ts.map +1 -1
- package/dist/rpc/request/print.js +5 -6
- 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 +3 -3
- package/dist/rpc/rewrite-rpc.d.ts.map +1 -1
- package/dist/rpc/rewrite-rpc.js +19 -16
- package/dist/rpc/rewrite-rpc.js.map +1 -1
- 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/version.txt +1 -1
- package/package.json +1 -1
- package/src/execution.ts +0 -2
- package/src/java/rpc.ts +68 -0
- package/src/java/tree.ts +1 -65
- package/src/java/visitor.ts +4 -4
- package/src/javascript/format.ts +2 -2
- package/src/javascript/parser.ts +19 -5
- package/src/javascript/print.ts +3 -3
- package/src/javascript/rpc.ts +4 -17
- package/src/javascript/type-mapping.ts +235 -170
- package/src/javascript/visitor.ts +1 -1
- 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 +6 -4
- 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 +5 -7
- package/src/rpc/request/visit.ts +6 -5
- package/src/rpc/rewrite-rpc.ts +24 -19
- package/src/test/rewrite-test.ts +1 -1
- package/src/text/rpc.ts +33 -37
|
@@ -34,8 +34,7 @@ export class JavaScriptTypeMapping {
|
|
|
34
34
|
private readonly regExpSymbol: ts.Symbol | undefined;
|
|
35
35
|
|
|
36
36
|
constructor(
|
|
37
|
-
private readonly checker: ts.TypeChecker
|
|
38
|
-
private readonly projectRoot: string = process.cwd()
|
|
37
|
+
private readonly checker: ts.TypeChecker
|
|
39
38
|
) {
|
|
40
39
|
this.regExpSymbol = checker.resolveName(
|
|
41
40
|
"RegExp",
|
|
@@ -62,15 +61,8 @@ export class JavaScriptTypeMapping {
|
|
|
62
61
|
return existing;
|
|
63
62
|
}
|
|
64
63
|
|
|
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)
|
|
64
|
+
// Check for class/interface/enum types (including arrays)
|
|
65
|
+
// Arrays in JavaScript are objects with methods, so we treat them as class types
|
|
74
66
|
const symbol = type.getSymbol?.();
|
|
75
67
|
if (symbol) {
|
|
76
68
|
if (symbol.flags & (ts.SymbolFlags.Class | ts.SymbolFlags.Interface | ts.SymbolFlags.Enum | ts.SymbolFlags.TypeAlias)) {
|
|
@@ -169,41 +161,164 @@ export class JavaScriptTypeMapping {
|
|
|
169
161
|
// Get the method name
|
|
170
162
|
if (ts.isPropertyAccessExpression(node.expression)) {
|
|
171
163
|
methodName = node.expression.name.getText();
|
|
164
|
+
|
|
165
|
+
// Check if the object is an imported symbol
|
|
166
|
+
const objSymbol = this.checker.getSymbolAtLocation(node.expression.expression);
|
|
167
|
+
let isImport = false;
|
|
168
|
+
if (objSymbol) {
|
|
169
|
+
// Only call getAliasedSymbol if the symbol is actually an alias
|
|
170
|
+
if (objSymbol.flags & ts.SymbolFlags.Alias) {
|
|
171
|
+
const aliasedSymbol = this.checker.getAliasedSymbol(objSymbol);
|
|
172
|
+
isImport = aliasedSymbol && aliasedSymbol !== objSymbol;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
172
176
|
const exprType = this.checker.getTypeAtLocation(node.expression.expression);
|
|
173
|
-
|
|
177
|
+
const mappedType = this.getType(exprType);
|
|
178
|
+
|
|
179
|
+
// Handle different types
|
|
180
|
+
if (mappedType && mappedType.kind === Type.Kind.Class) {
|
|
181
|
+
// Update the declaring type with the corrected FQN
|
|
182
|
+
if (isImport && objSymbol) {
|
|
183
|
+
const importName = objSymbol.getName();
|
|
184
|
+
const origFqn = (mappedType as Type.Class).fullyQualifiedName;
|
|
185
|
+
const lastDot = origFqn.lastIndexOf('.');
|
|
186
|
+
if (lastDot > 0) {
|
|
187
|
+
const typeName = origFqn.substring(lastDot + 1);
|
|
188
|
+
declaringType = {
|
|
189
|
+
kind: Type.Kind.Class,
|
|
190
|
+
fullyQualifiedName: `${importName}.${typeName}`
|
|
191
|
+
} as Type.FullyQualified;
|
|
192
|
+
} else {
|
|
193
|
+
declaringType = mappedType as Type.FullyQualified;
|
|
194
|
+
}
|
|
195
|
+
} else {
|
|
196
|
+
declaringType = mappedType as Type.FullyQualified;
|
|
197
|
+
}
|
|
198
|
+
} else {
|
|
199
|
+
// Handle primitive types and other non-class types
|
|
200
|
+
if (mappedType) {
|
|
201
|
+
if ((mappedType as any).keyword === 'String') {
|
|
202
|
+
declaringType = {
|
|
203
|
+
kind: Type.Kind.Class,
|
|
204
|
+
fullyQualifiedName: 'lib.String'
|
|
205
|
+
} as Type.FullyQualified;
|
|
206
|
+
} else if ((mappedType as any).keyword === 'Number') {
|
|
207
|
+
declaringType = {
|
|
208
|
+
kind: Type.Kind.Class,
|
|
209
|
+
fullyQualifiedName: 'lib.Number'
|
|
210
|
+
} as Type.FullyQualified;
|
|
211
|
+
} else {
|
|
212
|
+
// Fallback for other types
|
|
213
|
+
declaringType = mappedType as Type.FullyQualified;
|
|
214
|
+
}
|
|
215
|
+
} else {
|
|
216
|
+
// Default to unknown if we can't determine the type
|
|
217
|
+
declaringType = Type.unknownType as Type.FullyQualified;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// For string methods like 'hello'.split(), ensure we have a proper declaring type for primitives
|
|
222
|
+
if (!isImport && declaringType === Type.unknownType) {
|
|
223
|
+
// If the expression type is a primitive string, use lib.String as declaring type
|
|
224
|
+
const typeString = this.checker.typeToString(exprType);
|
|
225
|
+
if (typeString === 'string' || exprType.flags & ts.TypeFlags.String || exprType.flags & ts.TypeFlags.StringLiteral) {
|
|
226
|
+
declaringType = {
|
|
227
|
+
kind: Type.Kind.Class,
|
|
228
|
+
fullyQualifiedName: 'lib.String'
|
|
229
|
+
} as Type.FullyQualified;
|
|
230
|
+
} else if (typeString === 'number' || exprType.flags & ts.TypeFlags.Number || exprType.flags & ts.TypeFlags.NumberLiteral) {
|
|
231
|
+
declaringType = {
|
|
232
|
+
kind: Type.Kind.Class,
|
|
233
|
+
fullyQualifiedName: 'lib.Number'
|
|
234
|
+
} as Type.FullyQualified;
|
|
235
|
+
} else {
|
|
236
|
+
// Fallback for other primitive types or unknown
|
|
237
|
+
declaringType = Type.unknownType as Type.FullyQualified;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
174
241
|
} else if (ts.isIdentifier(node.expression)) {
|
|
175
242
|
methodName = node.expression.getText();
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
if (
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
243
|
+
|
|
244
|
+
// Check if this is an import first
|
|
245
|
+
const symbol = this.checker.getSymbolAtLocation(node.expression);
|
|
246
|
+
let moduleSpecifier: string | undefined;
|
|
247
|
+
|
|
248
|
+
if (symbol) {
|
|
249
|
+
// Check if this is an aliased symbol (i.e., an import)
|
|
250
|
+
let aliasedSymbol: ts.Symbol | undefined;
|
|
251
|
+
if (symbol.flags & ts.SymbolFlags.Alias) {
|
|
252
|
+
aliasedSymbol = this.checker.getAliasedSymbol(symbol);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// If getAliasedSymbol returns something different, it's an import
|
|
256
|
+
if (aliasedSymbol && aliasedSymbol !== symbol) {
|
|
257
|
+
// This is definitely an imported symbol
|
|
258
|
+
// Now find the import declaration to get the module specifier
|
|
259
|
+
if (symbol.declarations && symbol.declarations.length > 0) {
|
|
260
|
+
let importNode: ts.Node = symbol.declarations[0];
|
|
261
|
+
|
|
262
|
+
// Traverse up to find the ImportDeclaration
|
|
263
|
+
while (importNode && !ts.isImportDeclaration(importNode)) {
|
|
264
|
+
importNode = importNode.parent;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (importNode && ts.isImportDeclaration(importNode)) {
|
|
268
|
+
const importDeclNode = importNode as ts.ImportDeclaration;
|
|
269
|
+
if (ts.isStringLiteral(importDeclNode.moduleSpecifier)) {
|
|
270
|
+
moduleSpecifier = importDeclNode.moduleSpecifier.text;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (moduleSpecifier) {
|
|
278
|
+
// This is an imported function - use the module specifier as declaring type
|
|
279
|
+
if (moduleSpecifier.startsWith('node:')) {
|
|
280
|
+
// Node.js built-in module
|
|
190
281
|
declaringType = {
|
|
191
282
|
kind: Type.Kind.Class,
|
|
192
|
-
fullyQualifiedName:
|
|
283
|
+
fullyQualifiedName: 'node'
|
|
193
284
|
} as Type.FullyQualified;
|
|
285
|
+
methodName = moduleSpecifier.substring(5); // Remove 'node:' prefix
|
|
194
286
|
} else {
|
|
195
|
-
//
|
|
196
|
-
|
|
197
|
-
|
|
287
|
+
// Regular module import
|
|
288
|
+
declaringType = {
|
|
289
|
+
kind: Type.Kind.Class,
|
|
290
|
+
fullyQualifiedName: moduleSpecifier
|
|
291
|
+
} as Type.FullyQualified;
|
|
292
|
+
methodName = '<default>';
|
|
198
293
|
}
|
|
199
294
|
} else {
|
|
200
|
-
//
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
295
|
+
// Fall back to the original logic for non-imported functions
|
|
296
|
+
const exprType = this.checker.getTypeAtLocation(node.expression);
|
|
297
|
+
const funcType = this.getType(exprType);
|
|
298
|
+
|
|
299
|
+
if (funcType && funcType.kind === Type.Kind.Class) {
|
|
300
|
+
const fqn = (funcType as Type.Class).fullyQualifiedName;
|
|
301
|
+
const lastDot = fqn.lastIndexOf('.');
|
|
302
|
+
|
|
303
|
+
if (lastDot > 0) {
|
|
304
|
+
// For functions from modules, use the module part as declaring type
|
|
305
|
+
declaringType = {
|
|
306
|
+
kind: Type.Kind.Class,
|
|
307
|
+
fullyQualifiedName: fqn.substring(0, lastDot)
|
|
308
|
+
} as Type.FullyQualified;
|
|
309
|
+
} else {
|
|
310
|
+
// No dots in the name - the type IS the module itself
|
|
311
|
+
declaringType = funcType as Type.FullyQualified;
|
|
312
|
+
}
|
|
205
313
|
} else {
|
|
206
|
-
|
|
314
|
+
// Try to use the symbol's parent or module
|
|
315
|
+
const parent = (symbol as any).parent;
|
|
316
|
+
if (parent) {
|
|
317
|
+
const parentType = this.checker.getDeclaredTypeOfSymbol(parent);
|
|
318
|
+
declaringType = this.getType(parentType) as Type.FullyQualified;
|
|
319
|
+
} else {
|
|
320
|
+
declaringType = Type.unknownType as Type.FullyQualified;
|
|
321
|
+
}
|
|
207
322
|
}
|
|
208
323
|
}
|
|
209
324
|
} else {
|
|
@@ -298,27 +413,12 @@ export class JavaScriptTypeMapping {
|
|
|
298
413
|
}) as Type.Method;
|
|
299
414
|
}
|
|
300
415
|
|
|
301
|
-
/**
|
|
302
|
-
* Create a JavaType.Array from a TypeScript array type
|
|
303
|
-
*/
|
|
304
|
-
private createArrayType(type: ts.TypeReference): Type.Array {
|
|
305
|
-
// Get the element type (type argument of Array<T>)
|
|
306
|
-
const typeArgs = this.checker.getTypeArguments(type);
|
|
307
|
-
const elemType = typeArgs.length > 0 ? this.getType(typeArgs[0]) : Type.unknownType;
|
|
308
|
-
|
|
309
|
-
return Object.assign(new NonDraftableType(), {
|
|
310
|
-
kind: Type.Kind.Array,
|
|
311
|
-
elemType: elemType,
|
|
312
|
-
annotations: [],
|
|
313
|
-
toJSON: function () {
|
|
314
|
-
return Type.signature(this);
|
|
315
|
-
}
|
|
316
|
-
}) as Type.Array;
|
|
317
|
-
}
|
|
318
416
|
|
|
319
417
|
/**
|
|
320
418
|
* Get the fully qualified name for a TypeScript type.
|
|
321
|
-
*
|
|
419
|
+
* Uses TypeScript's built-in resolution which properly handles things like:
|
|
420
|
+
* - React.Component (not @types/react.Component)
|
|
421
|
+
* - _.LoDashStatic (not @types/lodash.LoDashStatic)
|
|
322
422
|
*/
|
|
323
423
|
private getFullyQualifiedName(type: ts.Type): string {
|
|
324
424
|
const symbol = type.getSymbol?.();
|
|
@@ -326,140 +426,105 @@ export class JavaScriptTypeMapping {
|
|
|
326
426
|
return "unknown";
|
|
327
427
|
}
|
|
328
428
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
if (
|
|
332
|
-
|
|
333
|
-
if (
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
// Check if this is a test file (snowflake ID as filename)
|
|
343
|
-
// Test files are generated with numeric IDs like "672087069480189952.ts"
|
|
344
|
-
if (/^\d+\.(ts|tsx|js|jsx)$/.test(fileName)) {
|
|
345
|
-
// For test files, just return the type name without module prefix
|
|
346
|
-
return typeName;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
// Check if this is from TypeScript's lib files (lib.d.ts, lib.dom.d.ts, etc.)
|
|
350
|
-
if (fileName.includes("/typescript/lib/lib.") || fileName.includes("\\typescript\\lib\\lib.")) {
|
|
351
|
-
return `lib.${typeName}`;
|
|
352
|
-
}
|
|
429
|
+
// First, check if this symbol is an import/alias
|
|
430
|
+
// For imported types, we want to use the module specifier instead of the file path
|
|
431
|
+
if (symbol.flags & ts.SymbolFlags.Alias) {
|
|
432
|
+
const aliasedSymbol = this.checker.getAliasedSymbol(symbol);
|
|
433
|
+
if (aliasedSymbol && aliasedSymbol !== symbol && symbol.declarations && symbol.declarations.length > 0) {
|
|
434
|
+
// Try to find the import declaration to get the module specifier
|
|
435
|
+
let importNode: ts.Node | undefined = symbol.declarations[0];
|
|
436
|
+
|
|
437
|
+
// Traverse up to find the ImportDeclaration or ImportSpecifier
|
|
438
|
+
while (importNode && importNode.parent && !ts.isImportDeclaration(importNode) && !ts.isImportSpecifier(importNode)) {
|
|
439
|
+
importNode = importNode.parent;
|
|
440
|
+
}
|
|
353
441
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
// For default exports from Node modules, we want the module to be the "class"
|
|
368
|
-
// But we still need to include the type name for proper identification
|
|
369
|
-
if (typeName === "default" || typeName === modulePath) {
|
|
370
|
-
// This is likely the default export, just use the module name
|
|
371
|
-
return `node.${modulePath}`;
|
|
442
|
+
let moduleSpecifier: string | undefined;
|
|
443
|
+
|
|
444
|
+
if (importNode && ts.isImportSpecifier(importNode)) {
|
|
445
|
+
// Named import like: import { ClipLoader } from 'react-spinners'
|
|
446
|
+
// ImportSpecifier -> NamedImports -> ImportClause -> ImportDeclaration
|
|
447
|
+
const namedImports = importNode.parent; // NamedImports
|
|
448
|
+
if (namedImports && ts.isNamedImports(namedImports)) {
|
|
449
|
+
const importClause = namedImports.parent; // ImportClause
|
|
450
|
+
if (importClause && ts.isImportClause(importClause)) {
|
|
451
|
+
const importDecl = importClause.parent; // ImportDeclaration
|
|
452
|
+
if (importDecl && ts.isImportDeclaration(importDecl) && ts.isStringLiteral(importDecl.moduleSpecifier)) {
|
|
453
|
+
moduleSpecifier = importDecl.moduleSpecifier.text;
|
|
454
|
+
}
|
|
372
455
|
}
|
|
373
|
-
// For named exports, include both module and type name
|
|
374
|
-
if (modulePath.includes('/')) {
|
|
375
|
-
return `node.${modulePath.replace(/\//g, '.')}.${typeName}`;
|
|
376
|
-
}
|
|
377
|
-
return `node.${modulePath}.${typeName}`;
|
|
378
456
|
}
|
|
379
|
-
|
|
380
|
-
|
|
457
|
+
} else if (importNode && ts.isImportDeclaration(importNode)) {
|
|
458
|
+
// Default or namespace import
|
|
459
|
+
if (ts.isStringLiteral(importNode.moduleSpecifier)) {
|
|
460
|
+
moduleSpecifier = importNode.moduleSpecifier.text;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
if (moduleSpecifier) {
|
|
465
|
+
// Build the fully qualified name from module specifier + symbol name
|
|
466
|
+
const symbolName = symbol.getName();
|
|
467
|
+
return `${moduleSpecifier}.${symbolName}`;
|
|
381
468
|
}
|
|
382
|
-
return `${packageName}.${typeName}`;
|
|
383
469
|
}
|
|
384
470
|
}
|
|
385
471
|
|
|
386
|
-
//
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
472
|
+
// Fall back to TypeScript's built-in getFullyQualifiedName
|
|
473
|
+
// This returns names with quotes that we need to clean up
|
|
474
|
+
// e.g., '"React"."Component"' -> 'React.Component'
|
|
475
|
+
const tsQualifiedName = this.checker.getFullyQualifiedName(symbol);
|
|
476
|
+
let cleanedName = tsQualifiedName.replace(/"/g, '');
|
|
477
|
+
|
|
478
|
+
// Check if this is a file path from node_modules (happens with some packages)
|
|
479
|
+
// TypeScript sometimes returns full paths instead of module names
|
|
480
|
+
if (cleanedName.includes('node_modules/')) {
|
|
481
|
+
// Extract the module name from the path
|
|
482
|
+
// Example: /private/var/.../node_modules/react-spinners/src/index.ClipLoader
|
|
483
|
+
// Should become: react-spinners.ClipLoader
|
|
484
|
+
const nodeModulesIndex = cleanedName.indexOf('node_modules/');
|
|
485
|
+
const afterNodeModules = cleanedName.substring(nodeModulesIndex + 'node_modules/'.length);
|
|
486
|
+
|
|
487
|
+
// Split by '/' to get parts of the path
|
|
488
|
+
const pathParts = afterNodeModules.split('/');
|
|
489
|
+
|
|
490
|
+
if (pathParts.length > 0) {
|
|
491
|
+
// First part is the package name (might be scoped like @types)
|
|
492
|
+
let packageName = pathParts[0];
|
|
493
|
+
|
|
494
|
+
// Handle scoped packages
|
|
495
|
+
if (packageName.startsWith('@') && pathParts.length > 1) {
|
|
496
|
+
packageName = `${packageName}/${pathParts[1]}`;
|
|
497
|
+
}
|
|
401
498
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
499
|
+
// Find the symbol name (everything after the last dot in the original cleaned name)
|
|
500
|
+
const lastDotIndex = cleanedName.lastIndexOf('.');
|
|
501
|
+
if (lastDotIndex > 0) {
|
|
502
|
+
const symbolName = cleanedName.substring(lastDotIndex + 1);
|
|
503
|
+
cleanedName = `${packageName}.${symbolName}`;
|
|
504
|
+
} else {
|
|
505
|
+
cleanedName = packageName;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
411
508
|
}
|
|
412
509
|
|
|
413
|
-
//
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
510
|
+
// If it's just a simple name without dots, check if it's a built-in type
|
|
511
|
+
if (!cleanedName.includes('.')) {
|
|
512
|
+
if (builtInTypes.has(cleanedName)) {
|
|
513
|
+
return `lib.${cleanedName}`;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
418
516
|
|
|
419
|
-
return
|
|
517
|
+
return cleanedName;
|
|
420
518
|
}
|
|
421
519
|
|
|
520
|
+
|
|
422
521
|
/**
|
|
423
522
|
* Create an empty JavaType.Class shell from a TypeScript type.
|
|
424
523
|
* The shell will be populated later to handle circular references.
|
|
425
524
|
*/
|
|
426
525
|
private createEmptyClassType(type: ts.Type): Type.Class {
|
|
427
|
-
// Use our
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
// If getFullyQualifiedName returned unknown, fall back to TypeScript's method
|
|
431
|
-
if (fullyQualifiedName === "unknown") {
|
|
432
|
-
const symbol = type.symbol;
|
|
433
|
-
fullyQualifiedName = symbol ? this.checker.getFullyQualifiedName(symbol) : `<anonymous>${this.checker.typeToString(type)}`;
|
|
434
|
-
|
|
435
|
-
// Fix FQN for types from @types packages
|
|
436
|
-
// TypeScript returns "_.LoDashStatic" but we want "@types/lodash.LoDashStatic"
|
|
437
|
-
if (symbol && symbol.declarations && symbol.declarations.length > 0) {
|
|
438
|
-
const sourceFile = symbol.declarations[0].getSourceFile();
|
|
439
|
-
const fileName = sourceFile.fileName;
|
|
440
|
-
// Check if this is from @types package
|
|
441
|
-
const typesMatch = fileName.match(/node_modules\/@types\/([^/]+)/);
|
|
442
|
-
if (typesMatch) {
|
|
443
|
-
const packageName = typesMatch[1];
|
|
444
|
-
// Special handling for @types/node - use "node" prefix instead
|
|
445
|
-
if (packageName === "node") {
|
|
446
|
-
// Extract the module name from the file path if possible
|
|
447
|
-
const nodeMatch = fileName.match(/node_modules\/@types\/node\/([^.]+)\.d\.ts/);
|
|
448
|
-
if (nodeMatch) {
|
|
449
|
-
const modulePath = nodeMatch[1];
|
|
450
|
-
// Replace the module specifier with node.module
|
|
451
|
-
fullyQualifiedName = fullyQualifiedName.replace(/^[^.]+\./, `node.${modulePath}.`);
|
|
452
|
-
} else {
|
|
453
|
-
// Fallback: just use "node" prefix
|
|
454
|
-
fullyQualifiedName = fullyQualifiedName.replace(/^[^.]+\./, `node.`);
|
|
455
|
-
}
|
|
456
|
-
} else {
|
|
457
|
-
// Replace the module specifier part with @types/package
|
|
458
|
-
fullyQualifiedName = fullyQualifiedName.replace(/^[^.]+\./, `@types/${packageName}.`);
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
}
|
|
526
|
+
// Use our getFullyQualifiedName method which uses TypeScript's built-in resolution
|
|
527
|
+
const fullyQualifiedName = this.getFullyQualifiedName(type);
|
|
463
528
|
|
|
464
529
|
// Determine the class kind based on symbol flags
|
|
465
530
|
let classKind = Type.Class.Kind.Interface; // Default to interface
|
|
@@ -40,7 +40,7 @@ export class JavaScriptVisitor<P> extends JavaVisitor<P> {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
// noinspection JSUnusedLocalSymbols
|
|
43
|
-
|
|
43
|
+
override async visitSpace(space: J.Space, p: P): Promise<J.Space> {
|
|
44
44
|
return space;
|
|
45
45
|
}
|
|
46
46
|
|
package/src/json/print.ts
CHANGED
|
@@ -75,7 +75,7 @@ class JsonPrinter extends JsonVisitor<PrintOutputCapture> {
|
|
|
75
75
|
return jsonObject;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
public async visitSpace(space: Json.Space, p: PrintOutputCapture): Promise<Json.Space> {
|
|
79
79
|
p.append(space.whitespace);
|
|
80
80
|
for (const comment of space.comments) {
|
|
81
81
|
await this.visitMarkers(comment.markers, p);
|
package/src/json/rpc.ts
CHANGED
|
@@ -14,11 +14,10 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
import {JsonVisitor} from "./visitor";
|
|
17
|
-
import {asRef,
|
|
17
|
+
import {asRef, RpcCodecs, RpcReceiveQueue, RpcSendQueue} from "../rpc";
|
|
18
18
|
import {Json} from "./tree";
|
|
19
19
|
import {produceAsync} from "../visitor";
|
|
20
20
|
import {createDraft, Draft, finishDraft} from "immer";
|
|
21
|
-
import {TreeKind} from "../tree";
|
|
22
21
|
|
|
23
22
|
class JsonSender extends JsonVisitor<RpcSendQueue> {
|
|
24
23
|
|
|
@@ -76,7 +75,7 @@ class JsonSender extends JsonVisitor<RpcSendQueue> {
|
|
|
76
75
|
return obj;
|
|
77
76
|
}
|
|
78
77
|
|
|
79
|
-
|
|
78
|
+
public async visitSpace(space: Json.Space, q: RpcSendQueue): Promise<Json.Space> {
|
|
80
79
|
await q.getAndSendList(space, s => s.comments, c => c.text + c.suffix, async c => {
|
|
81
80
|
await q.getAndSend(c, c2 => c2.multiline);
|
|
82
81
|
await q.getAndSend(c, c2 => c2.text);
|
|
@@ -87,7 +86,7 @@ class JsonSender extends JsonVisitor<RpcSendQueue> {
|
|
|
87
86
|
return space;
|
|
88
87
|
}
|
|
89
88
|
|
|
90
|
-
|
|
89
|
+
public async visitRightPadded<T extends Json>(right: Json.RightPadded<T>, q: RpcSendQueue): Promise<Json.RightPadded<T> | undefined> {
|
|
91
90
|
await q.getAndSend(right, r => r.element, j => this.visit(j, q));
|
|
92
91
|
await q.getAndSend(right, r => asRef(r.after), async space => await this.visitSpace(space, q));
|
|
93
92
|
await q.getAndSend(right, r => r.markers);
|
|
@@ -158,7 +157,7 @@ class JsonReceiver extends JsonVisitor<RpcReceiveQueue> {
|
|
|
158
157
|
return finishDraft(draft);
|
|
159
158
|
}
|
|
160
159
|
|
|
161
|
-
|
|
160
|
+
public async visitSpace(space: Json.Space, q: RpcReceiveQueue): Promise<Json.Space> {
|
|
162
161
|
return produceAsync<Json.Space>(space, async draft => {
|
|
163
162
|
draft.comments = await q.receiveListDefined(space.comments, async c => {
|
|
164
163
|
return await produceAsync(c, async draft => {
|
|
@@ -172,7 +171,7 @@ class JsonReceiver extends JsonVisitor<RpcReceiveQueue> {
|
|
|
172
171
|
});
|
|
173
172
|
}
|
|
174
173
|
|
|
175
|
-
|
|
174
|
+
public async visitRightPadded<T extends Json>(right: Json.RightPadded<T>, p: RpcReceiveQueue): Promise<Json.RightPadded<T> | undefined> {
|
|
176
175
|
if (!right) {
|
|
177
176
|
throw new Error("TreeDataReceiveQueue should have instantiated an empty padding")
|
|
178
177
|
}
|
|
@@ -184,18 +183,40 @@ class JsonReceiver extends JsonVisitor<RpcReceiveQueue> {
|
|
|
184
183
|
}
|
|
185
184
|
}
|
|
186
185
|
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
186
|
+
const receiver = new JsonReceiver();
|
|
187
|
+
const sender = new JsonSender();
|
|
188
|
+
|
|
189
|
+
// Register codec for all Java AST node types
|
|
190
|
+
for (const kind of Object.values(Json.Kind)) {
|
|
191
|
+
if (kind === Json.Kind.Space) {
|
|
192
|
+
RpcCodecs.registerCodec(kind, {
|
|
193
|
+
async rpcReceive(before: Json.Space, q: RpcReceiveQueue): Promise<Json.Space> {
|
|
194
|
+
return (await receiver.visitSpace(before, q))!;
|
|
195
|
+
},
|
|
196
|
+
|
|
197
|
+
async rpcSend(after: Json.Space, q: RpcSendQueue): Promise<void> {
|
|
198
|
+
await sender.visitSpace(after, q);
|
|
199
|
+
}
|
|
200
|
+
}, Json.Kind.Document);
|
|
201
|
+
} else if (kind === Json.Kind.RightPadded) {
|
|
202
|
+
RpcCodecs.registerCodec(kind, {
|
|
203
|
+
async rpcReceive<T extends Json>(before: Json.RightPadded<T>, q: RpcReceiveQueue): Promise<Json.RightPadded<T>> {
|
|
204
|
+
return (await receiver.visitRightPadded(before, q))!;
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
async rpcSend<T extends Json>(after: Json.RightPadded<T>, q: RpcSendQueue): Promise<void> {
|
|
208
|
+
await sender.visitRightPadded(after, q);
|
|
209
|
+
}
|
|
210
|
+
}, Json.Kind.Document);
|
|
211
|
+
} else {
|
|
212
|
+
RpcCodecs.registerCodec(kind as string, {
|
|
213
|
+
async rpcReceive(before: Json, q: RpcReceiveQueue): Promise<Json> {
|
|
214
|
+
return (await receiver.visit(before, q))!;
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
async rpcSend(after: Json, q: RpcSendQueue): Promise<void> {
|
|
218
|
+
await sender.visit(after, q);
|
|
219
|
+
}
|
|
220
|
+
}, Json.Kind.Document);
|
|
194
221
|
}
|
|
195
222
|
}
|
|
196
|
-
|
|
197
|
-
Object.values(Json.Kind).forEach(kind => {
|
|
198
|
-
if (!Object.values(TreeKind).includes(kind as any)) {
|
|
199
|
-
RpcCodecs.registerCodec(kind, jsonCodec);
|
|
200
|
-
}
|
|
201
|
-
});
|
package/src/json/visitor.ts
CHANGED
|
@@ -62,7 +62,7 @@ export class JsonVisitor<P> extends TreeVisitor<Json, P> {
|
|
|
62
62
|
});
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
public async visitRightPadded<T extends Json>(right: Json.RightPadded<T>, p: P):
|
|
66
66
|
Promise<Json.RightPadded<T> | undefined> {
|
|
67
67
|
return produceAsync<Json.RightPadded<T>>(right, async draft => {
|
|
68
68
|
draft.element = await this.visitDefined(right.element, p);
|
|
@@ -70,7 +70,7 @@ export class JsonVisitor<P> extends TreeVisitor<Json, P> {
|
|
|
70
70
|
});
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
public async visitSpace(space: Json.Space, p: P): Promise<Json.Space> {
|
|
74
74
|
return space;
|
|
75
75
|
}
|
|
76
76
|
|
package/src/print.ts
CHANGED
|
@@ -143,11 +143,13 @@ export class TreePrinters {
|
|
|
143
143
|
* @param target Helps to determine what kind of language we are dealing with when
|
|
144
144
|
* printing a subtree whose LST type is shared between multiple languages in a language family.
|
|
145
145
|
*/
|
|
146
|
-
static printer(target: Cursor | SourceFile): TreePrinter {
|
|
147
|
-
const sourceFileKind =
|
|
146
|
+
static printer(target: Cursor | SourceFile | string): TreePrinter {
|
|
147
|
+
const sourceFileKind = typeof target === 'string' ?
|
|
148
|
+
target :
|
|
149
|
+
(isSourceFile(target) ?
|
|
148
150
|
target as SourceFile :
|
|
149
151
|
target.firstEnclosing(isSourceFile)
|
|
150
|
-
|
|
152
|
+
)!.kind
|
|
151
153
|
|
|
152
154
|
if (!this._registry.has(sourceFileKind)) {
|
|
153
155
|
throw new Error(`No printer registered for ${sourceFileKind}`)
|
|
@@ -160,6 +162,6 @@ export class TreePrinters {
|
|
|
160
162
|
}
|
|
161
163
|
}
|
|
162
164
|
|
|
163
|
-
export function printer(target: Cursor | SourceFile): TreePrinter {
|
|
165
|
+
export function printer(target: Cursor | SourceFile | string): TreePrinter {
|
|
164
166
|
return TreePrinters.printer(target);
|
|
165
167
|
}
|