From 5825f763ce69e71e3ba37c780c2c41c69ab3f8ea Mon Sep 17 00:00:00 2001 From: Andrii Rodionov Date: Fri, 6 Dec 2024 15:53:43 +0100 Subject: [PATCH 1/2] Implemented MappedType mapping Creates JS.MappedType classes hierarchy --- openrewrite/src/javascript/parser.ts | 70 +++- openrewrite/src/javascript/remote/receiver.ts | 69 +++- openrewrite/src/javascript/remote/sender.ts | 34 +- .../src/javascript/tree/support_types.ts | 11 + openrewrite/src/javascript/tree/tree.ts | 325 ++++++++++++++++++ openrewrite/src/javascript/visitor.ts | 48 ++- .../test/javascript/parser/mappedType.test.ts | 179 ++++++++++ .../javascript/remote/JavaScriptReceiver.java | 70 ++++ .../javascript/remote/JavaScriptSender.java | 35 ++ .../remote/JavaScriptValidator.java | 23 ++ .../javascript/JavaScriptVisitor.java | 51 +++ .../internal/JavaScriptPrinter.java | 61 +++- .../org/openrewrite/javascript/tree/JS.java | 324 ++++++++++++++++- .../javascript/tree/JsContainer.java | 2 +- .../javascript/tree/JsLeftPadded.java | 6 +- .../javascript/tree/JsRightPadded.java | 4 +- .../openrewrite/javascript/tree/JsSpace.java | 12 + 17 files changed, 1314 insertions(+), 10 deletions(-) create mode 100644 openrewrite/test/javascript/parser/mappedType.test.ts diff --git a/openrewrite/src/javascript/parser.ts b/openrewrite/src/javascript/parser.ts index 999c3948..4513f443 100644 --- a/openrewrite/src/javascript/parser.ts +++ b/openrewrite/src/javascript/parser.ts @@ -1440,7 +1440,75 @@ export class JavaScriptParserVisitor { } visitMappedType(node: ts.MappedTypeNode) { - return this.visitUnknown(node); + function hasPrefixToken(readonlyToken?: ts.ReadonlyKeyword | ts.PlusToken | ts.MinusToken): boolean { + if (readonlyToken && (readonlyToken.kind == ts.SyntaxKind.PlusToken || readonlyToken.kind == ts.SyntaxKind.MinusToken)) { + return true; + } else { + return false; + } + } + + function hasSuffixToken(questionToken?: ts.QuestionToken | ts.PlusToken | ts.MinusToken): boolean { + if (questionToken && (questionToken.kind == ts.SyntaxKind.PlusToken || questionToken.kind == ts.SyntaxKind.MinusToken)) { + return true; + } else { + return false; + } + } + + return new JS.MappedType( + randomId(), + this.prefix(node), + Markers.EMPTY, + hasPrefixToken(node.readonlyToken) ? this.leftPadded(this.prefix(node.readonlyToken!), + new J.Literal( + randomId(), + this.prefix(node.readonlyToken!), + Markers.EMPTY, + null, + node.readonlyToken!.getText(), + null, + this.mapPrimitiveType(node.readonlyToken!) + )) : null, + node.readonlyToken ? this.leftPadded(this.prefix(this.findChildNode(node, ts.SyntaxKind.ReadonlyKeyword)!), true) : this.leftPadded(Space.EMPTY, false), + new JS.MappedType.KeysRemapping( + randomId(), + this.prefix(this.findChildNode(node, ts.SyntaxKind.OpenBracketToken)!), + Markers.EMPTY, + this.rightPadded( + new JS.MappedType.MappedTypeParameter( + randomId(), + this.prefix(node.typeParameter), + Markers.EMPTY, + this.visit(node.typeParameter.name), + this.leftPadded(this.suffix(node.typeParameter.name), this.visit(node.typeParameter.constraint!)) + ), + this.suffix(node.typeParameter)), + node.nameType ? this.rightPadded(this.visit(node.nameType), this.suffix(node.nameType)) : null, + ), + hasSuffixToken(node.questionToken) ? this.leftPadded(this.prefix(node.questionToken!), + new J.Literal( + randomId(), + this.prefix(node.questionToken!), + Markers.EMPTY, + null, + node.questionToken!.getText(), + null, + this.mapPrimitiveType(node.questionToken!) + ) + ): null, + node.questionToken ? this.leftPadded(this.prefix(this.findChildNode(node, ts.SyntaxKind.QuestionToken)!), true) : this.leftPadded(Space.EMPTY, false), + new JContainer( + this.prefix(this.findChildNode(node, ts.SyntaxKind.ColonToken)!), + [this.rightPadded(this.visit(node.type!), this.suffix(node.type!)), + this.findChildNode(node, ts.SyntaxKind.SemicolonToken) ? + this.rightPadded(this.newJEmpty(Space.EMPTY, Markers.build([new Semicolon(randomId())])), this.prefix(node.getLastToken()!)) + : this.rightPadded(this.newJEmpty(), this.prefix(node.getLastToken()!)) + ], + Markers.EMPTY + ), + this.mapType(node) + ); } visitLiteralType(node: ts.LiteralTypeNode) { diff --git a/openrewrite/src/javascript/remote/receiver.ts b/openrewrite/src/javascript/remote/receiver.ts index 1df16aa2..fa26d9d0 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, ConditionalType, DefaultType, Delete, Export, ExpressionStatement, ExpressionWithTypeArguments, FunctionType, InferType, ImportType, JsImport, JsImportSpecifier, JsBinary, LiteralType, ObjectBindingDeclarations, PropertyAssignment, SatisfiesExpression, ScopedVariableDeclarations, StatementExpression, TaggedTemplateExpression, TemplateExpression, Tuple, TypeDeclaration, TypeOf, TypeQuery, TypeOperator, TypePredicate, Unary, Union, Intersection, Void, Yield, TypeInfo, JSVariableDeclarations, JSMethodDeclaration, JSForOfLoop, JSForInLoop, JSForInOfLoopControl, NamespaceDeclaration, FunctionDeclaration, TypeLiteral, IndexSignatureDeclaration, ArrayBindingPattern, BindingElement, ExportDeclaration, ExportAssignment, NamedExports, ExportSpecifier, IndexedAccessType, JsAssignmentOperation} from '../tree'; +import {JS, JsLeftPadded, JsRightPadded, JsContainer, JsSpace, CompilationUnit, Alias, ArrowFunction, Await, ConditionalType, DefaultType, Delete, Export, ExpressionStatement, ExpressionWithTypeArguments, FunctionType, InferType, ImportType, JsImport, JsImportSpecifier, JsBinary, LiteralType, MappedType, ObjectBindingDeclarations, PropertyAssignment, SatisfiesExpression, ScopedVariableDeclarations, StatementExpression, TaggedTemplateExpression, TemplateExpression, Tuple, TypeDeclaration, TypeOf, TypeQuery, TypeOperator, TypePredicate, Unary, Union, Intersection, Void, Yield, TypeInfo, JSVariableDeclarations, JSMethodDeclaration, JSForOfLoop, JSForInLoop, JSForInOfLoopControl, NamespaceDeclaration, FunctionDeclaration, TypeLiteral, IndexSignatureDeclaration, ArrayBindingPattern, BindingElement, ExportDeclaration, ExportAssignment, NamedExports, ExportSpecifier, IndexedAccessType, JsAssignmentOperation} from '../tree'; import {Expression, J, JContainer, JLeftPadded, JRightPadded, NameTree, Space, Statement, TypeTree, TypedTree} from "../../java"; import * as Java from "../../java/tree"; @@ -209,6 +209,38 @@ class Visitor extends JavaScriptVisitor { return literalType; } + public visitMappedType(mappedType: MappedType, ctx: ReceiverContext): J { + mappedType = mappedType.withId(ctx.receiveValue(mappedType.id, ValueType.UUID)!); + mappedType = mappedType.withPrefix(ctx.receiveNode(mappedType.prefix, receiveSpace)!); + mappedType = mappedType.withMarkers(ctx.receiveNode(mappedType.markers, ctx.receiveMarkers)!); + mappedType = mappedType.padding.withPrefixToken(ctx.receiveNode(mappedType.padding.prefixToken, receiveLeftPaddedTree)); + mappedType = mappedType.padding.withHasReadonly(ctx.receiveNode(mappedType.padding.hasReadonly, leftPaddedValueReceiver(ValueType.Primitive))!); + mappedType = mappedType.withKeysRemapping(ctx.receiveNode(mappedType.keysRemapping, ctx.receiveTree)!); + mappedType = mappedType.padding.withSuffixToken(ctx.receiveNode(mappedType.padding.suffixToken, receiveLeftPaddedTree)); + mappedType = mappedType.padding.withHasQuestionToken(ctx.receiveNode(mappedType.padding.hasQuestionToken, leftPaddedValueReceiver(ValueType.Primitive))!); + mappedType = mappedType.padding.withValueType(ctx.receiveNode(mappedType.padding.valueType, receiveContainer)!); + mappedType = mappedType.withType(ctx.receiveValue(mappedType.type, ValueType.Object)); + return mappedType; + } + + public visitMappedTypeKeysRemapping(keysRemapping: MappedType.KeysRemapping, ctx: ReceiverContext): J { + keysRemapping = keysRemapping.withId(ctx.receiveValue(keysRemapping.id, ValueType.UUID)!); + keysRemapping = keysRemapping.withPrefix(ctx.receiveNode(keysRemapping.prefix, receiveSpace)!); + keysRemapping = keysRemapping.withMarkers(ctx.receiveNode(keysRemapping.markers, ctx.receiveMarkers)!); + keysRemapping = keysRemapping.padding.withTypeParameter(ctx.receiveNode(keysRemapping.padding.typeParameter, receiveRightPaddedTree)!); + keysRemapping = keysRemapping.padding.withNameType(ctx.receiveNode(keysRemapping.padding.nameType, receiveRightPaddedTree)); + return keysRemapping; + } + + public visitMappedTypeMappedTypeParameter(mappedTypeParameter: MappedType.MappedTypeParameter, ctx: ReceiverContext): J { + mappedTypeParameter = mappedTypeParameter.withId(ctx.receiveValue(mappedTypeParameter.id, ValueType.UUID)!); + mappedTypeParameter = mappedTypeParameter.withPrefix(ctx.receiveNode(mappedTypeParameter.prefix, receiveSpace)!); + mappedTypeParameter = mappedTypeParameter.withMarkers(ctx.receiveNode(mappedTypeParameter.markers, ctx.receiveMarkers)!); + mappedTypeParameter = mappedTypeParameter.withName(ctx.receiveNode(mappedTypeParameter.name, ctx.receiveTree)!); + mappedTypeParameter = mappedTypeParameter.padding.withIterateType(ctx.receiveNode(mappedTypeParameter.padding.iterateType, receiveLeftPaddedTree)!); + return mappedTypeParameter; + } + public visitObjectBindingDeclarations(objectBindingDeclarations: ObjectBindingDeclarations, ctx: ReceiverContext): J { objectBindingDeclarations = objectBindingDeclarations.withId(ctx.receiveValue(objectBindingDeclarations.id, ValueType.UUID)!); objectBindingDeclarations = objectBindingDeclarations.withPrefix(ctx.receiveNode(objectBindingDeclarations.prefix, receiveSpace)!); @@ -1472,6 +1504,41 @@ class Factory implements ReceiverFactory { ); } + if (type === "org.openrewrite.javascript.tree.JS$MappedType") { + return new MappedType( + ctx.receiveValue(null, ValueType.UUID)!, + ctx.receiveNode(null, receiveSpace)!, + ctx.receiveNode(null, ctx.receiveMarkers)!, + ctx.receiveNode>(null, receiveLeftPaddedTree), + ctx.receiveNode>(null, leftPaddedValueReceiver(ValueType.Primitive))!, + ctx.receiveNode(null, ctx.receiveTree)!, + ctx.receiveNode>(null, receiveLeftPaddedTree), + ctx.receiveNode>(null, leftPaddedValueReceiver(ValueType.Primitive))!, + ctx.receiveNode>(null, receiveContainer)!, + ctx.receiveValue(null, ValueType.Object) + ); + } + + if (type === "org.openrewrite.javascript.tree.JS$MappedType$KeysRemapping") { + return new MappedType.KeysRemapping( + ctx.receiveValue(null, ValueType.UUID)!, + ctx.receiveNode(null, receiveSpace)!, + ctx.receiveNode(null, ctx.receiveMarkers)!, + ctx.receiveNode>(null, receiveRightPaddedTree)!, + ctx.receiveNode>(null, receiveRightPaddedTree) + ); + } + + if (type === "org.openrewrite.javascript.tree.JS$MappedType$MappedTypeParameter") { + return new MappedType.MappedTypeParameter( + ctx.receiveValue(null, ValueType.UUID)!, + ctx.receiveNode(null, receiveSpace)!, + ctx.receiveNode(null, ctx.receiveMarkers)!, + ctx.receiveNode(null, ctx.receiveTree)!, + ctx.receiveNode>(null, receiveLeftPaddedTree)! + ); + } + if (type === "org.openrewrite.javascript.tree.JS$ObjectBindingDeclarations") { return new ObjectBindingDeclarations( ctx.receiveValue(null, ValueType.UUID)!, diff --git a/openrewrite/src/javascript/remote/sender.ts b/openrewrite/src/javascript/remote/sender.ts index 504d4a47..f4dbc3cc 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, ConditionalType, DefaultType, Delete, Export, ExpressionStatement, ExpressionWithTypeArguments, FunctionType, InferType, ImportType, JsImport, JsImportSpecifier, JsBinary, LiteralType, ObjectBindingDeclarations, PropertyAssignment, SatisfiesExpression, ScopedVariableDeclarations, StatementExpression, TaggedTemplateExpression, TemplateExpression, Tuple, TypeDeclaration, TypeOf, TypeQuery, TypeOperator, TypePredicate, Unary, Union, Intersection, Void, Yield, TypeInfo, JSVariableDeclarations, JSMethodDeclaration, JSForOfLoop, JSForInLoop, JSForInOfLoopControl, NamespaceDeclaration, FunctionDeclaration, TypeLiteral, IndexSignatureDeclaration, ArrayBindingPattern, BindingElement, ExportDeclaration, ExportAssignment, NamedExports, ExportSpecifier, IndexedAccessType, JsAssignmentOperation} from '../tree'; +import {JS, JsLeftPadded, JsRightPadded, JsContainer, JsSpace, CompilationUnit, Alias, ArrowFunction, Await, ConditionalType, DefaultType, Delete, Export, ExpressionStatement, ExpressionWithTypeArguments, FunctionType, InferType, ImportType, JsImport, JsImportSpecifier, JsBinary, LiteralType, MappedType, ObjectBindingDeclarations, PropertyAssignment, SatisfiesExpression, ScopedVariableDeclarations, StatementExpression, TaggedTemplateExpression, TemplateExpression, Tuple, TypeDeclaration, TypeOf, TypeQuery, TypeOperator, TypePredicate, Unary, Union, Intersection, Void, Yield, TypeInfo, JSVariableDeclarations, JSMethodDeclaration, JSForOfLoop, JSForInLoop, JSForInOfLoopControl, NamespaceDeclaration, FunctionDeclaration, TypeLiteral, IndexSignatureDeclaration, ArrayBindingPattern, BindingElement, ExportDeclaration, ExportAssignment, NamedExports, ExportSpecifier, IndexedAccessType, JsAssignmentOperation} from '../tree'; import {Expression, J, JContainer, JLeftPadded, JRightPadded, Space, Statement} from "../../java"; import * as Java from "../../java/tree"; @@ -204,6 +204,38 @@ class Visitor extends JavaScriptVisitor { return literalType; } + public visitMappedType(mappedType: MappedType, ctx: SenderContext): J { + ctx.sendValue(mappedType, v => v.id, ValueType.UUID); + ctx.sendNode(mappedType, v => v.prefix, Visitor.sendSpace); + ctx.sendNode(mappedType, v => v.markers, ctx.sendMarkers); + ctx.sendNode(mappedType, v => v.padding.prefixToken, Visitor.sendLeftPadded(ValueType.Tree)); + ctx.sendNode(mappedType, v => v.padding.hasReadonly, Visitor.sendLeftPadded(ValueType.Primitive)); + ctx.sendNode(mappedType, v => v.keysRemapping, ctx.sendTree); + ctx.sendNode(mappedType, v => v.padding.suffixToken, Visitor.sendLeftPadded(ValueType.Tree)); + ctx.sendNode(mappedType, v => v.padding.hasQuestionToken, Visitor.sendLeftPadded(ValueType.Primitive)); + ctx.sendNode(mappedType, v => v.padding.valueType, Visitor.sendContainer(ValueType.Tree)); + ctx.sendTypedValue(mappedType, v => v.type, ValueType.Object); + return mappedType; + } + + public visitMappedTypeKeysRemapping(keysRemapping: MappedType.KeysRemapping, ctx: SenderContext): J { + ctx.sendValue(keysRemapping, v => v.id, ValueType.UUID); + ctx.sendNode(keysRemapping, v => v.prefix, Visitor.sendSpace); + ctx.sendNode(keysRemapping, v => v.markers, ctx.sendMarkers); + ctx.sendNode(keysRemapping, v => v.padding.typeParameter, Visitor.sendRightPadded(ValueType.Tree)); + ctx.sendNode(keysRemapping, v => v.padding.nameType, Visitor.sendRightPadded(ValueType.Tree)); + return keysRemapping; + } + + public visitMappedTypeMappedTypeParameter(mappedTypeParameter: MappedType.MappedTypeParameter, ctx: SenderContext): J { + ctx.sendValue(mappedTypeParameter, v => v.id, ValueType.UUID); + ctx.sendNode(mappedTypeParameter, v => v.prefix, Visitor.sendSpace); + ctx.sendNode(mappedTypeParameter, v => v.markers, ctx.sendMarkers); + ctx.sendNode(mappedTypeParameter, v => v.name, ctx.sendTree); + ctx.sendNode(mappedTypeParameter, v => v.padding.iterateType, Visitor.sendLeftPadded(ValueType.Tree)); + return mappedTypeParameter; + } + public visitObjectBindingDeclarations(objectBindingDeclarations: ObjectBindingDeclarations, ctx: SenderContext): J { ctx.sendValue(objectBindingDeclarations, v => v.id, ValueType.UUID); ctx.sendNode(objectBindingDeclarations, v => v.prefix, Visitor.sendSpace); diff --git a/openrewrite/src/javascript/tree/support_types.ts b/openrewrite/src/javascript/tree/support_types.ts index 741cc6e7..ef4c1620 100644 --- a/openrewrite/src/javascript/tree/support_types.ts +++ b/openrewrite/src/javascript/tree/support_types.ts @@ -256,6 +256,9 @@ export namespace JsSpace { INDEXED_ACCESS_TYPE_INDEX_TYPE_SUFFIX, INDEXED_ACCESS_TYPE_INDEX_TYPE_ELEMENT_SUFFIX, JS_ASSIGNMENT_OPERATION_PREFIX, + MAPPED_TYPE_PREFIX, + MAPPED_TYPE_KEYS_REMAPPING_PREFIX, + MAPPED_TYPE_MAPPED_TYPE_PARAMETER_PREFIX, } } export namespace JsLeftPadded { @@ -293,6 +296,11 @@ export namespace JsLeftPadded { FUNCTION_DECLARATION_ASTERISK_TOKEN, FUNCTION_DECLARATION_NAME, JS_ASSIGNMENT_OPERATION_OPERATOR, + MAPPED_TYPE_PREFIX_TOKEN, + MAPPED_TYPE_SUFFIX_TOKEN, + MAPPED_TYPE_MAPPED_TYPE_PARAMETER_ITERATE_TYPE, + MAPPED_TYPE_HAS_READONLY, + MAPPED_TYPE_HAS_QUESTION_TOKEN, } } export namespace JsRightPadded { @@ -319,6 +327,8 @@ export namespace JsRightPadded { IMPORT_TYPE_HAS_TYPEOF, INDEXED_ACCESS_TYPE_INDEX_TYPE, INDEXED_ACCESS_TYPE_INDEX_TYPE_ELEMENT, + MAPPED_TYPE_KEYS_REMAPPING_TYPE_PARAMETER, + MAPPED_TYPE_KEYS_REMAPPING_NAME_TYPE, } } export namespace JsContainer { @@ -339,5 +349,6 @@ export namespace JsContainer { CONDITIONAL_TYPE_CONDITION, IMPORT_TYPE_TYPE_ARGUMENTS, NAMED_EXPORTS_ELEMENTS, + MAPPED_TYPE_VALUE_TYPE, } } diff --git a/openrewrite/src/javascript/tree/tree.ts b/openrewrite/src/javascript/tree/tree.ts index 5e0fa33a..05dcfd3e 100644 --- a/openrewrite/src/javascript/tree/tree.ts +++ b/openrewrite/src/javascript/tree/tree.ts @@ -1636,6 +1636,331 @@ export class LiteralType extends JSMixin(Object) implements Expression, TypeTree } +@LstType("org.openrewrite.javascript.tree.JS$MappedType") +export class MappedType extends JSMixin(Object) implements Expression, TypeTree { + public constructor(id: UUID, prefix: Space, markers: Markers, prefixToken: JLeftPadded | null, hasReadonly: JLeftPadded, keysRemapping: MappedType.KeysRemapping, suffixToken: JLeftPadded | null, hasQuestionToken: JLeftPadded, valueType: JContainer, _type: JavaType | null) { + super(); + this._id = id; + this._prefix = prefix; + this._markers = markers; + this._prefixToken = prefixToken; + this._hasReadonly = hasReadonly; + this._keysRemapping = keysRemapping; + this._suffixToken = suffixToken; + this._hasQuestionToken = hasQuestionToken; + this._valueType = valueType; + this._type = _type; + } + + private readonly _id: UUID; + + public get id(): UUID { + return this._id; + } + + public withId(id: UUID): MappedType { + return id === this._id ? this : new MappedType(id, this._prefix, this._markers, this._prefixToken, this._hasReadonly, this._keysRemapping, this._suffixToken, this._hasQuestionToken, this._valueType, this._type); + } + + private readonly _prefix: Space; + + public get prefix(): Space { + return this._prefix; + } + + public withPrefix(prefix: Space): MappedType { + return prefix === this._prefix ? this : new MappedType(this._id, prefix, this._markers, this._prefixToken, this._hasReadonly, this._keysRemapping, this._suffixToken, this._hasQuestionToken, this._valueType, this._type); + } + + private readonly _markers: Markers; + + public get markers(): Markers { + return this._markers; + } + + public withMarkers(markers: Markers): MappedType { + return markers === this._markers ? this : new MappedType(this._id, this._prefix, markers, this._prefixToken, this._hasReadonly, this._keysRemapping, this._suffixToken, this._hasQuestionToken, this._valueType, this._type); + } + + private readonly _prefixToken: JLeftPadded | null; + + public get prefixToken(): Java.Literal | null { + return this._prefixToken === null ? null : this._prefixToken.element; + } + + public withPrefixToken(prefixToken: Java.Literal | null): MappedType { + return this.padding.withPrefixToken(JLeftPadded.withElement(this._prefixToken, prefixToken)); + } + + private readonly _hasReadonly: JLeftPadded; + + public get hasReadonly(): boolean { + return this._hasReadonly.element; + } + + public withHasReadonly(hasReadonly: boolean): MappedType { + return this.padding.withHasReadonly(this._hasReadonly.withElement(hasReadonly)); + } + + private readonly _keysRemapping: MappedType.KeysRemapping; + + public get keysRemapping(): MappedType.KeysRemapping { + return this._keysRemapping; + } + + public withKeysRemapping(keysRemapping: MappedType.KeysRemapping): MappedType { + return keysRemapping === this._keysRemapping ? this : new MappedType(this._id, this._prefix, this._markers, this._prefixToken, this._hasReadonly, keysRemapping, this._suffixToken, this._hasQuestionToken, this._valueType, this._type); + } + + private readonly _suffixToken: JLeftPadded | null; + + public get suffixToken(): Java.Literal | null { + return this._suffixToken === null ? null : this._suffixToken.element; + } + + public withSuffixToken(suffixToken: Java.Literal | null): MappedType { + return this.padding.withSuffixToken(JLeftPadded.withElement(this._suffixToken, suffixToken)); + } + + private readonly _hasQuestionToken: JLeftPadded; + + public get hasQuestionToken(): boolean { + return this._hasQuestionToken.element; + } + + public withHasQuestionToken(hasQuestionToken: boolean): MappedType { + return this.padding.withHasQuestionToken(this._hasQuestionToken.withElement(hasQuestionToken)); + } + + private readonly _valueType: JContainer; + + public get valueType(): TypeTree[] { + return this._valueType.elements; + } + + public withValueType(valueType: TypeTree[]): MappedType { + return this.padding.withValueType(JContainer.withElements(this._valueType, valueType)); + } + + private readonly _type: JavaType | null; + + public get type(): JavaType | null { + return this._type; + } + + public withType(_type: JavaType | null): MappedType { + return _type === this._type ? this : new MappedType(this._id, this._prefix, this._markers, this._prefixToken, this._hasReadonly, this._keysRemapping, this._suffixToken, this._hasQuestionToken, this._valueType, _type); + } + + public acceptJavaScript

(v: JavaScriptVisitor

, p: P): J | null { + return v.visitMappedType(this, p); + } + + get padding() { + const t = this; + return new class { + public get prefixToken(): JLeftPadded | null { + return t._prefixToken; + } + public withPrefixToken(prefixToken: JLeftPadded | null): MappedType { + return t._prefixToken === prefixToken ? t : new MappedType(t._id, t._prefix, t._markers, prefixToken, t._hasReadonly, t._keysRemapping, t._suffixToken, t._hasQuestionToken, t._valueType, t._type); + } + public get hasReadonly(): JLeftPadded { + return t._hasReadonly; + } + public withHasReadonly(hasReadonly: JLeftPadded): MappedType { + return t._hasReadonly === hasReadonly ? t : new MappedType(t._id, t._prefix, t._markers, t._prefixToken, hasReadonly, t._keysRemapping, t._suffixToken, t._hasQuestionToken, t._valueType, t._type); + } + public get suffixToken(): JLeftPadded | null { + return t._suffixToken; + } + public withSuffixToken(suffixToken: JLeftPadded | null): MappedType { + return t._suffixToken === suffixToken ? t : new MappedType(t._id, t._prefix, t._markers, t._prefixToken, t._hasReadonly, t._keysRemapping, suffixToken, t._hasQuestionToken, t._valueType, t._type); + } + public get hasQuestionToken(): JLeftPadded { + return t._hasQuestionToken; + } + public withHasQuestionToken(hasQuestionToken: JLeftPadded): MappedType { + return t._hasQuestionToken === hasQuestionToken ? t : new MappedType(t._id, t._prefix, t._markers, t._prefixToken, t._hasReadonly, t._keysRemapping, t._suffixToken, hasQuestionToken, t._valueType, t._type); + } + public get valueType(): JContainer { + return t._valueType; + } + public withValueType(valueType: JContainer): MappedType { + return t._valueType === valueType ? t : new MappedType(t._id, t._prefix, t._markers, t._prefixToken, t._hasReadonly, t._keysRemapping, t._suffixToken, t._hasQuestionToken, valueType, t._type); + } + } + } + +} + +export namespace MappedType { + @LstType("org.openrewrite.javascript.tree.JS$MappedType$KeysRemapping") + export class KeysRemapping extends JSMixin(Object) implements Statement { + public constructor(id: UUID, prefix: Space, markers: Markers, typeParameter: JRightPadded, nameType: JRightPadded | null) { + super(); + this._id = id; + this._prefix = prefix; + this._markers = markers; + this._typeParameter = typeParameter; + this._nameType = nameType; + } + + private readonly _id: UUID; + + public get id(): UUID { + return this._id; + } + + public withId(id: UUID): MappedType.KeysRemapping { + return id === this._id ? this : new MappedType.KeysRemapping(id, this._prefix, this._markers, this._typeParameter, this._nameType); + } + + private readonly _prefix: Space; + + public get prefix(): Space { + return this._prefix; + } + + public withPrefix(prefix: Space): MappedType.KeysRemapping { + return prefix === this._prefix ? this : new MappedType.KeysRemapping(this._id, prefix, this._markers, this._typeParameter, this._nameType); + } + + private readonly _markers: Markers; + + public get markers(): Markers { + return this._markers; + } + + public withMarkers(markers: Markers): MappedType.KeysRemapping { + return markers === this._markers ? this : new MappedType.KeysRemapping(this._id, this._prefix, markers, this._typeParameter, this._nameType); + } + + private readonly _typeParameter: JRightPadded; + + public get typeParameter(): MappedType.MappedTypeParameter { + return this._typeParameter.element; + } + + public withTypeParameter(typeParameter: MappedType.MappedTypeParameter): MappedType.KeysRemapping { + return this.padding.withTypeParameter(this._typeParameter.withElement(typeParameter)); + } + + private readonly _nameType: JRightPadded | null; + + public get nameType(): Expression | null { + return this._nameType === null ? null : this._nameType.element; + } + + public withNameType(nameType: Expression | null): MappedType.KeysRemapping { + return this.padding.withNameType(JRightPadded.withElement(this._nameType, nameType)); + } + + public acceptJavaScript

(v: JavaScriptVisitor

, p: P): J | null { + return v.visitMappedTypeKeysRemapping(this, p); + } + + get padding() { + const t = this; + return new class { + public get typeParameter(): JRightPadded { + return t._typeParameter; + } + public withTypeParameter(typeParameter: JRightPadded): MappedType.KeysRemapping { + return t._typeParameter === typeParameter ? t : new MappedType.KeysRemapping(t._id, t._prefix, t._markers, typeParameter, t._nameType); + } + public get nameType(): JRightPadded | null { + return t._nameType; + } + public withNameType(nameType: JRightPadded | null): MappedType.KeysRemapping { + return t._nameType === nameType ? t : new MappedType.KeysRemapping(t._id, t._prefix, t._markers, t._typeParameter, nameType); + } + } + } + + } + + @LstType("org.openrewrite.javascript.tree.JS$MappedType$MappedTypeParameter") + export class MappedTypeParameter extends JSMixin(Object) implements Statement { + public constructor(id: UUID, prefix: Space, markers: Markers, name: Expression, iterateType: JLeftPadded) { + super(); + this._id = id; + this._prefix = prefix; + this._markers = markers; + this._name = name; + this._iterateType = iterateType; + } + + private readonly _id: UUID; + + public get id(): UUID { + return this._id; + } + + public withId(id: UUID): MappedType.MappedTypeParameter { + return id === this._id ? this : new MappedType.MappedTypeParameter(id, this._prefix, this._markers, this._name, this._iterateType); + } + + private readonly _prefix: Space; + + public get prefix(): Space { + return this._prefix; + } + + public withPrefix(prefix: Space): MappedType.MappedTypeParameter { + return prefix === this._prefix ? this : new MappedType.MappedTypeParameter(this._id, prefix, this._markers, this._name, this._iterateType); + } + + private readonly _markers: Markers; + + public get markers(): Markers { + return this._markers; + } + + public withMarkers(markers: Markers): MappedType.MappedTypeParameter { + return markers === this._markers ? this : new MappedType.MappedTypeParameter(this._id, this._prefix, markers, this._name, this._iterateType); + } + + private readonly _name: Expression; + + public get name(): Expression { + return this._name; + } + + public withName(name: Expression): MappedType.MappedTypeParameter { + return name === this._name ? this : new MappedType.MappedTypeParameter(this._id, this._prefix, this._markers, name, this._iterateType); + } + + private readonly _iterateType: JLeftPadded; + + public get iterateType(): TypeTree { + return this._iterateType.element; + } + + public withIterateType(iterateType: TypeTree): MappedType.MappedTypeParameter { + return this.padding.withIterateType(this._iterateType.withElement(iterateType)); + } + + public acceptJavaScript

(v: JavaScriptVisitor

, p: P): J | null { + return v.visitMappedTypeMappedTypeParameter(this, p); + } + + get padding() { + const t = this; + return new class { + public get iterateType(): JLeftPadded { + return t._iterateType; + } + public withIterateType(iterateType: JLeftPadded): MappedType.MappedTypeParameter { + return t._iterateType === iterateType ? t : new MappedType.MappedTypeParameter(t._id, t._prefix, t._markers, t._name, iterateType); + } + } + } + + } + +} + @LstType("org.openrewrite.javascript.tree.JS$ObjectBindingDeclarations") export class ObjectBindingDeclarations extends JSMixin(Object) implements Expression, TypedTree { public constructor(id: UUID, prefix: Space, markers: Markers, leadingAnnotations: Java.Annotation[], modifiers: Java.Modifier[], typeExpression: TypeTree | null, bindings: JContainer, initializer: JLeftPadded | null) { diff --git a/openrewrite/src/javascript/visitor.ts b/openrewrite/src/javascript/visitor.ts index afc0cf31..09eda2e1 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, ConditionalType, DefaultType, Delete, Export, ExpressionStatement, ExpressionWithTypeArguments, FunctionType, InferType, ImportType, JsImport, JsImportSpecifier, JsBinary, LiteralType, ObjectBindingDeclarations, PropertyAssignment, SatisfiesExpression, ScopedVariableDeclarations, StatementExpression, TaggedTemplateExpression, TemplateExpression, Tuple, TypeDeclaration, TypeOf, TypeQuery, TypeOperator, TypePredicate, Unary, Union, Intersection, Void, Yield, TypeInfo, JSVariableDeclarations, JSMethodDeclaration, JSForOfLoop, JSForInLoop, JSForInOfLoopControl, NamespaceDeclaration, FunctionDeclaration, TypeLiteral, IndexSignatureDeclaration, ArrayBindingPattern, BindingElement, ExportDeclaration, ExportAssignment, NamedExports, ExportSpecifier, IndexedAccessType, JsAssignmentOperation} from "./tree"; +import {CompilationUnit, Alias, ArrowFunction, Await, ConditionalType, DefaultType, Delete, Export, ExpressionStatement, ExpressionWithTypeArguments, FunctionType, InferType, ImportType, JsImport, JsImportSpecifier, JsBinary, LiteralType, MappedType, ObjectBindingDeclarations, PropertyAssignment, SatisfiesExpression, ScopedVariableDeclarations, StatementExpression, TaggedTemplateExpression, TemplateExpression, Tuple, TypeDeclaration, TypeOf, TypeQuery, TypeOperator, TypePredicate, Unary, Union, Intersection, Void, Yield, TypeInfo, JSVariableDeclarations, JSMethodDeclaration, JSForOfLoop, JSForInLoop, JSForInOfLoopControl, NamespaceDeclaration, FunctionDeclaration, TypeLiteral, IndexSignatureDeclaration, ArrayBindingPattern, BindingElement, ExportDeclaration, ExportAssignment, NamedExports, ExportSpecifier, IndexedAccessType, JsAssignmentOperation} from "./tree"; import {Expression, J, JContainer, JLeftPadded, JRightPadded, Space, Statement} from "../java/tree"; import {JavaVisitor} from "../java"; import * as Java from "../java/tree"; @@ -261,6 +261,52 @@ export class JavaScriptVisitor

extends JavaVisitor

{ return literalType; } + public visitMappedType(mappedType: MappedType, p: P): J | null { + mappedType = mappedType.withPrefix(this.visitJsSpace(mappedType.prefix, JsSpace.Location.MAPPED_TYPE_PREFIX, p)!); + let tempExpression = this.visitExpression(mappedType, p) as Expression; + if (!(tempExpression instanceof MappedType)) + { + return tempExpression; + } + mappedType = tempExpression as MappedType; + mappedType = mappedType.withMarkers(this.visitMarkers(mappedType.markers, p)); + mappedType = mappedType.padding.withPrefixToken(this.visitJsLeftPadded(mappedType.padding.prefixToken, JsLeftPadded.Location.MAPPED_TYPE_PREFIX_TOKEN, p)); + mappedType = mappedType.padding.withHasReadonly(this.visitJsLeftPadded(mappedType.padding.hasReadonly, JsLeftPadded.Location.MAPPED_TYPE_HAS_READONLY, p)!); + mappedType = mappedType.withKeysRemapping(this.visitAndCast(mappedType.keysRemapping, p)!); + mappedType = mappedType.padding.withSuffixToken(this.visitJsLeftPadded(mappedType.padding.suffixToken, JsLeftPadded.Location.MAPPED_TYPE_SUFFIX_TOKEN, p)); + mappedType = mappedType.padding.withHasQuestionToken(this.visitJsLeftPadded(mappedType.padding.hasQuestionToken, JsLeftPadded.Location.MAPPED_TYPE_HAS_QUESTION_TOKEN, p)!); + mappedType = mappedType.padding.withValueType(this.visitJsContainer(mappedType.padding.valueType, JsContainer.Location.MAPPED_TYPE_VALUE_TYPE, p)!); + return mappedType; + } + + public visitMappedTypeKeysRemapping(keysRemapping: MappedType.KeysRemapping, p: P): J | null { + keysRemapping = keysRemapping.withPrefix(this.visitJsSpace(keysRemapping.prefix, JsSpace.Location.MAPPED_TYPE_KEYS_REMAPPING_PREFIX, p)!); + let tempStatement = this.visitStatement(keysRemapping, p) as Statement; + if (!(tempStatement instanceof MappedType.KeysRemapping)) + { + return tempStatement; + } + keysRemapping = tempStatement as MappedType.KeysRemapping; + keysRemapping = keysRemapping.withMarkers(this.visitMarkers(keysRemapping.markers, p)); + keysRemapping = keysRemapping.padding.withTypeParameter(this.visitJsRightPadded(keysRemapping.padding.typeParameter, JsRightPadded.Location.MAPPED_TYPE_KEYS_REMAPPING_TYPE_PARAMETER, p)!); + keysRemapping = keysRemapping.padding.withNameType(this.visitJsRightPadded(keysRemapping.padding.nameType, JsRightPadded.Location.MAPPED_TYPE_KEYS_REMAPPING_NAME_TYPE, p)); + return keysRemapping; + } + + public visitMappedTypeMappedTypeParameter(mappedTypeParameter: MappedType.MappedTypeParameter, p: P): J | null { + mappedTypeParameter = mappedTypeParameter.withPrefix(this.visitJsSpace(mappedTypeParameter.prefix, JsSpace.Location.MAPPED_TYPE_MAPPED_TYPE_PARAMETER_PREFIX, p)!); + let tempStatement = this.visitStatement(mappedTypeParameter, p) as Statement; + if (!(tempStatement instanceof MappedType.MappedTypeParameter)) + { + return tempStatement; + } + mappedTypeParameter = tempStatement as MappedType.MappedTypeParameter; + mappedTypeParameter = mappedTypeParameter.withMarkers(this.visitMarkers(mappedTypeParameter.markers, p)); + mappedTypeParameter = mappedTypeParameter.withName(this.visitAndCast(mappedTypeParameter.name, p)!); + mappedTypeParameter = mappedTypeParameter.padding.withIterateType(this.visitJsLeftPadded(mappedTypeParameter.padding.iterateType, JsLeftPadded.Location.MAPPED_TYPE_MAPPED_TYPE_PARAMETER_ITERATE_TYPE, p)!); + return mappedTypeParameter; + } + public visitObjectBindingDeclarations(objectBindingDeclarations: ObjectBindingDeclarations, p: P): J | null { objectBindingDeclarations = objectBindingDeclarations.withPrefix(this.visitJsSpace(objectBindingDeclarations.prefix, JsSpace.Location.OBJECT_BINDING_DECLARATIONS_PREFIX, p)!); let tempExpression = this.visitExpression(objectBindingDeclarations, p) as Expression; diff --git a/openrewrite/test/javascript/parser/mappedType.test.ts b/openrewrite/test/javascript/parser/mappedType.test.ts new file mode 100644 index 00000000..2a1164ec --- /dev/null +++ b/openrewrite/test/javascript/parser/mappedType.test.ts @@ -0,0 +1,179 @@ +import {connect, disconnect, rewriteRun, typeScript} from '../testHarness'; + +describe('mapped type mapping', () => { + beforeAll(() => connect()); + afterAll(() => disconnect()); + + test('simple', () => { + rewriteRun( + //language=typescript + typeScript(` + type OptionsFlags = { + [Property in keyof Type]: /*a*/boolean/*b*/ + }; + `) + ); + }); + + test('with readonly', () => { + rewriteRun( + //language=typescript + typeScript(` + type ReadonlyType = { + /*a*/readonly/*b*/ [K in keyof T]: T[K]; + }; + `) + ); + }); + + test('with -readonly', () => { + rewriteRun( + //language=typescript + typeScript(` + type CreateMutable = { + /*a*/-/*b*/readonly/*c*/[Property in keyof Type]: Type[Property]; + }; + `) + ); + }); + + test('with suffix +?', () => { + rewriteRun( + //language=typescript + typeScript(` + type Concrete = { + [Property in keyof Type]+?: Type[Property]; + }; + `) + ); + }); + + test('with suffix -?', () => { + rewriteRun( + //language=typescript + typeScript(` + type Concrete = { + [Property in keyof Type]/*a*/-/*b*/?/*c*/: Type[Property]; + }; + `) + ); + }); + + test('record mapped type', () => { + rewriteRun( + //language=typescript + typeScript(` + type Record = { + [P in K]: T; + /*a*/}/*b*/ + ; + `) + ); + }); + + test('record mapped type with comments', () => { + rewriteRun( + //language=typescript + typeScript(` + type Record = /*a*/{ /*b*/ + /*0*/[/*1*/P /*2*/in /*3*/K/*4*/]/*c*/:/*d*/ T/*e*/;/*f*/ + }/*g*/; + `) + ); + }); + + test('mapped type with "as" nameType', () => { + rewriteRun( + //language=typescript + typeScript(` + type ReadonlyRenamed = { + + readonly [K in keyof T as \`readonly_\${string & K\}\`]: T[K]; + }; + `) + ); + }); + + test('recursive mapped types', () => { + rewriteRun( + //language=typescript + typeScript(` + type DeepPartial = { + [K in keyof T]/*a*/?/*b*/: T[K] extends object /*c*/? DeepPartial /*d*/: T[K]; + }; + `) + ); + }); + + test('with function type', () => { + rewriteRun( + //language=typescript + typeScript(` + type Getters = { + [Property in keyof Type as \`get\${Capitalize/*a*/}\`]: () => Type[Property] /*b*/ + }; + `) + ); + }); + + test('with repeating tokens', () => { + rewriteRun( + //language=typescript + typeScript(` + type EventConfig = { + /*a*/[/*b*/E /*c*/in /*d*/Events as /*e*/E/*f*/[/*g*/"kind"/*h*/]/*i*/]/*j*/:/*k*/ (/*l*/event/*m*/: /*n*/E)/*o*/ => void; + } + `) + ); + }); + + test('with conditional', () => { + rewriteRun( + //language=typescript + typeScript(` + type ExtractPII = { + [Property in keyof Type]: Type[Property] extends { pii: true } ? true : false; + }; + `) + ); + }); + + test('mapped types intersection', () => { + rewriteRun( + //language=typescript + typeScript(` + type MakeSpecificKeysReadonly = { + readonly [P in K]: T[P]; + } & { + [P in Exclude]: T[P]; + }; + `) + ); + }); + + test('specific type', () => { + rewriteRun( + //language=typescript + typeScript(` + type UnionMapper = { + [K in T]: { type: K }; + }[T]; + `) + ); + }); + + test('complex key remapping', () => { + rewriteRun( + //language=typescript + typeScript(` + type SnakeCaseKeys = { + [K in keyof T as K extends string + ? \`\${K extends \`\${infer First}\${infer Rest}\` + ? \`\${Lowercase}\${Rest extends Capitalize ? \`_\${Lowercase}\` : Rest}\` + : K}\` + : never]: T[K]; + }; + `) + ); + }); + +}); 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 48fefdc0..0d5a5e26 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 @@ -272,6 +272,41 @@ public JS.LiteralType visitLiteralType(JS.LiteralType literalType, ReceiverConte return literalType; } + @Override + public JS.MappedType visitMappedType(JS.MappedType mappedType, ReceiverContext ctx) { + mappedType = mappedType.withId(ctx.receiveNonNullValue(mappedType.getId(), UUID.class)); + mappedType = mappedType.withPrefix(ctx.receiveNonNullNode(mappedType.getPrefix(), JavaScriptReceiver::receiveSpace)); + mappedType = mappedType.withMarkers(ctx.receiveNonNullNode(mappedType.getMarkers(), ctx::receiveMarkers)); + mappedType = mappedType.getPadding().withPrefixToken(ctx.receiveNode(mappedType.getPadding().getPrefixToken(), JavaScriptReceiver::receiveLeftPaddedTree)); + mappedType = mappedType.getPadding().withHasReadonly(ctx.receiveNonNullNode(mappedType.getPadding().getHasReadonly(), leftPaddedValueReceiver(java.lang.Boolean.class))); + mappedType = mappedType.withKeysRemapping(ctx.receiveNonNullNode(mappedType.getKeysRemapping(), ctx::receiveTree)); + mappedType = mappedType.getPadding().withSuffixToken(ctx.receiveNode(mappedType.getPadding().getSuffixToken(), JavaScriptReceiver::receiveLeftPaddedTree)); + mappedType = mappedType.getPadding().withHasQuestionToken(ctx.receiveNonNullNode(mappedType.getPadding().getHasQuestionToken(), leftPaddedValueReceiver(java.lang.Boolean.class))); + mappedType = mappedType.getPadding().withValueType(ctx.receiveNonNullNode(mappedType.getPadding().getValueType(), JavaScriptReceiver::receiveContainer)); + mappedType = mappedType.withType(ctx.receiveValue(mappedType.getType(), JavaType.class)); + return mappedType; + } + + @Override + public JS.MappedType.KeysRemapping visitMappedTypeKeysRemapping(JS.MappedType.KeysRemapping keysRemapping, ReceiverContext ctx) { + keysRemapping = keysRemapping.withId(ctx.receiveNonNullValue(keysRemapping.getId(), UUID.class)); + keysRemapping = keysRemapping.withPrefix(ctx.receiveNonNullNode(keysRemapping.getPrefix(), JavaScriptReceiver::receiveSpace)); + keysRemapping = keysRemapping.withMarkers(ctx.receiveNonNullNode(keysRemapping.getMarkers(), ctx::receiveMarkers)); + keysRemapping = keysRemapping.getPadding().withTypeParameter(ctx.receiveNonNullNode(keysRemapping.getPadding().getTypeParameter(), JavaScriptReceiver::receiveRightPaddedTree)); + keysRemapping = keysRemapping.getPadding().withNameType(ctx.receiveNode(keysRemapping.getPadding().getNameType(), JavaScriptReceiver::receiveRightPaddedTree)); + return keysRemapping; + } + + @Override + public JS.MappedType.MappedTypeParameter visitMappedTypeMappedTypeParameter(JS.MappedType.MappedTypeParameter mappedTypeParameter, ReceiverContext ctx) { + mappedTypeParameter = mappedTypeParameter.withId(ctx.receiveNonNullValue(mappedTypeParameter.getId(), UUID.class)); + mappedTypeParameter = mappedTypeParameter.withPrefix(ctx.receiveNonNullNode(mappedTypeParameter.getPrefix(), JavaScriptReceiver::receiveSpace)); + mappedTypeParameter = mappedTypeParameter.withMarkers(ctx.receiveNonNullNode(mappedTypeParameter.getMarkers(), ctx::receiveMarkers)); + mappedTypeParameter = mappedTypeParameter.withName(ctx.receiveNonNullNode(mappedTypeParameter.getName(), ctx::receiveTree)); + mappedTypeParameter = mappedTypeParameter.getPadding().withIterateType(ctx.receiveNonNullNode(mappedTypeParameter.getPadding().getIterateType(), JavaScriptReceiver::receiveLeftPaddedTree)); + return mappedTypeParameter; + } + @Override public JS.ObjectBindingDeclarations visitObjectBindingDeclarations(JS.ObjectBindingDeclarations objectBindingDeclarations, ReceiverContext ctx) { objectBindingDeclarations = objectBindingDeclarations.withId(ctx.receiveNonNullValue(objectBindingDeclarations.getId(), UUID.class)); @@ -1604,6 +1639,41 @@ public T create(Class type, ReceiverContext ctx) { ); } + if (type == JS.MappedType.class) { + return (T) new JS.MappedType( + ctx.receiveNonNullValue(null, UUID.class), + ctx.receiveNonNullNode(null, JavaScriptReceiver::receiveSpace), + ctx.receiveNonNullNode(null, ctx::receiveMarkers), + ctx.receiveNode(null, JavaScriptReceiver::receiveLeftPaddedTree), + ctx.receiveNonNullNode(null, leftPaddedValueReceiver(java.lang.Boolean.class)), + ctx.receiveNonNullNode(null, ctx::receiveTree), + ctx.receiveNode(null, JavaScriptReceiver::receiveLeftPaddedTree), + ctx.receiveNonNullNode(null, leftPaddedValueReceiver(java.lang.Boolean.class)), + ctx.receiveNonNullNode(null, JavaScriptReceiver::receiveContainer), + ctx.receiveValue(null, JavaType.class) + ); + } + + if (type == JS.MappedType.KeysRemapping.class) { + return (T) new JS.MappedType.KeysRemapping( + ctx.receiveNonNullValue(null, UUID.class), + ctx.receiveNonNullNode(null, JavaScriptReceiver::receiveSpace), + ctx.receiveNonNullNode(null, ctx::receiveMarkers), + ctx.receiveNonNullNode(null, JavaScriptReceiver::receiveRightPaddedTree), + ctx.receiveNode(null, JavaScriptReceiver::receiveRightPaddedTree) + ); + } + + if (type == JS.MappedType.MappedTypeParameter.class) { + return (T) new JS.MappedType.MappedTypeParameter( + ctx.receiveNonNullValue(null, UUID.class), + ctx.receiveNonNullNode(null, JavaScriptReceiver::receiveSpace), + ctx.receiveNonNullNode(null, ctx::receiveMarkers), + ctx.receiveNonNullNode(null, ctx::receiveTree), + ctx.receiveNonNullNode(null, JavaScriptReceiver::receiveLeftPaddedTree) + ); + } + if (type == JS.ObjectBindingDeclarations.class) { return (T) new JS.ObjectBindingDeclarations( 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 9f0e0eb1..00f99719 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 @@ -255,6 +255,41 @@ public JS.LiteralType visitLiteralType(JS.LiteralType literalType, SenderContext return literalType; } + @Override + public JS.MappedType visitMappedType(JS.MappedType mappedType, SenderContext ctx) { + ctx.sendValue(mappedType, JS.MappedType::getId); + ctx.sendNode(mappedType, JS.MappedType::getPrefix, JavaScriptSender::sendSpace); + ctx.sendNode(mappedType, JS.MappedType::getMarkers, ctx::sendMarkers); + ctx.sendNode(mappedType, e -> e.getPadding().getPrefixToken(), JavaScriptSender::sendLeftPadded); + ctx.sendNode(mappedType, e -> e.getPadding().getHasReadonly(), JavaScriptSender::sendLeftPadded); + ctx.sendNode(mappedType, JS.MappedType::getKeysRemapping, ctx::sendTree); + ctx.sendNode(mappedType, e -> e.getPadding().getSuffixToken(), JavaScriptSender::sendLeftPadded); + ctx.sendNode(mappedType, e -> e.getPadding().getHasQuestionToken(), JavaScriptSender::sendLeftPadded); + ctx.sendNode(mappedType, e -> e.getPadding().getValueType(), JavaScriptSender::sendContainer); + ctx.sendTypedValue(mappedType, JS.MappedType::getType); + return mappedType; + } + + @Override + public JS.MappedType.KeysRemapping visitMappedTypeKeysRemapping(JS.MappedType.KeysRemapping keysRemapping, SenderContext ctx) { + ctx.sendValue(keysRemapping, JS.MappedType.KeysRemapping::getId); + ctx.sendNode(keysRemapping, JS.MappedType.KeysRemapping::getPrefix, JavaScriptSender::sendSpace); + ctx.sendNode(keysRemapping, JS.MappedType.KeysRemapping::getMarkers, ctx::sendMarkers); + ctx.sendNode(keysRemapping, e -> e.getPadding().getTypeParameter(), JavaScriptSender::sendRightPadded); + ctx.sendNode(keysRemapping, e -> e.getPadding().getNameType(), JavaScriptSender::sendRightPadded); + return keysRemapping; + } + + @Override + public JS.MappedType.MappedTypeParameter visitMappedTypeMappedTypeParameter(JS.MappedType.MappedTypeParameter mappedTypeParameter, SenderContext ctx) { + ctx.sendValue(mappedTypeParameter, JS.MappedType.MappedTypeParameter::getId); + ctx.sendNode(mappedTypeParameter, JS.MappedType.MappedTypeParameter::getPrefix, JavaScriptSender::sendSpace); + ctx.sendNode(mappedTypeParameter, JS.MappedType.MappedTypeParameter::getMarkers, ctx::sendMarkers); + ctx.sendNode(mappedTypeParameter, JS.MappedType.MappedTypeParameter::getName, ctx::sendTree); + ctx.sendNode(mappedTypeParameter, e -> e.getPadding().getIterateType(), JavaScriptSender::sendLeftPadded); + return mappedTypeParameter; + } + @Override public JS.ObjectBindingDeclarations visitObjectBindingDeclarations(JS.ObjectBindingDeclarations objectBindingDeclarations, SenderContext ctx) { ctx.sendValue(objectBindingDeclarations, JS.ObjectBindingDeclarations::getId); 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 a4a0962b..75c8aae0 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 @@ -170,6 +170,29 @@ public JS.LiteralType visitLiteralType(JS.LiteralType literalType, P p) { return literalType; } + @Override + public JS.MappedType visitMappedType(JS.MappedType mappedType, P p) { + visitAndValidate(mappedType.getPrefixToken(), J.Literal.class, p); + visitAndValidate(mappedType.getKeysRemapping(), JS.MappedType.KeysRemapping.class, p); + visitAndValidate(mappedType.getSuffixToken(), J.Literal.class, p); + visitAndValidate(mappedType.getValueType(), TypeTree.class, p); + return mappedType; + } + + @Override + public JS.MappedType.KeysRemapping visitMappedTypeKeysRemapping(JS.MappedType.KeysRemapping keysRemapping, P p) { + visitAndValidate(keysRemapping.getTypeParameter(), JS.MappedType.MappedTypeParameter.class, p); + visitAndValidate(keysRemapping.getNameType(), Expression.class, p); + return keysRemapping; + } + + @Override + public JS.MappedType.MappedTypeParameter visitMappedTypeMappedTypeParameter(JS.MappedType.MappedTypeParameter mappedTypeParameter, P p) { + visitAndValidate(mappedTypeParameter.getName(), Expression.class, p); + visitAndValidate(mappedTypeParameter.getIterateType(), TypeTree.class, p); + return mappedTypeParameter; + } + @Override public JS.ObjectBindingDeclarations visitObjectBindingDeclarations(JS.ObjectBindingDeclarations objectBindingDeclarations, P p) { ListUtils.map(objectBindingDeclarations.getLeadingAnnotations(), el -> visitAndValidate(el, J.Annotation.class, p)); 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 6a040463..7ce8257c 100644 --- a/rewrite-javascript/src/main/java/org/openrewrite/javascript/JavaScriptVisitor.java +++ b/rewrite-javascript/src/main/java/org/openrewrite/javascript/JavaScriptVisitor.java @@ -342,6 +342,57 @@ public J visitLiteralType(JS.LiteralType literalType, P p) { return type; } + public J visitMappedType(JS.MappedType mappedType, P p) { + JS.MappedType t = mappedType; + t = t.withPrefix(visitSpace(t.getPrefix(), JsSpace.Location.MAPPED_TYPE_PREFIX, p)); + t = t.withMarkers(visitMarkers(t.getMarkers(), p)); + Expression temp = (Expression) visitExpression(t, p); + if (!(temp instanceof JS.MappedType)) { + return temp; + } else { + t = (JS.MappedType) temp; + } + t = t.getPadding().withPrefixToken(visitLeftPadded(t.getPadding().getPrefixToken(), JsLeftPadded.Location.MAPPED_TYPE_PREFIX_TOKEN, p)); + t = t.getPadding().withHasReadonly(visitLeftPadded(t.getPadding().getHasReadonly(), JsLeftPadded.Location.MAPPED_TYPE_READONLY, p)); + t = t.withKeysRemapping(visitAndCast(t.getKeysRemapping(),p)); + t = t.getPadding().withSuffixToken(visitLeftPadded(t.getPadding().getSuffixToken(), JsLeftPadded.Location.MAPPED_TYPE_SUFFIX_TOKEN, p)); + t = t.getPadding().withHasQuestionToken(visitLeftPadded(t.getPadding().getHasQuestionToken(), JsLeftPadded.Location.MAPPED_TYPE_QUESTION_TOKEN, p)); + t = t.getPadding().withValueType(visitContainer(t.getPadding().getValueType(), JsContainer.Location.MAPPED_TYPE_VALUE_TYPE, p)); + return t; + } + + public J visitMappedTypeKeysRemapping(JS.MappedType.KeysRemapping mappedTypeKeys, P p) { + JS.MappedType.KeysRemapping m = mappedTypeKeys; + m = m.withPrefix(visitSpace(m.getPrefix(), JsSpace.Location.MAPPED_TYPE_KEYS_REMAPPING_PREFIX, p)); + m = m.withMarkers(visitMarkers(m.getMarkers(), p)); + Statement temp = (Statement) visitStatement(m, p); + if (!(temp instanceof JS.MappedType.KeysRemapping)) { + return temp; + } else { + m = (JS.MappedType.KeysRemapping) temp; + } + m = m.getPadding().withTypeParameter(visitRightPadded(m.getPadding().getTypeParameter(), JsRightPadded.Location.MAPPED_TYPE_KEYS_REMAPPING_TYPE_PARAMETER, p)); + if (m.getNameType() != null) { + m = m.getPadding().withNameType(visitRightPadded(m.getPadding().getNameType(), JsRightPadded.Location.MAPPED_TYPE_KEYS_REMAPPING_NAME_TYPE, p)); + } + return m; + } + + public J visitMappedTypeMappedTypeParameter(JS.MappedType.MappedTypeParameter mappedTypeParameter, P p) { + JS.MappedType.MappedTypeParameter m = mappedTypeParameter; + m = m.withPrefix(visitSpace(m.getPrefix(), JsSpace.Location.MAPPED_TYPE_MAPPED_TYPE_PARAMETER_PREFIX, p)); + m = m.withMarkers(visitMarkers(m.getMarkers(), p)); + Statement temp = (Statement) visitStatement(m, p); + if (!(temp instanceof JS.MappedType.MappedTypeParameter)) { + return temp; + } else { + m = (JS.MappedType.MappedTypeParameter) temp; + } + m = m.withName(visitAndCast(m.getName(), p)); + m = m.getPadding().withIterateType(visitLeftPadded(m.getPadding().getIterateType(), JsLeftPadded.Location.MAPPED_TYPE_MAPPED_TYPE_PARAMETER_ITERATE, p)); + return m; + } + public J visitObjectBindingDeclarations(JS.ObjectBindingDeclarations objectBindingDeclarations, P p) { JS.ObjectBindingDeclarations o = objectBindingDeclarations; o = o.withPrefix(visitSpace(o.getPrefix(), JsSpace.Location.OBJECT_BINDING_DECLARATIONS_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 ab8ea7fd..a10e6e00 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 @@ -442,6 +442,61 @@ public J visitLiteralType(JS.LiteralType literalType, PrintOutputCapture

p) { return literalType; } + @Override + public J visitMappedType(JS.MappedType mappedType, PrintOutputCapture

p) { + beforeSyntax(mappedType, JsSpace.Location.MAPPED_TYPE_PREFIX, p); + p.append("{"); + + if (mappedType.getPrefixToken() != null) { + visitLeftPadded(mappedType.getPadding().getPrefixToken(), JsLeftPadded.Location.MAPPED_TYPE_PREFIX_TOKEN, p); + } + + if (mappedType.isHasReadonly()) { + visitLeftPaddedBoolean("readonly", mappedType.getPadding().getHasReadonly(), JsLeftPadded.Location.MAPPED_TYPE_READONLY, p); + } + + visitMappedTypeKeysRemapping(mappedType.getKeysRemapping(), p); + + if (mappedType.getSuffixToken() != null) { + visitLeftPadded(mappedType.getPadding().getSuffixToken(), JsLeftPadded.Location.MAPPED_TYPE_SUFFIX_TOKEN, p); + } + + if (mappedType.isHasQuestionToken()) { + visitLeftPaddedBoolean("?", mappedType.getPadding().getHasQuestionToken(), JsLeftPadded.Location.MAPPED_TYPE_QUESTION_TOKEN, p); + } + + visitContainer(":", mappedType.getPadding().getValueType(), JsContainer.Location.MAPPED_TYPE_VALUE_TYPE, "", "", p); + + p.append("}"); + afterSyntax(mappedType, p); + return mappedType; + } + + @Override + public J visitMappedTypeKeysRemapping(JS.MappedType.KeysRemapping mappedTypeKeys, PrintOutputCapture

p) { + beforeSyntax(mappedTypeKeys, JsSpace.Location.MAPPED_TYPE_KEYS_REMAPPING_PREFIX, p); + p.append("["); + this.visitRightPadded(mappedTypeKeys.getPadding().getTypeParameter(), JsRightPadded.Location.MAPPED_TYPE_KEYS_REMAPPING_TYPE_PARAMETER, p); + + if (mappedTypeKeys.getNameType() != null) { + p.append("as"); + this.visitRightPadded(mappedTypeKeys.getPadding().getNameType(), JsRightPadded.Location.MAPPED_TYPE_KEYS_REMAPPING_NAME_TYPE, p); + } + + p.append("]"); + afterSyntax(mappedTypeKeys, p); + return mappedTypeKeys; + } + + @Override + public J visitMappedTypeMappedTypeParameter(JS.MappedType.MappedTypeParameter mappedTypeParameter, PrintOutputCapture

p) { + beforeSyntax(mappedTypeParameter, JsSpace.Location.MAPPED_TYPE_MAPPED_TYPE_PARAMETER_PREFIX, p); + visit(mappedTypeParameter.getName(), p); + this.visitLeftPadded("in", mappedTypeParameter.getPadding().getIterateType(), JsLeftPadded.Location.MAPPED_TYPE_MAPPED_TYPE_PARAMETER_ITERATE, p); + afterSyntax(mappedTypeParameter, p); + return mappedTypeParameter; + } + @Override public J visitObjectBindingDeclarations(JS.ObjectBindingDeclarations objectBindingDeclarations, PrintOutputCapture

p) { beforeSyntax(objectBindingDeclarations, Space.Location.VARIABLE_DECLARATIONS_PREFIX, p); @@ -1261,7 +1316,11 @@ public J visitTypeParameter(J.TypeParameter typeParameter, PrintOutputCapture

if (bounds != null) { visitSpace(bounds.getBefore(), JContainer.Location.TYPE_BOUNDS.getBeforeLocation(), p); JRightPadded constraintType = bounds.getPadding().getElements().get(0); - if (!(constraintType.getElement() instanceof J.Empty)) { + + if (getCursor().getParentTreeCursor().getValue() instanceof JS.MappedType) { + p.append("in"); + this.visitRightPadded(constraintType, JContainer.Location.TYPE_BOUNDS.getElementLocation(), p); + } else if (!(constraintType.getElement() instanceof J.Empty)) { p.append("extends"); this.visitRightPadded(constraintType, JContainer.Location.TYPE_BOUNDS.getElementLocation(), p); } diff --git a/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JS.java b/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JS.java index 38abc781..0a90d0e4 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 @@ -1498,6 +1498,326 @@ public CoordinateBuilder.Expression getCoordinates() { } } + @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) + @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) + @RequiredArgsConstructor + @AllArgsConstructor(access = AccessLevel.PRIVATE) + class MappedType implements JS, Expression, TypeTree { + + @Nullable + @NonFinal + transient WeakReference padding; + + @Getter + @With + @EqualsAndHashCode.Include + UUID id; + + @Getter + @With + Space prefix; + + @Getter + @With + Markers markers; + + @Nullable + JLeftPadded prefixToken; + + public @Nullable Literal getPrefixToken() { + return prefixToken == null ? null : prefixToken.getElement(); + } + + public MappedType withPrefixToken(@Nullable Literal prefixToken) { + return getPadding().withPrefixToken(JLeftPadded.withElement(this.prefixToken, prefixToken)); + } + + JLeftPadded hasReadonly; + + public boolean isHasReadonly() { + return hasReadonly.getElement(); + } + + public MappedType withHasReadonly(boolean hasReadonly) { + return getPadding().withHasReadonly(this.hasReadonly.withElement(hasReadonly)); + } + + @Getter + @With + KeysRemapping keysRemapping; + + @Nullable + JLeftPadded suffixToken; + + public @Nullable Literal getSuffixToken() { + return suffixToken == null ? null : suffixToken.getElement(); + } + + public MappedType withSuffixToken(@Nullable Literal suffixToken) { + return getPadding().withSuffixToken(JLeftPadded.withElement(this.suffixToken, suffixToken)); + } + + JLeftPadded hasQuestionToken; + + public boolean isHasQuestionToken() { + return hasQuestionToken.getElement(); + } + + public MappedType withHasQuestionToken(boolean hasQuestionToken) { + return getPadding().withHasQuestionToken(this.hasQuestionToken.withElement(hasQuestionToken)); + } + + JContainer valueType; + + public List getValueType() { + return valueType.getElements(); + } + + public MappedType withValueType(List valueType) { + return getPadding().withValueType(JContainer.withElements(this.valueType, valueType)); + } + + @Getter + @With + @Nullable + JavaType type; + + @Override + public

J acceptJavaScript(JavaScriptVisitor

v, P p) { + return v.visitMappedType(this, p); + } + + @Override + public CoordinateBuilder.Expression getCoordinates() { + return new CoordinateBuilder.Expression(this); + } + + public MappedType.Padding getPadding() { + MappedType.Padding p; + if (this.padding == null) { + p = new MappedType.Padding(this); + this.padding = new WeakReference<>(p); + } else { + p = this.padding.get(); + if (p == null || p.t != this) { + p = new MappedType.Padding(this); + this.padding = new WeakReference<>(p); + } + } + return p; + } + + @RequiredArgsConstructor + public static class Padding { + private final MappedType t; + + public @Nullable JLeftPadded getPrefixToken() { + return t.prefixToken; + } + + public MappedType withPrefixToken(@Nullable JLeftPadded prefixToken) { + return t.prefixToken == prefixToken ? t : new MappedType(t.id, t.prefix, t.markers, prefixToken, t.hasReadonly, t.keysRemapping, t.suffixToken, t.hasQuestionToken, t.valueType, t.type); + } + + public JLeftPadded getHasReadonly() { + return t.hasReadonly; + } + + public MappedType withHasReadonly(JLeftPadded hasReadonly) { + return t.hasReadonly == hasReadonly ? t : new MappedType(t.id, t.prefix, t.markers, t.prefixToken, hasReadonly, t.keysRemapping, t.suffixToken, t.hasQuestionToken, t.valueType, t.type); + } + + public @Nullable JLeftPadded getSuffixToken() { + return t.suffixToken; + } + + public MappedType withSuffixToken(@Nullable JLeftPadded suffixToken) { + return t.suffixToken == suffixToken ? t : new MappedType(t.id, t.prefix, t.markers, t.prefixToken, t.hasReadonly, t.keysRemapping, suffixToken, t.hasQuestionToken, t.valueType, t.type); + } + + public JLeftPadded getHasQuestionToken() { + return t.hasQuestionToken; + } + + public MappedType withHasQuestionToken(JLeftPadded hasQuestionToken) { + return t.hasQuestionToken == hasQuestionToken ? t : new MappedType(t.id, t.prefix, t.markers, t.prefixToken, t.hasReadonly, t.keysRemapping, t.suffixToken, hasQuestionToken, t.valueType, t.type); + } + + public JContainer getValueType() { + return t.valueType; + } + + public MappedType withValueType(JContainer valueType) { + return t.valueType == valueType ? t : new MappedType(t.id, t.prefix, t.markers, t.prefixToken, t.hasReadonly, t.keysRemapping, t.suffixToken, t.hasQuestionToken, valueType, t.type); + } + } + + @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) + @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) + @RequiredArgsConstructor + @AllArgsConstructor(access = AccessLevel.PRIVATE) + public static final class KeysRemapping implements JS, Statement { + @Nullable + @NonFinal + transient WeakReference padding; + + @With + @EqualsAndHashCode.Include + @Getter + UUID id; + + @With + @Getter + Space prefix; + + @With + @Getter + Markers markers; + + JRightPadded typeParameter; + + public MappedTypeParameter getTypeParameter() { + return typeParameter.getElement(); + } + + public KeysRemapping withTypeParameter(MappedTypeParameter typeParameter) { + return getPadding().withTypeParameter(JRightPadded.withElement(this.typeParameter, typeParameter)); + } + + @Nullable + JRightPadded nameType; + + public @Nullable Expression getNameType() { + return nameType == null ? null : nameType.getElement(); + } + + public KeysRemapping withNameType(@Nullable Expression element) { + return getPadding().withNameType(JRightPadded.withElement(this.nameType, element)); + } + + @Override + public

J acceptJavaScript(JavaScriptVisitor

v, P p) { + return v.visitMappedTypeKeysRemapping(this, p); + } + + @Override + public CoordinateBuilder.Statement getCoordinates() { + return new CoordinateBuilder.Statement(this); + } + + public KeysRemapping.Padding getPadding() { + KeysRemapping.Padding p; + if (this.padding == null) { + p = new KeysRemapping.Padding(this); + this.padding = new WeakReference<>(p); + } else { + p = this.padding.get(); + if (p == null || p.t != this) { + p = new KeysRemapping.Padding(this); + this.padding = new WeakReference<>(p); + } + } + return p; + } + + @RequiredArgsConstructor + public static class Padding { + private final KeysRemapping t; + + public JRightPadded getTypeParameter() { + return t.typeParameter; + } + + public KeysRemapping withTypeParameter(JRightPadded typeParameter) { + return t.typeParameter == typeParameter ? t : new KeysRemapping(t.id, t.prefix, t.markers, typeParameter, t.nameType); + } + + public JRightPadded getNameType() { + return t.nameType; + } + + public KeysRemapping withNameType(JRightPadded nameType) { + return t.nameType == nameType ? t : new KeysRemapping(t.id, t.prefix, t.markers, t.typeParameter, nameType); + } + } + } + + @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) + @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) + @RequiredArgsConstructor + @AllArgsConstructor(access = AccessLevel.PRIVATE) + public static final class MappedTypeParameter implements JS, Statement { + @Nullable + @NonFinal + transient WeakReference padding; + + @With + @EqualsAndHashCode.Include + @Getter + UUID id; + + @With + @Getter + Space prefix; + + @With + @Getter + Markers markers; + + @With + @Getter + Expression name; + + JLeftPadded iterateType; + + public TypeTree getIterateType() { + return iterateType.getElement(); + } + + public MappedTypeParameter withIterateType(TypeTree element) { + return getPadding().withIterateType(JLeftPadded.withElement(this.iterateType, element)); + } + + @Override + public

J acceptJavaScript(JavaScriptVisitor

v, P p) { + return v.visitMappedTypeMappedTypeParameter(this, p); + } + + @Override + public CoordinateBuilder.Statement getCoordinates() { + return new CoordinateBuilder.Statement(this); + } + + public MappedTypeParameter.Padding getPadding() { + MappedTypeParameter.Padding p; + if (this.padding == null) { + p = new MappedTypeParameter.Padding(this); + this.padding = new WeakReference<>(p); + } else { + p = this.padding.get(); + if (p == null || p.t != this) { + p = new MappedTypeParameter.Padding(this); + this.padding = new WeakReference<>(p); + } + } + return p; + } + + @RequiredArgsConstructor + public static class Padding { + private final MappedTypeParameter t; + + public JLeftPadded getIterateType() { + return t.iterateType; + } + + public MappedTypeParameter withIterateType(JLeftPadded iterateType) { + return t.iterateType == iterateType ? t : new MappedTypeParameter(t.id, t.prefix, t.markers, t.name, iterateType); + } + } + } + } + @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) @RequiredArgsConstructor @@ -1796,11 +2116,11 @@ public SatisfiesExpression.Padding getPadding() { public static class Padding { private final SatisfiesExpression t; - public @Nullable JLeftPadded getSatisfiesType() { + public JLeftPadded getSatisfiesType() { return t.satisfiesType; } - public SatisfiesExpression withSatisfiesType(@Nullable JLeftPadded satisfiesType) { + public SatisfiesExpression withSatisfiesType(JLeftPadded satisfiesType) { return t.satisfiesType == satisfiesType ? t : new SatisfiesExpression(t.id, t.prefix, t.markers, t.expression, satisfiesType, 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 4dd90584..494e0dbc 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 @@ -35,7 +35,7 @@ public enum Location { CONDITIONAL_TYPE_CONDITION(JsSpace.Location.CONDITIONAL_TYPE_CONDITION, JsRightPadded.Location.CONDITIONAL_TYPE_CONDITION), IMPORT_TYPE_TYPE_ARGUMENTS(JsSpace.Location.IMPORT_TYPE_TYPE_ARGUMENTS, JsRightPadded.Location.IMPORT_TYPE_TYPE_ARGUMENTS), NAMED_EXPORTS_ELEMENTS(JsSpace.Location.NAMED_EXPORTS_ELEMENTS_PREFIX, JsRightPadded.Location.NAMED_EXPORTS_ELEMENTS), - ; + MAPPED_TYPE_VALUE_TYPE(JsSpace.Location.MAPPED_TYPE_VALUE_TYPE, JsRightPadded.Location.MAPPED_TYPE_VALUE_TYPE); private final JsSpace.Location beforeLocation; private final JsRightPadded.Location elementLocation; 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 fec72178..e83cf194 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 @@ -46,7 +46,11 @@ public enum Location { FUNCTION_DECLARATION_NAME(JsSpace.Location.FUNCTION_DECLARATION_NAME_PREFIX), FUNCTION_DECLARATION_ASTERISK_TOKEN(JsSpace.Location.FUNCTION_DECLARATION_ASTERISK_TOKEN_PREFIX), ASSIGNMENT_OPERATION_OPERATOR(JsSpace.Location.ASSIGNMENT_OPERATION_OPERATOR_PREFIX), - ; + MAPPED_TYPE_PREFIX_TOKEN(JsSpace.Location.MAPPED_TYPE_PREFIX_TOKEN_PREFIX), + MAPPED_TYPE_SUFFIX_TOKEN(JsSpace.Location.MAPPED_TYPE_SUFFIX_TOKEN_PREFIX), + MAPPED_TYPE_MAPPED_TYPE_PARAMETER_ITERATE(JsSpace.Location.MAPPED_TYPE_MAPPED_TYPE_PARAMETER_ITERATE_PREFIX), + MAPPED_TYPE_READONLY(JsSpace.Location.MAPPED_TYPE_READONLY_PREFIX), + MAPPED_TYPE_QUESTION_TOKEN(JsSpace.Location.MAPPED_TYPE_QUESTION_TOKEN_PREFIX); 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 6d8cde29..7e334636 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 @@ -54,7 +54,9 @@ public enum Location { NAMED_EXPORTS_ELEMENTS(JsSpace.Location.NAMED_EXPORTS_ELEMENTS_SUFFIX), INDEXED_ACCESS_TYPE_INDEX_TYPE(JsSpace.Location.INDEXED_ACCESS_TYPE_INDEX_TYPE_SUFFIX), INDEXED_ACCESS_TYPE_INDEX_TYPE_ELEMENT(JsSpace.Location.INDEXED_ACCESS_TYPE_INDEX_TYPE_ELEMENT_SUFFIX), - ; + MAPPED_TYPE_VALUE_TYPE(JsSpace.Location.MAPPED_TYPE_VALUE_TYPE_SUFFIX), + MAPPED_TYPE_KEYS_REMAPPING_TYPE_PARAMETER(JsSpace.Location.MAPPED_TYPE_KEYS_REMAPPING_TYPE_PARAMETER_SUFFIX), + MAPPED_TYPE_KEYS_REMAPPING_NAME_TYPE(JsSpace.Location.MAPPED_TYPE_KEYS_REMAPPING_NAME_TYPE_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 4942c27f..4c05dd93 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 @@ -151,5 +151,17 @@ public enum Location { ASSIGNMENT_OPERATION_PREFIX, ASSIGNMENT_OPERATION_OPERATOR_PREFIX, ASSIGNMENT_OPERATION_OPERATOR, + MAPPED_TYPE_PREFIX, + MAPPED_TYPE_PREFIX_TOKEN_PREFIX, + MAPPED_TYPE_VALUE_TYPE, + MAPPED_TYPE_VALUE_TYPE_SUFFIX, + MAPPED_TYPE_SUFFIX_TOKEN_PREFIX, + MAPPED_TYPE_KEYS_REMAPPING_PREFIX, + MAPPED_TYPE_KEYS_REMAPPING_TYPE_PARAMETER_SUFFIX, + MAPPED_TYPE_MAPPED_TYPE_PARAMETER_PREFIX, + MAPPED_TYPE_MAPPED_TYPE_PARAMETER_ITERATE_PREFIX, + MAPPED_TYPE_KEYS_REMAPPING_NAME_TYPE_SUFFIX, + MAPPED_TYPE_READONLY_PREFIX, + MAPPED_TYPE_QUESTION_TOKEN_PREFIX; } } From db746981e04897217af4d7ae64763ed34f9bbbe7 Mon Sep 17 00:00:00 2001 From: Andrii Rodionov Date: Tue, 10 Dec 2024 12:31:59 +0100 Subject: [PATCH 2/2] simplified if-else --- openrewrite/src/javascript/parser.ts | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/openrewrite/src/javascript/parser.ts b/openrewrite/src/javascript/parser.ts index 4513f443..61bf41a4 100644 --- a/openrewrite/src/javascript/parser.ts +++ b/openrewrite/src/javascript/parser.ts @@ -1441,19 +1441,11 @@ export class JavaScriptParserVisitor { visitMappedType(node: ts.MappedTypeNode) { function hasPrefixToken(readonlyToken?: ts.ReadonlyKeyword | ts.PlusToken | ts.MinusToken): boolean { - if (readonlyToken && (readonlyToken.kind == ts.SyntaxKind.PlusToken || readonlyToken.kind == ts.SyntaxKind.MinusToken)) { - return true; - } else { - return false; - } + return !!(readonlyToken && (readonlyToken.kind == ts.SyntaxKind.PlusToken || readonlyToken.kind == ts.SyntaxKind.MinusToken)); } function hasSuffixToken(questionToken?: ts.QuestionToken | ts.PlusToken | ts.MinusToken): boolean { - if (questionToken && (questionToken.kind == ts.SyntaxKind.PlusToken || questionToken.kind == ts.SyntaxKind.MinusToken)) { - return true; - } else { - return false; - } + return !!(questionToken && (questionToken.kind == ts.SyntaxKind.PlusToken || questionToken.kind == ts.SyntaxKind.MinusToken)); } return new JS.MappedType(