diff --git a/openrewrite/src/javascript/parser.ts b/openrewrite/src/javascript/parser.ts index 44447c30..139a0877 100644 --- a/openrewrite/src/javascript/parser.ts +++ b/openrewrite/src/javascript/parser.ts @@ -539,6 +539,14 @@ export class JavaScriptParserVisitor { return this.mapIdentifier(node, 'never'); } + visitSymbolKeyword(node: ts.Node) { + return this.mapIdentifier(node, 'symbol'); + } + + visitBigIntKeyword(node: ts.Node) { + return this.mapIdentifier(node, 'bigint'); + } + private mapLiteral(node: ts.LiteralExpression | ts.TrueLiteral | ts.FalseLiteral | ts.NullLiteral | ts.Identifier | ts.TemplateHead | ts.TemplateMiddle | ts.TemplateTail, value: any): J.Literal { return new J.Literal( @@ -815,28 +823,54 @@ export class JavaScriptParserVisitor { ); } - return new J.VariableDeclarations( - randomId(), - this.prefix(node), - Markers.EMPTY, - [], // no decorators allowed - this.mapModifiers(node), - this.mapTypeInfo(node), - null, - [], - [this.rightPadded( - new J.VariableDeclarations.NamedVariable( - randomId(), - this.prefix(node.name), - Markers.EMPTY, - this.visit(node.name), - [], - null, - this.mapVariableType(node) - ), - Space.EMPTY - )] - ); + const nameExpression = this.visit(node.name) + + if (nameExpression instanceof J.Identifier) { + return new J.VariableDeclarations( + randomId(), + this.prefix(node), + Markers.EMPTY, + [], // no decorators allowed + this.mapModifiers(node), + this.mapTypeInfo(node), + null, + [], + [this.rightPadded( + new J.VariableDeclarations.NamedVariable( + randomId(), + this.prefix(node.name), + Markers.EMPTY, + nameExpression, + [], + null, + this.mapVariableType(node) + ), + Space.EMPTY + )] + ); + } else { + return new JS.JSVariableDeclarations( + randomId(), + this.prefix(node), + Markers.EMPTY, + [], // no decorators allowed + this.mapModifiers(node), + this.mapTypeInfo(node), + null, + [this.rightPadded( + new JS.JSVariableDeclarations.JSNamedVariable( + randomId(), + this.prefix(node.name), + Markers.EMPTY, + nameExpression, + [], + null, + this.mapVariableType(node) + ), + Space.EMPTY + )] + ); + } } visitPropertyDeclaration(node: ts.PropertyDeclaration) { @@ -864,6 +898,37 @@ export class JavaScriptParserVisitor { ); } + if (node.exclamationToken) { + return new JS.JSVariableDeclarations( + randomId(), + this.prefix(node), + Markers.EMPTY, + this.mapDecorators(node), + this.mapModifiers(node), + this.mapTypeInfo(node), + null, + [this.rightPadded( + new JS.JSVariableDeclarations.JSNamedVariable( + randomId(), + this.prefix(node.name), + Markers.EMPTY, + new JS.Unary( + randomId(), + Space.EMPTY, + Markers.EMPTY, + this.leftPadded(this.suffix(node.name), JS.Unary.Type.Exclamation), + this.visit(node.name), + this.mapType(node) + ), + [], + node.initializer ? this.leftPadded(this.prefix(node.getChildAt(node.getChildren().indexOf(node.initializer) - 1)), this.visit(node.initializer)) : null, + this.mapVariableType(node) + ), + Space.EMPTY + )] + ); + } + const nameExpression = this.visit(node.name) if (nameExpression instanceof J.Identifier) { @@ -1408,6 +1473,8 @@ export class JavaScriptParserVisitor { return JS.TypeOperator.Type.KeyOf; case ts.SyntaxKind.ReadonlyKeyword: return JS.TypeOperator.Type.ReadOnly; + case ts.SyntaxKind.UniqueKeyword: + return JS.TypeOperator.Type.Unique; } } @@ -1833,8 +1900,15 @@ export class JavaScriptParserVisitor { Markers.EMPTY, null, Space.EMPTY, - this.visit(node.expression), - this.mapCommaSeparatedList(node.arguments ? node.getChildren(this.sourceFile).slice(2) : []), + node.typeArguments ? new J.ParameterizedType( + randomId(), + Space.EMPTY, + Markers.EMPTY, + this.visit(node.expression), + this.mapTypeArguments(this.prefix(this.findChildNode(node, ts.SyntaxKind.LessThanToken)!), node.typeArguments), + null + ): this.visit(node.expression), + this.mapCommaSeparatedList(this.getParameterListNodes(node)), null, this.mapMethodType(node) ); @@ -1913,8 +1987,7 @@ export class JavaScriptParserVisitor { isParenthesized ? [this.rightPadded(this.newJEmpty(), this.prefix(this.findChildNode(node, ts.SyntaxKind.CloseParenToken)!))] : [] // to handle the case: (/*no*/) => ... ), this.mapTypeInfo(node), - this.prefix(node.equalsGreaterThanToken), - this.convert(node.body), + this.leftPadded(this.prefix(node.equalsGreaterThanToken), this.convert(node.body)), this.mapType(node) ); } @@ -2089,6 +2162,9 @@ export class JavaScriptParserVisitor { case ts.SyntaxKind.BarBarEqualsToken: assignmentOperation = JS.JsAssignmentOperation.Type.Or; break; + case ts.SyntaxKind.AsteriskAsteriskToken: + assignmentOperation = JS.JsAssignmentOperation.Type.Power; + break; } if (assignmentOperation !== undefined) { @@ -2368,6 +2444,7 @@ export class JavaScriptParserVisitor { } visitSyntheticExpression(node: ts.SyntheticExpression) { + // SyntheticExpression is a special type of node used internally by the TypeScript compiler return this.visitUnknown(node); } @@ -2431,6 +2508,7 @@ export class JavaScriptParserVisitor { visitIfStatement(node: ts.IfStatement) { const semicolonAfterThen = node.thenStatement.getLastToken()?.kind == ts.SyntaxKind.SemicolonToken; + const semicolonAfterElse = node.elseStatement?.getLastToken()?.kind == ts.SyntaxKind.SemicolonToken; return new J.If( randomId(), this.prefix(node), @@ -2452,8 +2530,8 @@ export class JavaScriptParserVisitor { Markers.EMPTY, this.rightPadded( this.convert(node.elseStatement), - semicolonAfterThen ? this.prefix(node.elseStatement.getLastToken()!) : Space.EMPTY, - semicolonAfterThen ? Markers.build([new Semicolon(randomId())]) : Markers.EMPTY + semicolonAfterElse ? this.prefix(node.elseStatement.getLastToken()!) : Space.EMPTY, + semicolonAfterElse ? Markers.build([new Semicolon(randomId())]) : Markers.EMPTY ) ) : null ); @@ -2641,7 +2719,10 @@ export class JavaScriptParserVisitor { } visitDebuggerStatement(node: ts.DebuggerStatement) { - return this.visitUnknown(node); + return new ExpressionStatement( + randomId(), + this.mapIdentifier(node, 'debugger') + ); } visitVariableDeclaration(node: ts.VariableDeclaration) { @@ -2733,7 +2814,7 @@ export class JavaScriptParserVisitor { ); } - private getParameterListNodes(node: ts.SignatureDeclarationBase, openToken : ts.SyntaxKind = ts.SyntaxKind.OpenParenToken) { + private getParameterListNodes(node: ts.SignatureDeclarationBase | ts.NewExpression, openToken : ts.SyntaxKind = ts.SyntaxKind.OpenParenToken) { const children = node.getChildren(this.sourceFile); for (let i = 0; i < children.length; i++) { if (children[i].kind == openToken) { diff --git a/openrewrite/src/javascript/remote/receiver.ts b/openrewrite/src/javascript/remote/receiver.ts index febc686e..b8756e92 100644 --- a/openrewrite/src/javascript/remote/receiver.ts +++ b/openrewrite/src/javascript/remote/receiver.ts @@ -60,8 +60,7 @@ class Visitor extends JavaScriptVisitor { arrowFunction = arrowFunction.withTypeParameters(ctx.receiveNode(arrowFunction.typeParameters, ctx.receiveTree)); arrowFunction = arrowFunction.withParameters(ctx.receiveNode(arrowFunction.parameters, ctx.receiveTree)!); arrowFunction = arrowFunction.withReturnTypeExpression(ctx.receiveNode(arrowFunction.returnTypeExpression, ctx.receiveTree)); - arrowFunction = arrowFunction.withArrow(ctx.receiveNode(arrowFunction.arrow, receiveSpace)!); - arrowFunction = arrowFunction.withBody(ctx.receiveNode(arrowFunction.body, ctx.receiveTree)!); + arrowFunction = arrowFunction.padding.withBody(ctx.receiveNode(arrowFunction.padding.body, receiveLeftPaddedTree)!); arrowFunction = arrowFunction.withType(ctx.receiveValue(arrowFunction.type, ValueType.Object)); return arrowFunction; } @@ -1349,8 +1348,7 @@ class Factory implements ReceiverFactory { ctx.receiveNode(null, ctx.receiveTree), ctx.receiveNode(null, ctx.receiveTree)!, ctx.receiveNode(null, ctx.receiveTree), - ctx.receiveNode(null, receiveSpace)!, - 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 c01149ba..b50de0ed 100644 --- a/openrewrite/src/javascript/remote/sender.ts +++ b/openrewrite/src/javascript/remote/sender.ts @@ -55,8 +55,7 @@ class Visitor extends JavaScriptVisitor { ctx.sendNode(arrowFunction, v => v.typeParameters, ctx.sendTree); ctx.sendNode(arrowFunction, v => v.parameters, ctx.sendTree); ctx.sendNode(arrowFunction, v => v.returnTypeExpression, ctx.sendTree); - ctx.sendNode(arrowFunction, v => v.arrow, Visitor.sendSpace); - ctx.sendNode(arrowFunction, v => v.body, ctx.sendTree); + ctx.sendNode(arrowFunction, v => v.padding.body, Visitor.sendLeftPadded(ValueType.Tree)); ctx.sendTypedValue(arrowFunction, v => v.type, ValueType.Object); return arrowFunction; } diff --git a/openrewrite/src/javascript/tree/support_types.ts b/openrewrite/src/javascript/tree/support_types.ts index ab52c316..eb6b417f 100644 --- a/openrewrite/src/javascript/tree/support_types.ts +++ b/openrewrite/src/javascript/tree/support_types.ts @@ -302,6 +302,7 @@ export namespace JsLeftPadded { MAPPED_TYPE_MAPPED_TYPE_PARAMETER_ITERATE_TYPE, MAPPED_TYPE_HAS_READONLY, MAPPED_TYPE_HAS_QUESTION_TOKEN, + ARROW_FUNCTION_BODY, } } export namespace JsRightPadded { diff --git a/openrewrite/src/javascript/tree/tree.ts b/openrewrite/src/javascript/tree/tree.ts index 4d919042..734e8e87 100644 --- a/openrewrite/src/javascript/tree/tree.ts +++ b/openrewrite/src/javascript/tree/tree.ts @@ -251,7 +251,7 @@ export class Alias extends JSMixin(Object) implements Expression { @LstType("org.openrewrite.javascript.tree.JS$ArrowFunction") export class ArrowFunction extends JSMixin(Object) implements Statement, Expression, TypedTree { - public constructor(id: UUID, prefix: Space, markers: Markers, leadingAnnotations: Java.Annotation[], modifiers: Java.Modifier[], typeParameters: Java.TypeParameters | null, parameters: Java.Lambda.Parameters, returnTypeExpression: TypeTree | null, arrow: Space, body: J, _type: JavaType | null) { + public constructor(id: UUID, prefix: Space, markers: Markers, leadingAnnotations: Java.Annotation[], modifiers: Java.Modifier[], typeParameters: Java.TypeParameters | null, parameters: Java.Lambda.Parameters, returnTypeExpression: TypeTree | null, body: JLeftPadded, _type: JavaType | null) { super(); this._id = id; this._prefix = prefix; @@ -261,7 +261,6 @@ export class ArrowFunction extends JSMixin(Object) implements Statement, Express this._typeParameters = typeParameters; this._parameters = parameters; this._returnTypeExpression = returnTypeExpression; - this._arrow = arrow; this._body = body; this._type = _type; } @@ -273,7 +272,7 @@ export class ArrowFunction extends JSMixin(Object) implements Statement, Express } public withId(id: UUID): ArrowFunction { - return id === this._id ? this : new ArrowFunction(id, this._prefix, this._markers, this._leadingAnnotations, this._modifiers, this._typeParameters, this._parameters, this._returnTypeExpression, this._arrow, this._body, this._type); + return id === this._id ? this : new ArrowFunction(id, this._prefix, this._markers, this._leadingAnnotations, this._modifiers, this._typeParameters, this._parameters, this._returnTypeExpression, this._body, this._type); } private readonly _prefix: Space; @@ -283,7 +282,7 @@ export class ArrowFunction extends JSMixin(Object) implements Statement, Express } public withPrefix(prefix: Space): ArrowFunction { - return prefix === this._prefix ? this : new ArrowFunction(this._id, prefix, this._markers, this._leadingAnnotations, this._modifiers, this._typeParameters, this._parameters, this._returnTypeExpression, this._arrow, this._body, this._type); + return prefix === this._prefix ? this : new ArrowFunction(this._id, prefix, this._markers, this._leadingAnnotations, this._modifiers, this._typeParameters, this._parameters, this._returnTypeExpression, this._body, this._type); } private readonly _markers: Markers; @@ -293,7 +292,7 @@ export class ArrowFunction extends JSMixin(Object) implements Statement, Express } public withMarkers(markers: Markers): ArrowFunction { - return markers === this._markers ? this : new ArrowFunction(this._id, this._prefix, markers, this._leadingAnnotations, this._modifiers, this._typeParameters, this._parameters, this._returnTypeExpression, this._arrow, this._body, this._type); + return markers === this._markers ? this : new ArrowFunction(this._id, this._prefix, markers, this._leadingAnnotations, this._modifiers, this._typeParameters, this._parameters, this._returnTypeExpression, this._body, this._type); } private readonly _leadingAnnotations: Java.Annotation[]; @@ -303,7 +302,7 @@ export class ArrowFunction extends JSMixin(Object) implements Statement, Express } public withLeadingAnnotations(leadingAnnotations: Java.Annotation[]): ArrowFunction { - return leadingAnnotations === this._leadingAnnotations ? this : new ArrowFunction(this._id, this._prefix, this._markers, leadingAnnotations, this._modifiers, this._typeParameters, this._parameters, this._returnTypeExpression, this._arrow, this._body, this._type); + return leadingAnnotations === this._leadingAnnotations ? this : new ArrowFunction(this._id, this._prefix, this._markers, leadingAnnotations, this._modifiers, this._typeParameters, this._parameters, this._returnTypeExpression, this._body, this._type); } private readonly _modifiers: Java.Modifier[]; @@ -313,7 +312,7 @@ export class ArrowFunction extends JSMixin(Object) implements Statement, Express } public withModifiers(modifiers: Java.Modifier[]): ArrowFunction { - return modifiers === this._modifiers ? this : new ArrowFunction(this._id, this._prefix, this._markers, this._leadingAnnotations, modifiers, this._typeParameters, this._parameters, this._returnTypeExpression, this._arrow, this._body, this._type); + return modifiers === this._modifiers ? this : new ArrowFunction(this._id, this._prefix, this._markers, this._leadingAnnotations, modifiers, this._typeParameters, this._parameters, this._returnTypeExpression, this._body, this._type); } private readonly _typeParameters: Java.TypeParameters | null; @@ -323,7 +322,7 @@ export class ArrowFunction extends JSMixin(Object) implements Statement, Express } public withTypeParameters(typeParameters: Java.TypeParameters | null): ArrowFunction { - return typeParameters === this._typeParameters ? this : new ArrowFunction(this._id, this._prefix, this._markers, this._leadingAnnotations, this._modifiers, typeParameters, this._parameters, this._returnTypeExpression, this._arrow, this._body, this._type); + return typeParameters === this._typeParameters ? this : new ArrowFunction(this._id, this._prefix, this._markers, this._leadingAnnotations, this._modifiers, typeParameters, this._parameters, this._returnTypeExpression, this._body, this._type); } private readonly _parameters: Java.Lambda.Parameters; @@ -333,7 +332,7 @@ export class ArrowFunction extends JSMixin(Object) implements Statement, Express } public withParameters(parameters: Java.Lambda.Parameters): ArrowFunction { - return parameters === this._parameters ? this : new ArrowFunction(this._id, this._prefix, this._markers, this._leadingAnnotations, this._modifiers, this._typeParameters, parameters, this._returnTypeExpression, this._arrow, this._body, this._type); + return parameters === this._parameters ? this : new ArrowFunction(this._id, this._prefix, this._markers, this._leadingAnnotations, this._modifiers, this._typeParameters, parameters, this._returnTypeExpression, this._body, this._type); } private readonly _returnTypeExpression: TypeTree | null; @@ -343,27 +342,17 @@ export class ArrowFunction extends JSMixin(Object) implements Statement, Express } public withReturnTypeExpression(returnTypeExpression: TypeTree | null): ArrowFunction { - return returnTypeExpression === this._returnTypeExpression ? this : new ArrowFunction(this._id, this._prefix, this._markers, this._leadingAnnotations, this._modifiers, this._typeParameters, this._parameters, returnTypeExpression, this._arrow, this._body, this._type); + return returnTypeExpression === this._returnTypeExpression ? this : new ArrowFunction(this._id, this._prefix, this._markers, this._leadingAnnotations, this._modifiers, this._typeParameters, this._parameters, returnTypeExpression, this._body, this._type); } - private readonly _arrow: Space; - - public get arrow(): Space { - return this._arrow; - } - - public withArrow(arrow: Space): ArrowFunction { - return arrow === this._arrow ? this : new ArrowFunction(this._id, this._prefix, this._markers, this._leadingAnnotations, this._modifiers, this._typeParameters, this._parameters, this._returnTypeExpression, arrow, this._body, this._type); - } - - private readonly _body: J; + private readonly _body: JLeftPadded; public get body(): J { - return this._body; + return this._body.element; } public withBody(body: J): ArrowFunction { - return body === this._body ? this : new ArrowFunction(this._id, this._prefix, this._markers, this._leadingAnnotations, this._modifiers, this._typeParameters, this._parameters, this._returnTypeExpression, this._arrow, body, this._type); + return this.padding.withBody(this._body.withElement(body)); } private readonly _type: JavaType | null; @@ -373,13 +362,25 @@ export class ArrowFunction extends JSMixin(Object) implements Statement, Express } public withType(_type: JavaType | null): ArrowFunction { - return _type === this._type ? this : new ArrowFunction(this._id, this._prefix, this._markers, this._leadingAnnotations, this._modifiers, this._typeParameters, this._parameters, this._returnTypeExpression, this._arrow, this._body, _type); + return _type === this._type ? this : new ArrowFunction(this._id, this._prefix, this._markers, this._leadingAnnotations, this._modifiers, this._typeParameters, this._parameters, this._returnTypeExpression, this._body, _type); } public acceptJavaScript

(v: JavaScriptVisitor

, p: P): J | null { return v.visitArrowFunction(this, p); } + get padding() { + const t = this; + return new class { + public get body(): JLeftPadded { + return t._body; + } + public withBody(body: JLeftPadded): ArrowFunction { + return t._body === body ? t : new ArrowFunction(t._id, t._prefix, t._markers, t._leadingAnnotations, t._modifiers, t._typeParameters, t._parameters, t._returnTypeExpression, body, t._type); + } + } + } + } @LstType("org.openrewrite.javascript.tree.JS$Await") @@ -2478,7 +2479,7 @@ export class TaggedTemplateExpression extends JSMixin(Object) implements Stateme } @LstType("org.openrewrite.javascript.tree.JS$TemplateExpression") -export class TemplateExpression extends JSMixin(Object) implements Statement, Expression { +export class TemplateExpression extends JSMixin(Object) implements Statement, Expression, TypeTree { public constructor(id: UUID, prefix: Space, markers: Markers, head: Java.Literal, templateSpans: JRightPadded[], _type: JavaType | null) { super(); this._id = id; @@ -3059,6 +3060,7 @@ export namespace TypeOperator { export enum Type { ReadOnly = 0, KeyOf = 1, + Unique = 2, } @@ -5595,6 +5597,7 @@ export namespace JsAssignmentOperation { QuestionQuestion = 0, And = 1, Or = 2, + Power = 3, } diff --git a/openrewrite/src/javascript/visitor.ts b/openrewrite/src/javascript/visitor.ts index b967e369..dbccf3fa 100644 --- a/openrewrite/src/javascript/visitor.ts +++ b/openrewrite/src/javascript/visitor.ts @@ -54,8 +54,7 @@ export class JavaScriptVisitor

extends JavaVisitor

{ arrowFunction = arrowFunction.withTypeParameters(this.visitAndCast(arrowFunction.typeParameters, p)); arrowFunction = arrowFunction.withParameters(this.visitAndCast(arrowFunction.parameters, p)!); arrowFunction = arrowFunction.withReturnTypeExpression(this.visitAndCast(arrowFunction.returnTypeExpression, p)); - arrowFunction = arrowFunction.withArrow(this.visitJsSpace(arrowFunction.arrow, JsSpace.Location.ARROW_FUNCTION_ARROW, p)!); - arrowFunction = arrowFunction.withBody(this.visitAndCast(arrowFunction.body, p)!); + arrowFunction = arrowFunction.padding.withBody(this.visitJsLeftPadded(arrowFunction.padding.body, JsLeftPadded.Location.ARROW_FUNCTION_BODY, p)!); return arrowFunction; } diff --git a/openrewrite/test/javascript/parser/binary.test.ts b/openrewrite/test/javascript/parser/binary.test.ts index ce5e50ce..cace22d1 100644 --- a/openrewrite/test/javascript/parser/binary.test.ts +++ b/openrewrite/test/javascript/parser/binary.test.ts @@ -80,6 +80,13 @@ describe('arithmetic operator mapping', () => { typeScript('1 >>> 2') ); }); + + test('power operation ', () => { + rewriteRun( + //language=typescript + typeScript('2 ** 3') + ); + }); }); describe('bitwise operator mapping', () => { diff --git a/openrewrite/test/javascript/parser/class.test.ts b/openrewrite/test/javascript/parser/class.test.ts index 1655f2d5..62cb2e34 100644 --- a/openrewrite/test/javascript/parser/class.test.ts +++ b/openrewrite/test/javascript/parser/class.test.ts @@ -469,4 +469,25 @@ describe('class mapping', () => { ); }); + + test('new class with type arguments', () => { + rewriteRun( + //language=typescript + typeScript(` + const _onDidChangeEnvironment = /*a*/new/*b*/ EventEmitter/*c*//*f*/(/*g*/)/*h*/; + `) + ); + }); + + test('property declaration', () => { + rewriteRun( + //language=typescript + typeScript(` + export class CodeLoopbackClient { + private server!: http.Server | https.Server; + } + `) + ); + }); + }); diff --git a/openrewrite/test/javascript/parser/expressionStatement.test.ts b/openrewrite/test/javascript/parser/expressionStatement.test.ts index 0ebfa2a7..95dc8b24 100644 --- a/openrewrite/test/javascript/parser/expressionStatement.test.ts +++ b/openrewrite/test/javascript/parser/expressionStatement.test.ts @@ -190,4 +190,16 @@ describe('expression statement mapping', () => { ); }); + test('debugging statement', () => { + rewriteRun( + //language=typescript + typeScript(` + function calculate(value: number) { + /*a*/debugger/*b*/;/*c*/ // Pauses execution when debugging + return value * 2; + } + `) + ); + }); + }); diff --git a/openrewrite/test/javascript/parser/function.test.ts b/openrewrite/test/javascript/parser/function.test.ts index 6d9c8bb0..f8dde7b8 100644 --- a/openrewrite/test/javascript/parser/function.test.ts +++ b/openrewrite/test/javascript/parser/function.test.ts @@ -421,4 +421,16 @@ describe('function mapping', () => { `) ); }); + + test('no additional comma test', () => { + rewriteRun( + //language=typescript + typeScript(` + new Promise(function() { + let x; + let y; + }) + `) + ); + }); }); diff --git a/openrewrite/test/javascript/parser/if.test.ts b/openrewrite/test/javascript/parser/if.test.ts index db2e6fad..3608aa1a 100644 --- a/openrewrite/test/javascript/parser/if.test.ts +++ b/openrewrite/test/javascript/parser/if.test.ts @@ -22,4 +22,16 @@ describe('if mapping', () => { typeScript('if (true) console.log("foo"); else console.log("bar");') ); }); + + test('if-else with semicolon', () => { + rewriteRun( + //language=typescript + typeScript(` + if (true) { + console.log("foo"); + } else + console.log("bar"); + `) + ); + }); }); diff --git a/openrewrite/test/javascript/parser/typeLiteral.test.ts b/openrewrite/test/javascript/parser/typeLiteral.test.ts index 78831eaa..7401bde9 100644 --- a/openrewrite/test/javascript/parser/typeLiteral.test.ts +++ b/openrewrite/test/javascript/parser/typeLiteral.test.ts @@ -45,4 +45,15 @@ describe('type literal mapping', () => { `) ); }); + + test('type literal in params', () => { + rewriteRun( + //language=typescript + typeScript(` + type ascii = { + " ": 32; "!": 33; + } + `) + ); + }); }); diff --git a/openrewrite/test/javascript/parser/variableDeclarations.test.ts b/openrewrite/test/javascript/parser/variableDeclarations.test.ts index a58c9013..f2ab59fb 100644 --- a/openrewrite/test/javascript/parser/variableDeclarations.test.ts +++ b/openrewrite/test/javascript/parser/variableDeclarations.test.ts @@ -88,6 +88,7 @@ describe('variable declaration mapping', () => { `) ); }); + test('exported variables', () => { rewriteRun( //language=typescript @@ -95,6 +96,31 @@ describe('variable declaration mapping', () => { ); }); + test('unique symbol', () => { + rewriteRun( + //language=typescript + typeScript('declare const unset: unique symbol;') + ); + }); + + test('bigint', () => { + rewriteRun( + //language=typescript + typeScript('type res3 = Call;\n') + ); + }); + + test('property signature as an array', () => { + rewriteRun( + //language=typescript + typeScript(` + export type Apply = (fn & { + [rawArgs]: args; + })["return"]; + `) + ); + }); + test('declaration with destruction', () => { rewriteRun( //language=typescript 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 a678f859..b4117a31 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 @@ -110,8 +110,7 @@ public JS.ArrowFunction visitArrowFunction(JS.ArrowFunction arrowFunction, Recei arrowFunction = arrowFunction.withTypeParameters(ctx.receiveNode(arrowFunction.getTypeParameters(), ctx::receiveTree)); arrowFunction = arrowFunction.withParameters(ctx.receiveNonNullNode(arrowFunction.getParameters(), ctx::receiveTree)); arrowFunction = arrowFunction.withReturnTypeExpression(ctx.receiveNode(arrowFunction.getReturnTypeExpression(), ctx::receiveTree)); - arrowFunction = arrowFunction.withArrow(ctx.receiveNonNullNode(arrowFunction.getArrow(), JavaScriptReceiver::receiveSpace)); - arrowFunction = arrowFunction.withBody(ctx.receiveNonNullNode(arrowFunction.getBody(), ctx::receiveTree)); + arrowFunction = arrowFunction.getPadding().withBody(ctx.receiveNonNullNode(arrowFunction.getPadding().getBody(), JavaScriptReceiver::receiveLeftPaddedTree)); arrowFunction = arrowFunction.withType(ctx.receiveValue(arrowFunction.getType(), JavaType.class)); return arrowFunction; } @@ -1624,8 +1623,7 @@ private static JS.ArrowFunction createJSArrowFunction(ReceiverContext ctx) { ctx.receiveNode(null, ctx::receiveTree), ctx.receiveNonNullNode(null, ctx::receiveTree), ctx.receiveNode(null, ctx::receiveTree), - ctx.receiveNonNullNode(null, JavaScriptReceiver::receiveSpace), - ctx.receiveNonNullNode(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 bd69cc8d..dd643dfb 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 @@ -92,8 +92,7 @@ public JS.ArrowFunction visitArrowFunction(JS.ArrowFunction arrowFunction, Sende ctx.sendNode(arrowFunction, JS.ArrowFunction::getTypeParameters, ctx::sendTree); ctx.sendNode(arrowFunction, JS.ArrowFunction::getParameters, ctx::sendTree); ctx.sendNode(arrowFunction, JS.ArrowFunction::getReturnTypeExpression, ctx::sendTree); - ctx.sendNode(arrowFunction, JS.ArrowFunction::getArrow, JavaScriptSender::sendSpace); - ctx.sendNode(arrowFunction, JS.ArrowFunction::getBody, ctx::sendTree); + ctx.sendNode(arrowFunction, e -> e.getPadding().getBody(), JavaScriptSender::sendLeftPadded); ctx.sendTypedValue(arrowFunction, JS.ArrowFunction::getType); return arrowFunction; } diff --git a/rewrite-javascript-remote/src/main/java/org/openrewrite/javascript/remote/JavaScriptValidator.java b/rewrite-javascript-remote/src/main/java/org/openrewrite/javascript/remote/JavaScriptValidator.java index 4bab4581..85ecef55 100644 --- a/rewrite-javascript-remote/src/main/java/org/openrewrite/javascript/remote/JavaScriptValidator.java +++ b/rewrite-javascript-remote/src/main/java/org/openrewrite/javascript/remote/JavaScriptValidator.java @@ -77,7 +77,7 @@ public JS.ArrowFunction visitArrowFunction(JS.ArrowFunction arrowFunction, P p) ListUtils.map(arrowFunction.getLeadingAnnotations(), el -> visitAndValidateNonNull(el, J.Annotation.class, p)); ListUtils.map(arrowFunction.getModifiers(), el -> visitAndValidateNonNull(el, J.Modifier.class, p)); visitAndValidate(arrowFunction.getTypeParameters(), J.TypeParameters.class, p); - visitAndValidateNonNull(arrowFunction.getParameters(), J.Lambda.Parameters.class, p); + visitAndValidate(arrowFunction.getParameters().getParameters(), J.class, p); visitAndValidate(arrowFunction.getReturnTypeExpression(), TypeTree.class, p); visitAndValidateNonNull(arrowFunction.getBody(), J.class, p); return arrowFunction; 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 54950e7d..4bdcfb23 100644 --- a/rewrite-javascript/src/main/java/org/openrewrite/javascript/JavaScriptVisitor.java +++ b/rewrite-javascript/src/main/java/org/openrewrite/javascript/JavaScriptVisitor.java @@ -101,7 +101,7 @@ public J visitArrowFunction(JS.ArrowFunction arrowFunction, P p) { ); a = a.withParameters(Objects.requireNonNull(visitAndCast(a.getParameters(), p))); a = a.withReturnTypeExpression(visitAndCast(a.getReturnTypeExpression(), p)); - a = a.withArrow(visitSpace(a.getArrow(), Space.Location.LAMBDA_ARROW_PREFIX, p)); + a = a.getPadding().withBody(visitLeftPadded(a.getPadding().getBody(), JsLeftPadded.Location.LAMBDA_ARROW, p)); a = a.withBody(Objects.requireNonNull(visitAndCast(a.getBody(), p))); a = a.withType(visitType(a.getType(), p)); return a; 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 7873bd21..bf96a0e1 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 @@ -50,6 +50,16 @@ public J visit(@Nullable Tree tree, PrintOutputCapture

p) { } } + @Override + public void setCursor(@Nullable Cursor cursor) { + super.setCursor(cursor); + delegate.internalSetCursor(cursor); + } + + private void internalSetCursor(@Nullable Cursor cursor) { + super.setCursor(cursor); + } + @Override public J visitCompilationUnit(JS.CompilationUnit cu, PrintOutputCapture

p) { beforeSyntax(cu, Space.Location.COMPILATION_UNIT_PREFIX, p); @@ -100,11 +110,8 @@ public J visitArrowFunction(JS.ArrowFunction arrowFunction, PrintOutputCapture

"); - visit(arrowFunction.getBody(), p); - } + visitLeftPadded("=>", arrowFunction.getPadding().getBody(), JsLeftPadded.Location.LAMBDA_ARROW, p); + afterSyntax(arrowFunction, p); return arrowFunction; } @@ -329,6 +336,9 @@ public J visitJsAssignmentOperation(JS.JsAssignmentOperation assignOp, PrintOutp case Or: keyword = "||="; break; + case Power: + keyword = "**"; + break; } beforeSyntax(assignOp, JsSpace.Location.ASSIGNMENT_OPERATION_PREFIX, p); visit(assignOp.getVariable(), p); @@ -577,6 +587,8 @@ public J visitTypeOperator(JS.TypeOperator typeOperator, PrintOutputCapture

p keyword = "readonly"; } else if (typeOperator.getOperator() == JS.TypeOperator.Type.KeyOf) { keyword = "keyof"; + } else if (typeOperator.getOperator() == JS.TypeOperator.Type.Unique) { + keyword = "unique"; } p.append(keyword); @@ -962,6 +974,16 @@ public J visit(@Nullable Tree tree, PrintOutputCapture

p) { } } + @Override + public void setCursor(@Nullable Cursor cursor) { + super.setCursor(cursor); + JavaScriptPrinter.this.internalSetCursor(cursor); + } + + public void internalSetCursor(@Nullable Cursor cursor) { + super.setCursor(cursor); + } + @Override public J visitEnumValue(J.EnumValue enum_, PrintOutputCapture

p) { beforeSyntax(enum_, Space.Location.ENUM_VALUE_PREFIX, p); @@ -1292,10 +1314,7 @@ public J visitTypeParameter(J.TypeParameter typeParameter, PrintOutputCapture

visitSpace(bounds.getBefore(), JContainer.Location.TYPE_BOUNDS.getBeforeLocation(), p); JRightPadded constraintType = bounds.getPadding().getElements().get(0); - if (getCursor().getParentTreeCursor().getValue() instanceof JS.MappedType) { - p.append("in"); - this.visitRightPadded(constraintType, JContainer.Location.TYPE_BOUNDS.getElementLocation(), p); - } else if (!(constraintType.getElement() instanceof J.Empty)) { + if (!(constraintType.getElement() instanceof J.Empty)) { p.append("extends"); this.visitRightPadded(constraintType, JContainer.Location.TYPE_BOUNDS.getElementLocation(), 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 63dddf78..848fc5b4 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 @@ -394,9 +394,15 @@ public JS.Alias withPropertyName(JRightPadded propertyName) { */ @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) + @RequiredArgsConstructor + @AllArgsConstructor(access = AccessLevel.PRIVATE) @Data final class ArrowFunction implements JS, Statement, Expression, TypedTree { + @Nullable + @NonFinal + transient WeakReference padding; + @With @EqualsAndHashCode.Include UUID id; @@ -425,11 +431,15 @@ final class ArrowFunction implements JS, Statement, Expression, TypedTree { @Nullable TypeTree returnTypeExpression; - @With - Space arrow; + JLeftPadded body; - @With - J body; + public J getBody() { + return body.getElement(); + } + + public ArrowFunction withBody(J body) { + return getPadding().withBody(JLeftPadded.withElement(this.body, body)); + } @With @Nullable @@ -445,6 +455,35 @@ public

J acceptJavaScript(JavaScriptVisitor

v, P p) { public CoordinateBuilder.Statement getCoordinates() { return new CoordinateBuilder.Statement(this); } + + public ArrowFunction.Padding getPadding() { + ArrowFunction.Padding p; + if (this.padding == null) { + p = new ArrowFunction.Padding(this); + this.padding = new WeakReference<>(p); + } else { + p = this.padding.get(); + if (p == null || p.f != this) { + p = new ArrowFunction.Padding(this); + this.padding = new WeakReference<>(p); + } + } + return p; + } + + @RequiredArgsConstructor + public static class Padding { + private final ArrowFunction f; + + public JLeftPadded getBody() { + return f.body; + } + + public ArrowFunction withBody(JLeftPadded body) { + return f.body == body ? f: new ArrowFunction(f.id, f.prefix, f.markers, f.leadingAnnotations, f.modifiers, f.typeParameters, f.parameters, f.returnTypeExpression, body, f.type); + } + } + } @Getter @@ -2387,7 +2426,7 @@ public TaggedTemplateExpression withTypeArguments(@Nullable JContainer