diff --git a/openrewrite/src/javascript/parser.ts b/openrewrite/src/javascript/parser.ts index dd2475e4..dd055b46 100644 --- a/openrewrite/src/javascript/parser.ts +++ b/openrewrite/src/javascript/parser.ts @@ -42,7 +42,7 @@ export class JavaScriptParser extends Parser { const result: SourceFile[] = []; for (const filePath of program.getRootFileNames()) { const sourceFile = program.getSourceFile(filePath)!; - const input = new ParserInput(filePath, null, false, () => Buffer.from(ts.sys.readFile(filePath)!)); + const input = new ParserInput(filePath, null, false, () => Buffer.from(ts.sys.readFile(filePath)!)); try { const parsed = new JavaScriptParserVisitor(this, sourceFile, typeChecker).visit(sourceFile) as SourceFile; result.push(parsed); @@ -532,7 +532,7 @@ export class JavaScriptParserVisitor { } visitQualifiedName(node: ts.QualifiedName) { - return new J.FieldAccess( + const fieldAccess = new J.FieldAccess( randomId(), this.prefix(node), Markers.EMPTY, @@ -540,6 +540,20 @@ export class JavaScriptParserVisitor { new JLeftPadded(this.suffix(node.left), this.convert(node.right), Markers.EMPTY), this.mapType(node) ); + + const parent = node.parent as ts.TypeReferenceNode; + if (parent.typeArguments) { + return new J.ParameterizedType( + randomId(), + this.prefix(parent), + Markers.EMPTY, + fieldAccess, + this.mapTypeArguments(parent.typeArguments), + this.mapType(parent) + ) + } else { + return fieldAccess; + } } visitComputedPropertyName(node: ts.ComputedPropertyName) { @@ -688,6 +702,10 @@ export class JavaScriptParserVisitor { visitTypeReference(node: ts.TypeReferenceNode) { if (node.typeArguments) { + // Temporary check for supported constructions with type arguments + if (ts.isQualifiedName(node.typeName)) { + return this.visit(node.typeName); + } return this.visitUnknown(node); } return this.visit(node.typeName); @@ -831,7 +849,7 @@ export class JavaScriptParserVisitor { const statements: JRightPadded[] = this.rightPaddedSeparatedList( [...statementList.getChildren(this.sourceFile)], ts.SyntaxKind.CommaToken, - (nodes, i) => i == nodes.length -2 && nodes[i + 1].kind == ts.SyntaxKind.CommaToken ? Markers.build([new TrailingComma(randomId(), this.prefix(nodes[i + 1]))]) : Markers.EMPTY + (nodes, i) => i == nodes.length - 2 && nodes[i + 1].kind == ts.SyntaxKind.CommaToken ? Markers.build([new TrailingComma(randomId(), this.prefix(nodes[i + 1]))]) : Markers.EMPTY ); return new J.Block( @@ -1929,6 +1947,24 @@ export class JavaScriptParserVisitor { return this.mapToContainer(nodes, this.trailingComma(nodes)); } + private mapTypeArguments(nodes: readonly ts.Node[]): JContainer { + if (nodes.length === 0) { + return JContainer.empty(); + } + + const args = nodes.map(node => + this.rightPadded( + this.visit(node), + this.suffix(node), + Markers.EMPTY + )) + return new JContainer( + this.prefix(nodes[0]), + args, + Markers.EMPTY + ); + } + private trailingComma = (nodes: readonly ts.Node[]) => (ns: readonly ts.Node[], i: number) => { const last = i === ns.length - 2; return last ? Markers.build([new TrailingComma(randomId(), this.prefix(nodes[2], false))]) : Markers.EMPTY; diff --git a/openrewrite/test/javascript/parser/qualifiedName.test.ts b/openrewrite/test/javascript/parser/qualifiedName.test.ts index 08167ab6..8ec05b41 100644 --- a/openrewrite/test/javascript/parser/qualifiedName.test.ts +++ b/openrewrite/test/javascript/parser/qualifiedName.test.ts @@ -11,6 +11,20 @@ describe('empty mapping', () => { ); }); + test('globalThis qualified name with generic', () => { + rewriteRun( + //language=typescript + typeScript('const value: globalThis.Promise< string > = null') + ); + }); + + test('globalThis qualified name with comments', () => { + rewriteRun( + //language=typescript + typeScript('const value /*a123*/ : globalThis. globalThis . /*asda*/ globalThis.Promise = null;') + ); + }); + test.skip('nested class qualified name', () => { rewriteRun( //language=typescript