diff --git a/openrewrite/src/javascript/parser.ts b/openrewrite/src/javascript/parser.ts index 085c60cd..546df440 100644 --- a/openrewrite/src/javascript/parser.ts +++ b/openrewrite/src/javascript/parser.ts @@ -247,7 +247,7 @@ export class JavaScriptParserVisitor { ); } - private mapModifiers(node: ts.VariableDeclarationList | ts.VariableStatement | ts.ClassDeclaration | ts.PropertyDeclaration | ts.FunctionDeclaration | ts.ParameterDeclaration | ts.MethodDeclaration | ts.EnumDeclaration | ts.InterfaceDeclaration | ts.PropertySignature | ts.ConstructorDeclaration) { + private mapModifiers(node: ts.VariableDeclarationList | ts.VariableStatement | ts.ClassDeclaration | ts.PropertyDeclaration | ts.FunctionDeclaration | ts.ParameterDeclaration | ts.MethodDeclaration | ts.EnumDeclaration | ts.InterfaceDeclaration | ts.PropertySignature | ts.ConstructorDeclaration | ts.ModuleDeclaration) { if (ts.isVariableStatement(node)) { return [new J.Modifier( randomId(), @@ -257,6 +257,8 @@ export class JavaScriptParserVisitor { J.Modifier.Type.LanguageExtension, [] )]; + } else if (ts.isModuleDeclaration(node)) { + return node.modifiers ? node.modifiers?.filter(ts.isModifier).map(this.mapModifier) : []; } else if (ts.isClassDeclaration(node)) { return node.modifiers ? node.modifiers?.filter(ts.isModifier).map(this.mapModifier) : []; } else if (ts.isEnumDeclaration(node) || ts.isInterfaceDeclaration(node)) { @@ -1824,11 +1826,55 @@ export class JavaScriptParserVisitor { } visitModuleDeclaration(node: ts.ModuleDeclaration) { - return this.visitUnknown(node); + const body = this.visit(node.body as ts.Node); + + const namespaceKeyword = this.findChildNode(node, ts.SyntaxKind.NamespaceKeyword); + if (body instanceof JS.NamespaceDeclaration) { + return new JS.NamespaceDeclaration( + randomId(), + Space.EMPTY, + Markers.EMPTY, + this.mapModifiers(node), + namespaceKeyword ? this.prefix(namespaceKeyword) : Space.EMPTY, + this.rightPadded( + new J.FieldAccess( + randomId(), + this.prefix(node), + Markers.EMPTY, + this.visit(node.name), + new J.JLeftPadded( + this.suffix(node.name), + body.name as J.Identifier, + Markers.EMPTY + ), + null + ), + Space.EMPTY + ), + body.body + ); + } else { + return new JS.NamespaceDeclaration( + randomId(), + node.parent.kind === ts.SyntaxKind.ModuleBlock ? this.prefix(node) : Space.EMPTY, + Markers.EMPTY, + this.mapModifiers(node), + namespaceKeyword ? this.prefix(namespaceKeyword) : Space.EMPTY, + this.rightPadded(this.convert(node.name), this.prefix(node)), // J.FieldAccess + body // J.Block + ); + } } visitModuleBlock(node: ts.ModuleBlock) { - return this.visitUnknown(node); + return new J.Block( + randomId(), + this.prefix(node), + Markers.EMPTY, + this.rightPadded(false, Space.EMPTY), + this.semicolonPaddedStatementList(node.statements), + this.prefix(node.getLastToken()!) + ); } visitCaseBlock(node: ts.CaseBlock) { diff --git a/openrewrite/src/javascript/remote/receiver.ts b/openrewrite/src/javascript/remote/receiver.ts index f8091a23..208f1c84 100644 --- a/openrewrite/src/javascript/remote/receiver.ts +++ b/openrewrite/src/javascript/remote/receiver.ts @@ -2,7 +2,7 @@ import * as extensions from "./remote_extensions"; import {Checksum, Cursor, FileAttributes, ListUtils, Tree} from '../../core'; import {DetailsReceiver, Receiver, ReceiverContext, ReceiverFactory, ValueType} from '@openrewrite/rewrite-remote'; import {JavaScriptVisitor} from '..'; -import {JS, JsLeftPadded, JsRightPadded, JsContainer, JsSpace, CompilationUnit, Alias, ArrowFunction, Await, DefaultType, Delete, Export, ExpressionStatement, FunctionType, JsImport, JsBinary, ObjectBindingDeclarations, PropertyAssignment, ScopedVariableDeclarations, StatementExpression, TemplateExpression, Tuple, TypeDeclaration, TypeOf, TypeOperator, Unary, Union, Void, Yield, TypeInfo} from '../tree'; +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 {Expression, J, JContainer, JLeftPadded, JRightPadded, NameTree, Space, Statement, TypeTree, TypedTree} from "../../java"; import * as Java from "../../java/tree"; @@ -300,6 +300,17 @@ class Visitor extends JavaScriptVisitor { return typeInfo; } + public visitNamespaceDeclaration(namespaceDeclaration: NamespaceDeclaration, ctx: ReceiverContext): J { + namespaceDeclaration = namespaceDeclaration.withId(ctx.receiveValue(namespaceDeclaration.id, ValueType.UUID)!); + namespaceDeclaration = namespaceDeclaration.withPrefix(ctx.receiveNode(namespaceDeclaration.prefix, receiveSpace)!); + namespaceDeclaration = namespaceDeclaration.withMarkers(ctx.receiveNode(namespaceDeclaration.markers, ctx.receiveMarkers)!); + namespaceDeclaration = namespaceDeclaration.withModifiers(ctx.receiveNodes(namespaceDeclaration.modifiers, ctx.receiveTree)!); + namespaceDeclaration = namespaceDeclaration.withNamespace(ctx.receiveNode(namespaceDeclaration.namespace, receiveSpace)!); + namespaceDeclaration = namespaceDeclaration.padding.withName(ctx.receiveNode(namespaceDeclaration.padding.name, receiveRightPaddedTree)!); + namespaceDeclaration = namespaceDeclaration.withBody(ctx.receiveNode(namespaceDeclaration.body, ctx.receiveTree)!); + return namespaceDeclaration; + } + public visitAnnotatedType(annotatedType: Java.AnnotatedType, ctx: ReceiverContext): J { annotatedType = annotatedType.withId(ctx.receiveValue(annotatedType.id, ValueType.UUID)!); annotatedType = annotatedType.withPrefix(ctx.receiveNode(annotatedType.prefix, receiveSpace)!); @@ -1270,6 +1281,18 @@ class Factory implements ReceiverFactory { ); } + if (type === "org.openrewrite.javascript.tree.JS$NamespaceDeclaration") { + return new NamespaceDeclaration( + ctx.receiveValue(null, ValueType.UUID)!, + ctx.receiveNode(null, receiveSpace)!, + ctx.receiveNode(null, ctx.receiveMarkers)!, + ctx.receiveNodes(null, ctx.receiveTree)!, + ctx.receiveNode(null, receiveSpace)!, + ctx.receiveNode>(null, receiveRightPaddedTree)!, + ctx.receiveNode(null, ctx.receiveTree)! + ); + } + if (type === "org.openrewrite.java.tree.J$AnnotatedType") { return new Java.AnnotatedType( ctx.receiveValue(null, ValueType.UUID)!, diff --git a/openrewrite/src/javascript/remote/sender.ts b/openrewrite/src/javascript/remote/sender.ts index a0531501..35f1c54f 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} 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, NamespaceDeclaration} from '../tree'; import {Expression, J, JContainer, JLeftPadded, JRightPadded, Space, Statement} from "../../java"; import * as Java from "../../java/tree"; @@ -295,6 +295,17 @@ class Visitor extends JavaScriptVisitor { return typeInfo; } + public visitNamespaceDeclaration(namespaceDeclaration: NamespaceDeclaration, ctx: SenderContext): J { + ctx.sendValue(namespaceDeclaration, v => v.id, ValueType.UUID); + ctx.sendNode(namespaceDeclaration, v => v.prefix, Visitor.sendSpace); + ctx.sendNode(namespaceDeclaration, v => v.markers, ctx.sendMarkers); + ctx.sendNodes(namespaceDeclaration, v => v.modifiers, ctx.sendTree, t => t.id); + ctx.sendNode(namespaceDeclaration, v => v.namespace, Visitor.sendSpace); + ctx.sendNode(namespaceDeclaration, v => v.padding.name, Visitor.sendRightPadded(ValueType.Tree)); + ctx.sendNode(namespaceDeclaration, v => v.body, ctx.sendTree); + return namespaceDeclaration; + } + public visitAnnotatedType(annotatedType: Java.AnnotatedType, ctx: SenderContext): J { ctx.sendValue(annotatedType, v => v.id, ValueType.UUID); ctx.sendNode(annotatedType, v => v.prefix, Visitor.sendSpace); diff --git a/openrewrite/src/javascript/tree/support_types.ts b/openrewrite/src/javascript/tree/support_types.ts index 15410180..daa2b5bd 100644 --- a/openrewrite/src/javascript/tree/support_types.ts +++ b/openrewrite/src/javascript/tree/support_types.ts @@ -213,6 +213,8 @@ export namespace JsSpace { VOID_PREFIX, YIELD_PREFIX, TYPE_INFO_PREFIX, + NAMESPACE_DECLARATION_PREFIX, + NAMESPACE_KEYWORD_DECLARATION_PREFIX } } export namespace JsLeftPadded { @@ -239,6 +241,7 @@ export namespace JsRightPadded { SCOPED_VARIABLE_DECLARATIONS_VARIABLES, TEMPLATE_EXPRESSION_TAG, UNION_TYPES, + NAMESPACE_DECLARATION_NAME, } } export namespace JsContainer { diff --git a/openrewrite/src/javascript/tree/tree.ts b/openrewrite/src/javascript/tree/tree.ts index b58408d6..4b884d22 100644 --- a/openrewrite/src/javascript/tree/tree.ts +++ b/openrewrite/src/javascript/tree/tree.ts @@ -2409,3 +2409,104 @@ export class TypeInfo extends JSMixin(Object) implements Expression, TypeTree { } } + +@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) { + super(); + this._id = id; + this._prefix = prefix; + this._markers = markers; + this._modifiers = modifiers; + this._namespace = namespace; + this._name = name; + this._body = body; + } + + private readonly _id: UUID; + + public get id(): UUID { + return this._id; + } + + public withId(id: UUID): NamespaceDeclaration { + return id === this._id ? this : new NamespaceDeclaration(id, this._prefix, this._markers, this._modifiers, this._namespace, this._name, this._body); + } + + private readonly _prefix: Space; + + public get prefix(): Space { + return this._prefix; + } + + public withPrefix(prefix: Space): NamespaceDeclaration { + return prefix === this._prefix ? this : new NamespaceDeclaration(this._id, prefix, this._markers, this._modifiers, this._namespace, this._name, this._body); + } + + private readonly _markers: Markers; + + public get markers(): Markers { + return this._markers; + } + + public withMarkers(markers: Markers): NamespaceDeclaration { + return markers === this._markers ? this : new NamespaceDeclaration(this._id, this._prefix, markers, this._modifiers, this._namespace, this._name, this._body); + } + + private readonly _modifiers: Java.Modifier[]; + + public get modifiers(): Java.Modifier[] { + return this._modifiers; + } + + public withModifiers(modifiers: Java.Modifier[]): NamespaceDeclaration { + return modifiers === this._modifiers ? this : new NamespaceDeclaration(this._id, this._prefix, this._markers, modifiers, this._namespace, this._name, this._body); + } + + private readonly _namespace: Space; + + public get namespace(): Space { + return this._namespace; + } + + public withNamespace(namespace: Space): NamespaceDeclaration { + return namespace === this._namespace ? this : new NamespaceDeclaration(this._id, this._prefix, this._markers, this._modifiers, namespace, this._name, this._body); + } + + private readonly _name: JRightPadded; + + public get name(): Expression { + return this._name.element; + } + + public withName(name: Expression): NamespaceDeclaration { + return this.padding.withName(this._name.withElement(name)); + } + + private readonly _body: Java.Block; + + public get body(): Java.Block { + return this._body; + } + + public withBody(body: Java.Block): NamespaceDeclaration { + return body === this._body ? this : new NamespaceDeclaration(this._id, this._prefix, this._markers, this._modifiers, this._namespace, this._name, body); + } + + public acceptJavaScript

(v: JavaScriptVisitor

, p: P): J | null { + return v.visitNamespaceDeclaration(this, p); + } + + get padding() { + const t = this; + return new class { + public get name(): JRightPadded { + return t._name; + } + public withName(name: JRightPadded): NamespaceDeclaration { + return t._name === name ? t : new NamespaceDeclaration(t._id, t._prefix, t._markers, t._modifiers, t._namespace, name, t._body); + } + } + } + +} diff --git a/openrewrite/src/javascript/visitor.ts b/openrewrite/src/javascript/visitor.ts index 9798e03b..4d152e06 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} 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 {Expression, J, JContainer, JLeftPadded, JRightPadded, Space, Statement} from "../java/tree"; import {JavaVisitor} from "../java"; import * as Java from "../java/tree"; @@ -395,6 +395,22 @@ export class JavaScriptVisitor

extends JavaVisitor

{ return typeInfo; } + 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; + if (!(tempStatement instanceof NamespaceDeclaration)) + { + return tempStatement; + } + 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.padding.withName(this.visitJsRightPadded(namespaceDeclaration.padding.name, JsRightPadded.Location.NAMESPACE_DECLARATION_NAME, p)!); + namespaceDeclaration = namespaceDeclaration.withBody(this.visitAndCast(namespaceDeclaration.body, p)!); + return namespaceDeclaration; + } + public visitJsLeftPadded(left: JLeftPadded | null, loc: JsLeftPadded.Location, p: P): JLeftPadded { return extensions.visitJsLeftPadded(this, left, loc, p); } diff --git a/openrewrite/test/javascript/parser/enum.test.ts b/openrewrite/test/javascript/parser/enum.test.ts index e0477949..cc78bf98 100644 --- a/openrewrite/test/javascript/parser/enum.test.ts +++ b/openrewrite/test/javascript/parser/enum.test.ts @@ -98,13 +98,26 @@ describe('empty mapping', () => { ); }); + test('enum with declare const modifier and comments', () => { + rewriteRun( + //language=typescript + typeScript(` + /*a*/ declare /*b*/ const /*c*/ enum Test { + A, + B, + C, + }; + `) + ); + }); + test('enum members with comments', () => { rewriteRun( //language=typescript typeScript(` enum Test /*xx*/ { A /*aa*/, - /*bb*/ B /*cc*/, + /*bb*/ B /*cc*/, C, /*dd*/ }; `) diff --git a/openrewrite/test/javascript/parser/interface.test.ts b/openrewrite/test/javascript/parser/interface.test.ts index 1a8ac1de..e227a452 100644 --- a/openrewrite/test/javascript/parser/interface.test.ts +++ b/openrewrite/test/javascript/parser/interface.test.ts @@ -57,7 +57,7 @@ describe('as mapping', () => { interface HasLegs { count: string; } - + interface Animal { name: string; } diff --git a/openrewrite/test/javascript/parser/namespace.test.ts b/openrewrite/test/javascript/parser/namespace.test.ts new file mode 100644 index 00000000..b389cd5f --- /dev/null +++ b/openrewrite/test/javascript/parser/namespace.test.ts @@ -0,0 +1,184 @@ +import {connect, disconnect, rewriteRun, typeScript} from '../testHarness'; + +describe('namespace mapping', () => { + beforeAll(() => connect()); + afterAll(() => disconnect()); + + test('namespace empty', () => { + rewriteRun( + //language=typescript + typeScript(` + namespace X { + } + `) + ); + }); + + test('namespace with statement body', () => { + rewriteRun( + //language=typescript + typeScript(` + namespace X { + const x = 10 + } + `) + ); + }); + + test('namespace with several statements in body', () => { + rewriteRun( + //language=typescript + typeScript(` + namespace X { + const x = 10; + const y = 5 + const z = 0; + } + `) + ); + }); + + test('namespace with several statements in body and comments', () => { + rewriteRun( + //language=typescript + typeScript(` + namespace X { + /*a*/ const x = 10/*b*/;/*c*/ + /*d*/ const y = 5 /*e*/ + const z = 0;/*f*/ + } + `) + ); + }); + + test('namespace with statement body and comments', () => { + rewriteRun( + //language=typescript + typeScript(` + /*a*/ namespace /*b*/ X /*c*/{ /*d*/ + /*e*/const x = 10 /*f*/ + } /*g*/ + `) + ); + }); + + test('namespace with statement body and modifier', () => { + rewriteRun( + //language=typescript + typeScript(` + declare namespace X { + const x = 10 + } + `) + ); + }); + + test('namespace with statement body, modifier and comments', () => { + rewriteRun( + //language=typescript + typeScript(` + /*a*/ declare /*b*/ namespace /*c*/ X /*d*/{ + const x = 10 + } + `) + ); + }); + + test('namespace empty with sub-namespaces', () => { + rewriteRun( + //language=typescript + typeScript(` + namespace X.Y.Z { + } + `) + ); + }); + + test('namespace empty with sub-namespaces and comments', () => { + rewriteRun( + //language=typescript + typeScript(` + namespace /*a*/X/*b*/./*c*/Y/*d*/./*e*/Z/*f*/ { + } + `) + ); + }); + + test('namespace non-empty with sub-namespaces and body', () => { + rewriteRun( + //language=typescript + typeScript(` + namespace X.Y.Z { + const x = 10 + } + `) + ); + }); + + test('namespace non-empty with sub-namespaces and body and modifier', () => { + rewriteRun( + //language=typescript + typeScript(` + declare /*a*/ namespace X.Y.Z { + const x = 10 + } + `) + ); + }); + + test('hierarchic namespaces with body with comments', () => { + rewriteRun( + //language=typescript + typeScript(` + /*0*/ namespace X { + /*a*/ namespace Y { + /*b*/ namespace Z { + /*c*/ interface Person { + name: string; + } + } + } + } + `) + ); + }); + + test('hierarchic namespaces with body', () => { + rewriteRun( + //language=typescript + typeScript(` + namespace X { + namespace Y { + namespace Z { + interface Person { + name: string; + } + } + } + } + `) + ); + }); + + test('namespace with expression', () => { + rewriteRun( + //language=typescript + typeScript(` + /*pref*/ declare namespace /*middle*/ TestNamespace /*after*/ { + /*bcd*/ + /*1*/ a = 10 + /*efg*/ + /*2*/ function abc() { + return null + } + /*fgh*/ + /*3*/ class X { + b: number; + c: string; + } + /*ghj*/ + } + `) + ); + }); +}); diff --git a/openrewrite/test/javascript/parser/qualifiedName.test.ts b/openrewrite/test/javascript/parser/qualifiedName.test.ts index fd296c5f..30bb552e 100644 --- a/openrewrite/test/javascript/parser/qualifiedName.test.ts +++ b/openrewrite/test/javascript/parser/qualifiedName.test.ts @@ -37,12 +37,12 @@ describe('empty mapping', () => { ); }); - test.skip('namespace qualified name', () => { + test('namespace qualified name', () => { rewriteRun( //language=typescript typeScript(` - namespace TestNamespace { - export class Test {} + namespace TestNamespace { + export class Test {} }; const value: TestNamespace.Test = null; `) diff --git a/openrewrite/test/javascript/testHarness.ts b/openrewrite/test/javascript/testHarness.ts index d031c3c6..b53b8639 100644 --- a/openrewrite/test/javascript/testHarness.ts +++ b/openrewrite/test/javascript/testHarness.ts @@ -138,7 +138,9 @@ export async function disconnect(): Promise { javaTestEngine.once('close', (code: string) => { resolve() }); - javaTestEngine.kill("SIGKILL"); + javaTestEngine.kill("SIGINT"); + } else { + resolve(); } } else { resolve(); 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 06b63a72..26a24c55 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,18 @@ public JS.TypeInfo visitTypeInfo(JS.TypeInfo typeInfo, ReceiverContext ctx) { return typeInfo; } + @Override + public JS.NamespaceDeclaration visitNamespaceDeclaration(JS.NamespaceDeclaration namespaceDeclaration, ReceiverContext ctx) { + namespaceDeclaration = namespaceDeclaration.withId(ctx.receiveNonNullValue(namespaceDeclaration.getId(), UUID.class)); + namespaceDeclaration = namespaceDeclaration.withPrefix(ctx.receiveNonNullNode(namespaceDeclaration.getPrefix(), JavaScriptReceiver::receiveSpace)); + namespaceDeclaration = namespaceDeclaration.withMarkers(ctx.receiveNonNullNode(namespaceDeclaration.getMarkers(), ctx::receiveMarkers)); + namespaceDeclaration = namespaceDeclaration.withModifiers(ctx.receiveNonNullNodes(namespaceDeclaration.getModifiers(), ctx::receiveTree)); + namespaceDeclaration = namespaceDeclaration.withNamespace(ctx.receiveNonNullNode(namespaceDeclaration.getNamespace(), JavaScriptReceiver::receiveSpace)); + namespaceDeclaration = namespaceDeclaration.getPadding().withName(ctx.receiveNonNullNode(namespaceDeclaration.getPadding().getName(), JavaScriptReceiver::receiveRightPaddedTree)); + namespaceDeclaration = namespaceDeclaration.withBody(ctx.receiveNonNullNode(namespaceDeclaration.getBody(), ctx::receiveTree)); + return namespaceDeclaration; + } + @Override public J.AnnotatedType visitAnnotatedType(J.AnnotatedType annotatedType, ReceiverContext ctx) { annotatedType = annotatedType.withId(ctx.receiveNonNullValue(annotatedType.getId(), UUID.class)); @@ -1373,6 +1385,18 @@ public T create(Class type, ReceiverContext ctx) { ); } + if (type == JS.NamespaceDeclaration.class) { + return (T) new JS.NamespaceDeclaration( + ctx.receiveNonNullValue(null, UUID.class), + ctx.receiveNonNullNode(null, JavaScriptReceiver::receiveSpace), + ctx.receiveNonNullNode(null, ctx::receiveMarkers), + ctx.receiveNonNullNodes(null, ctx::receiveTree), + ctx.receiveNonNullNode(null, JavaScriptReceiver::receiveSpace), + ctx.receiveNonNullNode(null, JavaScriptReceiver::receiveRightPaddedTree), + ctx.receiveNonNullNode(null, ctx::receiveTree) + ); + } + if (type == J.AnnotatedType.class) { return (T) new J.AnnotatedType( 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 2c588d30..18d0edf0 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,18 @@ public JS.TypeInfo visitTypeInfo(JS.TypeInfo typeInfo, SenderContext ctx) { return typeInfo; } + @Override + public JS.NamespaceDeclaration visitNamespaceDeclaration(JS.NamespaceDeclaration namespaceDeclaration, SenderContext ctx) { + ctx.sendValue(namespaceDeclaration, JS.NamespaceDeclaration::getId); + ctx.sendNode(namespaceDeclaration, JS.NamespaceDeclaration::getPrefix, JavaScriptSender::sendSpace); + ctx.sendNode(namespaceDeclaration, JS.NamespaceDeclaration::getMarkers, ctx::sendMarkers); + ctx.sendNodes(namespaceDeclaration, JS.NamespaceDeclaration::getModifiers, ctx::sendTree, Tree::getId); + ctx.sendNode(namespaceDeclaration, JS.NamespaceDeclaration::getNamespace, JavaScriptSender::sendSpace); + ctx.sendNode(namespaceDeclaration, e -> e.getPadding().getName(), JavaScriptSender::sendRightPadded); + ctx.sendNode(namespaceDeclaration, JS.NamespaceDeclaration::getBody, ctx::sendTree); + return namespaceDeclaration; + } + @Override public J.AnnotatedType visitAnnotatedType(J.AnnotatedType annotatedType, SenderContext ctx) { ctx.sendValue(annotatedType, J.AnnotatedType::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 a643060e..93c7a982 100644 --- a/rewrite-javascript/src/main/java/org/openrewrite/javascript/JavaScriptVisitor.java +++ b/rewrite-javascript/src/main/java/org/openrewrite/javascript/JavaScriptVisitor.java @@ -593,4 +593,23 @@ public J visitTypeInfo(JS.TypeInfo typeInfo, P p) { ti = ti.withTypeIdentifier(visitAndCast(ti.getTypeIdentifier(), p)); return ti; } + + public J visitNamespaceDeclaration(JS.NamespaceDeclaration namespaceDeclaration, P p) { + JS.NamespaceDeclaration ns = namespaceDeclaration; + ns = ns.withPrefix(visitSpace(ns.getPrefix(), JsSpace.Location.NAMESPACE_DECLARATION_PREFIX, p)); + ns = ns.withMarkers(visitMarkers(ns.getMarkers(), p)); + ns = ns.withModifiers(ListUtils.map(ns.getModifiers(), + mod -> mod.withPrefix(visitSpace(mod.getPrefix(), Space.Location.MODIFIER_PREFIX, p)))); + ns = ns.withModifiers(ListUtils.map(ns.getModifiers(), m -> visitAndCast(m, p))); + Statement temp = (Statement) visitStatement(ns, p); + if (!(temp instanceof JS.NamespaceDeclaration)) { + return temp; + } else { + ns = (JS.NamespaceDeclaration) temp; + } + ns = ns.withNamespace(visitSpace(ns.getNamespace(), JsSpace.Location.NAMESPACE_KEYWORD_DECLARATION_PREFIX, p)); + ns = ns.getPadding().withName(visitRightPadded(ns.getPadding().getName(), JsRightPadded.Location.NAMESPACE_DECLARATION_NAME, p)); + ns = ns.withBody(visitAndCast(ns.getBody(), p)); + return ns; + } } 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 3a0aefbf..ce749c72 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 @@ -250,6 +250,18 @@ public J visitPropertyAssignment(JS.PropertyAssignment propertyAssignment, Print return propertyAssignment; } + @Override + public J visitNamespaceDeclaration(JS.NamespaceDeclaration namespaceDeclaration, PrintOutputCapture

p) { + beforeSyntax(namespaceDeclaration, JsSpace.Location.NAMESPACE_DECLARATION_PREFIX, p); + namespaceDeclaration.getModifiers().forEach(it -> delegate.visitModifier(it, p)); + visitSpace(namespaceDeclaration.getNamespace(), JsSpace.Location.NAMESPACE_KEYWORD_DECLARATION_PREFIX, p); + p.append("namespace"); + visit(namespaceDeclaration.getName(), p); + visit(namespaceDeclaration.getBody(), p); + afterSyntax(namespaceDeclaration, p); + return namespaceDeclaration; + } + @Override public J visitScopedVariableDeclarations(JS.ScopedVariableDeclarations variableDeclarations, PrintOutputCapture

p) { beforeSyntax(variableDeclarations, Space.Location.VARIABLE_DECLARATIONS_PREFIX, 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 86811110..98e88afd 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 @@ -2145,4 +2145,89 @@ public CoordinateBuilder.Expression getCoordinates() { return new CoordinateBuilder.Expression(this); } } + + @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) + @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) + @RequiredArgsConstructor + @AllArgsConstructor(access = AccessLevel.PRIVATE) + final class NamespaceDeclaration implements JS, Statement { + + @Nullable + @NonFinal + transient WeakReference padding; + + @EqualsAndHashCode.Include + @With + @Getter + UUID id; + + @With + @Getter + Space prefix; + + @With + @Getter + Markers markers; + + @With + @Getter + List modifiers; + + @With + @Getter + Space namespace; + + JRightPadded name; + + public Expression getName() { + return name.getElement(); + } + + public NamespaceDeclaration withName(Expression expression) { + return getPadding().withName(JRightPadded.withElement(this.name, expression)); + } + + @With + @Getter + Block body; + + @Override + public

J acceptJavaScript(JavaScriptVisitor

v, P p) { + return v.visitNamespaceDeclaration(this, p); + } + + @Transient + @Override + public CoordinateBuilder.Statement getCoordinates() { + return new CoordinateBuilder.Statement(this); + } + + public NamespaceDeclaration.Padding getPadding() { + NamespaceDeclaration.Padding p; + if (this.padding == null) { + p = new NamespaceDeclaration.Padding(this); + this.padding = new WeakReference<>(p); + } else { + p = this.padding.get(); + if (p == null || p.t != this) { + p = new NamespaceDeclaration.Padding(this); + this.padding = new WeakReference<>(p); + } + } + return p; + } + + @RequiredArgsConstructor + public static class Padding { + private final NamespaceDeclaration t; + + public NamespaceDeclaration withName(JRightPadded name) { + return t.name == name ? t : new NamespaceDeclaration(t.id, t.prefix, t.markers, t.modifiers, t.namespace, name, t.body); + } + + public JRightPadded getName() { + return t.name; + } + } + } } 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 27515990..292b82ec 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,7 +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), - ; + 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 65f2586a..791e2b49 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,5 +73,7 @@ public enum Location { YIELD_PREFIX, TYPE_INFO_PREFIX, TYPE_REFERENCE_PREFIX, + NAMESPACE_DECLARATION_PREFIX, + NAMESPACE_KEYWORD_DECLARATION_PREFIX } }