diff --git a/openrewrite/src/javascript/parser.ts b/openrewrite/src/javascript/parser.ts index 0506ed28..01a6697a 100644 --- a/openrewrite/src/javascript/parser.ts +++ b/openrewrite/src/javascript/parser.ts @@ -9,7 +9,7 @@ import { JRightPadded, Space, Statement, - TextComment + TextComment, TypeTree } from '../java/tree'; import * as JS from './tree'; import { @@ -259,14 +259,46 @@ export class JavaScriptParserVisitor { node.name ? this.convert(node.name) : this.mapIdentifier(node, ""), this.mapTypeParameters(node), null, // FIXME primary constructor - node.heritageClauses ? this.visit(node.heritageClauses[0]) : null, - node.heritageClauses ? this.visit(node.heritageClauses[1]) : null, + this.mapExtends(node), + this.mapImplements(node), null, this.convertBlock(node.getChildren().slice(-3)), this.mapType(node) ); } + private mapExtends(node: ts.ClassDeclaration): JLeftPadded | null { + if (node.heritageClauses == undefined || node.heritageClauses.length == 0) { + return null; + } + for (let heritageClause of node.heritageClauses) { + if (heritageClause.token == ts.SyntaxKind.ExtendsKeyword) { + return this.leftPadded(this.prefix(heritageClause.getFirstToken()!), this.visit(heritageClause.types[0])); + } + } + return null; + } + + private mapImplements(node: ts.ClassDeclaration): JContainer | null { + if (node.heritageClauses == undefined || node.heritageClauses.length == 0) { + return null; + } + for (let heritageClause of node.heritageClauses) { + if (heritageClause.token == ts.SyntaxKind.ImplementsKeyword) { + const _implements: JRightPadded[] = []; + for (let type of heritageClause.types) { + _implements.push(this.rightPadded(this.visit(type), this.suffix(type))); + } + return _implements.length > 0 ? new JContainer( + this.prefix(heritageClause.getFirstToken()!), + _implements, + Markers.EMPTY + ) : null; + } + } + return null; + } + visitNumericLiteral(node: ts.NumericLiteral) { return this.mapLiteral(node, node.text); // FIXME value not in AST } @@ -927,7 +959,11 @@ export class JavaScriptParserVisitor { } visitExpressionWithTypeArguments(node: ts.ExpressionWithTypeArguments) { - return this.visitUnknown(node); + if (node.typeArguments) { + // FIXME + return this.visitUnknown(node); + } + return this.visit(node.expression); } visitAsExpression(node: ts.AsExpression) { @@ -1244,7 +1280,7 @@ export class JavaScriptParserVisitor { } visitHeritageClause(node: ts.HeritageClause) { - return this.visitUnknown(node); + return this.convert(node.types[0]); } visitCatchClause(node: ts.CatchClause) { diff --git a/openrewrite/src/javascript/parserUtils.ts b/openrewrite/src/javascript/parserUtils.ts index a72d2c62..9da333b4 100644 --- a/openrewrite/src/javascript/parserUtils.ts +++ b/openrewrite/src/javascript/parserUtils.ts @@ -17,7 +17,11 @@ export function getNextSibling(node: ts.Node): ts.Node | null { } // If the node is the last child in the SyntaxList, recursively check the parent's next sibling - if (nodeIndex === 0) { + if (nodeIndex === children.length - 1) { + const syntaxListIndex = parent.getChildren().indexOf(syntaxList); + if (parent.getChildCount() > syntaxListIndex + 1) { + return parent.getChildAt(syntaxListIndex + 1); + } const parentNextSibling = getNextSibling(parent); if (!parentNextSibling) { return null; diff --git a/openrewrite/test/javascript/parser/class.test.ts b/openrewrite/test/javascript/parser/class.test.ts index 5ca0c3eb..053af78e 100644 --- a/openrewrite/test/javascript/parser/class.test.ts +++ b/openrewrite/test/javascript/parser/class.test.ts @@ -10,11 +10,34 @@ describe('class mapping', () => { typeScript('class A {}') ); }); - test('body', () => { rewriteRun( //language=typescript typeScript('class A { foo: number; }') ); }); + test('extends', () => { + rewriteRun( + //language=typescript + typeScript('class A extends Object {}') + ); + }); + test('implements single', () => { + rewriteRun( + //language=typescript + typeScript('class A implements B {}') + ); + }); + test('implements multiple', () => { + rewriteRun( + //language=typescript + typeScript('class A implements B , C,D {}') + ); + }); + test('extends and implements', () => { + rewriteRun( + //language=typescript + typeScript('class A extends Object implements B , C,D {}') + ); + }); });