From 2ed30703736595386a15181677a4989fb0e2a7aa Mon Sep 17 00:00:00 2001 From: Oleh Dokuka Date: Wed, 27 Nov 2024 08:23:31 +0200 Subject: [PATCH] add bug fixes --- openrewrite/src/javascript/parser.ts | 26 ++- openrewrite/src/javascript/remote/receiver.ts | 4 +- openrewrite/src/javascript/remote/sender.ts | 2 +- .../src/javascript/tree/support_types.ts | 2 + openrewrite/src/javascript/tree/tree.ts | 14 +- openrewrite/src/javascript/visitor.ts | 2 +- .../e2e/google-maps-services-js_files.test.ts | 187 ++++++++++++++++++ .../test/javascript/parser/call.test.ts | 1 + .../test/javascript/parser/export.test.ts | 19 ++ .../test/javascript/parser/function.test.ts | 11 ++ .../javascript/parser/intersection.test.ts | 29 +++ .../test/javascript/parser/union.test.ts | 10 + .../parser/variableDeclarations.test.ts | 12 +- .../javascript/remote/JavaScriptReceiver.java | 4 +- .../javascript/remote/JavaScriptSender.java | 2 +- .../javascript/JavaScriptVisitor.java | 2 +- .../internal/JavaScriptPrinter.java | 4 +- .../org/openrewrite/javascript/tree/JS.java | 19 +- .../javascript/tree/JsLeftPadded.java | 4 +- .../openrewrite/javascript/tree/JsSpace.java | 1 + 20 files changed, 328 insertions(+), 27 deletions(-) create mode 100644 openrewrite/test/javascript/parser/export.test.ts create mode 100644 openrewrite/test/javascript/parser/intersection.test.ts diff --git a/openrewrite/src/javascript/parser.ts b/openrewrite/src/javascript/parser.ts index 81e91a60..2305480d 100644 --- a/openrewrite/src/javascript/parser.ts +++ b/openrewrite/src/javascript/parser.ts @@ -23,7 +23,7 @@ import { randomId, SourceFile } from "../core"; -import {binarySearch, compareTextSpans, getNextSibling, TextSpan} from "./parserUtils"; +import {binarySearch, compareTextSpans, getNextSibling, getPreviousSibling, TextSpan} from "./parserUtils"; import {JavaScriptTypeMapping} from "./typeMapping"; export class JavaScriptParser extends Parser { @@ -260,10 +260,10 @@ export class JavaScriptParserVisitor { private mapModifiers(node: ts.VariableDeclarationList | ts.VariableStatement | ts.ClassDeclaration | ts.PropertyDeclaration | ts.FunctionDeclaration | ts.ParameterDeclaration | ts.MethodDeclaration | ts.EnumDeclaration | ts.InterfaceDeclaration | ts.PropertySignature | ts.ConstructorDeclaration | ts.ModuleDeclaration | ts.GetAccessorDeclaration | ts.SetAccessorDeclaration - | ts.ArrowFunction | ts.IndexSignatureDeclaration) { + | ts.ArrowFunction | ts.IndexSignatureDeclaration | ts.TypeAliasDeclaration) { if (ts.isVariableStatement(node) || ts.isModuleDeclaration(node) || ts.isClassDeclaration(node) || ts.isEnumDeclaration(node) || ts.isInterfaceDeclaration(node) || ts.isPropertyDeclaration(node) || ts.isPropertySignature(node) || ts.isParameter(node) - || ts.isMethodDeclaration(node) || ts.isConstructorDeclaration(node) || ts.isArrowFunction(node) || ts.isIndexSignatureDeclaration(node)) { + || ts.isMethodDeclaration(node) || ts.isConstructorDeclaration(node) || ts.isArrowFunction(node) || ts.isIndexSignatureDeclaration(node) || ts.isTypeAliasDeclaration(node)) { return node.modifiers ? node.modifiers?.filter(ts.isModifier).map(this.mapModifier) : []; } else if (ts.isFunctionDeclaration(node)) { return [...node.modifiers ? node.modifiers?.filter(ts.isModifier).map(this.mapModifier) : [], @@ -393,8 +393,8 @@ export class JavaScriptParserVisitor { return last?.kind == ts.SyntaxKind.SemicolonToken ? this.prefix(last) : Space.EMPTY; } - private keywordPrefix = (token: ts.PunctuationSyntaxKind) => (node: ts.Node): Space => { - const last = getNextSibling(node); + private keywordPrefix = (token: ts.PunctuationSyntaxKind, findSibling : (node: ts.Node) => ts.Node | null) => (node: ts.Node): Space => { + const last = findSibling(node); return last?.kind == token ? this.prefix(last) : Space.EMPTY; } @@ -1309,21 +1309,29 @@ export class JavaScriptParserVisitor { } visitUnionType(node: ts.UnionTypeNode) { + const initialBar = getPreviousSibling(node.types[0]); return new JS.Union( randomId(), this.prefix(node), Markers.EMPTY, - this.rightPaddedList([...node.types], (n) => this.keywordPrefix(ts.SyntaxKind.BarToken)(n)), + [ + ...(initialBar?.kind == ts.SyntaxKind.BarToken ? [this.rightPadded(this.newJEmpty(), this.prefix(initialBar))] : []), + ...this.rightPaddedList([...node.types], (n) => this.keywordPrefix(ts.SyntaxKind.BarToken, getNextSibling)(n)) + ], this.mapType(node), ); } visitIntersectionType(node: ts.IntersectionTypeNode) { + const initialAmpersand = getPreviousSibling(node.types[0]); return new JS.Intersection( randomId(), this.prefix(node), Markers.EMPTY, - this.rightPaddedList([...node.types], (n) => this.keywordPrefix(ts.SyntaxKind.AmpersandToken)(n)), + [ + ...(initialAmpersand?.kind == ts.SyntaxKind.AmpersandToken ? [this.rightPadded(this.newJEmpty(), this.prefix(initialAmpersand))] : []), + ...this.rightPaddedList([...node.types], (n) => this.keywordPrefix(ts.SyntaxKind.AmpersandToken, getNextSibling)(n)) + ], this.mapType(node), ); } @@ -2527,8 +2535,8 @@ export class JavaScriptParserVisitor { randomId(), this.prefix(node), Markers.EMPTY, - [], - this.visit(node.name), + this.mapModifiers(node), + this.leftPadded(this.prefix(this.findChildNode(node, ts.SyntaxKind.TypeKeyword)!), this.visit(node.name)), node.typeParameters ? this.mapTypeParametersAsObject(node) : null, this.leftPadded(this.prefix(this.findChildNode(node, ts.SyntaxKind.EqualsToken)!), this.convert(node.type)), this.mapType(node) diff --git a/openrewrite/src/javascript/remote/receiver.ts b/openrewrite/src/javascript/remote/receiver.ts index 25f93fd8..5df47b72 100644 --- a/openrewrite/src/javascript/remote/receiver.ts +++ b/openrewrite/src/javascript/remote/receiver.ts @@ -259,7 +259,7 @@ class Visitor extends JavaScriptVisitor { typeDeclaration = typeDeclaration.withPrefix(ctx.receiveNode(typeDeclaration.prefix, receiveSpace)!); typeDeclaration = typeDeclaration.withMarkers(ctx.receiveNode(typeDeclaration.markers, ctx.receiveMarkers)!); typeDeclaration = typeDeclaration.withModifiers(ctx.receiveNodes(typeDeclaration.modifiers, ctx.receiveTree)!); - typeDeclaration = typeDeclaration.withName(ctx.receiveNode(typeDeclaration.name, ctx.receiveTree)!); + typeDeclaration = typeDeclaration.padding.withName(ctx.receiveNode(typeDeclaration.padding.name, receiveLeftPaddedTree)!); typeDeclaration = typeDeclaration.withTypeParameters(ctx.receiveNode(typeDeclaration.typeParameters, ctx.receiveTree)); typeDeclaration = typeDeclaration.padding.withInitializer(ctx.receiveNode(typeDeclaration.padding.initializer, receiveLeftPaddedTree)!); typeDeclaration = typeDeclaration.withType(ctx.receiveValue(typeDeclaration.type, ValueType.Object)); @@ -1405,7 +1405,7 @@ class Factory implements ReceiverFactory { ctx.receiveNode(null, receiveSpace)!, ctx.receiveNode(null, ctx.receiveMarkers)!, ctx.receiveNodes(null, ctx.receiveTree)!, - ctx.receiveNode(null, ctx.receiveTree)!, + ctx.receiveNode>(null, receiveLeftPaddedTree)!, ctx.receiveNode(null, ctx.receiveTree), ctx.receiveNode>(null, receiveLeftPaddedTree)!, ctx.receiveValue(null, ValueType.Object) diff --git a/openrewrite/src/javascript/remote/sender.ts b/openrewrite/src/javascript/remote/sender.ts index 9eb8baa3..056b86bb 100644 --- a/openrewrite/src/javascript/remote/sender.ts +++ b/openrewrite/src/javascript/remote/sender.ts @@ -254,7 +254,7 @@ class Visitor extends JavaScriptVisitor { ctx.sendNode(typeDeclaration, v => v.prefix, Visitor.sendSpace); ctx.sendNode(typeDeclaration, v => v.markers, ctx.sendMarkers); ctx.sendNodes(typeDeclaration, v => v.modifiers, ctx.sendTree, t => t.id); - ctx.sendNode(typeDeclaration, v => v.name, ctx.sendTree); + ctx.sendNode(typeDeclaration, v => v.padding.name, Visitor.sendLeftPadded(ValueType.Tree)); ctx.sendNode(typeDeclaration, v => v.typeParameters, ctx.sendTree); ctx.sendNode(typeDeclaration, v => v.padding.initializer, Visitor.sendLeftPadded(ValueType.Tree)); ctx.sendTypedValue(typeDeclaration, v => v.type, ValueType.Object); diff --git a/openrewrite/src/javascript/tree/support_types.ts b/openrewrite/src/javascript/tree/support_types.ts index 5f3bc5ef..5bc2ab19 100644 --- a/openrewrite/src/javascript/tree/support_types.ts +++ b/openrewrite/src/javascript/tree/support_types.ts @@ -210,6 +210,7 @@ export namespace JsSpace { TEMPLATE_EXPRESSION_VALUE_PREFIX, TUPLE_PREFIX, TYPE_DECLARATION_PREFIX, + TYPE_DECLARATION_NAME_PREFIX, TYPE_OF_PREFIX, TYPE_OPERATOR_PREFIX, UNARY_PREFIX, @@ -253,6 +254,7 @@ export namespace JsLeftPadded { OBJECT_BINDING_DECLARATIONS_BINDING_DIMENSIONS_AFTER_NAME, OBJECT_BINDING_DECLARATIONS_BINDING_INITIALIZER, TYPE_DECLARATION_INITIALIZER, + TYPE_DECLARATION_NAME, TYPE_OPERATOR_EXPRESSION, UNARY_OPERATOR, JSVARIABLE_DECLARATIONS_JSNAMED_VARIABLE_INITIALIZER, diff --git a/openrewrite/src/javascript/tree/tree.ts b/openrewrite/src/javascript/tree/tree.ts index b7a264c5..55021b8b 100644 --- a/openrewrite/src/javascript/tree/tree.ts +++ b/openrewrite/src/javascript/tree/tree.ts @@ -2021,7 +2021,7 @@ export class Tuple extends JSMixin(Object) implements Expression, TypeTree { @LstType("org.openrewrite.javascript.tree.JS$TypeDeclaration") export class TypeDeclaration extends JSMixin(Object) implements Statement, TypedTree { - public constructor(id: UUID, prefix: Space, markers: Markers, modifiers: Java.Modifier[], name: Java.Identifier, typeParameters: Java.TypeParameters | null, initializer: JLeftPadded, _type: JavaType | null) { + public constructor(id: UUID, prefix: Space, markers: Markers, modifiers: Java.Modifier[], name: JLeftPadded, typeParameters: Java.TypeParameters | null, initializer: JLeftPadded, _type: JavaType | null) { super(); this._id = id; this._prefix = prefix; @@ -2073,14 +2073,14 @@ export class TypeDeclaration extends JSMixin(Object) implements Statement, Typed return modifiers === this._modifiers ? this : new TypeDeclaration(this._id, this._prefix, this._markers, modifiers, this._name, this._typeParameters, this._initializer, this._type); } - private readonly _name: Java.Identifier; + private readonly _name: JLeftPadded; public get name(): Java.Identifier { - return this._name; + return this._name.element; } public withName(name: Java.Identifier): TypeDeclaration { - return name === this._name ? this : new TypeDeclaration(this._id, this._prefix, this._markers, this._modifiers, name, this._typeParameters, this._initializer, this._type); + return this.padding.withName(this._name.withElement(name)); } private readonly _typeParameters: Java.TypeParameters | null; @@ -2120,6 +2120,12 @@ export class TypeDeclaration extends JSMixin(Object) implements Statement, Typed get padding() { const t = this; return new class { + public get name(): JLeftPadded { + return t._name; + } + public withName(name: JLeftPadded): TypeDeclaration { + return t._name === name ? t : new TypeDeclaration(t._id, t._prefix, t._markers, t._modifiers, name, t._typeParameters, t._initializer, t._type); + } public get initializer(): JLeftPadded { return t._initializer; } diff --git a/openrewrite/src/javascript/visitor.ts b/openrewrite/src/javascript/visitor.ts index 32506cd1..fad3e942 100644 --- a/openrewrite/src/javascript/visitor.ts +++ b/openrewrite/src/javascript/visitor.ts @@ -341,7 +341,7 @@ export class JavaScriptVisitor

extends JavaVisitor

{ typeDeclaration = tempStatement as TypeDeclaration; typeDeclaration = typeDeclaration.withMarkers(this.visitMarkers(typeDeclaration.markers, p)); typeDeclaration = typeDeclaration.withModifiers(ListUtils.map(typeDeclaration.modifiers, el => this.visitAndCast(el, p))); - typeDeclaration = typeDeclaration.withName(this.visitAndCast(typeDeclaration.name, p)!); + typeDeclaration = typeDeclaration.padding.withName(this.visitJsLeftPadded(typeDeclaration.padding.name, JsLeftPadded.Location.TYPE_DECLARATION_NAME, p)!); typeDeclaration = typeDeclaration.withTypeParameters(this.visitAndCast(typeDeclaration.typeParameters, p)); typeDeclaration = typeDeclaration.padding.withInitializer(this.visitJsLeftPadded(typeDeclaration.padding.initializer, JsLeftPadded.Location.TYPE_DECLARATION_INITIALIZER, p)!); return typeDeclaration; diff --git a/openrewrite/test/javascript/e2e/google-maps-services-js_files.test.ts b/openrewrite/test/javascript/e2e/google-maps-services-js_files.test.ts index 40b8dd67..d605d7cb 100644 --- a/openrewrite/test/javascript/e2e/google-maps-services-js_files.test.ts +++ b/openrewrite/test/javascript/e2e/google-maps-services-js_files.test.ts @@ -363,6 +363,193 @@ describe('google-maps-services-js files tests', () => { }); `) ); + }) + + test('serialize.test.ts', () => { + rewriteRun( + //language=typescript + typeScript(` + /** + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + import { LatLng, LatLngLiteral } from "./common"; + import { + createPremiumPlanQueryString, + latLngArrayToStringMaybeEncoded, + latLngBoundsToString, + latLngToString, + objectToString, + serializer, + toLatLngLiteral, + toTimestamp, + } from "./serialize"; + + test("latLngToString is correct", () => { + expect(latLngToString("")).toBe(""); + expect(latLngToString("10,20")).toBe("10,20"); + expect(latLngToString([10, 20])).toBe("10,20"); + expect(latLngToString({ lat: 10, lng: 20 })).toBe("10,20"); + expect(latLngToString({ latitude: 10, longitude: 20 })).toBe("10,20"); + expect(() => { + latLngToString({} as LatLngLiteral); + }).toThrow(TypeError); + }); + + test("latLngBoundsToString is correct", () => { + expect(latLngBoundsToString("")).toBe(""); + expect( + latLngBoundsToString({ + southwest: { lat: 1, lng: 2 }, + northeast: { lat: 3, lng: 4 }, + }) + ).toBe("1,2|3,4"); + }); + + test("serializer", () => { + expect( + serializer({ quz: (o) => o }, "http://mock.url")({ foo: ["bar"] }) + ).toBe("foo=bar"); + expect( + serializer( + { + foo: (o) => o.map((latLng: LatLng) => latLngToString(latLng)), + }, + "http://mock.url" + )({ + foo: [ + [0, 1], + [2, 3], + ], + }) + ).toBe("foo=0%2C1|2%2C3"); + }); + + test("serializer should not mutate params", () => { + const location = { lat: 0, lng: 1 }; + const params = { + location, + }; + + serializer({ location: latLngToString }, "http://mock.url")(params); + expect(params.location).toBe(location); + }); + + test("serializer should return pipe joined arrays by default", () => { + expect(serializer({}, "http://mock.url")({ foo: ["b", "a", "r"] })).toBe( + "foo=b|a|r" + ); + }); + + test("serializer creates premium plan query string if premium plan params are included", () => { + const params = { + avoid: "ferries", + destination: { + lat: "38.8977", + lng: "-77.0365", + }, + mode: "driving", + origin: { + lat: "33.8121", + lng: "-117.9190", + }, + units: "imperial", + client_id: "testClient", + client_secret: "testClientSecret", + }; + + expect( + serializer( + { + origin: latLngToString, + destination: latLngToString, + }, + "https://test.url/maps/api/directions/json" + )(params) + ).toEqual( + "avoid=ferries&client=testClient&destination=38.8977%2C-77.0365&mode=driving&origin=33.8121%2C-117.9190&units=imperial&signature=YRJoTd6ohbpsR14WkWv3S7H6MqU=" + ); + }); + + test("objectToString", () => { + expect(objectToString("foo")).toBe("foo"); + expect(objectToString({ c: "c", a: "a", b: "b" })).toBe("a:a|b:b|c:c"); + }); + + test("latLngArrayToStringMaybeEncoded", () => { + expect(latLngArrayToStringMaybeEncoded("0,0")).toEqual("0,0"); + expect(latLngArrayToStringMaybeEncoded([[0, 0]])).toEqual("0,0"); + expect( + latLngArrayToStringMaybeEncoded([ + [40.714728, -73.998672], + [-34.397, 150.644], + ]) + ).toEqual("enc:abowFtzsbMhgmiMuobzi@"); + }); + + test("toLatLngLiteral", () => { + expect(toLatLngLiteral("0,1")).toEqual({ lat: 0, lng: 1 }); + expect(toLatLngLiteral([0, 1])).toEqual({ lat: 0, lng: 1 }); + expect(toLatLngLiteral({ lat: 0, lng: 1 })).toEqual({ + lat: 0, + lng: 1, + }); + expect(toLatLngLiteral({ latitude: 0, longitude: 1 })).toEqual({ + lat: 0, + lng: 1, + }); + expect(() => { + toLatLngLiteral({} as LatLngLiteral); + }).toThrow(TypeError); + }); + + test("toTimestamp", () => { + expect(toTimestamp(100)).toEqual(100); + + const dt = new Date(); + const seconds = Math.round(Number(dt) / 1000); + expect(toTimestamp(dt)).toEqual(seconds); + expect(toTimestamp("now")).toEqual("now"); + + expect(toTimestamp(new Date("2022-06-22T09:03:33.430Z"))).toEqual(1655888613); + }); + + test("createPremiumPlanQueryString", () => { + const serializedParams = { + avoid: "ferries", + destination: "38.8977,-77.0365", + mode: "driving", + origin: "33.8121,-117.9190", + units: "imperial", + client_id: "testClient", + client_secret: "testClientSecret", + }; + const queryStringOptions = { + arrayFormat: "separator", + arrayFormatSeparator: "|", + }; + const baseUrl = "https://test.url/maps/api/directions/json"; + + expect( + createPremiumPlanQueryString(serializedParams, queryStringOptions, baseUrl) + ).toEqual( + "avoid=ferries&client=testClient&destination=38.8977%2C-77.0365&mode=driving&origin=33.8121%2C-117.9190&units=imperial&signature=YRJoTd6ohbpsR14WkWv3S7H6MqU=" + ); + }); + `) + ); }); }); diff --git a/openrewrite/test/javascript/parser/call.test.ts b/openrewrite/test/javascript/parser/call.test.ts index 1bfe37e8..c69bcda6 100644 --- a/openrewrite/test/javascript/parser/call.test.ts +++ b/openrewrite/test/javascript/parser/call.test.ts @@ -86,6 +86,7 @@ describe('call mapping', () => { const result1 = identity?.("Hello TypeScript"); const result2 = identity?.("Hello TypeScript"); + const result3 = identity?.call("Hello TypeScript"); `) ); }); diff --git a/openrewrite/test/javascript/parser/export.test.ts b/openrewrite/test/javascript/parser/export.test.ts new file mode 100644 index 00000000..b1917493 --- /dev/null +++ b/openrewrite/test/javascript/parser/export.test.ts @@ -0,0 +1,19 @@ +import {connect, disconnect, rewriteRun, typeScript} from '../testHarness'; + +describe('export keyword tests', () => { + beforeAll(() => connect()); + afterAll(() => disconnect()); + + test('module.export', () => { + rewriteRun( + //language=typescript + typeScript(` + const nxPreset = require('@nx/jest/preset').default; + + module.exports = { ...nxPreset }; + `) + ); + }); +}); + + diff --git a/openrewrite/test/javascript/parser/function.test.ts b/openrewrite/test/javascript/parser/function.test.ts index 4735ed1a..ad09148c 100644 --- a/openrewrite/test/javascript/parser/function.test.ts +++ b/openrewrite/test/javascript/parser/function.test.ts @@ -337,4 +337,15 @@ describe('function mapping', () => { `) ); }); + + test('unnamed function', () => { + rewriteRun( + //language=typescript + typeScript(` + /*1*/ export /*2*/ default /*3*/ function /*4*/(/*5*/hljs/*6*/) /*7*/ { + + } + `) + ); + }); }); diff --git a/openrewrite/test/javascript/parser/intersection.test.ts b/openrewrite/test/javascript/parser/intersection.test.ts new file mode 100644 index 00000000..72e4fd86 --- /dev/null +++ b/openrewrite/test/javascript/parser/intersection.test.ts @@ -0,0 +1,29 @@ +import {connect, disconnect, rewriteRun, typeScript} from '../testHarness'; + +describe('intersection type mapping', () => { + beforeAll(() => connect()); + afterAll(() => disconnect()); + + test('simple', () => { + rewriteRun( + //language=typescript + typeScript('let c: number/*1*/ &/*2*/undefined/*3*/&/*4*/null') + ); + }); + test('literals', () => { + rewriteRun( + //language=typescript + typeScript('let c: & true & 1 & "foo"') + ); + }); + test('union which starts with & ', () => { + rewriteRun( + //language=typescript + typeScript(` + export type GeolocateResponse = + & GeolocateResponseSuccess + & GeolocateResponseError; + `) + ); + }); +}); diff --git a/openrewrite/test/javascript/parser/union.test.ts b/openrewrite/test/javascript/parser/union.test.ts index 105a09c1..8c35f9b2 100644 --- a/openrewrite/test/javascript/parser/union.test.ts +++ b/openrewrite/test/javascript/parser/union.test.ts @@ -16,4 +16,14 @@ describe('union type mapping', () => { typeScript('let c: true | 1 | "foo"') ); }); + test('union which starts with | ', () => { + rewriteRun( + //language=typescript + typeScript(` + export type GeolocateResponse = + | GeolocateResponseSuccess + | GeolocateResponseError; + `) + ); + }); }); diff --git a/openrewrite/test/javascript/parser/variableDeclarations.test.ts b/openrewrite/test/javascript/parser/variableDeclarations.test.ts index 4106e5dd..a58c9013 100644 --- a/openrewrite/test/javascript/parser/variableDeclarations.test.ts +++ b/openrewrite/test/javascript/parser/variableDeclarations.test.ts @@ -78,6 +78,16 @@ describe('variable declaration mapping', () => { typeScript(' /*0.1*/ let /*0.2*/ a /*1*/ : /*2*/ number =2 /*3*/ , /*4*/ b /*5*/:/*6*/ /*7*/string /*8*/ =/*9*/ "2" /*10*/ ; //11') ); }); + test('a b c', () => { + rewriteRun( + //language=typescript + + typeScript(` + const obj : any | undefined = {} + obj ?. a ?. b ?. c + `) + ); + }); test('exported variables', () => { rewriteRun( //language=typescript @@ -130,7 +140,7 @@ describe('variable declaration mapping', () => { //language=typescript typeScript(` /*1*/ const /*2*/ { /*3*/ a/*4*/ :/*5*/ aa /*6*/ = /*7*/ 10 /*8*/ , /*9*/ b /*10*/ : /*11*/ bb = { } /*12*/ , /*13*/ } = { a: 3 }; - `) + `), ); }); }); diff --git a/rewrite-javascript-remote/src/main/java/org/openrewrite/javascript/remote/JavaScriptReceiver.java b/rewrite-javascript-remote/src/main/java/org/openrewrite/javascript/remote/JavaScriptReceiver.java index 1e3fe0a4..d44ce6bd 100644 --- a/rewrite-javascript-remote/src/main/java/org/openrewrite/javascript/remote/JavaScriptReceiver.java +++ b/rewrite-javascript-remote/src/main/java/org/openrewrite/javascript/remote/JavaScriptReceiver.java @@ -328,7 +328,7 @@ public JS.TypeDeclaration visitTypeDeclaration(JS.TypeDeclaration typeDeclaratio typeDeclaration = typeDeclaration.withPrefix(ctx.receiveNonNullNode(typeDeclaration.getPrefix(), JavaScriptReceiver::receiveSpace)); typeDeclaration = typeDeclaration.withMarkers(ctx.receiveNonNullNode(typeDeclaration.getMarkers(), ctx::receiveMarkers)); typeDeclaration = typeDeclaration.withModifiers(ctx.receiveNonNullNodes(typeDeclaration.getModifiers(), ctx::receiveTree)); - typeDeclaration = typeDeclaration.withName(ctx.receiveNonNullNode(typeDeclaration.getName(), ctx::receiveTree)); + typeDeclaration = typeDeclaration.getPadding().withName(ctx.receiveNonNullNode(typeDeclaration.getPadding().getName(), JavaScriptReceiver::receiveLeftPaddedTree)); typeDeclaration = typeDeclaration.withTypeParameters(ctx.receiveNode(typeDeclaration.getTypeParameters(), ctx::receiveTree)); typeDeclaration = typeDeclaration.getPadding().withInitializer(ctx.receiveNonNullNode(typeDeclaration.getPadding().getInitializer(), JavaScriptReceiver::receiveLeftPaddedTree)); typeDeclaration = typeDeclaration.withType(ctx.receiveValue(typeDeclaration.getType(), JavaType.class)); @@ -1525,7 +1525,7 @@ public T create(Class type, ReceiverContext ctx) { ctx.receiveNonNullNode(null, JavaScriptReceiver::receiveSpace), ctx.receiveNonNullNode(null, ctx::receiveMarkers), ctx.receiveNonNullNodes(null, ctx::receiveTree), - ctx.receiveNonNullNode(null, ctx::receiveTree), + ctx.receiveNonNullNode(null, JavaScriptReceiver::receiveLeftPaddedTree), ctx.receiveNode(null, ctx::receiveTree), ctx.receiveNonNullNode(null, JavaScriptReceiver::receiveLeftPaddedTree), ctx.receiveValue(null, JavaType.class) diff --git a/rewrite-javascript-remote/src/main/java/org/openrewrite/javascript/remote/JavaScriptSender.java b/rewrite-javascript-remote/src/main/java/org/openrewrite/javascript/remote/JavaScriptSender.java index c3ec7dbe..a61d78b1 100644 --- a/rewrite-javascript-remote/src/main/java/org/openrewrite/javascript/remote/JavaScriptSender.java +++ b/rewrite-javascript-remote/src/main/java/org/openrewrite/javascript/remote/JavaScriptSender.java @@ -311,7 +311,7 @@ public JS.TypeDeclaration visitTypeDeclaration(JS.TypeDeclaration typeDeclaratio ctx.sendNode(typeDeclaration, JS.TypeDeclaration::getPrefix, JavaScriptSender::sendSpace); ctx.sendNode(typeDeclaration, JS.TypeDeclaration::getMarkers, ctx::sendMarkers); ctx.sendNodes(typeDeclaration, JS.TypeDeclaration::getModifiers, ctx::sendTree, Tree::getId); - ctx.sendNode(typeDeclaration, JS.TypeDeclaration::getName, ctx::sendTree); + ctx.sendNode(typeDeclaration, e -> e.getPadding().getName(), JavaScriptSender::sendLeftPadded); ctx.sendNode(typeDeclaration, JS.TypeDeclaration::getTypeParameters, ctx::sendTree); ctx.sendNode(typeDeclaration, e -> e.getPadding().getInitializer(), JavaScriptSender::sendLeftPadded); ctx.sendTypedValue(typeDeclaration, JS.TypeDeclaration::getType); diff --git a/rewrite-javascript/src/main/java/org/openrewrite/javascript/JavaScriptVisitor.java b/rewrite-javascript/src/main/java/org/openrewrite/javascript/JavaScriptVisitor.java index 067a0cd6..a1400a99 100644 --- a/rewrite-javascript/src/main/java/org/openrewrite/javascript/JavaScriptVisitor.java +++ b/rewrite-javascript/src/main/java/org/openrewrite/javascript/JavaScriptVisitor.java @@ -466,7 +466,7 @@ public J visitTypeDeclaration(JS.TypeDeclaration typeDeclaration, P p) { t = t.withModifiers(ListUtils.map(t.getModifiers(), mod -> mod.withPrefix(visitSpace(mod.getPrefix(), Space.Location.MODIFIER_PREFIX, p)))); t = t.withModifiers(Objects.requireNonNull(ListUtils.map(t.getModifiers(), e -> visitAndCast(e, p)))); - t = t.withName(visitAndCast(t.getName(), p)); + t = t.getPadding().withName(visitLeftPadded(t.getPadding().getName(), JsLeftPadded.Location.TYPE_DECLARATION_NAME, p)); t = t.withTypeParameters(visitAndCast(t.getTypeParameters(), p)); t = t.getPadding().withInitializer(visitLeftPadded(t.getPadding().getInitializer(), JsLeftPadded.Location.TYPE_DECLARATION_INITIALIZER, p)); diff --git a/rewrite-javascript/src/main/java/org/openrewrite/javascript/internal/JavaScriptPrinter.java b/rewrite-javascript/src/main/java/org/openrewrite/javascript/internal/JavaScriptPrinter.java index 302d2d04..27d421a8 100644 --- a/rewrite-javascript/src/main/java/org/openrewrite/javascript/internal/JavaScriptPrinter.java +++ b/rewrite-javascript/src/main/java/org/openrewrite/javascript/internal/JavaScriptPrinter.java @@ -396,8 +396,8 @@ public J visitTuple(JS.Tuple tuple, PrintOutputCapture

p) { public J visitTypeDeclaration(JS.TypeDeclaration typeDeclaration, PrintOutputCapture

p) { beforeSyntax(typeDeclaration, JsSpace.Location.TYPE_DECLARATION_PREFIX, p); typeDeclaration.getModifiers().forEach(m -> delegate.visitModifier(m, p)); - p.append("type"); - visit(typeDeclaration.getName(), p); + + visitLeftPadded("type", typeDeclaration.getPadding().getName(), JsLeftPadded.Location.TYPE_DECLARATION_NAME, p); J.TypeParameters typeParameters = typeDeclaration.getTypeParameters(); if (typeParameters != null) { visit(typeParameters.getAnnotations(), p); diff --git a/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JS.java b/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JS.java index e6a1b93a..f14f65a3 100644 --- a/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JS.java +++ b/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JS.java @@ -1958,8 +1958,15 @@ final class TypeDeclaration implements JS, Statement, TypedTree { @With List modifiers; - @With - J.Identifier name; + JLeftPadded name; + + public J.Identifier getName() { + return name.getElement(); + } + + public TypeDeclaration withName(J.Identifier name) { + return getPadding().withName(JLeftPadded.withElement(this.name, name)); + } @With J.@Nullable TypeParameters typeParameters; @@ -2025,6 +2032,14 @@ public JLeftPadded getInitializer() { public TypeDeclaration withInitializer(JLeftPadded initializer) { return t.initializer == initializer ? t : new TypeDeclaration(t.id, t.prefix, t.markers, t.modifiers, t.name, t.typeParameters, initializer, t.type); } + + public JLeftPadded getName() { + return t.name; + } + + public TypeDeclaration withName(JLeftPadded name) { + return t.name == name ? t : new TypeDeclaration(t.id, t.prefix, t.markers, t.modifiers, name, t.typeParameters, t.initializer, t.type); + } } } diff --git a/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JsLeftPadded.java b/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JsLeftPadded.java index 09e6464a..666bd6b9 100644 --- a/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JsLeftPadded.java +++ b/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JsLeftPadded.java @@ -24,6 +24,7 @@ public enum Location { BINDING_ELEMENT_INITIALIZER(JsSpace.Location.BINDING_INITIALIZER_PREFIX), EXPORT_INITIALIZER(JsSpace.Location.EXPORT_INITIALIZER_PREFIX), IMPORT_INITIALIZER(JsSpace.Location.IMPORT_INITIALIZER_PREFIX), + TYPE_DECLARATION_NAME(JsSpace.Location.TYPE_DECLARATION_NAME_PREFIX), TYPE_DECLARATION_INITIALIZER(JsSpace.Location.TYPE_DECLARATION_INITIALIZER_PREFIX), TYPE_OPERATOR(JsSpace.Location.TYPE_OPERATOR_PREFIX), JSVARIABLE_INITIALIZER(JsSpace.Location.JSVARIABLE_INITIALIZER), @@ -32,7 +33,8 @@ public enum Location { JS_IMPORT_IMPORT_TYPE(JsSpace.Location.JS_IMPORT_IMPORT_TYPE_PREFIX), JS_IMPORT_SPECIFIER_IMPORT_TYPE(JsSpace.Location.JS_IMPORT_SPECIFIER_IMPORT_TYPE_PREFIX), INDEXED_SIGNATURE_DECLARATION_TYPE_EXPRESSION(JsSpace.Location.INDEXED_SIGNATURE_DECLARATION_TYPE_EXPRESSION_PREFIX), - FOR_OF_AWAIT(JsSpace.Location.FOR_OF_AWAIT_PREFIX); + FOR_OF_AWAIT(JsSpace.Location.FOR_OF_AWAIT_PREFIX), + ; private final JsSpace.Location beforeLocation; diff --git a/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JsSpace.java b/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JsSpace.java index df1256eb..858d10fb 100644 --- a/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JsSpace.java +++ b/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JsSpace.java @@ -63,6 +63,7 @@ public enum Location { TUPLE_ELEMENT_SUFFIX, TUPLE_PREFIX, TYPEOF_PREFIX, + TYPE_DECLARATION_NAME_PREFIX, TYPE_DECLARATION_INITIALIZER_PREFIX, TYPE_DECLARATION_PREFIX, TYPE_OPERATOR_PREFIX,