diff --git a/openrewrite/src/java/tree/support_types.ts b/openrewrite/src/java/tree/support_types.ts index f13acfa5..b54a78fd 100644 --- a/openrewrite/src/java/tree/support_types.ts +++ b/openrewrite/src/java/tree/support_types.ts @@ -373,12 +373,66 @@ export class JLeftPadded { this._markers = markers; } + static getElements(ls: Array>): Array { + if (ls == null) { + return []; + } + const list = new Array(ls.length); + for (let l of ls) { + if (l == null) { + continue; + } + const elem = l.element; + list.push(elem); + } + return list; + } + static withElement(before: JLeftPadded | null, element: T | null): JLeftPadded | null { if (element == null) return null; if (before == null) return new JLeftPadded(Space.EMPTY, element, Markers.EMPTY); return before.withElement(element); } + static withElements(before: JLeftPadded[], elements: T[]): JLeftPadded[] { + // a cheaper check for the most common case when there are no changes + if (elements.length === before.length) { + let hasChanges = false; + for (let i = 0; i < before.length; i++) { + if (before[i].element !== elements[i]) { + hasChanges = true; + break; + } + } + if (!hasChanges) { + return before; + } + } else if (elements.length === 0) { + return []; + } + + const after: JLeftPadded[] = new Array>(); + const beforeById: Map> = new Map(); + + for (const j of before) { + if (beforeById.has(j.element)) { + throw new Error("Duplicate key"); + } + beforeById.set(j.element, j); + } + + for (const t of elements) { + const found = beforeById.get(t); + if (found) { + after.push(found.withElement(t)); + } else { + after.push(new JLeftPadded(Space.EMPTY, t, Markers.EMPTY)); + } + } + + return after; + } + private readonly _before: Space; get before(): Space { @@ -756,4 +810,4 @@ export namespace JContainer { return null!; } } -} \ No newline at end of file +} diff --git a/openrewrite/src/javascript/parser.ts b/openrewrite/src/javascript/parser.ts index 546df440..64673566 100644 --- a/openrewrite/src/javascript/parser.ts +++ b/openrewrite/src/javascript/parser.ts @@ -636,6 +636,37 @@ export class JavaScriptParserVisitor { } visitParameter(node: ts.ParameterDeclaration) { + if (node.questionToken) { + return new JS.JSVariableDeclarations( + randomId(), + this.prefix(node), + Markers.EMPTY, + [], + this.mapModifiers(node), + this.mapTypeInfo(node), + null, + [this.rightPadded( + new JS.JSVariableDeclarations.JSNamedVariable( + randomId(), + this.prefix(node.name), + Markers.EMPTY, + new JS.Unary( + randomId(), + Space.EMPTY, + Markers.EMPTY, + this.leftPadded(this.suffix(node.name), JS.Unary.Type.Optional), + this.visit(node.name), + this.mapType(node) + ), + [], + node.initializer ? this.leftPadded(this.prefix(node.getChildAt(node.getChildCount(this.sourceFile) - 2)), this.visit(node.initializer)) : null, + this.mapVariableType(node) + ), + this.suffix(node.name) + )] + ); + } + return new J.VariableDeclarations( randomId(), this.prefix(node), diff --git a/openrewrite/src/javascript/remote/receiver.ts b/openrewrite/src/javascript/remote/receiver.ts index 208f1c84..2c7b0b7d 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, CompilationUnit, Alias, ArrowFunction, Await, DefaultType, Delete, Export, ExpressionStatement, FunctionType, JsImport, JsBinary, ObjectBindingDeclarations, PropertyAssignment, ScopedVariableDeclarations, StatementExpression, TemplateExpression, Tuple, TypeDeclaration, TypeOf, TypeOperator, Unary, Union, Void, Yield, TypeInfo, NamespaceDeclaration} from '../tree'; +import {JS, JsLeftPadded, JsRightPadded, JsContainer, JsSpace, CompilationUnit, Alias, ArrowFunction, Await, DefaultType, Delete, Export, ExpressionStatement, FunctionType, JsImport, JsBinary, ObjectBindingDeclarations, PropertyAssignment, ScopedVariableDeclarations, StatementExpression, TemplateExpression, Tuple, TypeDeclaration, TypeOf, TypeOperator, Unary, Union, Void, Yield, TypeInfo, JSVariableDeclarations, NamespaceDeclaration} from '../tree'; import {Expression, J, JContainer, JLeftPadded, JRightPadded, NameTree, Space, Statement, TypeTree, TypedTree} from "../../java"; import * as Java from "../../java/tree"; @@ -300,6 +300,29 @@ class Visitor extends JavaScriptVisitor { return typeInfo; } + public visitJSVariableDeclarations(jSVariableDeclarations: JSVariableDeclarations, ctx: ReceiverContext): J { + jSVariableDeclarations = jSVariableDeclarations.withId(ctx.receiveValue(jSVariableDeclarations.id, ValueType.UUID)!); + jSVariableDeclarations = jSVariableDeclarations.withPrefix(ctx.receiveNode(jSVariableDeclarations.prefix, receiveSpace)!); + jSVariableDeclarations = jSVariableDeclarations.withMarkers(ctx.receiveNode(jSVariableDeclarations.markers, ctx.receiveMarkers)!); + jSVariableDeclarations = jSVariableDeclarations.withLeadingAnnotations(ctx.receiveNodes(jSVariableDeclarations.leadingAnnotations, ctx.receiveTree)!); + jSVariableDeclarations = jSVariableDeclarations.withModifiers(ctx.receiveNodes(jSVariableDeclarations.modifiers, ctx.receiveTree)!); + jSVariableDeclarations = jSVariableDeclarations.withTypeExpression(ctx.receiveNode(jSVariableDeclarations.typeExpression, ctx.receiveTree)); + jSVariableDeclarations = jSVariableDeclarations.withVarargs(ctx.receiveNode(jSVariableDeclarations.varargs, receiveSpace)); + jSVariableDeclarations = jSVariableDeclarations.padding.withVariables(ctx.receiveNodes(jSVariableDeclarations.padding.variables, receiveRightPaddedTree)!); + return jSVariableDeclarations; + } + + public visitJSVariableDeclarationsJSNamedVariable(jSNamedVariable: JSVariableDeclarations.JSNamedVariable, ctx: ReceiverContext): J { + jSNamedVariable = jSNamedVariable.withId(ctx.receiveValue(jSNamedVariable.id, ValueType.UUID)!); + jSNamedVariable = jSNamedVariable.withPrefix(ctx.receiveNode(jSNamedVariable.prefix, receiveSpace)!); + jSNamedVariable = jSNamedVariable.withMarkers(ctx.receiveNode(jSNamedVariable.markers, ctx.receiveMarkers)!); + jSNamedVariable = jSNamedVariable.withName(ctx.receiveNode(jSNamedVariable.name, ctx.receiveTree)!); + jSNamedVariable = jSNamedVariable.padding.withDimensionsAfterName(ctx.receiveNodes(jSNamedVariable.padding.dimensionsAfterName, leftPaddedNodeReceiver(Space))!); + jSNamedVariable = jSNamedVariable.padding.withInitializer(ctx.receiveNode(jSNamedVariable.padding.initializer, receiveLeftPaddedTree)); + jSNamedVariable = jSNamedVariable.withVariableType(ctx.receiveValue(jSNamedVariable.variableType, ValueType.Object)); + return jSNamedVariable; + } + public visitNamespaceDeclaration(namespaceDeclaration: NamespaceDeclaration, ctx: ReceiverContext): J { namespaceDeclaration = namespaceDeclaration.withId(ctx.receiveValue(namespaceDeclaration.id, ValueType.UUID)!); namespaceDeclaration = namespaceDeclaration.withPrefix(ctx.receiveNode(namespaceDeclaration.prefix, receiveSpace)!); @@ -1281,6 +1304,31 @@ class Factory implements ReceiverFactory { ); } + if (type === "org.openrewrite.javascript.tree.JS$JSVariableDeclarations") { + return new JSVariableDeclarations( + ctx.receiveValue(null, ValueType.UUID)!, + ctx.receiveNode(null, receiveSpace)!, + ctx.receiveNode(null, ctx.receiveMarkers)!, + ctx.receiveNodes(null, ctx.receiveTree)!, + ctx.receiveNodes(null, ctx.receiveTree)!, + ctx.receiveNode(null, ctx.receiveTree), + ctx.receiveNode(null, receiveSpace), + ctx.receiveNodes(null, receiveRightPaddedTree)! + ); + } + + if (type === "org.openrewrite.javascript.tree.JS$JSVariableDeclarations$JSNamedVariable") { + return new JSVariableDeclarations.JSNamedVariable( + ctx.receiveValue(null, ValueType.UUID)!, + ctx.receiveNode(null, receiveSpace)!, + ctx.receiveNode(null, ctx.receiveMarkers)!, + ctx.receiveNode(null, ctx.receiveTree)!, + ctx.receiveNodes(null, leftPaddedNodeReceiver(Space))!, + ctx.receiveNode>(null, receiveLeftPaddedTree), + ctx.receiveValue(null, ValueType.Object) + ); + } + if (type === "org.openrewrite.javascript.tree.JS$NamespaceDeclaration") { return new NamespaceDeclaration( ctx.receiveValue(null, ValueType.UUID)!, diff --git a/openrewrite/src/javascript/remote/sender.ts b/openrewrite/src/javascript/remote/sender.ts index 35f1c54f..ef938444 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, JsBinary, ObjectBindingDeclarations, PropertyAssignment, ScopedVariableDeclarations, StatementExpression, TemplateExpression, Tuple, TypeDeclaration, TypeOf, TypeOperator, Unary, Union, Void, Yield, TypeInfo, NamespaceDeclaration} from '../tree'; +import {JS, JsLeftPadded, JsRightPadded, JsContainer, JsSpace, CompilationUnit, Alias, ArrowFunction, Await, DefaultType, Delete, Export, ExpressionStatement, FunctionType, JsImport, JsBinary, ObjectBindingDeclarations, PropertyAssignment, ScopedVariableDeclarations, StatementExpression, TemplateExpression, Tuple, TypeDeclaration, TypeOf, TypeOperator, Unary, Union, Void, Yield, TypeInfo, JSVariableDeclarations, NamespaceDeclaration} from '../tree'; import {Expression, J, JContainer, JLeftPadded, JRightPadded, Space, Statement} from "../../java"; import * as Java from "../../java/tree"; @@ -295,6 +295,29 @@ class Visitor extends JavaScriptVisitor { return typeInfo; } + public visitJSVariableDeclarations(jSVariableDeclarations: JSVariableDeclarations, ctx: SenderContext): J { + ctx.sendValue(jSVariableDeclarations, v => v.id, ValueType.UUID); + ctx.sendNode(jSVariableDeclarations, v => v.prefix, Visitor.sendSpace); + ctx.sendNode(jSVariableDeclarations, v => v.markers, ctx.sendMarkers); + ctx.sendNodes(jSVariableDeclarations, v => v.leadingAnnotations, ctx.sendTree, t => t.id); + ctx.sendNodes(jSVariableDeclarations, v => v.modifiers, ctx.sendTree, t => t.id); + ctx.sendNode(jSVariableDeclarations, v => v.typeExpression, ctx.sendTree); + ctx.sendNode(jSVariableDeclarations, v => v.varargs, Visitor.sendSpace); + ctx.sendNodes(jSVariableDeclarations, v => v.padding.variables, Visitor.sendRightPadded(ValueType.Tree), t => t.element.id); + return jSVariableDeclarations; + } + + public visitJSVariableDeclarationsJSNamedVariable(jSNamedVariable: JSVariableDeclarations.JSNamedVariable, ctx: SenderContext): J { + ctx.sendValue(jSNamedVariable, v => v.id, ValueType.UUID); + ctx.sendNode(jSNamedVariable, v => v.prefix, Visitor.sendSpace); + ctx.sendNode(jSNamedVariable, v => v.markers, ctx.sendMarkers); + ctx.sendNode(jSNamedVariable, v => v.name, ctx.sendTree); + ctx.sendNodes(jSNamedVariable, v => v.padding.dimensionsAfterName, Visitor.sendLeftPadded(ValueType.Object), t => t); + ctx.sendNode(jSNamedVariable, v => v.padding.initializer, Visitor.sendLeftPadded(ValueType.Tree)); + ctx.sendTypedValue(jSNamedVariable, v => v.variableType, ValueType.Object); + return jSNamedVariable; + } + public visitNamespaceDeclaration(namespaceDeclaration: NamespaceDeclaration, ctx: SenderContext): J { ctx.sendValue(namespaceDeclaration, v => v.id, ValueType.UUID); ctx.sendNode(namespaceDeclaration, v => v.prefix, Visitor.sendSpace); diff --git a/openrewrite/src/javascript/tree/support_types.ts b/openrewrite/src/javascript/tree/support_types.ts index daa2b5bd..9d856270 100644 --- a/openrewrite/src/javascript/tree/support_types.ts +++ b/openrewrite/src/javascript/tree/support_types.ts @@ -213,8 +213,11 @@ export namespace JsSpace { VOID_PREFIX, YIELD_PREFIX, TYPE_INFO_PREFIX, + JSVARIABLE_DECLARATIONS_PREFIX, + JSVARIABLE_DECLARATIONS_VARARGS, + JSVARIABLE_DECLARATIONS_JSNAMED_VARIABLE_PREFIX, NAMESPACE_DECLARATION_PREFIX, - NAMESPACE_KEYWORD_DECLARATION_PREFIX + NAMESPACE_DECLARATION_NAMESPACE } } export namespace JsLeftPadded { @@ -229,6 +232,8 @@ export namespace JsLeftPadded { TYPE_DECLARATION_INITIALIZER, TYPE_OPERATOR_EXPRESSION, UNARY_OPERATOR, + JSVARIABLE_DECLARATIONS_JSNAMED_VARIABLE_INITIALIZER, + JSVARIABLE_DECLARATIONS_JSNAMED_VARIABLE_DIMENSIONS_AFTER_NAME, } } export namespace JsRightPadded { @@ -241,6 +246,7 @@ export namespace JsRightPadded { SCOPED_VARIABLE_DECLARATIONS_VARIABLES, TEMPLATE_EXPRESSION_TAG, UNION_TYPES, + JSVARIABLE_DECLARATIONS_VARIABLES, NAMESPACE_DECLARATION_NAME, } } diff --git a/openrewrite/src/javascript/tree/tree.ts b/openrewrite/src/javascript/tree/tree.ts index 4b884d22..5c5e29eb 100644 --- a/openrewrite/src/javascript/tree/tree.ts +++ b/openrewrite/src/javascript/tree/tree.ts @@ -2120,6 +2120,7 @@ export class Unary extends JSMixin(Object) implements Statement, Expression, Typ export namespace Unary { export enum Type { Spread = 0, + Optional = 1, } @@ -2410,6 +2411,244 @@ export class TypeInfo extends JSMixin(Object) implements Expression, TypeTree { } +@LstType("org.openrewrite.javascript.tree.JS$JSVariableDeclarations") +export class JSVariableDeclarations extends JSMixin(Object) implements Statement, TypedTree { + public constructor(id: UUID, prefix: Space, markers: Markers, leadingAnnotations: Java.Annotation[], modifiers: Java.Modifier[], typeExpression: TypeTree | null, varargs: Space | null, variables: JRightPadded[]) { + super(); + this._id = id; + this._prefix = prefix; + this._markers = markers; + this._leadingAnnotations = leadingAnnotations; + this._modifiers = modifiers; + this._typeExpression = typeExpression; + this._varargs = varargs; + this._variables = variables; + } + + private readonly _id: UUID; + + public get id(): UUID { + return this._id; + } + + public withId(id: UUID): JSVariableDeclarations { + return id === this._id ? this : new JSVariableDeclarations(id, this._prefix, this._markers, this._leadingAnnotations, this._modifiers, this._typeExpression, this._varargs, this._variables); + } + + private readonly _prefix: Space; + + public get prefix(): Space { + return this._prefix; + } + + public withPrefix(prefix: Space): JSVariableDeclarations { + return prefix === this._prefix ? this : new JSVariableDeclarations(this._id, prefix, this._markers, this._leadingAnnotations, this._modifiers, this._typeExpression, this._varargs, this._variables); + } + + private readonly _markers: Markers; + + public get markers(): Markers { + return this._markers; + } + + public withMarkers(markers: Markers): JSVariableDeclarations { + return markers === this._markers ? this : new JSVariableDeclarations(this._id, this._prefix, markers, this._leadingAnnotations, this._modifiers, this._typeExpression, this._varargs, this._variables); + } + + private readonly _leadingAnnotations: Java.Annotation[]; + + public get leadingAnnotations(): Java.Annotation[] { + return this._leadingAnnotations; + } + + public withLeadingAnnotations(leadingAnnotations: Java.Annotation[]): JSVariableDeclarations { + return leadingAnnotations === this._leadingAnnotations ? this : new JSVariableDeclarations(this._id, this._prefix, this._markers, leadingAnnotations, this._modifiers, this._typeExpression, this._varargs, this._variables); + } + + private readonly _modifiers: Java.Modifier[]; + + public get modifiers(): Java.Modifier[] { + return this._modifiers; + } + + public withModifiers(modifiers: Java.Modifier[]): JSVariableDeclarations { + return modifiers === this._modifiers ? this : new JSVariableDeclarations(this._id, this._prefix, this._markers, this._leadingAnnotations, modifiers, this._typeExpression, this._varargs, this._variables); + } + + private readonly _typeExpression: TypeTree | null; + + public get typeExpression(): TypeTree | null { + return this._typeExpression; + } + + public withTypeExpression(typeExpression: TypeTree | null): JSVariableDeclarations { + return typeExpression === this._typeExpression ? this : new JSVariableDeclarations(this._id, this._prefix, this._markers, this._leadingAnnotations, this._modifiers, typeExpression, this._varargs, this._variables); + } + + private readonly _varargs: Space | null; + + public get varargs(): Space | null { + return this._varargs; + } + + public withVarargs(varargs: Space | null): JSVariableDeclarations { + return varargs === this._varargs ? this : new JSVariableDeclarations(this._id, this._prefix, this._markers, this._leadingAnnotations, this._modifiers, this._typeExpression, varargs, this._variables); + } + + private readonly _variables: JRightPadded[]; + + public get variables(): JSVariableDeclarations.JSNamedVariable[] { + return JRightPadded.getElements(this._variables); + } + + public withVariables(variables: JSVariableDeclarations.JSNamedVariable[]): JSVariableDeclarations { + return this.padding.withVariables(JRightPadded.withElements(this._variables, variables)); + } + + public acceptJavaScript

(v: JavaScriptVisitor

, p: P): J | null { + return v.visitJSVariableDeclarations(this, p); + } + + public get type(): JavaType | null { + return extensions.getJavaType(this); + } + + public withType(type: JavaType): JSVariableDeclarations { + return extensions.withJavaType(this, type); + } + + get padding() { + const t = this; + return new class { + public get variables(): JRightPadded[] { + return t._variables; + } + public withVariables(variables: JRightPadded[]): JSVariableDeclarations { + return t._variables === variables ? t : new JSVariableDeclarations(t._id, t._prefix, t._markers, t._leadingAnnotations, t._modifiers, t._typeExpression, t._varargs, variables); + } + } + } + +} + +export namespace JSVariableDeclarations { + @LstType("org.openrewrite.javascript.tree.JS$JSVariableDeclarations$JSNamedVariable") + export class JSNamedVariable extends JSMixin(Object) implements NameTree { + public constructor(id: UUID, prefix: Space, markers: Markers, name: Expression, dimensionsAfterName: JLeftPadded[], initializer: JLeftPadded | null, variableType: JavaType.Variable | null) { + super(); + this._id = id; + this._prefix = prefix; + this._markers = markers; + this._name = name; + this._dimensionsAfterName = dimensionsAfterName; + this._initializer = initializer; + this._variableType = variableType; + } + + private readonly _id: UUID; + + public get id(): UUID { + return this._id; + } + + public withId(id: UUID): JSVariableDeclarations.JSNamedVariable { + return id === this._id ? this : new JSVariableDeclarations.JSNamedVariable(id, this._prefix, this._markers, this._name, this._dimensionsAfterName, this._initializer, this._variableType); + } + + private readonly _prefix: Space; + + public get prefix(): Space { + return this._prefix; + } + + public withPrefix(prefix: Space): JSVariableDeclarations.JSNamedVariable { + return prefix === this._prefix ? this : new JSVariableDeclarations.JSNamedVariable(this._id, prefix, this._markers, this._name, this._dimensionsAfterName, this._initializer, this._variableType); + } + + private readonly _markers: Markers; + + public get markers(): Markers { + return this._markers; + } + + public withMarkers(markers: Markers): JSVariableDeclarations.JSNamedVariable { + return markers === this._markers ? this : new JSVariableDeclarations.JSNamedVariable(this._id, this._prefix, markers, this._name, this._dimensionsAfterName, this._initializer, this._variableType); + } + + private readonly _name: Expression; + + public get name(): Expression { + return this._name; + } + + public withName(name: Expression): JSVariableDeclarations.JSNamedVariable { + return name === this._name ? this : new JSVariableDeclarations.JSNamedVariable(this._id, this._prefix, this._markers, name, this._dimensionsAfterName, this._initializer, this._variableType); + } + + private readonly _dimensionsAfterName: JLeftPadded[]; + + public get dimensionsAfterName(): Space[] { + return JLeftPadded.getElements(this._dimensionsAfterName); + } + + public withDimensionsAfterName(dimensionsAfterName: Space[]): JSVariableDeclarations.JSNamedVariable { + return this.padding.withDimensionsAfterName(JLeftPadded.withElements(this._dimensionsAfterName, dimensionsAfterName)); + } + + private readonly _initializer: JLeftPadded | null; + + public get initializer(): Expression | null { + return this._initializer === null ? null : this._initializer.element; + } + + public withInitializer(initializer: Expression | null): JSVariableDeclarations.JSNamedVariable { + return this.padding.withInitializer(JLeftPadded.withElement(this._initializer, initializer)); + } + + private readonly _variableType: JavaType.Variable | null; + + public get variableType(): JavaType.Variable | null { + return this._variableType; + } + + public withVariableType(variableType: JavaType.Variable | null): JSVariableDeclarations.JSNamedVariable { + return variableType === this._variableType ? this : new JSVariableDeclarations.JSNamedVariable(this._id, this._prefix, this._markers, this._name, this._dimensionsAfterName, this._initializer, variableType); + } + + public acceptJavaScript

(v: JavaScriptVisitor

, p: P): J | null { + return v.visitJSVariableDeclarationsJSNamedVariable(this, p); + } + + public get type(): JavaType | null { + return extensions.getJavaType(this); + } + + public withType(type: JavaType): JSVariableDeclarations.JSNamedVariable { + return extensions.withJavaType(this, type); + } + + get padding() { + const t = this; + return new class { + public get dimensionsAfterName(): JLeftPadded[] { + return t._dimensionsAfterName; + } + public withDimensionsAfterName(dimensionsAfterName: JLeftPadded[]): JSVariableDeclarations.JSNamedVariable { + return t._dimensionsAfterName === dimensionsAfterName ? t : new JSVariableDeclarations.JSNamedVariable(t._id, t._prefix, t._markers, t._name, dimensionsAfterName, t._initializer, t._variableType); + } + public get initializer(): JLeftPadded | null { + return t._initializer; + } + public withInitializer(initializer: JLeftPadded | null): JSVariableDeclarations.JSNamedVariable { + return t._initializer === initializer ? t : new JSVariableDeclarations.JSNamedVariable(t._id, t._prefix, t._markers, t._name, t._dimensionsAfterName, initializer, t._variableType); + } + } + } + + } + +} + @LstType("org.openrewrite.javascript.tree.JS$NamespaceDeclaration") export class NamespaceDeclaration extends JSMixin(Object) implements Statement { public constructor(id: UUID, prefix: Space, markers: Markers, modifiers: Java.Modifier[], namespace: Space, name: JRightPadded, body: Java.Block) { diff --git a/openrewrite/src/javascript/visitor.ts b/openrewrite/src/javascript/visitor.ts index 4d152e06..e3d12b8d 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, JsBinary, ObjectBindingDeclarations, PropertyAssignment, ScopedVariableDeclarations, StatementExpression, TemplateExpression, Tuple, TypeDeclaration, TypeOf, TypeOperator, Unary, Union, Void, Yield, TypeInfo, NamespaceDeclaration} from "./tree"; +import {CompilationUnit, Alias, ArrowFunction, Await, DefaultType, Delete, Export, ExpressionStatement, FunctionType, JsImport, JsBinary, ObjectBindingDeclarations, PropertyAssignment, ScopedVariableDeclarations, StatementExpression, TemplateExpression, Tuple, TypeDeclaration, TypeOf, TypeOperator, Unary, Union, Void, Yield, TypeInfo, JSVariableDeclarations, NamespaceDeclaration} from "./tree"; import {Expression, J, JContainer, JLeftPadded, JRightPadded, Space, Statement} from "../java/tree"; import {JavaVisitor} from "../java"; import * as Java from "../java/tree"; @@ -395,6 +395,32 @@ export class JavaScriptVisitor

extends JavaVisitor

{ return typeInfo; } + public visitJSVariableDeclarations(jSVariableDeclarations: JSVariableDeclarations, p: P): J | null { + jSVariableDeclarations = jSVariableDeclarations.withPrefix(this.visitJsSpace(jSVariableDeclarations.prefix, JsSpace.Location.JSVARIABLE_DECLARATIONS_PREFIX, p)!); + let tempStatement = this.visitStatement(jSVariableDeclarations, p) as Statement; + if (!(tempStatement instanceof JSVariableDeclarations)) + { + return tempStatement; + } + jSVariableDeclarations = tempStatement as JSVariableDeclarations; + jSVariableDeclarations = jSVariableDeclarations.withMarkers(this.visitMarkers(jSVariableDeclarations.markers, p)); + jSVariableDeclarations = jSVariableDeclarations.withLeadingAnnotations(ListUtils.map(jSVariableDeclarations.leadingAnnotations, el => this.visitAndCast(el, p))); + jSVariableDeclarations = jSVariableDeclarations.withModifiers(ListUtils.map(jSVariableDeclarations.modifiers, el => this.visitAndCast(el, p))); + jSVariableDeclarations = jSVariableDeclarations.withTypeExpression(this.visitAndCast(jSVariableDeclarations.typeExpression, p)); + jSVariableDeclarations = jSVariableDeclarations.withVarargs(this.visitJsSpace(jSVariableDeclarations.varargs, JsSpace.Location.JSVARIABLE_DECLARATIONS_VARARGS, p)); + jSVariableDeclarations = jSVariableDeclarations.padding.withVariables(ListUtils.map(jSVariableDeclarations.padding.variables, el => this.visitJsRightPadded(el, JsRightPadded.Location.JSVARIABLE_DECLARATIONS_VARIABLES, p))); + return jSVariableDeclarations; + } + + public visitJSVariableDeclarationsJSNamedVariable(jSNamedVariable: JSVariableDeclarations.JSNamedVariable, p: P): J | null { + jSNamedVariable = jSNamedVariable.withPrefix(this.visitJsSpace(jSNamedVariable.prefix, JsSpace.Location.JSVARIABLE_DECLARATIONS_JSNAMED_VARIABLE_PREFIX, p)!); + jSNamedVariable = jSNamedVariable.withMarkers(this.visitMarkers(jSNamedVariable.markers, p)); + jSNamedVariable = jSNamedVariable.withName(this.visitAndCast(jSNamedVariable.name, p)!); + jSNamedVariable = jSNamedVariable.padding.withDimensionsAfterName(ListUtils.map(jSNamedVariable.padding.dimensionsAfterName, el => this.visitJsLeftPadded(el, JsLeftPadded.Location.JSVARIABLE_DECLARATIONS_JSNAMED_VARIABLE_DIMENSIONS_AFTER_NAME, p))); + jSNamedVariable = jSNamedVariable.padding.withInitializer(this.visitJsLeftPadded(jSNamedVariable.padding.initializer, JsLeftPadded.Location.JSVARIABLE_DECLARATIONS_JSNAMED_VARIABLE_INITIALIZER, p)); + return jSNamedVariable; + } + public visitNamespaceDeclaration(namespaceDeclaration: NamespaceDeclaration, p: P): J | null { namespaceDeclaration = namespaceDeclaration.withPrefix(this.visitJsSpace(namespaceDeclaration.prefix, JsSpace.Location.NAMESPACE_DECLARATION_PREFIX, p)!); let tempStatement = this.visitStatement(namespaceDeclaration, p) as Statement; @@ -405,7 +431,7 @@ export class JavaScriptVisitor

extends JavaVisitor

{ namespaceDeclaration = tempStatement as NamespaceDeclaration; namespaceDeclaration = namespaceDeclaration.withMarkers(this.visitMarkers(namespaceDeclaration.markers, p)); namespaceDeclaration = namespaceDeclaration.withModifiers(ListUtils.map(namespaceDeclaration.modifiers, el => this.visitAndCast(el, p))); - namespaceDeclaration = namespaceDeclaration.withNamespace(this.visitJsSpace(namespaceDeclaration.namespace, JsSpace.Location.NAMESPACE_KEYWORD_DECLARATION_PREFIX, p)!); + namespaceDeclaration = namespaceDeclaration.withNamespace(this.visitJsSpace(namespaceDeclaration.namespace, JsSpace.Location.NAMESPACE_DECLARATION_NAMESPACE, p)!); namespaceDeclaration = namespaceDeclaration.padding.withName(this.visitJsRightPadded(namespaceDeclaration.padding.name, JsRightPadded.Location.NAMESPACE_DECLARATION_NAME, p)!); namespaceDeclaration = namespaceDeclaration.withBody(this.visitAndCast(namespaceDeclaration.body, p)!); return namespaceDeclaration; diff --git a/openrewrite/test/javascript/parser/method.test.ts b/openrewrite/test/javascript/parser/method.test.ts index ac9debb9..8de8cf80 100644 --- a/openrewrite/test/javascript/parser/method.test.ts +++ b/openrewrite/test/javascript/parser/method.test.ts @@ -96,6 +96,19 @@ describe('method mapping', () => { ); }); + test('optional parameter with trailing comma', () => { + rewriteRun( + //language=typescript + typeScript(` + class Handler { + test( input ? : string , ) { + // hello world comment + } + } + `) + ); + }); + test('type parameters', () => { rewriteRun( //language=typescript diff --git a/openrewrite/test/javascript/testHarness.ts b/openrewrite/test/javascript/testHarness.ts index b53b8639..2c994586 100644 --- a/openrewrite/test/javascript/testHarness.ts +++ b/openrewrite/test/javascript/testHarness.ts @@ -1,6 +1,6 @@ // for side-effects (`java` must come after `javascript`) -import "../../dist/src/javascript/remote"; -import "../../dist/src/java/remote"; +import {registerCodecs as registerJsCodecs} from "../../dist/src/javascript/remote"; +import {registerCodecs as registerJavaCodecs} from "../../dist/src/java/remote"; import { Cursor, @@ -16,7 +16,7 @@ import { import * as J from "../../dist/src/java/tree"; import * as JS from "../../dist/src/javascript/tree"; import dedent from "dedent"; -import {RemotePrinterFactory, RemotingContext} from "@openrewrite/rewrite-remote"; +import {ReceiverContext, RemotePrinterFactory, RemotingContext, SenderContext} from "@openrewrite/rewrite-remote"; import net from "net"; import {JavaScriptParser, JavaScriptVisitor} from "../../dist/src/javascript"; import {ChildProcessWithoutNullStreams, spawn} from "node:child_process"; @@ -30,6 +30,9 @@ export interface RewriteTestOptions { export type SourceSpec = (options: RewriteTestOptions) => void; +registerJsCodecs(SenderContext, ReceiverContext, RemotingContext) +registerJavaCodecs(SenderContext, ReceiverContext, RemotingContext) + let client: net.Socket; let remoting: RemotingContext; let javaTestEngine: ChildProcessWithoutNullStreams 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 26a24c55..a435777f 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 @@ -373,6 +373,31 @@ public JS.TypeInfo visitTypeInfo(JS.TypeInfo typeInfo, ReceiverContext ctx) { return typeInfo; } + @Override + public JS.JSVariableDeclarations visitJSVariableDeclarations(JS.JSVariableDeclarations jSVariableDeclarations, ReceiverContext ctx) { + jSVariableDeclarations = jSVariableDeclarations.withId(ctx.receiveNonNullValue(jSVariableDeclarations.getId(), UUID.class)); + jSVariableDeclarations = jSVariableDeclarations.withPrefix(ctx.receiveNonNullNode(jSVariableDeclarations.getPrefix(), JavaScriptReceiver::receiveSpace)); + jSVariableDeclarations = jSVariableDeclarations.withMarkers(ctx.receiveNonNullNode(jSVariableDeclarations.getMarkers(), ctx::receiveMarkers)); + jSVariableDeclarations = jSVariableDeclarations.withLeadingAnnotations(ctx.receiveNonNullNodes(jSVariableDeclarations.getLeadingAnnotations(), ctx::receiveTree)); + jSVariableDeclarations = jSVariableDeclarations.withModifiers(ctx.receiveNonNullNodes(jSVariableDeclarations.getModifiers(), ctx::receiveTree)); + jSVariableDeclarations = jSVariableDeclarations.withTypeExpression(ctx.receiveNode(jSVariableDeclarations.getTypeExpression(), ctx::receiveTree)); + jSVariableDeclarations = jSVariableDeclarations.withVarargs(ctx.receiveNode(jSVariableDeclarations.getVarargs(), JavaScriptReceiver::receiveSpace)); + jSVariableDeclarations = jSVariableDeclarations.getPadding().withVariables(ctx.receiveNonNullNodes(jSVariableDeclarations.getPadding().getVariables(), JavaScriptReceiver::receiveRightPaddedTree)); + return jSVariableDeclarations; + } + + @Override + public JS.JSVariableDeclarations.JSNamedVariable visitJSVariableDeclarationsJSNamedVariable(JS.JSVariableDeclarations.JSNamedVariable jSNamedVariable, ReceiverContext ctx) { + jSNamedVariable = jSNamedVariable.withId(ctx.receiveNonNullValue(jSNamedVariable.getId(), UUID.class)); + jSNamedVariable = jSNamedVariable.withPrefix(ctx.receiveNonNullNode(jSNamedVariable.getPrefix(), JavaScriptReceiver::receiveSpace)); + jSNamedVariable = jSNamedVariable.withMarkers(ctx.receiveNonNullNode(jSNamedVariable.getMarkers(), ctx::receiveMarkers)); + jSNamedVariable = jSNamedVariable.withName(ctx.receiveNonNullNode(jSNamedVariable.getName(), ctx::receiveTree)); + jSNamedVariable = jSNamedVariable.withDimensionsAfterName(ctx.receiveNonNullNodes(jSNamedVariable.getDimensionsAfterName(), leftPaddedNodeReceiver(org.openrewrite.java.tree.Space.class))); + jSNamedVariable = jSNamedVariable.getPadding().withInitializer(ctx.receiveNode(jSNamedVariable.getPadding().getInitializer(), JavaScriptReceiver::receiveLeftPaddedTree)); + jSNamedVariable = jSNamedVariable.withVariableType(ctx.receiveValue(jSNamedVariable.getVariableType(), JavaType.Variable.class)); + return jSNamedVariable; + } + @Override public JS.NamespaceDeclaration visitNamespaceDeclaration(JS.NamespaceDeclaration namespaceDeclaration, ReceiverContext ctx) { namespaceDeclaration = namespaceDeclaration.withId(ctx.receiveNonNullValue(namespaceDeclaration.getId(), UUID.class)); @@ -1385,6 +1410,31 @@ public T create(Class type, ReceiverContext ctx) { ); } + if (type == JS.JSVariableDeclarations.class) { + return (T) new JS.JSVariableDeclarations( + ctx.receiveNonNullValue(null, UUID.class), + ctx.receiveNonNullNode(null, JavaScriptReceiver::receiveSpace), + ctx.receiveNonNullNode(null, ctx::receiveMarkers), + ctx.receiveNonNullNodes(null, ctx::receiveTree), + ctx.receiveNonNullNodes(null, ctx::receiveTree), + ctx.receiveNode(null, ctx::receiveTree), + ctx.receiveNode(null, JavaScriptReceiver::receiveSpace), + ctx.receiveNonNullNodes(null, JavaScriptReceiver::receiveRightPaddedTree) + ); + } + + if (type == JS.JSVariableDeclarations.JSNamedVariable.class) { + return (T) new JS.JSVariableDeclarations.JSNamedVariable( + ctx.receiveNonNullValue(null, UUID.class), + ctx.receiveNonNullNode(null, JavaScriptReceiver::receiveSpace), + ctx.receiveNonNullNode(null, ctx::receiveMarkers), + ctx.receiveNonNullNode(null, ctx::receiveTree), + ctx.receiveNonNullNodes(null, leftPaddedNodeReceiver(org.openrewrite.java.tree.Space.class)), + ctx.receiveNode(null, JavaScriptReceiver::receiveLeftPaddedTree), + ctx.receiveValue(null, JavaType.Variable.class) + ); + } + if (type == JS.NamespaceDeclaration.class) { return (T) new JS.NamespaceDeclaration( ctx.receiveNonNullValue(null, UUID.class), diff --git a/rewrite-javascript-remote/src/main/java/org/openrewrite/javascript/remote/JavaScriptSender.java b/rewrite-javascript-remote/src/main/java/org/openrewrite/javascript/remote/JavaScriptSender.java index 18d0edf0..21a0c695 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 @@ -356,6 +356,31 @@ public JS.TypeInfo visitTypeInfo(JS.TypeInfo typeInfo, SenderContext ctx) { return typeInfo; } + @Override + public JS.JSVariableDeclarations visitJSVariableDeclarations(JS.JSVariableDeclarations jSVariableDeclarations, SenderContext ctx) { + ctx.sendValue(jSVariableDeclarations, JS.JSVariableDeclarations::getId); + ctx.sendNode(jSVariableDeclarations, JS.JSVariableDeclarations::getPrefix, JavaScriptSender::sendSpace); + ctx.sendNode(jSVariableDeclarations, JS.JSVariableDeclarations::getMarkers, ctx::sendMarkers); + ctx.sendNodes(jSVariableDeclarations, JS.JSVariableDeclarations::getLeadingAnnotations, ctx::sendTree, Tree::getId); + ctx.sendNodes(jSVariableDeclarations, JS.JSVariableDeclarations::getModifiers, ctx::sendTree, Tree::getId); + ctx.sendNode(jSVariableDeclarations, JS.JSVariableDeclarations::getTypeExpression, ctx::sendTree); + ctx.sendNode(jSVariableDeclarations, JS.JSVariableDeclarations::getVarargs, JavaScriptSender::sendSpace); + ctx.sendNodes(jSVariableDeclarations, e -> e.getPadding().getVariables(), JavaScriptSender::sendRightPadded, e -> e.getElement().getId()); + return jSVariableDeclarations; + } + + @Override + public JS.JSVariableDeclarations.JSNamedVariable visitJSVariableDeclarationsJSNamedVariable(JS.JSVariableDeclarations.JSNamedVariable jSNamedVariable, SenderContext ctx) { + ctx.sendValue(jSNamedVariable, JS.JSVariableDeclarations.JSNamedVariable::getId); + ctx.sendNode(jSNamedVariable, JS.JSVariableDeclarations.JSNamedVariable::getPrefix, JavaScriptSender::sendSpace); + ctx.sendNode(jSNamedVariable, JS.JSVariableDeclarations.JSNamedVariable::getMarkers, ctx::sendMarkers); + ctx.sendNode(jSNamedVariable, JS.JSVariableDeclarations.JSNamedVariable::getName, ctx::sendTree); + ctx.sendNodes(jSNamedVariable, JS.JSVariableDeclarations.JSNamedVariable::getDimensionsAfterName, JavaScriptSender::sendLeftPadded, Function.identity()); + ctx.sendNode(jSNamedVariable, e -> e.getPadding().getInitializer(), JavaScriptSender::sendLeftPadded); + ctx.sendTypedValue(jSNamedVariable, JS.JSVariableDeclarations.JSNamedVariable::getVariableType); + return jSNamedVariable; + } + @Override public JS.NamespaceDeclaration visitNamespaceDeclaration(JS.NamespaceDeclaration namespaceDeclaration, SenderContext ctx) { ctx.sendValue(namespaceDeclaration, JS.NamespaceDeclaration::getId); 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 93c7a982..842e926d 100644 --- a/rewrite-javascript/src/main/java/org/openrewrite/javascript/JavaScriptVisitor.java +++ b/rewrite-javascript/src/main/java/org/openrewrite/javascript/JavaScriptVisitor.java @@ -594,6 +594,37 @@ public J visitTypeInfo(JS.TypeInfo typeInfo, P p) { return ti; } + public J visitJSVariableDeclarations(JS.JSVariableDeclarations multiVariable, P p) { + JS.JSVariableDeclarations m = multiVariable.withPrefix(this.visitSpace(multiVariable.getPrefix(), JsSpace.Location.JSVARIABLE_DECLARATIONS_PREFIX, p)); + m = m.withMarkers(this.visitMarkers(m.getMarkers(), p)); + Statement temp = (Statement)this.visitStatement(m, p); + if (!(temp instanceof J.VariableDeclarations)) { + return temp; + } else { + m = (JS.JSVariableDeclarations)temp; + m = m.withLeadingAnnotations(ListUtils.map(m.getLeadingAnnotations(), (a) -> this.visitAndCast(a, p))); + m = m.withModifiers(Objects.requireNonNull(ListUtils.map(m.getModifiers(), (e) -> (J.Modifier)this.visitAndCast(e, p)))); + m = m.withTypeExpression(this.visitAndCast(m.getTypeExpression(), p)); + m = m.withTypeExpression(m.getTypeExpression() == null ? null : this.visitTypeName(m.getTypeExpression(), p)); + m = m.withVarargs(m.getVarargs() == null ? null : this.visitSpace(m.getVarargs(), Space.Location.VARARGS, p)); + m = m.getPadding().withVariables(ListUtils.map(m.getPadding().getVariables(), (t) -> this.visitRightPadded(t, JsRightPadded.Location.JSNAMED_VARIABLE, p))); + return m; + } + } + + public J visitJSVariableDeclarationsJSNamedVariable(JS.JSVariableDeclarations.JSNamedVariable variable, P p) { + JS.JSVariableDeclarations.JSNamedVariable v = variable.withPrefix(this.visitSpace(variable.getPrefix(), JsSpace.Location.JSVARIABLE_PREFIX, p)); + v = v.withMarkers(this.visitMarkers(v.getMarkers(), p)); + v = v.withName(this.visitAndCast(v.getName(), p)); + v = v.withDimensionsAfterName(ListUtils.map(v.getDimensionsAfterName(), (dim) -> dim.withBefore(this.visitSpace(dim.getBefore(), Space.Location.DIMENSION_PREFIX, p)).withElement(this.visitSpace((Space)dim.getElement(), Space.Location.DIMENSION, p)))); + if (v.getPadding().getInitializer() != null) { + v = v.getPadding().withInitializer(this.visitLeftPadded(v.getPadding().getInitializer(), JsLeftPadded.Location.JSVARIABLE_INITIALIZER, p)); + } + + v = v.withVariableType((JavaType.Variable)this.visitType(v.getVariableType(), p)); + return v; + } + public J visitNamespaceDeclaration(JS.NamespaceDeclaration namespaceDeclaration, P p) { JS.NamespaceDeclaration ns = namespaceDeclaration; ns = ns.withPrefix(visitSpace(ns.getPrefix(), JsSpace.Location.NAMESPACE_DECLARATION_PREFIX, p)); diff --git a/rewrite-javascript/src/main/java/org/openrewrite/javascript/internal/JavaScriptPrinter.java b/rewrite-javascript/src/main/java/org/openrewrite/javascript/internal/JavaScriptPrinter.java index ce749c72..018a07e0 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 @@ -398,6 +398,11 @@ public J visitUnary(JS.Unary unary, PrintOutputCapture

p) { p.append("..."); visit(unary.getExpression(), p); break; + case Optional: + visit(unary.getExpression(), p); + visitSpace(unary.getPadding().getOperator().getBefore(), Space.Location.UNARY_OPERATOR, p); + p.append("?"); + break; default: break; } @@ -451,6 +456,52 @@ public J visitTypeInfo(JS.TypeInfo typeInfo, PrintOutputCapture

p) { return typeInfo; } + @Override + public J visitJSVariableDeclarations(JS.JSVariableDeclarations multiVariable, PrintOutputCapture

p) { + beforeSyntax(multiVariable, JsSpace.Location.JSVARIABLE_DECLARATIONS_PREFIX, p); + visit(multiVariable.getLeadingAnnotations(), p); + multiVariable.getModifiers().forEach(it -> visitModifier(it, p)); + + List> variables = multiVariable.getPadding().getVariables(); + for (int i = 0; i < variables.size(); i++) { + JRightPadded variable = variables.get(i); + beforeSyntax(variable.getElement(), JsSpace.Location.JSVARIABLE_PREFIX, p); + if (multiVariable.getVarargs() != null) { + p.append("..."); + } + visit(variable.getElement().getName(), p); + visitSpace(variable.getAfter(), JsSpace.Location.JSNAMED_VARIABLE_SUFFIX, p); + if (multiVariable.getTypeExpression() != null) { + visit(multiVariable.getTypeExpression(), p); + } + + if (variable.getElement().getInitializer() != null) { + JavaScriptPrinter.this.visitLeftPadded("=", + variable.getElement().getPadding().getInitializer(), JsLeftPadded.Location.JSVARIABLE_INITIALIZER, p); + } + + afterSyntax(variable.getElement(), p); + if (i < variables.size() - 1) { + p.append(","); + } else if (variable.getMarkers().findFirst(Semicolon.class).isPresent()) { + p.append(";"); + } + } + + afterSyntax(multiVariable, p); + return multiVariable; + } + + @Override + public J visitJSVariableDeclarationsJSNamedVariable(JS.JSVariableDeclarations.JSNamedVariable variable, PrintOutputCapture

p) { + beforeSyntax(variable, JsSpace.Location.JSVARIABLE_PREFIX, p); + visit(variable.getName(), p); + JLeftPadded initializer = variable.getPadding().getInitializer(); + visitLeftPadded("=", initializer, JsLeftPadded.Location.JSVARIABLE_INITIALIZER, p); + afterSyntax(variable, p); + return variable; + } + private class JavaScriptJavaPrinter extends JavaPrinter

{ @Override 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 98e88afd..9377d198 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 @@ -1921,7 +1921,9 @@ public List getSideEffects() { @SuppressWarnings("SwitchStatementWithTooFewBranches") public enum Type { - Spread; + Spread, + Optional, + ; public boolean isModifying() { switch (this) { @@ -2146,6 +2148,233 @@ public CoordinateBuilder.Expression getCoordinates() { } } + @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) + @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) + @RequiredArgsConstructor + @AllArgsConstructor(access = AccessLevel.PRIVATE) + final class JSVariableDeclarations implements JS, Statement, TypedTree { + @Nullable + @NonFinal + transient WeakReference padding; + + @With + @EqualsAndHashCode.Include + @Getter + UUID id; + + @With + @Getter + Space prefix; + + @With + @Getter + Markers markers; + + @With + @Getter + List leadingAnnotations; + + @With + @Getter + List modifiers; + + @With + @Nullable + @Getter + TypeTree typeExpression; + + @With + @Nullable + @Getter + Space varargs; + + List> variables; + + public List getVariables() { + return JRightPadded.getElements(variables); + } + + public JSVariableDeclarations withVariables(List vars) { + return getPadding().withVariables(JRightPadded.withElements(this.variables, vars)); + } + + @Override + public

J acceptJavaScript(JavaScriptVisitor

v, P p) { + return v.visitJSVariableDeclarations(this, p); + } + + @Override + @Transient + public CoordinateBuilder.Statement getCoordinates() { + return new CoordinateBuilder.Statement(this); + } + + public JavaType.@Nullable FullyQualified getTypeAsFullyQualified() { + return typeExpression == null ? null : TypeUtils.asFullyQualified(typeExpression.getType()); + } + + @Override + public @Nullable JavaType getType() { + return typeExpression == null ? null : typeExpression.getType(); + } + + @SuppressWarnings("unchecked") + @Override + public JSVariableDeclarations withType(@Nullable JavaType type) { + return typeExpression == null ? this : + withTypeExpression(typeExpression.withType(type)); + } + + @Override + public String toString() { + return withPrefix(Space.EMPTY).printTrimmed(new JavaPrinter<>()); + } + + @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) + @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) + @RequiredArgsConstructor + @AllArgsConstructor(access = AccessLevel.PRIVATE) + public static final class JSNamedVariable implements JS, NameTree { + @Nullable + @NonFinal + transient WeakReference padding; + + @With + @EqualsAndHashCode.Include + @Getter + UUID id; + + @With + @Getter + Space prefix; + + @With + @Getter + Markers markers; + + @With + @Getter + Expression name; + + @With + @Getter + List> dimensionsAfterName; + + @Nullable + JLeftPadded initializer; + + public @Nullable Expression getInitializer() { + return initializer == null ? null : initializer.getElement(); + } + + public JSNamedVariable withInitializer(@Nullable Expression initializer) { + if (initializer == null) { + return this.initializer == null ? this : new JSNamedVariable(id, prefix, markers, name, dimensionsAfterName, null, variableType); + } + return getPadding().withInitializer(JLeftPadded.withElement(this.initializer, initializer)); + } + + @With + @Getter + JavaType.@Nullable Variable variableType; + + @Override + public JavaType getType() { + return variableType != null ? variableType.getType() : null; + } + + @SuppressWarnings("unchecked") + @Override + public JSNamedVariable withType(@Nullable JavaType type) { + return variableType != null ? withVariableType(variableType.withType(type)) : this; + } + + @Override + public

J acceptJavaScript(JavaScriptVisitor

v, P p) { + return v.visitJSVariableDeclarationsJSNamedVariable(this, p); + } + + public Cursor getDeclaringScope(Cursor cursor) { + return cursor.dropParentUntil(it -> + it instanceof J.Block || + it instanceof J.Lambda || + it instanceof J.MethodDeclaration || + it == Cursor.ROOT_VALUE); + } + + public boolean isField(Cursor cursor) { + Cursor declaringScope = getDeclaringScope(cursor); + return declaringScope.getValue() instanceof J.Block && + declaringScope.getParentTreeCursor().getValue() instanceof J.ClassDeclaration; + } + + public JSNamedVariable.Padding getPadding() { + JSNamedVariable.Padding p; + if (this.padding == null) { + p = new JSNamedVariable.Padding(this); + this.padding = new WeakReference<>(p); + } else { + p = this.padding.get(); + if (p == null || p.t != this) { + p = new JSNamedVariable.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 JSNamedVariable t; + + public @Nullable JLeftPadded getInitializer() { + return t.initializer; + } + + public JSNamedVariable withInitializer(@Nullable JLeftPadded initializer) { + return t.initializer == initializer ? t : new JSNamedVariable(t.id, t.prefix, t.markers, t.name, t.dimensionsAfterName, initializer, t.variableType); + } + } + } + + public boolean hasModifier(Modifier.Type modifier) { + return Modifier.hasModifier(getModifiers(), modifier); + } + + public Padding getPadding() { + Padding p; + if (this.padding == null) { + p = new Padding(this); + this.padding = new WeakReference<>(p); + } else { + p = this.padding.get(); + if (p == null || p.t != this) { + p = new Padding(this); + this.padding = new WeakReference<>(p); + } + } + return p; + } + + @RequiredArgsConstructor + public static class Padding { + private final JSVariableDeclarations t; + + public List> getVariables() { + return t.variables; + } + + public JSVariableDeclarations withVariables(List> variables) { + return t.variables == variables ? t : new JSVariableDeclarations(t.id, t.prefix, t.markers, t.leadingAnnotations, t.modifiers, t.typeExpression, t.varargs, variables); + } + } + } + @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) @RequiredArgsConstructor diff --git a/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JsLeftPadded.java b/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JsLeftPadded.java index 3d21341f..3aabbe51 100644 --- a/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JsLeftPadded.java +++ b/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JsLeftPadded.java @@ -25,7 +25,8 @@ public enum Location { EXPORT_INITIALIZER(JsSpace.Location.EXPORT_INITIALIZER_PREFIX), IMPORT_INITIALIZER(JsSpace.Location.IMPORT_INITIALIZER_PREFIX), TYPE_DECLARATION_INITIALIZER(JsSpace.Location.TYPE_DECLARATION_INITIALIZER_PREFIX), - TYPE_OPERATOR(JsSpace.Location.TYPE_OPERATOR_PREFIX) + TYPE_OPERATOR(JsSpace.Location.TYPE_OPERATOR_PREFIX), + JSVARIABLE_INITIALIZER(JsSpace.Location.JSVARIABLE_INITIALIZER), ; private final JsSpace.Location beforeLocation; 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 292b82ec..a5e48ae8 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 @@ -33,6 +33,7 @@ public enum Location { TAG(JsSpace.Location.TAG_SUFFIX), TUPLE_ELEMENT_SUFFIX(JsSpace.Location.TUPLE_ELEMENT_SUFFIX), UNION_TYPE(JsSpace.Location.UNION_TYPE_SUFFIX), + JSNAMED_VARIABLE(JsSpace.Location.JSNAMED_VARIABLE_SUFFIX), NAMESPACE_DECLARATION_NAME(JsSpace.Location.NAMESPACE_DECLARATION_PREFIX); 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 791e2b49..9d510c2b 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 @@ -73,6 +73,10 @@ public enum Location { YIELD_PREFIX, TYPE_INFO_PREFIX, TYPE_REFERENCE_PREFIX, + JSVARIABLE_DECLARATIONS_PREFIX, + JSVARIABLE_PREFIX, + JSVARIABLE_INITIALIZER, + JSNAMED_VARIABLE_SUFFIX, NAMESPACE_DECLARATION_PREFIX, NAMESPACE_KEYWORD_DECLARATION_PREFIX }