diff --git a/openrewrite/src/javascript/parser.ts b/openrewrite/src/javascript/parser.ts index c2e962b8..81e91a60 100644 --- a/openrewrite/src/javascript/parser.ts +++ b/openrewrite/src/javascript/parser.ts @@ -534,7 +534,8 @@ export class JavaScriptParserVisitor { return this.mapLiteral(node, null); } - private mapLiteral(node: ts.LiteralExpression | ts.TrueLiteral | ts.FalseLiteral | ts.NullLiteral | ts.Identifier, value: any): J.Literal { + 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( randomId(), this.prefix(node), @@ -567,15 +568,15 @@ export class JavaScriptParserVisitor { } visitTemplateHead(node: ts.TemplateHead) { - return this.visitUnknown(node); + return this.mapLiteral(node, node.text); } visitTemplateMiddle(node: ts.TemplateMiddle) { - return this.visitUnknown(node); + return this.mapLiteral(node, node.text); } visitTemplateTail(node: ts.TemplateTail) { - return this.visitUnknown(node); + return this.mapLiteral(node, node.text); } visitIdentifier(node: ts.Identifier) { @@ -1328,7 +1329,28 @@ export class JavaScriptParserVisitor { } visitConditionalType(node: ts.ConditionalTypeNode) { - return this.visitUnknown(node); + return new JS.ConditionalType( + randomId(), + this.prefix(node), + Markers.EMPTY, + this.visit(node.checkType), + new JContainer( + this.prefix(this.findChildNode(node, ts.SyntaxKind.ExtendsKeyword)!), + [this.rightPadded( + new J.Ternary( + randomId(), + Space.EMPTY, + Markers.EMPTY, + this.convert(node.extendsType), + this.leftPadded(this.suffix(node.extendsType), this.convert(node.trueType)), + this.leftPadded(this.suffix(node.trueType), this.convert(node.falseType)), + this.mapType(node)), + Space.EMPTY + )], + Markers.EMPTY + ), + this.mapType(node) + ); } visitInferType(node: ts.InferTypeNode) { @@ -1379,11 +1401,24 @@ export class JavaScriptParserVisitor { } visitTemplateLiteralType(node: ts.TemplateLiteralTypeNode) { - return this.visitUnknown(node); + return new JS.TemplateExpression( + randomId(), + this.prefix(node), + Markers.EMPTY, + this.visit(node.head), + node.templateSpans.map(s => this.rightPadded(this.visit(s), this.suffix(s))), + this.mapType(node) + ) } visitTemplateLiteralTypeSpan(node: ts.TemplateLiteralTypeSpan) { - return this.visitUnknown(node); + return new JS.TemplateExpression.TemplateSpan( + randomId(), + this.prefix(node), + Markers.EMPTY, + this.convert(node.type), + this.visit(node.literal) + ) } visitImportType(node: ts.ImportTypeNode) { @@ -1591,7 +1626,15 @@ export class JavaScriptParserVisitor { } visitTaggedTemplateExpression(node: ts.TaggedTemplateExpression) { - return this.visitUnknown(node); + return new JS.TaggedTemplateExpression( + randomId(), + this.prefix(node), + Markers.EMPTY, + this.rightPadded(this.visit(node.tag), this.suffix(node.tag)), + node.typeArguments ? this.mapTypeArguments(Space.EMPTY, node.typeArguments) : null, + this.visit(node.template), + this.mapType(node) + ) } visitTypeAssertionExpression(node: ts.TypeAssertion) { @@ -1959,7 +2002,14 @@ export class JavaScriptParserVisitor { } visitTemplateExpression(node: ts.TemplateExpression) { - return this.visitUnknown(node); + return new JS.TemplateExpression( + randomId(), + this.prefix(node), + Markers.EMPTY, + this.visit(node.head), + node.templateSpans.map(s => this.rightPadded(this.visit(s), this.suffix(s))), + this.mapType(node) + ) } visitYieldExpression(node: ts.YieldExpression) { @@ -2029,16 +2079,14 @@ export class JavaScriptParserVisitor { visitExpressionWithTypeArguments(node: ts.ExpressionWithTypeArguments) { if (node.typeArguments) { - if (node.typeArguments) { - return new J.ParameterizedType( - randomId(), - this.prefix(node), - Markers.EMPTY, - this.visit(node.expression), - this.mapTypeArguments(this.suffix(node.expression), node.typeArguments), - this.mapType(node) - ) - } + return new JS.ExpressionWithTypeArguments( + randomId(), + this.prefix(node), + Markers.EMPTY, + this.visit(node.expression), + this.mapTypeArguments(this.suffix(node.expression), node.typeArguments), + this.mapType(node) + ) } return this.visit(node.expression); } @@ -2079,7 +2127,13 @@ export class JavaScriptParserVisitor { } visitTemplateSpan(node: ts.TemplateSpan) { - return this.visitUnknown(node); + return new JS.TemplateExpression.TemplateSpan( + randomId(), + this.prefix(node), + Markers.EMPTY, + this.convert(node.expression), + this.visit(node.literal) + ) } visitSemicolonClassElement(node: ts.SemicolonClassElement) { diff --git a/openrewrite/src/javascript/remote/receiver.ts b/openrewrite/src/javascript/remote/receiver.ts index 05a0351b..25f93fd8 100644 --- a/openrewrite/src/javascript/remote/receiver.ts +++ b/openrewrite/src/javascript/remote/receiver.ts @@ -2,7 +2,7 @@ import * as extensions from "./remote_extensions"; import {Checksum, Cursor, FileAttributes, ListUtils, Tree} from '../../core'; import {DetailsReceiver, Receiver, ReceiverContext, ReceiverFactory, ValueType} from '@openrewrite/rewrite-remote'; import {JavaScriptVisitor} from '..'; -import {JS, JsLeftPadded, JsRightPadded, JsContainer, JsSpace, CompilationUnit, Alias, ArrowFunction, Await, DefaultType, Delete, Export, ExpressionStatement, FunctionType, JsImport, JsImportSpecifier, JsBinary, ObjectBindingDeclarations, PropertyAssignment, ScopedVariableDeclarations, StatementExpression, TemplateExpression, Tuple, TypeDeclaration, TypeOf, TypeQuery, TypeOperator, Unary, Union, Intersection, Void, Yield, TypeInfo, JSVariableDeclarations, JSMethodDeclaration, JSForOfLoop, JSForInLoop, JSForInOfLoopControl, NamespaceDeclaration, FunctionDeclaration, TypeLiteral, IndexSignatureDeclaration, ArrayBindingPattern, BindingElement} from '../tree'; +import {JS, JsLeftPadded, JsRightPadded, JsContainer, JsSpace, CompilationUnit, Alias, ArrowFunction, Await, ConditionalType, DefaultType, Delete, Export, ExpressionStatement, ExpressionWithTypeArguments, FunctionType, JsImport, JsImportSpecifier, JsBinary, ObjectBindingDeclarations, PropertyAssignment, ScopedVariableDeclarations, StatementExpression, TaggedTemplateExpression, TemplateExpression, Tuple, TypeDeclaration, TypeOf, TypeQuery, TypeOperator, Unary, Union, Intersection, Void, Yield, TypeInfo, JSVariableDeclarations, JSMethodDeclaration, JSForOfLoop, JSForInLoop, JSForInOfLoopControl, NamespaceDeclaration, FunctionDeclaration, TypeLiteral, IndexSignatureDeclaration, ArrayBindingPattern, BindingElement} from '../tree'; import {Expression, J, JContainer, JLeftPadded, JRightPadded, NameTree, Space, Statement, TypeTree, TypedTree} from "../../java"; import * as Java from "../../java/tree"; @@ -75,6 +75,16 @@ class Visitor extends JavaScriptVisitor { return await; } + public visitConditionalType(conditionalType: ConditionalType, ctx: ReceiverContext): J { + conditionalType = conditionalType.withId(ctx.receiveValue(conditionalType.id, ValueType.UUID)!); + conditionalType = conditionalType.withPrefix(ctx.receiveNode(conditionalType.prefix, receiveSpace)!); + conditionalType = conditionalType.withMarkers(ctx.receiveNode(conditionalType.markers, ctx.receiveMarkers)!); + conditionalType = conditionalType.withCheckType(ctx.receiveNode(conditionalType.checkType, ctx.receiveTree)!); + conditionalType = conditionalType.padding.withCondition(ctx.receiveNode(conditionalType.padding.condition, receiveContainer)!); + conditionalType = conditionalType.withType(ctx.receiveValue(conditionalType.type, ValueType.Object)); + return conditionalType; + } + public visitDefaultType(defaultType: DefaultType, ctx: ReceiverContext): J { defaultType = defaultType.withId(ctx.receiveValue(defaultType.id, ValueType.UUID)!); defaultType = defaultType.withPrefix(ctx.receiveNode(defaultType.prefix, receiveSpace)!); @@ -112,6 +122,16 @@ class Visitor extends JavaScriptVisitor { return expressionStatement; } + public visitExpressionWithTypeArguments(expressionWithTypeArguments: ExpressionWithTypeArguments, ctx: ReceiverContext): J { + expressionWithTypeArguments = expressionWithTypeArguments.withId(ctx.receiveValue(expressionWithTypeArguments.id, ValueType.UUID)!); + expressionWithTypeArguments = expressionWithTypeArguments.withPrefix(ctx.receiveNode(expressionWithTypeArguments.prefix, receiveSpace)!); + expressionWithTypeArguments = expressionWithTypeArguments.withMarkers(ctx.receiveNode(expressionWithTypeArguments.markers, ctx.receiveMarkers)!); + expressionWithTypeArguments = expressionWithTypeArguments.withClazz(ctx.receiveNode(expressionWithTypeArguments.clazz, ctx.receiveTree)!); + expressionWithTypeArguments = expressionWithTypeArguments.padding.withTypeArguments(ctx.receiveNode(expressionWithTypeArguments.padding.typeArguments, receiveContainer)); + expressionWithTypeArguments = expressionWithTypeArguments.withType(ctx.receiveValue(expressionWithTypeArguments.type, ValueType.Object)); + return expressionWithTypeArguments; + } + public visitFunctionType(functionType: FunctionType, ctx: ReceiverContext): J { functionType = functionType.withId(ctx.receiveValue(functionType.id, ValueType.UUID)!); functionType = functionType.withPrefix(ctx.receiveNode(functionType.prefix, receiveSpace)!); @@ -195,25 +215,34 @@ class Visitor extends JavaScriptVisitor { return statementExpression; } + public visitTaggedTemplateExpression(taggedTemplateExpression: TaggedTemplateExpression, ctx: ReceiverContext): J { + taggedTemplateExpression = taggedTemplateExpression.withId(ctx.receiveValue(taggedTemplateExpression.id, ValueType.UUID)!); + taggedTemplateExpression = taggedTemplateExpression.withPrefix(ctx.receiveNode(taggedTemplateExpression.prefix, receiveSpace)!); + taggedTemplateExpression = taggedTemplateExpression.withMarkers(ctx.receiveNode(taggedTemplateExpression.markers, ctx.receiveMarkers)!); + taggedTemplateExpression = taggedTemplateExpression.padding.withTag(ctx.receiveNode(taggedTemplateExpression.padding.tag, receiveRightPaddedTree)); + taggedTemplateExpression = taggedTemplateExpression.padding.withTypeArguments(ctx.receiveNode(taggedTemplateExpression.padding.typeArguments, receiveContainer)); + taggedTemplateExpression = taggedTemplateExpression.withTemplateExpression(ctx.receiveNode(taggedTemplateExpression.templateExpression, ctx.receiveTree)!); + taggedTemplateExpression = taggedTemplateExpression.withType(ctx.receiveValue(taggedTemplateExpression.type, ValueType.Object)); + return taggedTemplateExpression; + } + public visitTemplateExpression(templateExpression: TemplateExpression, ctx: ReceiverContext): J { templateExpression = templateExpression.withId(ctx.receiveValue(templateExpression.id, ValueType.UUID)!); templateExpression = templateExpression.withPrefix(ctx.receiveNode(templateExpression.prefix, receiveSpace)!); templateExpression = templateExpression.withMarkers(ctx.receiveNode(templateExpression.markers, ctx.receiveMarkers)!); - templateExpression = templateExpression.withDelimiter(ctx.receiveValue(templateExpression.delimiter, ValueType.Primitive)!); - templateExpression = templateExpression.padding.withTag(ctx.receiveNode(templateExpression.padding.tag, receiveRightPaddedTree)); - templateExpression = templateExpression.withStrings(ctx.receiveNodes(templateExpression.strings, ctx.receiveTree)!); + templateExpression = templateExpression.withHead(ctx.receiveNode(templateExpression.head, ctx.receiveTree)!); + templateExpression = templateExpression.padding.withTemplateSpans(ctx.receiveNodes(templateExpression.padding.templateSpans, receiveRightPaddedTree)!); templateExpression = templateExpression.withType(ctx.receiveValue(templateExpression.type, ValueType.Object)); return templateExpression; } - public visitTemplateExpressionValue(value: TemplateExpression.Value, ctx: ReceiverContext): J { - value = value.withId(ctx.receiveValue(value.id, ValueType.UUID)!); - value = value.withPrefix(ctx.receiveNode(value.prefix, receiveSpace)!); - value = value.withMarkers(ctx.receiveNode(value.markers, ctx.receiveMarkers)!); - value = value.withTree(ctx.receiveNode(value.tree, ctx.receiveTree)!); - value = value.withAfter(ctx.receiveNode(value.after, receiveSpace)!); - value = value.withEnclosedInBraces(ctx.receiveValue(value.enclosedInBraces, ValueType.Primitive)!); - return value; + public visitTemplateExpressionTemplateSpan(templateSpan: TemplateExpression.TemplateSpan, ctx: ReceiverContext): J { + templateSpan = templateSpan.withId(ctx.receiveValue(templateSpan.id, ValueType.UUID)!); + templateSpan = templateSpan.withPrefix(ctx.receiveNode(templateSpan.prefix, receiveSpace)!); + templateSpan = templateSpan.withMarkers(ctx.receiveNode(templateSpan.markers, ctx.receiveMarkers)!); + templateSpan = templateSpan.withExpression(ctx.receiveNode(templateSpan.expression, ctx.receiveTree)!); + templateSpan = templateSpan.withTail(ctx.receiveNode(templateSpan.tail, ctx.receiveTree)!); + return templateSpan; } public visitTuple(tuple: Tuple, ctx: ReceiverContext): J { @@ -1173,6 +1202,17 @@ class Factory implements ReceiverFactory { ); } + if (type === "org.openrewrite.javascript.tree.JS$ConditionalType") { + return new ConditionalType( + ctx.receiveValue(null, ValueType.UUID)!, + ctx.receiveNode(null, receiveSpace)!, + ctx.receiveNode(null, ctx.receiveMarkers)!, + ctx.receiveNode(null, ctx.receiveTree)!, + ctx.receiveNode>(null, receiveContainer)!, + ctx.receiveValue(null, ValueType.Object) + ); + } + if (type === "org.openrewrite.javascript.tree.JS$DefaultType") { return new DefaultType( ctx.receiveValue(null, ValueType.UUID)!, @@ -1214,6 +1254,17 @@ class Factory implements ReceiverFactory { ); } + if (type === "org.openrewrite.javascript.tree.JS$ExpressionWithTypeArguments") { + return new ExpressionWithTypeArguments( + ctx.receiveValue(null, ValueType.UUID)!, + ctx.receiveNode(null, receiveSpace)!, + ctx.receiveNode(null, ctx.receiveMarkers)!, + ctx.receiveNode(null, ctx.receiveTree)!, + ctx.receiveNode>(null, receiveContainer), + ctx.receiveValue(null, ValueType.Object) + ); + } + if (type === "org.openrewrite.javascript.tree.JS$FunctionType") { return new FunctionType( ctx.receiveValue(null, ValueType.UUID)!, @@ -1305,26 +1356,36 @@ class Factory implements ReceiverFactory { ); } + if (type === "org.openrewrite.javascript.tree.JS$TaggedTemplateExpression") { + return new TaggedTemplateExpression( + ctx.receiveValue(null, ValueType.UUID)!, + ctx.receiveNode(null, receiveSpace)!, + ctx.receiveNode(null, ctx.receiveMarkers)!, + ctx.receiveNode>(null, receiveRightPaddedTree), + ctx.receiveNode>(null, receiveContainer), + ctx.receiveNode(null, ctx.receiveTree)!, + ctx.receiveValue(null, ValueType.Object) + ); + } + if (type === "org.openrewrite.javascript.tree.JS$TemplateExpression") { return new TemplateExpression( ctx.receiveValue(null, ValueType.UUID)!, ctx.receiveNode(null, receiveSpace)!, ctx.receiveNode(null, ctx.receiveMarkers)!, - ctx.receiveValue(null, ValueType.Primitive)!, - ctx.receiveNode>(null, receiveRightPaddedTree), - ctx.receiveNodes(null, ctx.receiveTree)!, + ctx.receiveNode(null, ctx.receiveTree)!, + ctx.receiveNodes(null, receiveRightPaddedTree)!, ctx.receiveValue(null, ValueType.Object) ); } - if (type === "org.openrewrite.javascript.tree.JS$TemplateExpression$Value") { - return new TemplateExpression.Value( + if (type === "org.openrewrite.javascript.tree.JS$TemplateExpression$TemplateSpan") { + return new TemplateExpression.TemplateSpan( ctx.receiveValue(null, ValueType.UUID)!, ctx.receiveNode(null, receiveSpace)!, ctx.receiveNode(null, ctx.receiveMarkers)!, ctx.receiveNode(null, ctx.receiveTree)!, - ctx.receiveNode(null, receiveSpace)!, - ctx.receiveValue(null, ValueType.Primitive)! + ctx.receiveNode(null, ctx.receiveTree)! ); } diff --git a/openrewrite/src/javascript/remote/sender.ts b/openrewrite/src/javascript/remote/sender.ts index 02c73602..9eb8baa3 100644 --- a/openrewrite/src/javascript/remote/sender.ts +++ b/openrewrite/src/javascript/remote/sender.ts @@ -2,7 +2,7 @@ import * as extensions from "./remote_extensions"; import {Cursor, ListUtils, Tree} from '../../core'; import {Sender, SenderContext, ValueType} from '@openrewrite/rewrite-remote'; import {JavaScriptVisitor} from '..'; -import {JS, JsLeftPadded, JsRightPadded, JsContainer, JsSpace, CompilationUnit, Alias, ArrowFunction, Await, DefaultType, Delete, Export, ExpressionStatement, FunctionType, JsImport, JsImportSpecifier, JsBinary, ObjectBindingDeclarations, PropertyAssignment, ScopedVariableDeclarations, StatementExpression, TemplateExpression, Tuple, TypeDeclaration, TypeOf, TypeQuery, TypeOperator, Unary, Union, Intersection, Void, Yield, TypeInfo, JSVariableDeclarations, JSMethodDeclaration, JSForOfLoop, JSForInLoop, JSForInOfLoopControl, NamespaceDeclaration, FunctionDeclaration, TypeLiteral, IndexSignatureDeclaration, ArrayBindingPattern, BindingElement} from '../tree'; +import {JS, JsLeftPadded, JsRightPadded, JsContainer, JsSpace, CompilationUnit, Alias, ArrowFunction, Await, ConditionalType, DefaultType, Delete, Export, ExpressionStatement, ExpressionWithTypeArguments, FunctionType, JsImport, JsImportSpecifier, JsBinary, ObjectBindingDeclarations, PropertyAssignment, ScopedVariableDeclarations, StatementExpression, TaggedTemplateExpression, TemplateExpression, Tuple, TypeDeclaration, TypeOf, TypeQuery, TypeOperator, Unary, Union, Intersection, Void, Yield, TypeInfo, JSVariableDeclarations, JSMethodDeclaration, JSForOfLoop, JSForInLoop, JSForInOfLoopControl, NamespaceDeclaration, FunctionDeclaration, TypeLiteral, IndexSignatureDeclaration, ArrayBindingPattern, BindingElement} from '../tree'; import {Expression, J, JContainer, JLeftPadded, JRightPadded, Space, Statement} from "../../java"; import * as Java from "../../java/tree"; @@ -70,6 +70,16 @@ class Visitor extends JavaScriptVisitor { return await; } + public visitConditionalType(conditionalType: ConditionalType, ctx: SenderContext): J { + ctx.sendValue(conditionalType, v => v.id, ValueType.UUID); + ctx.sendNode(conditionalType, v => v.prefix, Visitor.sendSpace); + ctx.sendNode(conditionalType, v => v.markers, ctx.sendMarkers); + ctx.sendNode(conditionalType, v => v.checkType, ctx.sendTree); + ctx.sendNode(conditionalType, v => v.padding.condition, Visitor.sendContainer(ValueType.Tree)); + ctx.sendTypedValue(conditionalType, v => v.type, ValueType.Object); + return conditionalType; + } + public visitDefaultType(defaultType: DefaultType, ctx: SenderContext): J { ctx.sendValue(defaultType, v => v.id, ValueType.UUID); ctx.sendNode(defaultType, v => v.prefix, Visitor.sendSpace); @@ -107,6 +117,16 @@ class Visitor extends JavaScriptVisitor { return expressionStatement; } + public visitExpressionWithTypeArguments(expressionWithTypeArguments: ExpressionWithTypeArguments, ctx: SenderContext): J { + ctx.sendValue(expressionWithTypeArguments, v => v.id, ValueType.UUID); + ctx.sendNode(expressionWithTypeArguments, v => v.prefix, Visitor.sendSpace); + ctx.sendNode(expressionWithTypeArguments, v => v.markers, ctx.sendMarkers); + ctx.sendNode(expressionWithTypeArguments, v => v.clazz, ctx.sendTree); + ctx.sendNode(expressionWithTypeArguments, v => v.padding.typeArguments, Visitor.sendContainer(ValueType.Tree)); + ctx.sendTypedValue(expressionWithTypeArguments, v => v.type, ValueType.Object); + return expressionWithTypeArguments; + } + public visitFunctionType(functionType: FunctionType, ctx: SenderContext): J { ctx.sendValue(functionType, v => v.id, ValueType.UUID); ctx.sendNode(functionType, v => v.prefix, Visitor.sendSpace); @@ -190,25 +210,34 @@ class Visitor extends JavaScriptVisitor { return statementExpression; } + public visitTaggedTemplateExpression(taggedTemplateExpression: TaggedTemplateExpression, ctx: SenderContext): J { + ctx.sendValue(taggedTemplateExpression, v => v.id, ValueType.UUID); + ctx.sendNode(taggedTemplateExpression, v => v.prefix, Visitor.sendSpace); + ctx.sendNode(taggedTemplateExpression, v => v.markers, ctx.sendMarkers); + ctx.sendNode(taggedTemplateExpression, v => v.padding.tag, Visitor.sendRightPadded(ValueType.Tree)); + ctx.sendNode(taggedTemplateExpression, v => v.padding.typeArguments, Visitor.sendContainer(ValueType.Tree)); + ctx.sendNode(taggedTemplateExpression, v => v.templateExpression, ctx.sendTree); + ctx.sendTypedValue(taggedTemplateExpression, v => v.type, ValueType.Object); + return taggedTemplateExpression; + } + public visitTemplateExpression(templateExpression: TemplateExpression, ctx: SenderContext): J { ctx.sendValue(templateExpression, v => v.id, ValueType.UUID); ctx.sendNode(templateExpression, v => v.prefix, Visitor.sendSpace); ctx.sendNode(templateExpression, v => v.markers, ctx.sendMarkers); - ctx.sendValue(templateExpression, v => v.delimiter, ValueType.Primitive); - ctx.sendNode(templateExpression, v => v.padding.tag, Visitor.sendRightPadded(ValueType.Tree)); - ctx.sendNodes(templateExpression, v => v.strings, ctx.sendTree, t => t.id); + ctx.sendNode(templateExpression, v => v.head, ctx.sendTree); + ctx.sendNodes(templateExpression, v => v.padding.templateSpans, Visitor.sendRightPadded(ValueType.Tree), t => t.element.id); ctx.sendTypedValue(templateExpression, v => v.type, ValueType.Object); return templateExpression; } - public visitTemplateExpressionValue(value: TemplateExpression.Value, ctx: SenderContext): J { - ctx.sendValue(value, v => v.id, ValueType.UUID); - ctx.sendNode(value, v => v.prefix, Visitor.sendSpace); - ctx.sendNode(value, v => v.markers, ctx.sendMarkers); - ctx.sendNode(value, v => v.tree, ctx.sendTree); - ctx.sendNode(value, v => v.after, Visitor.sendSpace); - ctx.sendValue(value, v => v.enclosedInBraces, ValueType.Primitive); - return value; + public visitTemplateExpressionTemplateSpan(templateSpan: TemplateExpression.TemplateSpan, ctx: SenderContext): J { + ctx.sendValue(templateSpan, v => v.id, ValueType.UUID); + ctx.sendNode(templateSpan, v => v.prefix, Visitor.sendSpace); + ctx.sendNode(templateSpan, v => v.markers, ctx.sendMarkers); + ctx.sendNode(templateSpan, v => v.expression, ctx.sendTree); + ctx.sendNode(templateSpan, v => v.tail, ctx.sendTree); + return templateSpan; } public visitTuple(tuple: Tuple, ctx: SenderContext): J { diff --git a/openrewrite/src/javascript/tree/support_types.ts b/openrewrite/src/javascript/tree/support_types.ts index 2c6fd4ed..5f3bc5ef 100644 --- a/openrewrite/src/javascript/tree/support_types.ts +++ b/openrewrite/src/javascript/tree/support_types.ts @@ -236,6 +236,10 @@ export namespace JsSpace { JSFOR_IN_OF_LOOP_CONTROL_PREFIX, TYPE_QUERY_PREFIX, ARRAY_BINDING_PATTERN_PREFIX, + EXPRESSION_WITH_TYPE_ARGUMENTS_PREFIX, + TEMPLATE_EXPRESSION_TEMPLATE_SPAN_PREFIX, + TAGGED_TEMPLATE_EXPRESSION_PREFIX, + CONDITIONAL_TYPE_PREFIX, } } export namespace JsLeftPadded { @@ -270,7 +274,6 @@ export namespace JsRightPadded { BINDING_ELEMENT_PROPERTY_NAME, PROPERTY_ASSIGNMENT_NAME, SCOPED_VARIABLE_DECLARATIONS_VARIABLES, - TEMPLATE_EXPRESSION_TAG, UNION_TYPES, JSVARIABLE_DECLARATIONS_VARIABLES, NAMESPACE_DECLARATION_NAME, @@ -282,6 +285,8 @@ export namespace JsRightPadded { JSFOR_OF_LOOP_BODY, JSFOR_IN_LOOP_BODY, FUNCTION_TYPE_CONSTRUCTOR_TYPE, + TEMPLATE_EXPRESSION_TEMPLATE_SPANS, + TAGGED_TEMPLATE_EXPRESSION_TAG, } } export namespace JsContainer { @@ -297,5 +302,8 @@ export namespace JsContainer { TYPE_LITERAL_MEMBERS, INDEX_SIGNATURE_DECLARATION_PARAMETERS, ARRAY_BINDING_PATTERN_ELEMENTS, + EXPRESSION_WITH_TYPE_ARGUMENTS_TYPE_ARGUMENTS, + TAGGED_TEMPLATE_EXPRESSION_TYPE_ARGUMENTS, + CONDITIONAL_TYPE_CONDITION, } } diff --git a/openrewrite/src/javascript/tree/tree.ts b/openrewrite/src/javascript/tree/tree.ts index d067b46d..b7a264c5 100644 --- a/openrewrite/src/javascript/tree/tree.ts +++ b/openrewrite/src/javascript/tree/tree.ts @@ -449,6 +449,96 @@ export class Await extends JSMixin(Object) implements Expression { } +@LstType("org.openrewrite.javascript.tree.JS$ConditionalType") +export class ConditionalType extends JSMixin(Object) implements TypeTree, Expression { + public constructor(id: UUID, prefix: Space, markers: Markers, checkType: Expression, condition: JContainer, _type: JavaType | null) { + super(); + this._id = id; + this._prefix = prefix; + this._markers = markers; + this._checkType = checkType; + this._condition = condition; + this._type = _type; + } + + private readonly _id: UUID; + + public get id(): UUID { + return this._id; + } + + public withId(id: UUID): ConditionalType { + return id === this._id ? this : new ConditionalType(id, this._prefix, this._markers, this._checkType, this._condition, this._type); + } + + private readonly _prefix: Space; + + public get prefix(): Space { + return this._prefix; + } + + public withPrefix(prefix: Space): ConditionalType { + return prefix === this._prefix ? this : new ConditionalType(this._id, prefix, this._markers, this._checkType, this._condition, this._type); + } + + private readonly _markers: Markers; + + public get markers(): Markers { + return this._markers; + } + + public withMarkers(markers: Markers): ConditionalType { + return markers === this._markers ? this : new ConditionalType(this._id, this._prefix, markers, this._checkType, this._condition, this._type); + } + + private readonly _checkType: Expression; + + public get checkType(): Expression { + return this._checkType; + } + + public withCheckType(checkType: Expression): ConditionalType { + return checkType === this._checkType ? this : new ConditionalType(this._id, this._prefix, this._markers, checkType, this._condition, this._type); + } + + private readonly _condition: JContainer; + + public get condition(): TypedTree[] { + return this._condition.elements; + } + + public withCondition(condition: TypedTree[]): ConditionalType { + return this.padding.withCondition(JContainer.withElements(this._condition, condition)); + } + + private readonly _type: JavaType | null; + + public get type(): JavaType | null { + return this._type; + } + + public withType(_type: JavaType | null): ConditionalType { + return _type === this._type ? this : new ConditionalType(this._id, this._prefix, this._markers, this._checkType, this._condition, _type); + } + + public acceptJavaScript

(v: JavaScriptVisitor

, p: P): J | null { + return v.visitConditionalType(this, p); + } + + get padding() { + const t = this; + return new class { + public get condition(): JContainer { + return t._condition; + } + public withCondition(condition: JContainer): ConditionalType { + return t._condition === condition ? t : new ConditionalType(t._id, t._prefix, t._markers, t._checkType, condition, t._type); + } + } + } + +} + @LstType("org.openrewrite.javascript.tree.JS$DefaultType") export class DefaultType extends JSMixin(Object) implements Expression, TypedTree, NameTree { public constructor(id: UUID, prefix: Space, markers: Markers, left: Expression, beforeEquals: Space, right: Expression, _type: JavaType | null) { @@ -712,6 +802,96 @@ export class Export extends JSMixin(Object) implements Statement { } +@LstType("org.openrewrite.javascript.tree.JS$ExpressionWithTypeArguments") +export class ExpressionWithTypeArguments extends JSMixin(Object) implements TypeTree, Expression { + public constructor(id: UUID, prefix: Space, markers: Markers, clazz: NameTree, typeArguments: JContainer | null, _type: JavaType | null) { + super(); + this._id = id; + this._prefix = prefix; + this._markers = markers; + this._clazz = clazz; + this._typeArguments = typeArguments; + this._type = _type; + } + + private readonly _id: UUID; + + public get id(): UUID { + return this._id; + } + + public withId(id: UUID): ExpressionWithTypeArguments { + return id === this._id ? this : new ExpressionWithTypeArguments(id, this._prefix, this._markers, this._clazz, this._typeArguments, this._type); + } + + private readonly _prefix: Space; + + public get prefix(): Space { + return this._prefix; + } + + public withPrefix(prefix: Space): ExpressionWithTypeArguments { + return prefix === this._prefix ? this : new ExpressionWithTypeArguments(this._id, prefix, this._markers, this._clazz, this._typeArguments, this._type); + } + + private readonly _markers: Markers; + + public get markers(): Markers { + return this._markers; + } + + public withMarkers(markers: Markers): ExpressionWithTypeArguments { + return markers === this._markers ? this : new ExpressionWithTypeArguments(this._id, this._prefix, markers, this._clazz, this._typeArguments, this._type); + } + + private readonly _clazz: NameTree; + + public get clazz(): NameTree { + return this._clazz; + } + + public withClazz(clazz: NameTree): ExpressionWithTypeArguments { + return clazz === this._clazz ? this : new ExpressionWithTypeArguments(this._id, this._prefix, this._markers, clazz, this._typeArguments, this._type); + } + + private readonly _typeArguments: JContainer | null; + + public get typeArguments(): Expression[] | null { + return this._typeArguments === null ? null : this._typeArguments.elements; + } + + public withTypeArguments(typeArguments: Expression[] | null): ExpressionWithTypeArguments { + return this.padding.withTypeArguments(JContainer.withElementsNullable(this._typeArguments, typeArguments)); + } + + private readonly _type: JavaType | null; + + public get type(): JavaType | null { + return this._type; + } + + public withType(_type: JavaType | null): ExpressionWithTypeArguments { + return _type === this._type ? this : new ExpressionWithTypeArguments(this._id, this._prefix, this._markers, this._clazz, this._typeArguments, _type); + } + + public acceptJavaScript

(v: JavaScriptVisitor

, p: P): J | null { + return v.visitExpressionWithTypeArguments(this, p); + } + + get padding() { + const t = this; + return new class { + public get typeArguments(): JContainer | null { + return t._typeArguments; + } + public withTypeArguments(typeArguments: JContainer | null): ExpressionWithTypeArguments { + return t._typeArguments === typeArguments ? t : new ExpressionWithTypeArguments(t._id, t._prefix, t._markers, t._clazz, typeArguments, t._type); + } + } + } + +} + @LstType("org.openrewrite.javascript.tree.JS$FunctionType") export class FunctionType extends JSMixin(Object) implements Expression, TypeTree { public constructor(id: UUID, prefix: Space, markers: Markers, constructorType: JRightPadded, parameters: JContainer, arrow: Space, returnType: Expression, _type: JavaType | null) { @@ -1493,16 +1673,16 @@ export namespace ScopedVariableDeclarations { } -@LstType("org.openrewrite.javascript.tree.JS$TemplateExpression") -export class TemplateExpression extends JSMixin(Object) implements Statement, Expression { - public constructor(id: UUID, prefix: Space, markers: Markers, delimiter: string, tag: JRightPadded | null, strings: J[], _type: JavaType | null) { +@LstType("org.openrewrite.javascript.tree.JS$TaggedTemplateExpression") +export class TaggedTemplateExpression extends JSMixin(Object) implements Statement, Expression { + public constructor(id: UUID, prefix: Space, markers: Markers, tag: JRightPadded | null, typeArguments: JContainer | null, templateExpression: TemplateExpression, _type: JavaType | null) { super(); this._id = id; this._prefix = prefix; this._markers = markers; - this._delimiter = delimiter; this._tag = tag; - this._strings = strings; + this._typeArguments = typeArguments; + this._templateExpression = templateExpression; this._type = _type; } @@ -1512,8 +1692,8 @@ export class TemplateExpression extends JSMixin(Object) implements Statement, Ex return this._id; } - public withId(id: UUID): TemplateExpression { - return id === this._id ? this : new TemplateExpression(id, this._prefix, this._markers, this._delimiter, this._tag, this._strings, this._type); + public withId(id: UUID): TaggedTemplateExpression { + return id === this._id ? this : new TaggedTemplateExpression(id, this._prefix, this._markers, this._tag, this._typeArguments, this._templateExpression, this._type); } private readonly _prefix: Space; @@ -1522,8 +1702,8 @@ export class TemplateExpression extends JSMixin(Object) implements Statement, Ex return this._prefix; } - public withPrefix(prefix: Space): TemplateExpression { - return prefix === this._prefix ? this : new TemplateExpression(this._id, prefix, this._markers, this._delimiter, this._tag, this._strings, this._type); + public withPrefix(prefix: Space): TaggedTemplateExpression { + return prefix === this._prefix ? this : new TaggedTemplateExpression(this._id, prefix, this._markers, this._tag, this._typeArguments, this._templateExpression, this._type); } private readonly _markers: Markers; @@ -1532,38 +1712,38 @@ export class TemplateExpression extends JSMixin(Object) implements Statement, Ex return this._markers; } - public withMarkers(markers: Markers): TemplateExpression { - return markers === this._markers ? this : new TemplateExpression(this._id, this._prefix, markers, this._delimiter, this._tag, this._strings, this._type); + public withMarkers(markers: Markers): TaggedTemplateExpression { + return markers === this._markers ? this : new TaggedTemplateExpression(this._id, this._prefix, markers, this._tag, this._typeArguments, this._templateExpression, this._type); } - private readonly _delimiter: string; + private readonly _tag: JRightPadded | null; - public get delimiter(): string { - return this._delimiter; + public get tag(): Expression | null { + return this._tag === null ? null : this._tag.element; } - public withDelimiter(delimiter: string): TemplateExpression { - return delimiter === this._delimiter ? this : new TemplateExpression(this._id, this._prefix, this._markers, delimiter, this._tag, this._strings, this._type); + public withTag(tag: Expression | null): TaggedTemplateExpression { + return this.padding.withTag(JRightPadded.withElement(this._tag, tag)); } - private readonly _tag: JRightPadded | null; + private readonly _typeArguments: JContainer | null; - public get tag(): Expression | null { - return this._tag === null ? null : this._tag.element; + public get typeArguments(): Expression[] | null { + return this._typeArguments === null ? null : this._typeArguments.elements; } - public withTag(tag: Expression | null): TemplateExpression { - return this.padding.withTag(JRightPadded.withElement(this._tag, tag)); + public withTypeArguments(typeArguments: Expression[] | null): TaggedTemplateExpression { + return this.padding.withTypeArguments(JContainer.withElementsNullable(this._typeArguments, typeArguments)); } - private readonly _strings: J[]; + private readonly _templateExpression: TemplateExpression; - public get strings(): J[] { - return this._strings; + public get templateExpression(): TemplateExpression { + return this._templateExpression; } - public withStrings(strings: J[]): TemplateExpression { - return strings === this._strings ? this : new TemplateExpression(this._id, this._prefix, this._markers, this._delimiter, this._tag, strings, this._type); + public withTemplateExpression(templateExpression: TemplateExpression): TaggedTemplateExpression { + return templateExpression === this._templateExpression ? this : new TaggedTemplateExpression(this._id, this._prefix, this._markers, this._tag, this._typeArguments, templateExpression, this._type); } private readonly _type: JavaType | null; @@ -1572,12 +1752,12 @@ export class TemplateExpression extends JSMixin(Object) implements Statement, Ex return this._type; } - public withType(_type: JavaType | null): TemplateExpression { - return _type === this._type ? this : new TemplateExpression(this._id, this._prefix, this._markers, this._delimiter, this._tag, this._strings, _type); + public withType(_type: JavaType | null): TaggedTemplateExpression { + return _type === this._type ? this : new TaggedTemplateExpression(this._id, this._prefix, this._markers, this._tag, this._typeArguments, this._templateExpression, _type); } public acceptJavaScript

(v: JavaScriptVisitor

, p: P): J | null { - return v.visitTemplateExpression(this, p); + return v.visitTaggedTemplateExpression(this, p); } get padding() { @@ -1586,8 +1766,104 @@ export class TemplateExpression extends JSMixin(Object) implements Statement, Ex public get tag(): JRightPadded | null { return t._tag; } - public withTag(tag: JRightPadded | null): TemplateExpression { - return t._tag === tag ? t : new TemplateExpression(t._id, t._prefix, t._markers, t._delimiter, tag, t._strings, t._type); + public withTag(tag: JRightPadded | null): TaggedTemplateExpression { + return t._tag === tag ? t : new TaggedTemplateExpression(t._id, t._prefix, t._markers, tag, t._typeArguments, t._templateExpression, t._type); + } + public get typeArguments(): JContainer | null { + return t._typeArguments; + } + public withTypeArguments(typeArguments: JContainer | null): TaggedTemplateExpression { + return t._typeArguments === typeArguments ? t : new TaggedTemplateExpression(t._id, t._prefix, t._markers, t._tag, typeArguments, t._templateExpression, t._type); + } + } + } + +} + +@LstType("org.openrewrite.javascript.tree.JS$TemplateExpression") +export class TemplateExpression extends JSMixin(Object) implements Statement, Expression { + public constructor(id: UUID, prefix: Space, markers: Markers, head: Java.Literal, templateSpans: JRightPadded[], _type: JavaType | null) { + super(); + this._id = id; + this._prefix = prefix; + this._markers = markers; + this._head = head; + this._templateSpans = templateSpans; + this._type = _type; + } + + private readonly _id: UUID; + + public get id(): UUID { + return this._id; + } + + public withId(id: UUID): TemplateExpression { + return id === this._id ? this : new TemplateExpression(id, this._prefix, this._markers, this._head, this._templateSpans, this._type); + } + + private readonly _prefix: Space; + + public get prefix(): Space { + return this._prefix; + } + + public withPrefix(prefix: Space): TemplateExpression { + return prefix === this._prefix ? this : new TemplateExpression(this._id, prefix, this._markers, this._head, this._templateSpans, this._type); + } + + private readonly _markers: Markers; + + public get markers(): Markers { + return this._markers; + } + + public withMarkers(markers: Markers): TemplateExpression { + return markers === this._markers ? this : new TemplateExpression(this._id, this._prefix, markers, this._head, this._templateSpans, this._type); + } + + private readonly _head: Java.Literal; + + public get head(): Java.Literal { + return this._head; + } + + public withHead(head: Java.Literal): TemplateExpression { + return head === this._head ? this : new TemplateExpression(this._id, this._prefix, this._markers, head, this._templateSpans, this._type); + } + + private readonly _templateSpans: JRightPadded[]; + + public get templateSpans(): TemplateExpression.TemplateSpan[] { + return JRightPadded.getElements(this._templateSpans); + } + + public withTemplateSpans(templateSpans: TemplateExpression.TemplateSpan[]): TemplateExpression { + return this.padding.withTemplateSpans(JRightPadded.withElements(this._templateSpans, templateSpans)); + } + + private readonly _type: JavaType | null; + + public get type(): JavaType | null { + return this._type; + } + + public withType(_type: JavaType | null): TemplateExpression { + return _type === this._type ? this : new TemplateExpression(this._id, this._prefix, this._markers, this._head, this._templateSpans, _type); + } + + public acceptJavaScript

(v: JavaScriptVisitor

, p: P): J | null { + return v.visitTemplateExpression(this, p); + } + + get padding() { + const t = this; + return new class { + public get templateSpans(): JRightPadded[] { + return t._templateSpans; + } + public withTemplateSpans(templateSpans: JRightPadded[]): TemplateExpression { + return t._templateSpans === templateSpans ? t : new TemplateExpression(t._id, t._prefix, t._markers, t._head, templateSpans, t._type); } } } @@ -1595,16 +1871,15 @@ export class TemplateExpression extends JSMixin(Object) implements Statement, Ex } export namespace TemplateExpression { - @LstType("org.openrewrite.javascript.tree.JS$TemplateExpression$Value") - export class Value extends JSMixin(Object) { - public constructor(id: UUID, prefix: Space, markers: Markers, tree: J, after: Space, enclosedInBraces: boolean) { + @LstType("org.openrewrite.javascript.tree.JS$TemplateExpression$TemplateSpan") + export class TemplateSpan extends JSMixin(Object) { + public constructor(id: UUID, prefix: Space, markers: Markers, expression: J, tail: Java.Literal) { super(); this._id = id; this._prefix = prefix; this._markers = markers; - this._tree = tree; - this._after = after; - this._enclosedInBraces = enclosedInBraces; + this._expression = expression; + this._tail = tail; } private readonly _id: UUID; @@ -1613,8 +1888,8 @@ export namespace TemplateExpression { return this._id; } - public withId(id: UUID): TemplateExpression.Value { - return id === this._id ? this : new TemplateExpression.Value(id, this._prefix, this._markers, this._tree, this._after, this._enclosedInBraces); + public withId(id: UUID): TemplateExpression.TemplateSpan { + return id === this._id ? this : new TemplateExpression.TemplateSpan(id, this._prefix, this._markers, this._expression, this._tail); } private readonly _prefix: Space; @@ -1623,8 +1898,8 @@ export namespace TemplateExpression { return this._prefix; } - public withPrefix(prefix: Space): TemplateExpression.Value { - return prefix === this._prefix ? this : new TemplateExpression.Value(this._id, prefix, this._markers, this._tree, this._after, this._enclosedInBraces); + public withPrefix(prefix: Space): TemplateExpression.TemplateSpan { + return prefix === this._prefix ? this : new TemplateExpression.TemplateSpan(this._id, prefix, this._markers, this._expression, this._tail); } private readonly _markers: Markers; @@ -1633,42 +1908,32 @@ export namespace TemplateExpression { return this._markers; } - public withMarkers(markers: Markers): TemplateExpression.Value { - return markers === this._markers ? this : new TemplateExpression.Value(this._id, this._prefix, markers, this._tree, this._after, this._enclosedInBraces); - } - - private readonly _tree: J; - - public get tree(): J { - return this._tree; - } - - public withTree(tree: J): TemplateExpression.Value { - return tree === this._tree ? this : new TemplateExpression.Value(this._id, this._prefix, this._markers, tree, this._after, this._enclosedInBraces); + public withMarkers(markers: Markers): TemplateExpression.TemplateSpan { + return markers === this._markers ? this : new TemplateExpression.TemplateSpan(this._id, this._prefix, markers, this._expression, this._tail); } - private readonly _after: Space; + private readonly _expression: J; - public get after(): Space { - return this._after; + public get expression(): J { + return this._expression; } - public withAfter(after: Space): TemplateExpression.Value { - return after === this._after ? this : new TemplateExpression.Value(this._id, this._prefix, this._markers, this._tree, after, this._enclosedInBraces); + public withExpression(expression: J): TemplateExpression.TemplateSpan { + return expression === this._expression ? this : new TemplateExpression.TemplateSpan(this._id, this._prefix, this._markers, expression, this._tail); } - private readonly _enclosedInBraces: boolean; + private readonly _tail: Java.Literal; - public get enclosedInBraces(): boolean { - return this._enclosedInBraces; + public get tail(): Java.Literal { + return this._tail; } - public withEnclosedInBraces(enclosedInBraces: boolean): TemplateExpression.Value { - return enclosedInBraces === this._enclosedInBraces ? this : new TemplateExpression.Value(this._id, this._prefix, this._markers, this._tree, this._after, enclosedInBraces); + public withTail(tail: Java.Literal): TemplateExpression.TemplateSpan { + return tail === this._tail ? this : new TemplateExpression.TemplateSpan(this._id, this._prefix, this._markers, this._expression, tail); } public acceptJavaScript

(v: JavaScriptVisitor

, p: P): J | null { - return v.visitTemplateExpressionValue(this, p); + return v.visitTemplateExpressionTemplateSpan(this, p); } } diff --git a/openrewrite/src/javascript/visitor.ts b/openrewrite/src/javascript/visitor.ts index d67c4bb0..32506cd1 100644 --- a/openrewrite/src/javascript/visitor.ts +++ b/openrewrite/src/javascript/visitor.ts @@ -1,7 +1,7 @@ import * as extensions from "./extensions"; import {ListUtils, SourceFile, Tree, TreeVisitor} from "../core"; import {JS, isJavaScript, JsLeftPadded, JsRightPadded, JsContainer, JsSpace} from "./tree"; -import {CompilationUnit, Alias, ArrowFunction, Await, DefaultType, Delete, Export, ExpressionStatement, FunctionType, JsImport, JsImportSpecifier, JsBinary, ObjectBindingDeclarations, PropertyAssignment, ScopedVariableDeclarations, StatementExpression, TemplateExpression, Tuple, TypeDeclaration, TypeOf, TypeQuery, TypeOperator, Unary, Union, Intersection, Void, Yield, TypeInfo, JSVariableDeclarations, JSMethodDeclaration, JSForOfLoop, JSForInLoop, JSForInOfLoopControl, NamespaceDeclaration, FunctionDeclaration, TypeLiteral, IndexSignatureDeclaration, ArrayBindingPattern, BindingElement} from "./tree"; +import {CompilationUnit, Alias, ArrowFunction, Await, ConditionalType, DefaultType, Delete, Export, ExpressionStatement, ExpressionWithTypeArguments, FunctionType, JsImport, JsImportSpecifier, JsBinary, ObjectBindingDeclarations, PropertyAssignment, ScopedVariableDeclarations, StatementExpression, TaggedTemplateExpression, TemplateExpression, Tuple, TypeDeclaration, TypeOf, TypeQuery, TypeOperator, Unary, Union, Intersection, Void, Yield, TypeInfo, JSVariableDeclarations, JSMethodDeclaration, JSForOfLoop, JSForInLoop, JSForInOfLoopControl, NamespaceDeclaration, FunctionDeclaration, TypeLiteral, IndexSignatureDeclaration, ArrayBindingPattern, BindingElement} from "./tree"; import {Expression, J, JContainer, JLeftPadded, JRightPadded, Space, Statement} from "../java/tree"; import {JavaVisitor} from "../java"; import * as Java from "../java/tree"; @@ -72,6 +72,20 @@ export class JavaScriptVisitor

extends JavaVisitor

{ return await; } + public visitConditionalType(conditionalType: ConditionalType, p: P): J | null { + conditionalType = conditionalType.withPrefix(this.visitJsSpace(conditionalType.prefix, JsSpace.Location.CONDITIONAL_TYPE_PREFIX, p)!); + let tempExpression = this.visitExpression(conditionalType, p) as Expression; + if (!(tempExpression instanceof ConditionalType)) + { + return tempExpression; + } + conditionalType = tempExpression as ConditionalType; + conditionalType = conditionalType.withMarkers(this.visitMarkers(conditionalType.markers, p)); + conditionalType = conditionalType.withCheckType(this.visitAndCast(conditionalType.checkType, p)!); + conditionalType = conditionalType.padding.withCondition(this.visitJsContainer(conditionalType.padding.condition, JsContainer.Location.CONDITIONAL_TYPE_CONDITION, p)!); + return conditionalType; + } + public visitDefaultType(defaultType: DefaultType, p: P): J | null { defaultType = defaultType.withPrefix(this.visitJsSpace(defaultType.prefix, JsSpace.Location.DEFAULT_TYPE_PREFIX, p)!); let tempExpression = this.visitExpression(defaultType, p) as Expression; @@ -127,6 +141,20 @@ export class JavaScriptVisitor

extends JavaVisitor

{ return expressionStatement; } + public visitExpressionWithTypeArguments(expressionWithTypeArguments: ExpressionWithTypeArguments, p: P): J | null { + expressionWithTypeArguments = expressionWithTypeArguments.withPrefix(this.visitJsSpace(expressionWithTypeArguments.prefix, JsSpace.Location.EXPRESSION_WITH_TYPE_ARGUMENTS_PREFIX, p)!); + let tempExpression = this.visitExpression(expressionWithTypeArguments, p) as Expression; + if (!(tempExpression instanceof ExpressionWithTypeArguments)) + { + return tempExpression; + } + expressionWithTypeArguments = tempExpression as ExpressionWithTypeArguments; + expressionWithTypeArguments = expressionWithTypeArguments.withMarkers(this.visitMarkers(expressionWithTypeArguments.markers, p)); + expressionWithTypeArguments = expressionWithTypeArguments.withClazz(this.visitAndCast(expressionWithTypeArguments.clazz, p)!); + expressionWithTypeArguments = expressionWithTypeArguments.padding.withTypeArguments(this.visitJsContainer(expressionWithTypeArguments.padding.typeArguments, JsContainer.Location.EXPRESSION_WITH_TYPE_ARGUMENTS_TYPE_ARGUMENTS, p)); + return expressionWithTypeArguments; + } + public visitFunctionType(functionType: FunctionType, p: P): J | null { functionType = functionType.withPrefix(this.visitJsSpace(functionType.prefix, JsSpace.Location.FUNCTION_TYPE_PREFIX, p)!); let tempExpression = this.visitExpression(functionType, p) as Expression; @@ -241,6 +269,27 @@ export class JavaScriptVisitor

extends JavaVisitor

{ return statementExpression; } + public visitTaggedTemplateExpression(taggedTemplateExpression: TaggedTemplateExpression, p: P): J | null { + taggedTemplateExpression = taggedTemplateExpression.withPrefix(this.visitJsSpace(taggedTemplateExpression.prefix, JsSpace.Location.TAGGED_TEMPLATE_EXPRESSION_PREFIX, p)!); + let tempStatement = this.visitStatement(taggedTemplateExpression, p) as Statement; + if (!(tempStatement instanceof TaggedTemplateExpression)) + { + return tempStatement; + } + taggedTemplateExpression = tempStatement as TaggedTemplateExpression; + let tempExpression = this.visitExpression(taggedTemplateExpression, p) as Expression; + if (!(tempExpression instanceof TaggedTemplateExpression)) + { + return tempExpression; + } + taggedTemplateExpression = tempExpression as TaggedTemplateExpression; + taggedTemplateExpression = taggedTemplateExpression.withMarkers(this.visitMarkers(taggedTemplateExpression.markers, p)); + taggedTemplateExpression = taggedTemplateExpression.padding.withTag(this.visitJsRightPadded(taggedTemplateExpression.padding.tag, JsRightPadded.Location.TAGGED_TEMPLATE_EXPRESSION_TAG, p)); + taggedTemplateExpression = taggedTemplateExpression.padding.withTypeArguments(this.visitJsContainer(taggedTemplateExpression.padding.typeArguments, JsContainer.Location.TAGGED_TEMPLATE_EXPRESSION_TYPE_ARGUMENTS, p)); + taggedTemplateExpression = taggedTemplateExpression.withTemplateExpression(this.visitAndCast(taggedTemplateExpression.templateExpression, p)!); + return taggedTemplateExpression; + } + public visitTemplateExpression(templateExpression: TemplateExpression, p: P): J | null { templateExpression = templateExpression.withPrefix(this.visitJsSpace(templateExpression.prefix, JsSpace.Location.TEMPLATE_EXPRESSION_PREFIX, p)!); let tempStatement = this.visitStatement(templateExpression, p) as Statement; @@ -256,17 +305,17 @@ export class JavaScriptVisitor

extends JavaVisitor

{ } templateExpression = tempExpression as TemplateExpression; templateExpression = templateExpression.withMarkers(this.visitMarkers(templateExpression.markers, p)); - templateExpression = templateExpression.padding.withTag(this.visitJsRightPadded(templateExpression.padding.tag, JsRightPadded.Location.TEMPLATE_EXPRESSION_TAG, p)); - templateExpression = templateExpression.withStrings(ListUtils.map(templateExpression.strings, el => this.visitAndCast(el, p))); + templateExpression = templateExpression.withHead(this.visitAndCast(templateExpression.head, p)!); + templateExpression = templateExpression.padding.withTemplateSpans(ListUtils.map(templateExpression.padding.templateSpans, el => this.visitJsRightPadded(el, JsRightPadded.Location.TEMPLATE_EXPRESSION_TEMPLATE_SPANS, p))); return templateExpression; } - public visitTemplateExpressionValue(value: TemplateExpression.Value, p: P): J | null { - value = value.withPrefix(this.visitJsSpace(value.prefix, JsSpace.Location.TEMPLATE_EXPRESSION_VALUE_PREFIX, p)!); - value = value.withMarkers(this.visitMarkers(value.markers, p)); - value = value.withTree(this.visitAndCast(value.tree, p)!); - value = value.withAfter(this.visitJsSpace(value.after, JsSpace.Location.TEMPLATE_EXPRESSION_VALUE_AFTER, p)!); - return value; + public visitTemplateExpressionTemplateSpan(templateSpan: TemplateExpression.TemplateSpan, p: P): J | null { + templateSpan = templateSpan.withPrefix(this.visitJsSpace(templateSpan.prefix, JsSpace.Location.TEMPLATE_EXPRESSION_TEMPLATE_SPAN_PREFIX, p)!); + templateSpan = templateSpan.withMarkers(this.visitMarkers(templateSpan.markers, p)); + templateSpan = templateSpan.withExpression(this.visitAndCast(templateSpan.expression, p)!); + templateSpan = templateSpan.withTail(this.visitAndCast(templateSpan.tail, p)!); + return templateSpan; } public visitTuple(tuple: Tuple, p: P): J | null { diff --git a/openrewrite/test/javascript/parser/call.test.ts b/openrewrite/test/javascript/parser/call.test.ts index daf1cae7..1bfe37e8 100644 --- a/openrewrite/test/javascript/parser/call.test.ts +++ b/openrewrite/test/javascript/parser/call.test.ts @@ -46,7 +46,6 @@ describe('call mapping', () => { const func = (message: string) => message; const result1 = func/*a*/?./*b*/("TS"); // Invokes the function const result2 = func/*a*/?./*b*/call("TS"); // Invokes the function - `) ); }); diff --git a/openrewrite/test/javascript/parser/for.test.ts b/openrewrite/test/javascript/parser/for.test.ts index 4ff75742..8136ee98 100644 --- a/openrewrite/test/javascript/parser/for.test.ts +++ b/openrewrite/test/javascript/parser/for.test.ts @@ -143,7 +143,7 @@ describe('for mapping', () => { ); }); - test.skip('for-in with keyof typeof TypeOperator', () => { + test('for-in with keyof typeof TypeOperator', () => { rewriteRun( //language=typescript typeScript(` diff --git a/openrewrite/test/javascript/parser/templateExpression.test.ts b/openrewrite/test/javascript/parser/templateExpression.test.ts new file mode 100644 index 00000000..b0ce4632 --- /dev/null +++ b/openrewrite/test/javascript/parser/templateExpression.test.ts @@ -0,0 +1,162 @@ +import {connect, disconnect, rewriteRun, typeScript} from '../testHarness'; + +describe('template expression mapping', () => { + beforeAll(() => connect()); + afterAll(() => disconnect()); + + + test('simple template', () => { + rewriteRun( + //language=typescript + typeScript(` + const v = \`\${42}\`; + `) + ); + }); + + test('simple template with comments', () => { + rewriteRun( + //language=typescript + typeScript(` + const v = /*a*/\`\/*b*/${/*c*/42/*d*/}/*e*/\`; + `) + ); + }); + + test('simple template with text', () => { + rewriteRun( + //language=typescript + typeScript(` + const a = 5; + const sum = \`The value of \${a}.\`; + `) + ); + }); + + test('simple template with expression', () => { + rewriteRun( + //language=typescript + typeScript(` + const a = 5; + const b = 10; + const sum = \`The sum of \${/*a*/a /*b*/} and \${/*c*/b/*d*/} is \${a /*e*/ + /*f*/b /*g*/}. \`; + `) + ); + }); + + test('simple template with ternary', () => { + rewriteRun( + //language=typescript + typeScript(` + const isAdmin = true; + const roleMessage = \`User is \${ isAdmin ? "an Admin" : "a Guest" }.\`; + `) + ); + }); + + test('simple template with function', () => { + rewriteRun( + //language=typescript + typeScript(` + function greet(name: string): string { + return \`Hello, \${name}\`; + } + + const username = "Alice"; + const message = \`The greeting is: \${greet(username)}\`; + `) + ); + }); + + test('template tag', () => { + rewriteRun( + //language=typescript + typeScript(` + function tag(strings: TemplateStringsArray, ...values: any[]) { + return strings.reduce((result, str, i) => \`\${result}\${str}\${values[i] || ""}\`, ""); + } + + const name = "Alice"; + const age = 25; + const result = tag\`My name is \${name} and I am \${age} years old.\`; + `) + ); + }); + + test('template tag with comments', () => { + rewriteRun( + //language=typescript + typeScript(` + const result = /*a*/tag/*b*/\` My name is \${name} and I am \${age} years old.\`; + `) + ); + }); + + test('template tag with type arguments', () => { + rewriteRun( + //language=typescript + typeScript(` + function genericTag( + strings: TemplateStringsArray, + ...values: T[] + ): string { + return strings.reduce((result, str, i) => \`\${result}\${str}\${values[i] || ""}\`, ""); + } + + // Using generic types + const result = genericTag\`The sum is \${42}\`; + `) + ); + }); + + test('template tag with type arguments and comments', () => { + rewriteRun( + //language=typescript + typeScript(` + const result = /*a*/genericTag/*b*//*e*/\`The sum is \${42}\`; + `) + ); + }); + + test('template LiteralType ', () => { + rewriteRun( + //language=typescript + typeScript(` + type Name = "Alice"; + type Greeting = \`Hello, \${Name}!\`; + `) + ); + }); + + test('template LiteralType union', () => { + rewriteRun( + //language=typescript + typeScript(` + type Action = "create" | "update"; + type Entity = "user" | "post"; + type APIEndpoint = \`\${Action}_\${Entity}\`; + + const endpoint: APIEndpoint = "create_user"; + `) + ); + }); + + test('template LiteralType with conditional', () => { + rewriteRun( + //language=typescript + typeScript(` + type Role = "admin" | "editor" | "viewer"; + type Permissions = RoleType extends "admin" + ? \`can_manage_\${string}\` + : \`can_read_\${string}\`; + + // Valid permissions: + const adminPermission: Permissions<"admin"> = "can_manage_users"; + const viewerPermission: Permissions<"viewer"> = "can_read_posts"; + + // Invalid permission: + const invalidPermission: Permissions<"editor"> = "can_delete_posts"; // Error + `) + ); + }); +}); diff --git a/openrewrite/test/javascript/parser/typeAlias.test.ts b/openrewrite/test/javascript/parser/typeAlias.test.ts index 574a1643..d7b33ec5 100644 --- a/openrewrite/test/javascript/parser/typeAlias.test.ts +++ b/openrewrite/test/javascript/parser/typeAlias.test.ts @@ -175,16 +175,25 @@ describe('type alias mapping', () => { ); }); - test.skip('basic conditional type', () => { + test('basic conditional type', () => { rewriteRun( //language=typescript typeScript(` - type IsString = T extends string ? "Yes" : "No"; + type IsString = T extends string ? 'Yes' : 'No'; `) ); }); - test.skip('conditional type', () => { + test('basic conditional type with comments', () => { + rewriteRun( + //language=typescript + typeScript(` + type IsString = /*a*/T/*b*/ extends /*c*/string /*d*/? /*e*/'Yes' /*f*/:/*g*/ 'No'/*h*/; + `) + ); + }); + + test.skip('conditional type with parenthesized type', () => { rewriteRun( //language=typescript 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 6b4299b5..1e3fe0a4 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 @@ -125,6 +125,17 @@ public JS.Await visitAwait(JS.Await await, ReceiverContext ctx) { return await; } + @Override + public JS.ConditionalType visitConditionalType(JS.ConditionalType conditionalType, ReceiverContext ctx) { + conditionalType = conditionalType.withId(ctx.receiveNonNullValue(conditionalType.getId(), UUID.class)); + conditionalType = conditionalType.withPrefix(ctx.receiveNonNullNode(conditionalType.getPrefix(), JavaScriptReceiver::receiveSpace)); + conditionalType = conditionalType.withMarkers(ctx.receiveNonNullNode(conditionalType.getMarkers(), ctx::receiveMarkers)); + conditionalType = conditionalType.withCheckType(ctx.receiveNonNullNode(conditionalType.getCheckType(), ctx::receiveTree)); + conditionalType = conditionalType.getPadding().withCondition(ctx.receiveNonNullNode(conditionalType.getPadding().getCondition(), JavaScriptReceiver::receiveContainer)); + conditionalType = conditionalType.withType(ctx.receiveValue(conditionalType.getType(), JavaType.class)); + return conditionalType; + } + @Override public JS.DefaultType visitDefaultType(JS.DefaultType defaultType, ReceiverContext ctx) { defaultType = defaultType.withId(ctx.receiveNonNullValue(defaultType.getId(), UUID.class)); @@ -166,6 +177,17 @@ public JS.ExpressionStatement visitExpressionStatement(JS.ExpressionStatement ex return expressionStatement; } + @Override + public JS.ExpressionWithTypeArguments visitExpressionWithTypeArguments(JS.ExpressionWithTypeArguments expressionWithTypeArguments, ReceiverContext ctx) { + expressionWithTypeArguments = expressionWithTypeArguments.withId(ctx.receiveNonNullValue(expressionWithTypeArguments.getId(), UUID.class)); + expressionWithTypeArguments = expressionWithTypeArguments.withPrefix(ctx.receiveNonNullNode(expressionWithTypeArguments.getPrefix(), JavaScriptReceiver::receiveSpace)); + expressionWithTypeArguments = expressionWithTypeArguments.withMarkers(ctx.receiveNonNullNode(expressionWithTypeArguments.getMarkers(), ctx::receiveMarkers)); + expressionWithTypeArguments = expressionWithTypeArguments.withClazz(ctx.receiveNonNullNode(expressionWithTypeArguments.getClazz(), ctx::receiveTree)); + expressionWithTypeArguments = expressionWithTypeArguments.getPadding().withTypeArguments(ctx.receiveNode(expressionWithTypeArguments.getPadding().getTypeArguments(), JavaScriptReceiver::receiveContainer)); + expressionWithTypeArguments = expressionWithTypeArguments.withType(ctx.receiveValue(expressionWithTypeArguments.getType(), JavaType.class)); + return expressionWithTypeArguments; + } + @Override public JS.FunctionType visitFunctionType(JS.FunctionType functionType, ReceiverContext ctx) { functionType = functionType.withId(ctx.receiveNonNullValue(functionType.getId(), UUID.class)); @@ -257,27 +279,37 @@ public JS.StatementExpression visitStatementExpression(JS.StatementExpression st return statementExpression; } + @Override + public JS.TaggedTemplateExpression visitTaggedTemplateExpression(JS.TaggedTemplateExpression taggedTemplateExpression, ReceiverContext ctx) { + taggedTemplateExpression = taggedTemplateExpression.withId(ctx.receiveNonNullValue(taggedTemplateExpression.getId(), UUID.class)); + taggedTemplateExpression = taggedTemplateExpression.withPrefix(ctx.receiveNonNullNode(taggedTemplateExpression.getPrefix(), JavaScriptReceiver::receiveSpace)); + taggedTemplateExpression = taggedTemplateExpression.withMarkers(ctx.receiveNonNullNode(taggedTemplateExpression.getMarkers(), ctx::receiveMarkers)); + taggedTemplateExpression = taggedTemplateExpression.getPadding().withTag(ctx.receiveNode(taggedTemplateExpression.getPadding().getTag(), JavaScriptReceiver::receiveRightPaddedTree)); + taggedTemplateExpression = taggedTemplateExpression.getPadding().withTypeArguments(ctx.receiveNode(taggedTemplateExpression.getPadding().getTypeArguments(), JavaScriptReceiver::receiveContainer)); + taggedTemplateExpression = taggedTemplateExpression.withTemplateExpression(ctx.receiveNonNullNode(taggedTemplateExpression.getTemplateExpression(), ctx::receiveTree)); + taggedTemplateExpression = taggedTemplateExpression.withType(ctx.receiveValue(taggedTemplateExpression.getType(), JavaType.class)); + return taggedTemplateExpression; + } + @Override public JS.TemplateExpression visitTemplateExpression(JS.TemplateExpression templateExpression, ReceiverContext ctx) { templateExpression = templateExpression.withId(ctx.receiveNonNullValue(templateExpression.getId(), UUID.class)); templateExpression = templateExpression.withPrefix(ctx.receiveNonNullNode(templateExpression.getPrefix(), JavaScriptReceiver::receiveSpace)); templateExpression = templateExpression.withMarkers(ctx.receiveNonNullNode(templateExpression.getMarkers(), ctx::receiveMarkers)); - templateExpression = templateExpression.withDelimiter(ctx.receiveNonNullValue(templateExpression.getDelimiter(), String.class)); - templateExpression = templateExpression.getPadding().withTag(ctx.receiveNode(templateExpression.getPadding().getTag(), JavaScriptReceiver::receiveRightPaddedTree)); - templateExpression = templateExpression.withStrings(ctx.receiveNonNullNodes(templateExpression.getStrings(), ctx::receiveTree)); + templateExpression = templateExpression.withHead(ctx.receiveNonNullNode(templateExpression.getHead(), ctx::receiveTree)); + templateExpression = templateExpression.getPadding().withTemplateSpans(ctx.receiveNonNullNodes(templateExpression.getPadding().getTemplateSpans(), JavaScriptReceiver::receiveRightPaddedTree)); templateExpression = templateExpression.withType(ctx.receiveValue(templateExpression.getType(), JavaType.class)); return templateExpression; } @Override - public JS.TemplateExpression.Value visitTemplateExpressionValue(JS.TemplateExpression.Value value, ReceiverContext ctx) { - value = value.withId(ctx.receiveNonNullValue(value.getId(), UUID.class)); - value = value.withPrefix(ctx.receiveNonNullNode(value.getPrefix(), JavaScriptReceiver::receiveSpace)); - value = value.withMarkers(ctx.receiveNonNullNode(value.getMarkers(), ctx::receiveMarkers)); - value = value.withTree(ctx.receiveNonNullNode(value.getTree(), ctx::receiveTree)); - value = value.withAfter(ctx.receiveNonNullNode(value.getAfter(), JavaScriptReceiver::receiveSpace)); - value = value.withEnclosedInBraces(ctx.receiveNonNullValue(value.isEnclosedInBraces(), boolean.class)); - return value; + public JS.TemplateExpression.TemplateSpan visitTemplateExpressionTemplateSpan(JS.TemplateExpression.TemplateSpan templateSpan, ReceiverContext ctx) { + templateSpan = templateSpan.withId(ctx.receiveNonNullValue(templateSpan.getId(), UUID.class)); + templateSpan = templateSpan.withPrefix(ctx.receiveNonNullNode(templateSpan.getPrefix(), JavaScriptReceiver::receiveSpace)); + templateSpan = templateSpan.withMarkers(ctx.receiveNonNullNode(templateSpan.getMarkers(), ctx::receiveMarkers)); + templateSpan = templateSpan.withExpression(ctx.receiveNonNullNode(templateSpan.getExpression(), ctx::receiveTree)); + templateSpan = templateSpan.withTail(ctx.receiveNonNullNode(templateSpan.getTail(), ctx::receiveTree)); + return templateSpan; } @Override @@ -1290,6 +1322,17 @@ public T create(Class type, ReceiverContext ctx) { ); } + if (type == JS.ConditionalType.class) { + return (T) new JS.ConditionalType( + ctx.receiveNonNullValue(null, UUID.class), + ctx.receiveNonNullNode(null, JavaScriptReceiver::receiveSpace), + ctx.receiveNonNullNode(null, ctx::receiveMarkers), + ctx.receiveNonNullNode(null, ctx::receiveTree), + ctx.receiveNonNullNode(null, JavaScriptReceiver::receiveContainer), + ctx.receiveValue(null, JavaType.class) + ); + } + if (type == JS.DefaultType.class) { return (T) new JS.DefaultType( ctx.receiveNonNullValue(null, UUID.class), @@ -1331,6 +1374,17 @@ public T create(Class type, ReceiverContext ctx) { ); } + if (type == JS.ExpressionWithTypeArguments.class) { + return (T) new JS.ExpressionWithTypeArguments( + ctx.receiveNonNullValue(null, UUID.class), + ctx.receiveNonNullNode(null, JavaScriptReceiver::receiveSpace), + ctx.receiveNonNullNode(null, ctx::receiveMarkers), + ctx.receiveNonNullNode(null, ctx::receiveTree), + ctx.receiveNode(null, JavaScriptReceiver::receiveContainer), + ctx.receiveValue(null, JavaType.class) + ); + } + if (type == JS.FunctionType.class) { return (T) new JS.FunctionType( ctx.receiveNonNullValue(null, UUID.class), @@ -1422,26 +1476,36 @@ public T create(Class type, ReceiverContext ctx) { ); } - if (type == JS.TemplateExpression.class) { - return (T) new JS.TemplateExpression( + if (type == JS.TaggedTemplateExpression.class) { + return (T) new JS.TaggedTemplateExpression( ctx.receiveNonNullValue(null, UUID.class), ctx.receiveNonNullNode(null, JavaScriptReceiver::receiveSpace), ctx.receiveNonNullNode(null, ctx::receiveMarkers), - ctx.receiveNonNullValue(null, String.class), ctx.receiveNode(null, JavaScriptReceiver::receiveRightPaddedTree), - ctx.receiveNonNullNodes(null, ctx::receiveTree), + ctx.receiveNode(null, JavaScriptReceiver::receiveContainer), + ctx.receiveNonNullNode(null, ctx::receiveTree), ctx.receiveValue(null, JavaType.class) ); } - if (type == JS.TemplateExpression.Value.class) { - return (T) new JS.TemplateExpression.Value( + if (type == JS.TemplateExpression.class) { + return (T) new JS.TemplateExpression( ctx.receiveNonNullValue(null, UUID.class), ctx.receiveNonNullNode(null, JavaScriptReceiver::receiveSpace), ctx.receiveNonNullNode(null, ctx::receiveMarkers), ctx.receiveNonNullNode(null, ctx::receiveTree), + ctx.receiveNonNullNodes(null, JavaScriptReceiver::receiveRightPaddedTree), + ctx.receiveValue(null, JavaType.class) + ); + } + + if (type == JS.TemplateExpression.TemplateSpan.class) { + return (T) new JS.TemplateExpression.TemplateSpan( + ctx.receiveNonNullValue(null, UUID.class), ctx.receiveNonNullNode(null, JavaScriptReceiver::receiveSpace), - ctx.receiveNonNullValue(null, boolean.class) + ctx.receiveNonNullNode(null, ctx::receiveMarkers), + ctx.receiveNonNullNode(null, ctx::receiveTree), + ctx.receiveNonNullNode(null, ctx::receiveTree) ); } 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 25fd7a8f..c3ec7dbe 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 @@ -108,6 +108,17 @@ public JS.Await visitAwait(JS.Await await, SenderContext ctx) { return await; } + @Override + public JS.ConditionalType visitConditionalType(JS.ConditionalType conditionalType, SenderContext ctx) { + ctx.sendValue(conditionalType, JS.ConditionalType::getId); + ctx.sendNode(conditionalType, JS.ConditionalType::getPrefix, JavaScriptSender::sendSpace); + ctx.sendNode(conditionalType, JS.ConditionalType::getMarkers, ctx::sendMarkers); + ctx.sendNode(conditionalType, JS.ConditionalType::getCheckType, ctx::sendTree); + ctx.sendNode(conditionalType, e -> e.getPadding().getCondition(), JavaScriptSender::sendContainer); + ctx.sendTypedValue(conditionalType, JS.ConditionalType::getType); + return conditionalType; + } + @Override public JS.DefaultType visitDefaultType(JS.DefaultType defaultType, SenderContext ctx) { ctx.sendValue(defaultType, JS.DefaultType::getId); @@ -149,6 +160,17 @@ public JS.ExpressionStatement visitExpressionStatement(JS.ExpressionStatement ex return expressionStatement; } + @Override + public JS.ExpressionWithTypeArguments visitExpressionWithTypeArguments(JS.ExpressionWithTypeArguments expressionWithTypeArguments, SenderContext ctx) { + ctx.sendValue(expressionWithTypeArguments, JS.ExpressionWithTypeArguments::getId); + ctx.sendNode(expressionWithTypeArguments, JS.ExpressionWithTypeArguments::getPrefix, JavaScriptSender::sendSpace); + ctx.sendNode(expressionWithTypeArguments, JS.ExpressionWithTypeArguments::getMarkers, ctx::sendMarkers); + ctx.sendNode(expressionWithTypeArguments, JS.ExpressionWithTypeArguments::getClazz, ctx::sendTree); + ctx.sendNode(expressionWithTypeArguments, e -> e.getPadding().getTypeArguments(), JavaScriptSender::sendContainer); + ctx.sendTypedValue(expressionWithTypeArguments, JS.ExpressionWithTypeArguments::getType); + return expressionWithTypeArguments; + } + @Override public JS.FunctionType visitFunctionType(JS.FunctionType functionType, SenderContext ctx) { ctx.sendValue(functionType, JS.FunctionType::getId); @@ -240,27 +262,37 @@ public JS.StatementExpression visitStatementExpression(JS.StatementExpression st return statementExpression; } + @Override + public JS.TaggedTemplateExpression visitTaggedTemplateExpression(JS.TaggedTemplateExpression taggedTemplateExpression, SenderContext ctx) { + ctx.sendValue(taggedTemplateExpression, JS.TaggedTemplateExpression::getId); + ctx.sendNode(taggedTemplateExpression, JS.TaggedTemplateExpression::getPrefix, JavaScriptSender::sendSpace); + ctx.sendNode(taggedTemplateExpression, JS.TaggedTemplateExpression::getMarkers, ctx::sendMarkers); + ctx.sendNode(taggedTemplateExpression, e -> e.getPadding().getTag(), JavaScriptSender::sendRightPadded); + ctx.sendNode(taggedTemplateExpression, e -> e.getPadding().getTypeArguments(), JavaScriptSender::sendContainer); + ctx.sendNode(taggedTemplateExpression, JS.TaggedTemplateExpression::getTemplateExpression, ctx::sendTree); + ctx.sendTypedValue(taggedTemplateExpression, JS.TaggedTemplateExpression::getType); + return taggedTemplateExpression; + } + @Override public JS.TemplateExpression visitTemplateExpression(JS.TemplateExpression templateExpression, SenderContext ctx) { ctx.sendValue(templateExpression, JS.TemplateExpression::getId); ctx.sendNode(templateExpression, JS.TemplateExpression::getPrefix, JavaScriptSender::sendSpace); ctx.sendNode(templateExpression, JS.TemplateExpression::getMarkers, ctx::sendMarkers); - ctx.sendValue(templateExpression, JS.TemplateExpression::getDelimiter); - ctx.sendNode(templateExpression, e -> e.getPadding().getTag(), JavaScriptSender::sendRightPadded); - ctx.sendNodes(templateExpression, JS.TemplateExpression::getStrings, ctx::sendTree, Tree::getId); + ctx.sendNode(templateExpression, JS.TemplateExpression::getHead, ctx::sendTree); + ctx.sendNodes(templateExpression, e -> e.getPadding().getTemplateSpans(), JavaScriptSender::sendRightPadded, e -> e.getElement().getId()); ctx.sendTypedValue(templateExpression, JS.TemplateExpression::getType); return templateExpression; } @Override - public JS.TemplateExpression.Value visitTemplateExpressionValue(JS.TemplateExpression.Value value, SenderContext ctx) { - ctx.sendValue(value, JS.TemplateExpression.Value::getId); - ctx.sendNode(value, JS.TemplateExpression.Value::getPrefix, JavaScriptSender::sendSpace); - ctx.sendNode(value, JS.TemplateExpression.Value::getMarkers, ctx::sendMarkers); - ctx.sendNode(value, JS.TemplateExpression.Value::getTree, ctx::sendTree); - ctx.sendNode(value, JS.TemplateExpression.Value::getAfter, JavaScriptSender::sendSpace); - ctx.sendValue(value, JS.TemplateExpression.Value::isEnclosedInBraces); - return value; + public JS.TemplateExpression.TemplateSpan visitTemplateExpressionTemplateSpan(JS.TemplateExpression.TemplateSpan templateSpan, SenderContext ctx) { + ctx.sendValue(templateSpan, JS.TemplateExpression.TemplateSpan::getId); + ctx.sendNode(templateSpan, JS.TemplateExpression.TemplateSpan::getPrefix, JavaScriptSender::sendSpace); + ctx.sendNode(templateSpan, JS.TemplateExpression.TemplateSpan::getMarkers, ctx::sendMarkers); + ctx.sendNode(templateSpan, JS.TemplateExpression.TemplateSpan::getExpression, ctx::sendTree); + ctx.sendNode(templateSpan, JS.TemplateExpression.TemplateSpan::getTail, ctx::sendTree); + return templateSpan; } @Override 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 feefcb15..cb5d3540 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 @@ -79,6 +79,13 @@ public JS.Await visitAwait(JS.Await await, P p) { return await; } + @Override + public JS.ConditionalType visitConditionalType(JS.ConditionalType conditionalType, P p) { + visitAndValidate(conditionalType.getCheckType(), Expression.class, p); + visitAndValidate(conditionalType.getCondition(), TypedTree.class, p); + return conditionalType; + } + @Override public JS.DefaultType visitDefaultType(JS.DefaultType defaultType, P p) { visitAndValidate(defaultType.getLeft(), Expression.class, p); @@ -106,6 +113,13 @@ public JS.ExpressionStatement visitExpressionStatement(JS.ExpressionStatement ex return expressionStatement; } + @Override + public JS.ExpressionWithTypeArguments visitExpressionWithTypeArguments(JS.ExpressionWithTypeArguments expressionWithTypeArguments, P p) { + visitAndValidate(expressionWithTypeArguments.getClazz(), NameTree.class, p); + visitAndValidate(expressionWithTypeArguments.getTypeArguments(), Expression.class, p); + return expressionWithTypeArguments; + } + @Override public JS.FunctionType visitFunctionType(JS.FunctionType functionType, P p) { visitAndValidate(functionType.getParameters(), Statement.class, p); @@ -165,17 +179,26 @@ public JS.StatementExpression visitStatementExpression(JS.StatementExpression st return statementExpression; } + @Override + public JS.TaggedTemplateExpression visitTaggedTemplateExpression(JS.TaggedTemplateExpression taggedTemplateExpression, P p) { + visitAndValidate(taggedTemplateExpression.getTag(), Expression.class, p); + visitAndValidate(taggedTemplateExpression.getTypeArguments(), Expression.class, p); + visitAndValidate(taggedTemplateExpression.getTemplateExpression(), JS.TemplateExpression.class, p); + return taggedTemplateExpression; + } + @Override public JS.TemplateExpression visitTemplateExpression(JS.TemplateExpression templateExpression, P p) { - visitAndValidate(templateExpression.getTag(), Expression.class, p); - ListUtils.map(templateExpression.getStrings(), el -> visitAndValidate(el, J.class, p)); + visitAndValidate(templateExpression.getHead(), J.Literal.class, p); + ListUtils.map(templateExpression.getTemplateSpans(), el -> visitAndValidate(el, JS.TemplateExpression.TemplateSpan.class, p)); return templateExpression; } @Override - public JS.TemplateExpression.Value visitTemplateExpressionValue(JS.TemplateExpression.Value value, P p) { - visitAndValidate(value.getTree(), J.class, p); - return value; + public JS.TemplateExpression.TemplateSpan visitTemplateExpressionTemplateSpan(JS.TemplateExpression.TemplateSpan templateSpan, P p) { + visitAndValidate(templateSpan.getExpression(), J.class, p); + visitAndValidate(templateSpan.getTail(), J.Literal.class, p); + return templateSpan; } @Override diff --git a/rewrite-javascript/src/main/java/org/openrewrite/javascript/JavaScriptIsoVisitor.java b/rewrite-javascript/src/main/java/org/openrewrite/javascript/JavaScriptIsoVisitor.java index 7571b1f0..f77e70a6 100644 --- a/rewrite-javascript/src/main/java/org/openrewrite/javascript/JavaScriptIsoVisitor.java +++ b/rewrite-javascript/src/main/java/org/openrewrite/javascript/JavaScriptIsoVisitor.java @@ -109,8 +109,8 @@ public JS.TemplateExpression visitTemplateExpression(JS.TemplateExpression templ } @Override - public JS.TemplateExpression.Value visitTemplateExpressionValue(JS.TemplateExpression.Value value, P p) { - return (JS.TemplateExpression.Value) super.visitTemplateExpressionValue(value, p); + public JS.TemplateExpression.TemplateSpan visitTemplateExpressionTemplateSpan(JS.TemplateExpression.TemplateSpan value, P p) { + return (JS.TemplateExpression.TemplateSpan) super.visitTemplateExpressionTemplateSpan(value, p); } @Override 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 21010e71..067a0cd6 100644 --- a/rewrite-javascript/src/main/java/org/openrewrite/javascript/JavaScriptVisitor.java +++ b/rewrite-javascript/src/main/java/org/openrewrite/javascript/JavaScriptVisitor.java @@ -138,6 +138,19 @@ public J visitBindingElement(JS.BindingElement binding, P p) { return b; } + public J visitConditionalType(JS.ConditionalType conditionalType, P p) { + JS.ConditionalType t = conditionalType; + t = t.withPrefix(visitSpace(t.getPrefix(), JsSpace.Location.CONDITIONAL_TYPE_PREFIX, p)); + t = t.withMarkers(visitMarkers(t.getMarkers(), p)); + t = t.withCheckType(visitAndCast(t.getCheckType(), p)); + if (t.getCheckType() instanceof NameTree) { + t = t.withCheckType((Expression) visitTypeName((NameTree) t.getCheckType(), p)); + } + t = t.getPadding().withCondition(visitContainer(t.getPadding().getCondition(), JsContainer.Location.CONDITIONAL_TYPE_CONDITION, p)); + t = t.withType(visitType(t.getType(), p)); + return t; + } + public J visitDefaultType(JS.DefaultType defaultType, P p) { JS.DefaultType d = defaultType; d = d.withPrefix(visitSpace(d.getPrefix(), Space.Location.ASSIGNMENT_PREFIX, p)); @@ -210,6 +223,25 @@ public J visitExpressionStatement(JS.ExpressionStatement statement, P p) { return es; } + public J visitExpressionWithTypeArguments(JS.ExpressionWithTypeArguments expressionWithTypeArguments, P p) { + JS.ExpressionWithTypeArguments ta = expressionWithTypeArguments; + ta = ta.withPrefix(visitSpace(ta.getPrefix(), JsSpace.Location.EXPR_WITH_TYPE_ARG_PREFIX, p)); + ta = ta.withMarkers(visitMarkers(ta.getMarkers(), p)); + Expression temp = (Expression) visitExpression(ta, p); + if (!(temp instanceof JS.ExpressionWithTypeArguments)) { + return temp; + } else { + ta = (JS.ExpressionWithTypeArguments) temp; + } + ta = ta.withClazz(visitAndCast(ta.getClazz(), p)); + if (ta.getPadding().getTypeArguments() != null) { + ta = ta.getPadding().withTypeArguments(visitContainer(ta.getPadding().getTypeArguments(), JsContainer.Location.EXPR_WITH_TYPE_ARG_PARAMETERS, p)); + } + ta = ta.getPadding().withTypeArguments(visitTypeNames(ta.getPadding().getTypeArguments(), p)); + ta = ta.withType(visitType(ta.getType(), p)); + return ta; + } + public J visitFunctionType(JS.FunctionType functionType, P p) { JS.FunctionType f = functionType; f = f.withPrefix(visitSpace(f.getPrefix(), JsSpace.Location.FUNCTION_TYPE_PREFIX, p)); @@ -362,28 +394,47 @@ public J visitStatementExpression(JS.StatementExpression expression, P p) { return se; } + public J visitTaggedTemplateExpression (JS.TaggedTemplateExpression taggedTemplateExpression, P p) { + JS.TaggedTemplateExpression ta = taggedTemplateExpression; + ta = ta.withPrefix(visitSpace(ta.getPrefix(), JsSpace.Location.TAGGED_TEMPLATE_EXPRESSION_PREFIX, p)); + ta = ta.withMarkers(visitMarkers(ta.getMarkers(), p)); + Expression temp = (Expression) visitExpression(ta, p); + if (!(temp instanceof JS.TaggedTemplateExpression)) { + return temp; + } else { + ta = (JS.TaggedTemplateExpression) temp; + } + ta = ta.getPadding().withTag(visitRightPadded(ta.getPadding().getTag(), JsRightPadded.Location.TEMPLATE_EXPRESSION_TAG, p)); + if (ta.getPadding().getTypeArguments() != null) { + ta = ta.getPadding().withTypeArguments(visitContainer(ta.getPadding().getTypeArguments(), JsContainer.Location.TEMPLATE_EXPRESSION_TYPE_ARG_PARAMETERS, p)); + } + ta = ta.withTemplateExpression(visitAndCast(ta.getTemplateExpression(), p)); + return ta; + } + public J visitTemplateExpression(JS.TemplateExpression templateExpression, P p) { - JS.TemplateExpression s = templateExpression; - s = s.withPrefix(visitSpace(s.getPrefix(), JsSpace.Location.TEMPLATE_EXPRESSION_PREFIX, p)); - s = s.withMarkers(visitMarkers(s.getMarkers(), p)); - Expression temp = (Expression) visitExpression(s, p); + JS.TemplateExpression te = templateExpression; + te = te.withPrefix(visitSpace(te.getPrefix(), JsSpace.Location.TEMPLATE_EXPRESSION_PREFIX, p)); + te = te.withMarkers(visitMarkers(te.getMarkers(), p)); + Expression temp = (Expression) visitExpression(te, p); if (!(temp instanceof JS.TemplateExpression)) { return temp; } else { - s = (JS.TemplateExpression) temp; + te = (JS.TemplateExpression) temp; } - s = s.getPadding().withTag(visitRightPadded(s.getPadding().getTag(), JsRightPadded.Location.ALIAS_PROPERTY_NAME, p)); - s = s.withStrings(ListUtils.map(s.getStrings(), e -> visitAndCast(e, p))); - s = s.withType(visitType(s.getType(), p)); - return s; + te = te.withHead(visitAndCast(te.getHead(), p)); + te = te.getPadding().withTemplateSpans(ListUtils.map(te.getPadding().getTemplateSpans(), (t) -> this.visitRightPadded(t, JsRightPadded.Location.TEMPLATE_EXPRESSION_TEMPLATE_SPAN, p))); + te = te.withType(visitType(te.getType(), p)); + return te; } - public J visitTemplateExpressionValue(JS.TemplateExpression.Value value, P p) { - JS.TemplateExpression.Value s = value; - s = s.withPrefix(visitSpace(s.getPrefix(), JsSpace.Location.TEMPLATE_EXPRESSION_VALUE_PREFIX, p)); + public J visitTemplateExpressionTemplateSpan(JS.TemplateExpression.TemplateSpan span, P p) { + JS.TemplateExpression.TemplateSpan s = span; + s = s.withPrefix(visitSpace(s.getPrefix(), JsSpace.Location.TEMPLATE_EXPRESSION_SPAN_PREFIX, p)); s = s.withMarkers(visitMarkers(s.getMarkers(), p)); - s = s.withTree(visit(s.getTree(), p)); - s = s.withAfter(visitSpace(s.getAfter(), JsSpace.Location.TEMPLATE_EXPRESSION_VALUE_SUFFIX, p)); + s = s.withExpression(visitAndCast(s.getExpression(), p)); + s = s.withTail(visitAndCast(s.getTail(), p)); + s = s.withTail(s.getTail()); return s; } 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 1bf94615..302d2d04 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 @@ -131,6 +131,15 @@ public J visitBindingElement(JS.BindingElement binding, PrintOutputCapture

p) return binding; } + @Override + public J visitConditionalType(JS.ConditionalType conditionalType, PrintOutputCapture

p) { + beforeSyntax(conditionalType, JsSpace.Location.CONDITIONAL_TYPE_PREFIX, p); + visit(conditionalType.getCheckType(), p); + visitContainer("extends", conditionalType.getPadding().getCondition(), JsContainer.Location.CONDITIONAL_TYPE_CONDITION, "", "", p); + afterSyntax(conditionalType, p); + return conditionalType; + } + @Override public J visitDefaultType(JS.DefaultType defaultType, PrintOutputCapture

p) { beforeSyntax(defaultType, JsSpace.Location.DEFAULT_TYPE_PREFIX, p); @@ -151,6 +160,15 @@ public J visitDelete(JS.Delete delete, PrintOutputCapture

p) { return delete; } + @Override + public J visitExpressionWithTypeArguments(JS.ExpressionWithTypeArguments type, PrintOutputCapture

p) { + beforeSyntax(type, JsSpace.Location.EXPR_WITH_TYPE_ARG_PREFIX, p); + visit(type.getClazz(), p); + visitContainer("<", type.getPadding().getTypeArguments(), JsContainer.Location.EXPR_WITH_TYPE_ARG_PARAMETERS, ",", ">", p); + afterSyntax(type, p); + return type; + } + @Override public J visitExport(JS.Export export, PrintOutputCapture

p) { beforeSyntax(export, JsSpace.Location.EXPORT_PREFIX, p); @@ -338,36 +356,30 @@ public J visitObjectBindingDeclarations(JS.ObjectBindingDeclarations objectBindi return objectBindingDeclarations; } + @Override + public J visitTaggedTemplateExpression(JS.TaggedTemplateExpression taggedTemplateExpression, PrintOutputCapture

p) { + beforeSyntax(taggedTemplateExpression, JsSpace.Location.TEMPLATE_EXPRESSION_PREFIX, p); + visitRightPadded(taggedTemplateExpression.getPadding().getTag(), JsRightPadded.Location.TEMPLATE_EXPRESSION_TAG, p); + visitContainer("<", taggedTemplateExpression.getPadding().getTypeArguments(), JsContainer.Location.TEMPLATE_EXPRESSION_TYPE_ARG_PARAMETERS, ",", ">", p); + visit(taggedTemplateExpression.getTemplateExpression(), p); + afterSyntax(taggedTemplateExpression, p); + return taggedTemplateExpression; + } + @Override public J visitTemplateExpression(JS.TemplateExpression templateExpression, PrintOutputCapture

p) { beforeSyntax(templateExpression, JsSpace.Location.TEMPLATE_EXPRESSION_PREFIX, p); - String delimiter = templateExpression.getDelimiter(); - visitRightPadded(templateExpression.getPadding().getTag(), JsRightPadded.Location.TAG, p); - PostFixOperator postFixOperator = templateExpression.getMarkers().findFirst(PostFixOperator.class).orElse(null); - if (postFixOperator != null) { - visitSpace(postFixOperator.getPrefix(), Space.Location.LAMBDA_PARAMETERS_PREFIX, p); - p.append(postFixOperator.getOperator().getValue()); - } - p.append(delimiter); - visit(templateExpression.getStrings(), p); - p.append(delimiter); + visit(templateExpression.getHead(), p); + visitRightPadded(templateExpression.getPadding().getTemplateSpans(), JsRightPadded.Location.TEMPLATE_EXPRESSION_TEMPLATE_SPAN, "", p); afterSyntax(templateExpression, p); return templateExpression; } @Override - public J visitTemplateExpressionValue(JS.TemplateExpression.Value value, PrintOutputCapture

p) { - beforeSyntax(value, JsSpace.Location.TEMPLATE_EXPRESSION_VALUE_PREFIX, p); - if (value.isEnclosedInBraces()) { - p.append("${"); - } else { - p.append("$"); - } - visit(value.getTree(), p); - visitSpace(value.getAfter(), JsSpace.Location.TEMPLATE_EXPRESSION_VALUE_SUFFIX, p); - if (value.isEnclosedInBraces()) { - p.append('}'); - } + public J visitTemplateExpressionTemplateSpan(JS.TemplateExpression.TemplateSpan value, PrintOutputCapture

p) { + beforeSyntax(value, JsSpace.Location.TEMPLATE_EXPRESSION_SPAN_PREFIX, p); + visit(value.getExpression(), p); + visit(value.getTail(), p); afterSyntax(value, p); return value; } 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 b0a92481..e6a1b93a 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 @@ -478,6 +478,85 @@ public CoordinateBuilder.Expression getCoordinates() { } } + @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) + @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) + @RequiredArgsConstructor + @AllArgsConstructor(access = AccessLevel.PRIVATE) + final class ConditionalType implements JS, TypeTree, Expression { + @Nullable + @NonFinal + transient WeakReference padding; + + @With + @EqualsAndHashCode.Include + @Getter + UUID id; + + @With + @Getter + Space prefix; + + @With + @Getter + Markers markers; + + @With + @Getter + Expression checkType; + + JContainer condition; + + public List getCondition() { + return condition.getElements(); + } + + public ConditionalType withCondition(@Nullable List bounds) { + return getPadding().withCondition(JContainer.withElementsNullable(this.condition, bounds)); + } + + @With + @Getter + @Nullable + JavaType type; + + public CoordinateBuilder.Expression getCoordinates() { + return new CoordinateBuilder.Expression(this); + } + + @Override + public

J acceptJavaScript(JavaScriptVisitor

v, P p) { + return v.visitConditionalType(this, p); + } + + public ConditionalType.Padding getPadding() { + ConditionalType.Padding p; + if (this.padding == null) { + p = new ConditionalType.Padding(this); + this.padding = new WeakReference<>(p); + } else { + p = this.padding.get(); + if (p == null || p.t != this) { + p = new ConditionalType.Padding(this); + this.padding = new WeakReference<>(p); + } + } + return p; + } + + @RequiredArgsConstructor + public static class Padding { + private final ConditionalType t; + + public @Nullable JContainer getCondition() { + return t.condition; + } + + public ConditionalType withCondition(@Nullable JContainer condition) { + return t.condition == condition ? t : new ConditionalType(t.id, t.prefix, t.markers, t.checkType, condition, t.type); + } + } + } + @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) @Data @@ -692,6 +771,93 @@ public CoordinateBuilder.Statement getCoordinates() { } } + @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) + @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) + @RequiredArgsConstructor + @AllArgsConstructor(access = AccessLevel.PRIVATE) + final class ExpressionWithTypeArguments implements JS, TypeTree, Expression { + @Nullable + @NonFinal + transient WeakReference padding; + + @With + @EqualsAndHashCode.Include + @Getter + UUID id; + + @With + @Getter + Space prefix; + + @With + @Getter + Markers markers; + + @With + @Getter + NameTree clazz; + + @Nullable + JContainer typeArguments; + + public @Nullable List getTypeArguments() { + return typeArguments == null ? null : typeArguments.getElements(); + } + + public ExpressionWithTypeArguments withTypeArguments(@Nullable List typeParameters) { + return getPadding().withTypeArguments(JContainer.withElementsNullable(this.typeArguments, typeParameters)); + } + + @With + @Getter + @Nullable + JavaType type; + + @Override + public

J acceptJavaScript(JavaScriptVisitor

v, P p) { + return v.visitExpressionWithTypeArguments(this, p); + } + + @Override + @Transient + public CoordinateBuilder.Expression getCoordinates() { + return new CoordinateBuilder.Expression(this); + } + + public ExpressionWithTypeArguments.Padding getPadding() { + ExpressionWithTypeArguments.Padding p; + if (this.padding == null) { + p = new ExpressionWithTypeArguments.Padding(this); + this.padding = new WeakReference<>(p); + } else { + p = this.padding.get(); + if (p == null || p.t != this) { + p = new ExpressionWithTypeArguments.Padding(this); + this.padding = new WeakReference<>(p); + } + } + return p; + } + + @Override + public String toString() { + return withPrefix(Space.EMPTY).printTrimmed(new JavaPrinter<>()); + } + + @RequiredArgsConstructor + public static class Padding { + private final ExpressionWithTypeArguments t; + + public @Nullable JContainer getTypeArguments() { + return t.typeArguments; + } + + public ExpressionWithTypeArguments withTypeArguments(@Nullable JContainer typeArguments) { + return t.typeArguments == typeArguments ? t : new ExpressionWithTypeArguments(t.id, t.prefix, t.markers, t.clazz, typeArguments, t.type); + } + } + } + @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) @RequiredArgsConstructor @@ -1486,16 +1652,16 @@ public CoordinateBuilder.Statement getCoordinates() { } } + @Getter @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) @RequiredArgsConstructor @AllArgsConstructor(access = AccessLevel.PRIVATE) - @Data - final class TemplateExpression implements JS, Statement, Expression { + final class TaggedTemplateExpression implements JS, Statement, Expression { @Nullable @NonFinal - transient WeakReference padding; + transient WeakReference padding; @EqualsAndHashCode.Include @With @@ -1507,9 +1673,6 @@ final class TemplateExpression implements JS, Statement, Expression { @With Markers markers; - @With - String delimiter; - @Nullable JRightPadded tag; @@ -1517,12 +1680,109 @@ final class TemplateExpression implements JS, Statement, Expression { return tag == null ? null : tag.getElement(); } - public TemplateExpression withTag(@Nullable Expression tag) { + public TaggedTemplateExpression withTag(@Nullable Expression tag) { return getPadding().withTag(JRightPadded.withElement(this.tag, tag)); } + @Nullable + JContainer typeArguments; + + public @Nullable List getTypeArguments() { + return typeArguments == null ? null : typeArguments.getElements(); + } + + public TaggedTemplateExpression withTypeArguments(@Nullable List typeParameters) { + return getPadding().withTypeArguments(JContainer.withElementsNullable(this.typeArguments, typeParameters)); + } + + @With + TemplateExpression templateExpression; + + @With + @Nullable + JavaType type; + + @Override + public

J acceptJavaScript(JavaScriptVisitor

v, P p) { + return v.visitTaggedTemplateExpression(this, p); + } + + @Transient + @Override + public CoordinateBuilder.Statement getCoordinates() { + return new CoordinateBuilder.Statement(this); + } + + public TaggedTemplateExpression.Padding getPadding() { + TaggedTemplateExpression.Padding p; + if (this.padding == null) { + p = new TaggedTemplateExpression.Padding(this); + this.padding = new WeakReference<>(p); + } else { + p = this.padding.get(); + if (p == null || p.t != this) { + p = new TaggedTemplateExpression.Padding(this); + this.padding = new WeakReference<>(p); + } + } + return p; + } + + @RequiredArgsConstructor + public static class Padding { + private final TaggedTemplateExpression t; + + public @Nullable JRightPadded getTag() { + return t.tag; + } + + public TaggedTemplateExpression withTag(@Nullable JRightPadded tag) { + return t.tag == tag ? t : new TaggedTemplateExpression(t.id, t.prefix, t.markers, tag, t.typeArguments, t.templateExpression, t.type); + } + + public @Nullable JContainer getTypeArguments() { + return t.typeArguments; + } + + public TaggedTemplateExpression withTypeArguments(@Nullable JContainer typeArguments) { + return t.typeArguments == typeArguments ? t : new TaggedTemplateExpression(t.id, t.prefix, t.markers, t.tag, typeArguments, t.templateExpression, t.type); + } + } + } + + @Getter + @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) + @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) + @RequiredArgsConstructor + @AllArgsConstructor(access = AccessLevel.PRIVATE) + final class TemplateExpression implements JS, Statement, Expression { + + @Nullable + @NonFinal + transient WeakReference padding; + + @EqualsAndHashCode.Include @With - List strings; + UUID id; + + @With + Space prefix; + + @With + Markers markers; + + @With + J.Literal head; + + List> templateSpans; + + public List getTemplateSpans() { + return JRightPadded.getElements(templateSpans); + } + + public TemplateExpression withTemplateSpans(List spans) { + return getPadding().withTemplateSpans(JRightPadded.withElements(this.templateSpans, spans)); + } @With @Nullable @@ -1541,19 +1801,32 @@ public CoordinateBuilder.Statement getCoordinates() { @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) - @Data - @With - public static final class Value implements JS { + @RequiredArgsConstructor + public static final class TemplateSpan implements JS { + @With + @EqualsAndHashCode.Include + @Getter UUID id; + + @With + @Getter Space prefix; + + @With + @Getter Markers markers; - J tree; - Space after; - boolean enclosedInBraces; + + @With + @Getter + J expression; + + @With + @Getter + J.Literal tail; @Override public

J acceptJavaScript(JavaScriptVisitor

v, P p) { - return v.visitTemplateExpressionValue(this, p); + return v.visitTemplateExpressionTemplateSpan(this, p); } } @@ -1576,12 +1849,12 @@ public TemplateExpression.Padding getPadding() { public static class Padding { private final TemplateExpression t; - public @Nullable JRightPadded getTag() { - return t.tag; + public List> getTemplateSpans() { + return t.templateSpans; } - public TemplateExpression withTag(@Nullable JRightPadded tag) { - return t.tag == tag ? t : new TemplateExpression(t.id, t.prefix, t.markers, t.delimiter, tag, t.strings, t.type); + public TemplateExpression withTemplateSpans(List> templateSpans) { + return t.templateSpans == templateSpans ? t : new TemplateExpression(t.id, t.prefix, t.markers, t.head, templateSpans, t.type); } } } diff --git a/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JsContainer.java b/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JsContainer.java index 97747607..d21d3da2 100644 --- a/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JsContainer.java +++ b/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JsContainer.java @@ -30,7 +30,9 @@ public enum Location { TYPE_LITERAL_MEMBERS(JsSpace.Location.TYPE_LITERAL_MEMBERS_PREFIX, JsRightPadded.Location.TYPE_LITERAL_MEMBERS), INDEXED_SIGNATURE_DECLARATION_PARAMETERS(JsSpace.Location.INDEXED_SIGNATURE_DECLARATION_PARAMETERS_PREFIX, JsRightPadded.Location.INDEXED_SIGNATURE_DECLARATION_PARAMETERS), ARRAY_BINDING_PATTERN_ELEMENTS(JsSpace.Location.ARRAY_BINDING_PATTERN_ELEMENTS_PREFIX, JsRightPadded.Location.ARRAY_BINDING_PATTERN_ELEMENTS), - ; + EXPR_WITH_TYPE_ARG_PARAMETERS(JsSpace.Location.EXPR_WITH_TYPE_ARG_PARAMETERS, JsRightPadded.Location.EXPR_WITH_TYPE_ARG_PARAMETERS_SUFFIX), + TEMPLATE_EXPRESSION_TYPE_ARG_PARAMETERS(JsSpace.Location.TEMPLATE_EXPRESSION_TYPE_ARG_PARAMETERS, JsRightPadded.Location.TEMPLATE_EXPRESSION_TYPE_ARG_PARAMETERS_SUFFIX), + CONDITIONAL_TYPE_CONDITION(JsSpace.Location.CONDITIONAL_TYPE_CONDITION, JsRightPadded.Location.CONDITIONAL_TYPE_CONDITION); private final JsSpace.Location beforeLocation; private final JsRightPadded.Location elementLocation; diff --git a/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JsRightPadded.java b/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JsRightPadded.java index 9c461ec9..d8c1a117 100644 --- a/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JsRightPadded.java +++ b/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JsRightPadded.java @@ -44,7 +44,11 @@ public enum Location { FOR_BODY(JsSpace.Location.FOR_BODY_SUFFIX), FUNCTION_TYPE_CONSTRUCTOR(JsSpace.Location.FUNCTION_TYPE_CONSTRUCTOR_SUFFIX), ARRAY_BINDING_PATTERN_ELEMENTS(JsSpace.Location.FOR_BODY_SUFFIX), - ; + EXPR_WITH_TYPE_ARG_PARAMETERS_SUFFIX(JsSpace.Location.EXPR_WITH_TYPE_ARG_PARAMETERS_SUFFIX), + TEMPLATE_EXPRESSION_TAG(JsSpace.Location.TEMPLATE_EXPRESSION_TAG_SUFFIX), + TEMPLATE_EXPRESSION_TYPE_ARG_PARAMETERS_SUFFIX(JsSpace.Location.TEMPLATE_EXPRESSION_TYPE_ARG_PARAMETERS_SUFFIX), + TEMPLATE_EXPRESSION_TEMPLATE_SPAN(JsSpace.Location.TEMPLATE_EXPRESSION_TEMPLATE_SPAN_SUFFIX), + CONDITIONAL_TYPE_CONDITION(JsSpace.Location.CONDITIONAL_TYPE_CONDITION_SUFFIX); private final JsSpace.Location afterLocation; 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 d421ee55..df1256eb 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 @@ -57,8 +57,8 @@ public enum Location { SCOPED_VARIABLE_DECLARATIONS_VARIABLE_SUFFIX, TAG_SUFFIX, TEMPLATE_EXPRESSION_PREFIX, - TEMPLATE_EXPRESSION_VALUE_PREFIX, - TEMPLATE_EXPRESSION_VALUE_SUFFIX, + TEMPLATE_EXPRESSION_SPAN_PREFIX, + TEMPLATE_EXPRESSION_SPAN_SUFFIX, TUPLE_ELEMENT, TUPLE_ELEMENT_SUFFIX, TUPLE_PREFIX, @@ -107,6 +107,17 @@ public enum Location { ARRAY_BINDING_PATTERN_PREFIX, ARRAY_BINDING_PATTERN_ELEMENTS_PREFIX, ARRAY_BINDING_PATTERN_ELEMENTS_SUFFIX, + EXPR_WITH_TYPE_ARG_PREFIX, + EXPR_WITH_TYPE_ARG_PARAMETERS, + EXPR_WITH_TYPE_ARG_PARAMETERS_SUFFIX, + TEMPLATE_EXPRESSION_TAG_SUFFIX, + TEMPLATE_EXPRESSION_TYPE_ARG_PARAMETERS, + TEMPLATE_EXPRESSION_TYPE_ARG_PARAMETERS_SUFFIX, + TEMPLATE_EXPRESSION_TEMPLATE_SPAN_SUFFIX, + TAGGED_TEMPLATE_EXPRESSION_PREFIX, + CONDITIONAL_TYPE_PREFIX, + CONDITIONAL_TYPE_CONDITION, + CONDITIONAL_TYPE_CONDITION_SUFFIX, } }