diff --git a/openrewrite/src/javascript/parser.ts b/openrewrite/src/javascript/parser.ts index c365efd3..a5239f31 100644 --- a/openrewrite/src/javascript/parser.ts +++ b/openrewrite/src/javascript/parser.ts @@ -14,7 +14,6 @@ import { } from "../core"; import {binarySearch, compareTextSpans, getNextSibling, TextSpan} from "./parserUtils"; import {JavaScriptTypeMapping} from "./typeMapping"; -import {SignatureDeclarationBase} from "typescript"; export class JavaScriptParser extends Parser { @@ -839,7 +838,6 @@ export class JavaScriptParserVisitor { Markers.EMPTY, [], // no decorators allowed [], // no modifiers allowed - this.mapTypeParametersAsObject(node), this.mapTypeInfo(node), this.getOptionalUnary(node), @@ -913,7 +911,8 @@ export class JavaScriptParserVisitor { } private mapTypeInfo(node: ts.MethodDeclaration | ts.PropertyDeclaration | ts.VariableDeclaration | ts.ParameterDeclaration - | ts.PropertySignature | ts.MethodSignature | ts.ArrowFunction | ts.CallSignatureDeclaration | ts.GetAccessorDeclaration | ts.FunctionDeclaration) { + | ts.PropertySignature | ts.MethodSignature | ts.ArrowFunction | ts.CallSignatureDeclaration | ts.GetAccessorDeclaration + | ts.FunctionDeclaration | ts.ConstructSignatureDeclaration) { return node.type ? new JS.TypeInfo(randomId(), this.prefix(node.getChildAt(node.getChildren().indexOf(node.type) - 1)), Markers.EMPTY, this.visit(node.type)) : null; } @@ -922,7 +921,7 @@ export class JavaScriptParserVisitor { randomId(), this.prefix(node), Markers.EMPTY, - new JRightPadded(true,this.prefix(node.body.getChildren().find(v => v.kind === ts.SyntaxKind.OpenBraceToken)!), Markers.EMPTY), + new JRightPadded(true, this.prefix(this.findChildNode(node.body, ts.SyntaxKind.OpenBraceToken)!), Markers.EMPTY), node.body.statements.map(ce => new JRightPadded( this.convert(ce), ce.getLastToken()?.kind === ts.SyntaxKind.SemicolonToken ? this.prefix(ce.getLastToken()!) : Space.EMPTY, @@ -1023,7 +1022,32 @@ export class JavaScriptParserVisitor { } visitConstructSignature(node: ts.ConstructSignatureDeclaration) { - return this.visitUnknown(node); + return new J.MethodDeclaration( + randomId(), + this.prefix(node), + Markers.EMPTY, + [], // no decorators allowed + [], // no modifiers allowed + this.mapTypeParametersAsObject(node), + this.mapTypeInfo(node), + new J.MethodDeclaration.IdentifierWithAnnotations( + new J.Identifier( + randomId(), + Space.EMPTY, + Markers.EMPTY, + [], + 'new', + null, + null + ), + [] + ), + this.mapCommaSeparatedList(this.getParameterListNodes(node)), + null, + null, + null, + this.mapMethodType(node) + ); } visitIndexSignature(node: ts.IndexSignatureDeclaration) { @@ -2572,10 +2596,16 @@ export class JavaScriptParserVisitor { : null; } - private mapTypeParametersAsObject(node: ts.MethodDeclaration | ts.MethodSignature | ts.FunctionDeclaration | ts.CallSignatureDeclaration) : J.TypeParameters | null { - return node.typeParameters - ? new J.TypeParameters(randomId(), node.questionToken ? this.suffix(node.questionToken) : node.name ? this.suffix(node.name) : Space.EMPTY, Markers.EMPTY, [], node.typeParameters.map(tp => this.rightPadded(this.visit(tp), this.suffix(tp)))) - : null; + private mapTypeParametersAsObject(node: ts.MethodDeclaration | ts.MethodSignature | ts.FunctionDeclaration | ts.CallSignatureDeclaration | ts.ConstructSignatureDeclaration) : J.TypeParameters | null { + if (!node.typeParameters) return null; + + let ts_prefix; + if (ts.isConstructSignatureDeclaration(node)) { + ts_prefix = this.suffix(this.findChildNode(node, ts.SyntaxKind.NewKeyword)!); + } else { + ts_prefix = node.questionToken ? this.suffix(node.questionToken) : node.name ? this.suffix(node.name) : Space.EMPTY; + } + return new J.TypeParameters(randomId(), ts_prefix, Markers.EMPTY, [], node.typeParameters.map(tp => this.rightPadded(this.visit(tp), this.suffix(tp)))); } private mapTypeParametersList(typeParamsNodeArray: ts.NodeArray) : JRightPadded[] { diff --git a/openrewrite/test/javascript/parser/interface.test.ts b/openrewrite/test/javascript/parser/interface.test.ts index 38dc624a..0a475a57 100644 --- a/openrewrite/test/javascript/parser/interface.test.ts +++ b/openrewrite/test/javascript/parser/interface.test.ts @@ -1,6 +1,6 @@ import {connect, disconnect, rewriteRun, typeScript} from '../testHarness'; -describe('as mapping', () => { +describe('interface mapping', () => { beforeAll(() => connect()); afterAll(() => disconnect()); @@ -186,7 +186,7 @@ describe('as mapping', () => { ); }); - test.skip('interface with constructor signature', () => { + test('interface with constructor signature', () => { rewriteRun( //language=typescript typeScript(` @@ -197,12 +197,23 @@ describe('as mapping', () => { ); }); - test.skip('interface with optional constructor signature', () => { + test('interface with constructor signature with type parameters', () => { rewriteRun( //language=typescript typeScript(` - interface Constructible { - new? (name: string, age: number): Person; // Interface that defines a constructor signature + interface GenericConstructor { + new (value: R, value: T): GenericClass; + } + `) + ); + }); + + test('interface with constructor signature with type parameters and comments', () => { + rewriteRun( + //language=typescript + typeScript(` + interface GenericConstructor { + /*a*/new /*b*//*g*/ (value1: R, value2: T)/*e*/: GenericClass/*j*/; } `) ); @@ -372,7 +383,7 @@ describe('as mapping', () => { //language=typescript typeScript(` interface X { - find ? (v1: R, v2: T): string; + find ? (v1: R, v2: T): string; } `) );