From 997e8236d045df3653c5819f32abba9786b4edb8 Mon Sep 17 00:00:00 2001 From: Knut Wannheden Date: Thu, 26 Sep 2024 14:56:43 +0200 Subject: [PATCH] Map `ts.TypeAssertion` and `ts.AsExpression` --- openrewrite/src/core/markers.ts | 2 +- openrewrite/src/javascript/parser.ts | 37 ++++++++++++++++--- openrewrite/src/javascript/tree/tree.ts | 7 ++-- openrewrite/test/javascript/parser/as.test.ts | 13 +++++++ .../test/javascript/parser/cast.test.ts | 13 +++++++ openrewrite/test/javascript/testHarness.ts | 31 ++++++++++++++-- .../internal/JavaScriptPrinter.java | 21 +++++++++-- .../org/openrewrite/javascript/tree/JS.java | 1 + 8 files changed, 110 insertions(+), 15 deletions(-) create mode 100644 openrewrite/test/javascript/parser/as.test.ts create mode 100644 openrewrite/test/javascript/parser/cast.test.ts diff --git a/openrewrite/src/core/markers.ts b/openrewrite/src/core/markers.ts index aea974ed..4be72b66 100644 --- a/openrewrite/src/core/markers.ts +++ b/openrewrite/src/core/markers.ts @@ -129,7 +129,7 @@ export class ParseExceptionResult implements Marker { this._exceptionType = exceptionType; this._exceptionMessage = exceptionMessage; this._message = message; - this._treeType = treeType; + this._treeType = treeType ?? null; } static build(parser: Parser, exception: Error): ParseExceptionResult { diff --git a/openrewrite/src/javascript/parser.ts b/openrewrite/src/javascript/parser.ts index 9aed0d19..a4bca480 100644 --- a/openrewrite/src/javascript/parser.ts +++ b/openrewrite/src/javascript/parser.ts @@ -79,7 +79,7 @@ export class JavaScriptParser extends Parser { } sourcePathFromSourceText(prefix: string, sourceCode: string): string { - return prefix + "/source.js"; + return prefix + "/source.ts"; } static builder(): JavaScriptParser.Builder { @@ -208,6 +208,14 @@ export class JavaScriptParserVisitor { return this.mapLiteral(node, true); } + visitNumberKeyword(node: ts.Node) { + return this.mapIdentifier(node, 'number'); + } + + visitStringKeyword(node: ts.Node) { + return this.mapIdentifier(node, 'string'); + } + visitFalseKeyword(node: ts.FalseLiteral) { return this.mapLiteral(node, false); } @@ -264,7 +272,7 @@ export class JavaScriptParserVisitor { return this.mapIdentifier(node, node.text); } - private mapIdentifier(node: ts.PrimaryExpression, name: string) { + private mapIdentifier(node: ts.Node, name: string) { let type = this.mapType(node); return new J.Identifier( randomId(), @@ -529,7 +537,18 @@ export class JavaScriptParserVisitor { } visitTypeAssertionExpression(node: ts.TypeAssertion) { - return this.visitUnknown(node); + return new J.TypeCast( + randomId(), + this.prefix(node), + Markers.EMPTY, + new J.ControlParentheses( + randomId(), + this.prefix(node.getFirstToken()!), + Markers.EMPTY, + this.rightPadded(this.convert(node.type), this.prefix(node.getChildAt(2))) + ), + this.convert(node.expression) + ); } visitParenthesizedExpression(node: ts.ParenthesizedExpression) { @@ -606,7 +625,15 @@ export class JavaScriptParserVisitor { } visitAsExpression(node: ts.AsExpression) { - return this.visitUnknown(node); + return new JS.JsBinary( + randomId(), + this.prefix(node), + Markers.EMPTY, + this.convert(node.expression), + this.leftPadded(this.prefix(node.getChildAt(1)), JS.JsBinary.Type.As), + this.convert(node.type), + this.mapType(node) + ); } visitNonNullExpression(node: ts.NonNullExpression) { @@ -1128,7 +1155,7 @@ export class JavaScriptParserVisitor { return this.prefix(getNextSibling(node)!); } - private mapType(node: ts.Expression): JavaType | null { + private mapType(node: ts.Node): JavaType | null { if (ts.isLiteralExpression(node)) { if (ts.isNumericLiteral(node)) { return JavaType.Primitive.of(JavaType.PrimitiveKind.Int); diff --git a/openrewrite/src/javascript/tree/tree.ts b/openrewrite/src/javascript/tree/tree.ts index 43ce695d..56b79d2d 100644 --- a/openrewrite/src/javascript/tree/tree.ts +++ b/openrewrite/src/javascript/tree/tree.ts @@ -962,9 +962,10 @@ export class JsBinary extends JSMixin(Object) implements Expression, TypedTree { export namespace JsBinary { export enum Type { - IdentityEquals = 0, - IdentityNotEquals = 1, - In = 2, + As = 0, + IdentityEquals = 1, + IdentityNotEquals = 2, + In = 3, } diff --git a/openrewrite/test/javascript/parser/as.test.ts b/openrewrite/test/javascript/parser/as.test.ts new file mode 100644 index 00000000..08515f7b --- /dev/null +++ b/openrewrite/test/javascript/parser/as.test.ts @@ -0,0 +1,13 @@ +import {connect, disconnect, javaScript, rewriteRun} from '../testHarness'; + +describe('as mapping', () => { + beforeAll(() => connect()); + afterAll(() => disconnect()); + + test('primitive type', () => { + rewriteRun( + //language=typescript + javaScript('1 as number') + ); + }); +}); diff --git a/openrewrite/test/javascript/parser/cast.test.ts b/openrewrite/test/javascript/parser/cast.test.ts new file mode 100644 index 00000000..68989623 --- /dev/null +++ b/openrewrite/test/javascript/parser/cast.test.ts @@ -0,0 +1,13 @@ +import {connect, disconnect, javaScript, rewriteRun, typeScript} from '../testHarness'; + +describe('cast mapping', () => { + beforeAll(() => connect()); + afterAll(() => disconnect()); + + test('primitive type', () => { + rewriteRun( + //language=typescript + typeScript('< string > "x"') + ); + }); +}); diff --git a/openrewrite/test/javascript/testHarness.ts b/openrewrite/test/javascript/testHarness.ts index 5b35cd41..3663fbde 100644 --- a/openrewrite/test/javascript/testHarness.ts +++ b/openrewrite/test/javascript/testHarness.ts @@ -1,4 +1,12 @@ -import {Cursor, PrinterFactory, PrintOutputCapture, RecipeRunException, SourceFile} from '../../dist/core'; +import { + Cursor, + InMemoryExecutionContext, + ParserInput, + PrinterFactory, + PrintOutputCapture, + RecipeRunException, + SourceFile +} from '../../dist/core'; import * as J from "../../dist/java/tree"; import * as JS from "../../dist/javascript/tree"; import dedent from "dedent"; @@ -68,9 +76,18 @@ export function rewriteRunWithOptions(options: RewriteTestOptions, ...sourceSpec const parser = JavaScriptParser.builder().build(); -export function javaScript(before: string, spec?: (sourceFile: JS.CompilationUnit) => void): SourceSpec { +function sourceFile(before: string, defaultPath: string, spec?: (sourceFile: JS.CompilationUnit) => void) { return (options: RewriteTestOptions) => { - const [sourceFile] = parser.parseStrings(options.normalizeIndent ?? true ? dedent(before) : before) as Iterable; + const ctx = new InMemoryExecutionContext(); + const [sourceFile] = parser.parseInputs( + [new ParserInput( + defaultPath, + null, + true, + () => Buffer.from(options.normalizeIndent ?? true ? dedent(before) : before) + )], + null, + ctx) as Iterable; if (!(options.allowUnknowns ?? false)) { try { let unknowns: J.Unknown[] = []; @@ -97,6 +114,14 @@ export function javaScript(before: string, spec?: (sourceFile: JS.CompilationUni }; } +export function javaScript(before: string, spec?: (sourceFile: JS.CompilationUnit) => void): SourceSpec { + return sourceFile(before, 'test.js', spec); +} + +export function typeScript(before: string, spec?: (sourceFile: JS.CompilationUnit) => void): SourceSpec { + return sourceFile(before, 'test.ts', spec); +} + function print(parsed: SourceFile) { remoting.reset(); remoting.client?.reset(); diff --git a/src/main/java/org/openrewrite/javascript/internal/JavaScriptPrinter.java b/src/main/java/org/openrewrite/javascript/internal/JavaScriptPrinter.java index ea5ea91e..38d54540 100644 --- a/src/main/java/org/openrewrite/javascript/internal/JavaScriptPrinter.java +++ b/src/main/java/org/openrewrite/javascript/internal/JavaScriptPrinter.java @@ -207,6 +207,9 @@ public J visitJsBinary(JS.JsBinary binary, PrintOutputCapture

p) { visit(binary.getLeft(), p); String keyword = ""; switch (binary.getOperator()) { + case As: + keyword = "as"; + break; case IdentityEquals: keyword = "==="; break; @@ -655,14 +658,26 @@ public J visitNewClass(J.NewClass newClass, PrintOutputCapture

p) { return newClass; } + @Override + public J visitControlParentheses(J.ControlParentheses controlParens, PrintOutputCapture

p) { + beforeSyntax(controlParens, Space.Location.CONTROL_PARENTHESES_PREFIX, p); + if (getCursor().getParentTreeCursor().getValue() instanceof J.TypeCast) { + p.append('<'); + visitRightPadded(controlParens.getPadding().getTree(), JRightPadded.Location.PARENTHESES, ">", p); + } else { + p.append('('); + visitRightPadded(controlParens.getPadding().getTree(), JRightPadded.Location.PARENTHESES, ")", p); + } + afterSyntax(controlParens, p); + return controlParens; + } + @Override public J visitTypeCast(J.TypeCast typeCast, PrintOutputCapture

p) { beforeSyntax(typeCast, Space.Location.TYPE_CAST_PREFIX, p); + visit(typeCast.getClazz(), p); visit(typeCast.getExpression(), p); - visitSpace(typeCast.getClazz().getPrefix(), Space.Location.LANGUAGE_EXTENSION, p); - p.append("as"); - visitRightPadded(typeCast.getClazz().getPadding().getTree(), JRightPadded.Location.NAMED_VARIABLE, p); afterSyntax(typeCast, p); return typeCast; diff --git a/src/main/java/org/openrewrite/javascript/tree/JS.java b/src/main/java/org/openrewrite/javascript/tree/JS.java index 0d5a9f13..bdc81945 100644 --- a/src/main/java/org/openrewrite/javascript/tree/JS.java +++ b/src/main/java/org/openrewrite/javascript/tree/JS.java @@ -884,6 +884,7 @@ public CoordinateBuilder.Expression getCoordinates() { } public enum Type { + As, IdentityEquals, IdentityNotEquals, In