Skip to content
This repository was archived by the owner on May 12, 2025. It is now read-only.

Commit 8373432

Browse files
arodionovAndrii Rodionov
andauthored
Fixed trailing comma in TypeParameters, updated decorators (#179)
Co-authored-by: Andrii Rodionov <andriih@moderne.io>
1 parent 0e88045 commit 8373432

File tree

18 files changed

+191
-44
lines changed

18 files changed

+191
-44
lines changed

openrewrite/src/javascript/parser.ts

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -771,7 +771,14 @@ export class JavaScriptParserVisitor {
771771
let _arguments: JContainer<J.Expression> | null = null;
772772

773773
if (ts.isCallExpression(node.expression)) {
774-
annotationType = this.convert(node.expression.expression);
774+
annotationType = new JS.ExpressionWithTypeArguments(
775+
randomId(),
776+
Space.EMPTY,
777+
Markers.EMPTY,
778+
this.convert(node.expression.expression),
779+
node.expression.typeArguments ? this.mapTypeArguments(this.suffix(node.expression.expression), node.expression.typeArguments) : null,
780+
null
781+
);
775782
_arguments = this.mapCommaSeparatedList(node.expression.getChildren(this.sourceFile).slice(-3))
776783
} else if (ts.isIdentifier(node.expression)) {
777784
annotationType = this.convert(node.expression);
@@ -1146,7 +1153,7 @@ export class JavaScriptParserVisitor {
11461153
randomId(),
11471154
this.prefix(node),
11481155
Markers.EMPTY,
1149-
[],
1156+
this.mapDecorators(node),
11501157
this.mapModifiers(node),
11511158
null,
11521159
this.mapTypeInfo(node),
@@ -1163,7 +1170,7 @@ export class JavaScriptParserVisitor {
11631170
randomId(),
11641171
this.prefix(node),
11651172
Markers.EMPTY,
1166-
[],
1173+
this.mapDecorators(node),
11671174
this.mapModifiers(node),
11681175
null,
11691176
this.mapTypeInfo(node),
@@ -1186,7 +1193,7 @@ export class JavaScriptParserVisitor {
11861193
randomId(),
11871194
this.prefix(node),
11881195
Markers.EMPTY,
1189-
[],
1196+
this.mapDecorators(node),
11901197
this.mapModifiers(node),
11911198
null,
11921199
null,
@@ -1203,7 +1210,7 @@ export class JavaScriptParserVisitor {
12031210
randomId(),
12041211
this.prefix(node),
12051212
Markers.EMPTY,
1206-
[],
1213+
this.mapDecorators(node),
12071214
this.mapModifiers(node),
12081215
null,
12091216
null,
@@ -2615,7 +2622,7 @@ export class JavaScriptParserVisitor {
26152622
Markers.EMPTY,
26162623
[node.initializer ?
26172624
(ts.isVariableDeclarationList(node.initializer) ? this.rightPadded(this.visit(node.initializer), Space.EMPTY) :
2618-
this.rightPadded(new ExpressionStatement(randomId(), this.visit(node.initializer)), this.suffix(node.initializer.getLastToken()!))) :
2625+
this.rightPadded(new ExpressionStatement(randomId(), this.visit(node.initializer)), this.suffix(node.initializer))) :
26192626
this.rightPadded(this.newJEmpty(), this.suffix(this.findChildNode(node, ts.SyntaxKind.OpenParenToken)!))], // to handle for (/*_*/; ; );
26202627
node.condition ? this.rightPadded(ts.isStatement(node.condition) ? this.visit(node.condition) : new ExpressionStatement(randomId(), this.visit(node.condition)), this.suffix(node.condition)) :
26212628
this.rightPadded(this.newJEmpty(), this.suffix(this.findChildNode(node, ts.SyntaxKind.SemicolonToken)!)), // to handle for ( ;/*_*/; );
@@ -2758,7 +2765,7 @@ export class JavaScriptParserVisitor {
27582765
visitVariableDeclaration(node: ts.VariableDeclaration) {
27592766
const nameExpression = this.visit(node.name);
27602767

2761-
if (nameExpression instanceof J.Identifier) {
2768+
if (nameExpression instanceof J.Identifier && !node.exclamationToken) {
27622769
return new J.VariableDeclarations.NamedVariable(
27632770
randomId(),
27642771
this.prefix(node),
@@ -2774,7 +2781,17 @@ export class JavaScriptParserVisitor {
27742781
randomId(),
27752782
this.prefix(node),
27762783
Markers.EMPTY,
2777-
nameExpression,
2784+
node.exclamationToken ? new JS.Unary(
2785+
randomId(),
2786+
Space.EMPTY,
2787+
Markers.EMPTY,
2788+
this.leftPadded(
2789+
this.suffix(node.name),
2790+
JS.Unary.Type.Exclamation
2791+
),
2792+
nameExpression,
2793+
this.mapType(node)
2794+
) : nameExpression,
27782795
[],
27792796
node.initializer ? this.leftPadded(this.prefix(node.getChildAt(node.getChildCount(this.sourceFile) - 2)), this.visit(node.initializer)) : null,
27802797
this.mapVariableType(node)
@@ -2945,9 +2962,15 @@ export class JavaScriptParserVisitor {
29452962
visitModuleDeclaration(node: ts.ModuleDeclaration) {
29462963
const body = node.body ? this.visit(node.body as ts.Node) : null;
29472964

2948-
let namespaceKeyword = this.findChildNode(node, ts.SyntaxKind.NamespaceKeyword);
2949-
const keywordType = namespaceKeyword ? JS.NamespaceDeclaration.KeywordType.Namespace : JS.NamespaceDeclaration.KeywordType.Module
2950-
namespaceKeyword ??= this.findChildNode(node, ts.SyntaxKind.ModuleKeyword);
2965+
let namespaceKeyword = this.findChildNode(node, ts.SyntaxKind.NamespaceKeyword) ?? this.findChildNode(node, ts.SyntaxKind.ModuleKeyword);
2966+
let keywordType: JS.NamespaceDeclaration.KeywordType;
2967+
if (namespaceKeyword == undefined) {
2968+
keywordType = JS.NamespaceDeclaration.KeywordType.Empty;
2969+
} else if (namespaceKeyword?.kind === ts.SyntaxKind.NamespaceKeyword) {
2970+
keywordType = JS.NamespaceDeclaration.KeywordType.Namespace;
2971+
} else {
2972+
keywordType = JS.NamespaceDeclaration.KeywordType.Module;
2973+
}
29512974
if (body instanceof JS.NamespaceDeclaration) {
29522975
return new JS.NamespaceDeclaration(
29532976
randomId(),
@@ -3368,6 +3391,7 @@ export class JavaScriptParserVisitor {
33683391
this.prefix(node),
33693392
Markers.EMPTY,
33703393
this.rightPadded(this.visit(node.name), this.suffix(node.name)),
3394+
JS.PropertyAssignment.AssigmentToken.Colon,
33713395
this.visit(node.initializer)
33723396
);
33733397
}
@@ -3378,7 +3402,8 @@ export class JavaScriptParserVisitor {
33783402
this.prefix(node),
33793403
Markers.EMPTY,
33803404
this.rightPadded(this.visit(node.name), this.suffix(node.name)),
3381-
null
3405+
JS.PropertyAssignment.AssigmentToken.Equals,
3406+
node.objectAssignmentInitializer ? this.visit(node.objectAssignmentInitializer) : null
33823407
);
33833408
}
33843409

@@ -3401,6 +3426,7 @@ export class JavaScriptParserVisitor {
34013426
),
34023427
this.suffix(node.expression)
34033428
),
3429+
JS.PropertyAssignment.AssigmentToken.Empty,
34043430
null
34053431
);
34063432
}
@@ -3740,15 +3766,18 @@ export class JavaScriptParserVisitor {
37403766
return args;
37413767
}
37423768

3743-
private mapDecorators(node: ts.ClassDeclaration | ts.FunctionDeclaration | ts.MethodDeclaration | ts.ConstructorDeclaration | ts.ParameterDeclaration | ts.PropertyDeclaration): J.Annotation[] {
3769+
private mapDecorators(node: ts.ClassDeclaration | ts.FunctionDeclaration | ts.MethodDeclaration | ts.ConstructorDeclaration | ts.ParameterDeclaration | ts.PropertyDeclaration | ts.SetAccessorDeclaration | ts.GetAccessorDeclaration): J.Annotation[] {
37443770
return node.modifiers?.filter(ts.isDecorator)?.map(this.convert<J.Annotation>) ?? [];
37453771
}
37463772

37473773
private mapTypeParametersAsJContainer(node: ts.ClassDeclaration | ts.InterfaceDeclaration | ts.ClassExpression): JContainer<J.TypeParameter> | null {
37483774
return node.typeParameters
37493775
? JContainer.build(
37503776
this.suffix(this.findChildNode(node, ts.SyntaxKind.Identifier)!),
3751-
this.mapTypeParametersList(node.typeParameters),
3777+
this.mapTypeParametersList(node.typeParameters)
3778+
.concat(node.typeParameters.hasTrailingComma ? this.rightPadded(
3779+
new J.TypeParameter(randomId(), Space.EMPTY, Markers.EMPTY, [], [], this.newJEmpty(), null),
3780+
this.prefix(this.findChildNode(node, ts.SyntaxKind.GreaterThanToken)!)) : []),
37523781
Markers.EMPTY
37533782
)
37543783
: null;
@@ -3765,7 +3794,9 @@ export class JavaScriptParserVisitor {
37653794
Markers.EMPTY,
37663795
[],
37673796
typeParameters.map(tp => this.rightPadded(this.visit(tp), this.suffix(tp)))
3768-
.concat(typeParameters.hasTrailingComma ? this.rightPadded(this.newJEmpty(), this.prefix(this.findChildNode(node, ts.SyntaxKind.GreaterThanToken)!)) : []),
3797+
.concat(typeParameters.hasTrailingComma ? this.rightPadded(
3798+
new J.TypeParameter(randomId(), Space.EMPTY, Markers.EMPTY, [], [], this.newJEmpty(), null),
3799+
this.prefix(this.findChildNode(node, ts.SyntaxKind.GreaterThanToken)!)) : []),
37693800
);
37703801
}
37713802

openrewrite/src/javascript/remote/receiver.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ class Visitor extends JavaScriptVisitor<ReceiverContext> {
258258
propertyAssignment = propertyAssignment.withPrefix(ctx.receiveNode(propertyAssignment.prefix, receiveSpace)!);
259259
propertyAssignment = propertyAssignment.withMarkers(ctx.receiveNode(propertyAssignment.markers, ctx.receiveMarkers)!);
260260
propertyAssignment = propertyAssignment.padding.withName(ctx.receiveNode(propertyAssignment.padding.name, receiveRightPaddedTree)!);
261+
propertyAssignment = propertyAssignment.withAssigmentToken(ctx.receiveValue(propertyAssignment.assigmentToken, ValueType.Enum)!);
261262
propertyAssignment = propertyAssignment.withInitializer(ctx.receiveNode(propertyAssignment.initializer, ctx.receiveTree));
262263
return propertyAssignment;
263264
}
@@ -1575,6 +1576,7 @@ class Factory implements ReceiverFactory {
15751576
ctx.receiveNode(null, receiveSpace)!,
15761577
ctx.receiveNode(null, ctx.receiveMarkers)!,
15771578
ctx.receiveNode<JRightPadded<Expression>>(null, receiveRightPaddedTree)!,
1579+
ctx.receiveValue(null, ValueType.Enum)!,
15781580
ctx.receiveNode<Expression>(null, ctx.receiveTree)
15791581
);
15801582
}
@@ -1941,7 +1943,7 @@ class Factory implements ReceiverFactory {
19411943
ctx.receiveValue(null, ValueType.UUID)!,
19421944
ctx.receiveNode(null, receiveSpace)!,
19431945
ctx.receiveNode(null, ctx.receiveMarkers)!,
1944-
ctx.receiveNode<JContainer<ExportSpecifier>>(null, receiveContainer)!,
1946+
ctx.receiveNode<JContainer<Expression>>(null, receiveContainer)!,
19451947
ctx.receiveValue(null, ValueType.Object)
19461948
);
19471949
}

openrewrite/src/javascript/remote/sender.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ class Visitor extends JavaScriptVisitor<SenderContext> {
253253
ctx.sendNode(propertyAssignment, v => v.prefix, Visitor.sendSpace);
254254
ctx.sendNode(propertyAssignment, v => v.markers, ctx.sendMarkers);
255255
ctx.sendNode(propertyAssignment, v => v.padding.name, Visitor.sendRightPadded(ValueType.Tree));
256+
ctx.sendValue(propertyAssignment, v => v.assigmentToken, ValueType.Enum);
256257
ctx.sendNode(propertyAssignment, v => v.initializer, ctx.sendTree);
257258
return propertyAssignment;
258259
}

openrewrite/src/javascript/tree/tree.ts

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2101,12 +2101,13 @@ export class ObjectBindingDeclarations extends JSMixin(Object) implements Expres
21012101

21022102
@LstType("org.openrewrite.javascript.tree.JS$PropertyAssignment")
21032103
export class PropertyAssignment extends JSMixin(Object) implements Statement, TypedTree {
2104-
public constructor(id: UUID, prefix: Space, markers: Markers, name: JRightPadded<Expression>, initializer: Expression | null) {
2104+
public constructor(id: UUID, prefix: Space, markers: Markers, name: JRightPadded<Expression>, assigmentToken: PropertyAssignment.AssigmentToken, initializer: Expression | null) {
21052105
super();
21062106
this._id = id;
21072107
this._prefix = prefix;
21082108
this._markers = markers;
21092109
this._name = name;
2110+
this._assigmentToken = assigmentToken;
21102111
this._initializer = initializer;
21112112
}
21122113

@@ -2117,7 +2118,7 @@ export class PropertyAssignment extends JSMixin(Object) implements Statement, Ty
21172118
}
21182119

21192120
public withId(id: UUID): PropertyAssignment {
2120-
return id === this._id ? this : new PropertyAssignment(id, this._prefix, this._markers, this._name, this._initializer);
2121+
return id === this._id ? this : new PropertyAssignment(id, this._prefix, this._markers, this._name, this._assigmentToken, this._initializer);
21212122
}
21222123

21232124
private readonly _prefix: Space;
@@ -2127,7 +2128,7 @@ export class PropertyAssignment extends JSMixin(Object) implements Statement, Ty
21272128
}
21282129

21292130
public withPrefix(prefix: Space): PropertyAssignment {
2130-
return prefix === this._prefix ? this : new PropertyAssignment(this._id, prefix, this._markers, this._name, this._initializer);
2131+
return prefix === this._prefix ? this : new PropertyAssignment(this._id, prefix, this._markers, this._name, this._assigmentToken, this._initializer);
21312132
}
21322133

21332134
private readonly _markers: Markers;
@@ -2137,7 +2138,7 @@ export class PropertyAssignment extends JSMixin(Object) implements Statement, Ty
21372138
}
21382139

21392140
public withMarkers(markers: Markers): PropertyAssignment {
2140-
return markers === this._markers ? this : new PropertyAssignment(this._id, this._prefix, markers, this._name, this._initializer);
2141+
return markers === this._markers ? this : new PropertyAssignment(this._id, this._prefix, markers, this._name, this._assigmentToken, this._initializer);
21412142
}
21422143

21432144
private readonly _name: JRightPadded<Expression>;
@@ -2150,14 +2151,24 @@ export class PropertyAssignment extends JSMixin(Object) implements Statement, Ty
21502151
return this.padding.withName(this._name.withElement(name));
21512152
}
21522153

2154+
private readonly _assigmentToken: PropertyAssignment.AssigmentToken;
2155+
2156+
public get assigmentToken(): PropertyAssignment.AssigmentToken {
2157+
return this._assigmentToken;
2158+
}
2159+
2160+
public withAssigmentToken(assigmentToken: PropertyAssignment.AssigmentToken): PropertyAssignment {
2161+
return assigmentToken === this._assigmentToken ? this : new PropertyAssignment(this._id, this._prefix, this._markers, this._name, assigmentToken, this._initializer);
2162+
}
2163+
21532164
private readonly _initializer: Expression | null;
21542165

21552166
public get initializer(): Expression | null {
21562167
return this._initializer;
21572168
}
21582169

21592170
public withInitializer(initializer: Expression | null): PropertyAssignment {
2160-
return initializer === this._initializer ? this : new PropertyAssignment(this._id, this._prefix, this._markers, this._name, initializer);
2171+
return initializer === this._initializer ? this : new PropertyAssignment(this._id, this._prefix, this._markers, this._name, this._assigmentToken, initializer);
21612172
}
21622173

21632174
public acceptJavaScript<P>(v: JavaScriptVisitor<P>, p: P): J | null {
@@ -2179,13 +2190,23 @@ export class PropertyAssignment extends JSMixin(Object) implements Statement, Ty
21792190
return t._name;
21802191
}
21812192
public withName(name: JRightPadded<Expression>): PropertyAssignment {
2182-
return t._name === name ? t : new PropertyAssignment(t._id, t._prefix, t._markers, name, t._initializer);
2193+
return t._name === name ? t : new PropertyAssignment(t._id, t._prefix, t._markers, name, t._assigmentToken, t._initializer);
21832194
}
21842195
}
21852196
}
21862197

21872198
}
21882199

2200+
export namespace PropertyAssignment {
2201+
export enum AssigmentToken {
2202+
Colon = 0,
2203+
Equals = 1,
2204+
Empty = 2,
2205+
2206+
}
2207+
2208+
}
2209+
21892210
@LstType("org.openrewrite.javascript.tree.JS$SatisfiesExpression")
21902211
export class SatisfiesExpression extends JSMixin(Object) implements Expression {
21912212
public constructor(id: UUID, prefix: Space, markers: Markers, expression: J, satisfiesType: JLeftPadded<Expression>, _type: JavaType | null) {
@@ -4482,6 +4503,7 @@ export namespace NamespaceDeclaration {
44824503
export enum KeywordType {
44834504
Namespace = 0,
44844505
Module = 1,
4506+
Empty = 2,
44854507

44864508
}
44874509

@@ -5211,7 +5233,7 @@ export class ExportAssignment extends JSMixin(Object) implements Statement {
52115233

52125234
@LstType("org.openrewrite.javascript.tree.JS$NamedExports")
52135235
export class NamedExports extends JSMixin(Object) implements Expression {
5214-
public constructor(id: UUID, prefix: Space, markers: Markers, elements: JContainer<ExportSpecifier>, _type: JavaType | null) {
5236+
public constructor(id: UUID, prefix: Space, markers: Markers, elements: JContainer<Expression>, _type: JavaType | null) {
52155237
super();
52165238
this._id = id;
52175239
this._prefix = prefix;
@@ -5250,13 +5272,13 @@ export class NamedExports extends JSMixin(Object) implements Expression {
52505272
return markers === this._markers ? this : new NamedExports(this._id, this._prefix, markers, this._elements, this._type);
52515273
}
52525274

5253-
private readonly _elements: JContainer<ExportSpecifier>;
5275+
private readonly _elements: JContainer<Expression>;
52545276

5255-
public get elements(): ExportSpecifier[] {
5277+
public get elements(): Expression[] {
52565278
return this._elements.elements;
52575279
}
52585280

5259-
public withElements(elements: ExportSpecifier[]): NamedExports {
5281+
public withElements(elements: Expression[]): NamedExports {
52605282
return this.padding.withElements(JContainer.withElements(this._elements, elements));
52615283
}
52625284

@@ -5277,10 +5299,10 @@ export class NamedExports extends JSMixin(Object) implements Expression {
52775299
get padding() {
52785300
const t = this;
52795301
return new class {
5280-
public get elements(): JContainer<ExportSpecifier> {
5302+
public get elements(): JContainer<Expression> {
52815303
return t._elements;
52825304
}
5283-
public withElements(elements: JContainer<ExportSpecifier>): NamedExports {
5305+
public withElements(elements: JContainer<Expression>): NamedExports {
52845306
return t._elements === elements ? t : new NamedExports(t._id, t._prefix, t._markers, elements, t._type);
52855307
}
52865308
}

openrewrite/test/javascript/parser/call.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ describe('call mapping', () => {
162162
//language=typescript
163163
typeScript(`
164164
var d = (new Date).getTime()
165+
// use marker omit
165166
`)
166167
);
167168
});

openrewrite/test/javascript/parser/class.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,4 +542,15 @@ describe('class mapping', () => {
542542
);
543543
});
544544

545+
test('class with type param with trailing comma', () => {
546+
rewriteRun(
547+
//language=typescript
548+
typeScript(`
549+
export class APIError<
550+
TData extends null | object = { [key: string]: unknown } | null,
551+
> extends ExtendableError<TData> {}
552+
`)
553+
);
554+
});
555+
545556
});

openrewrite/test/javascript/parser/decorator.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,15 @@ describe('class decorator mapping', () => {
4545
`)
4646
);
4747
});
48+
test('decorator with type params', () => {
49+
rewriteRun(
50+
//language=typescript
51+
typeScript(`
52+
@StaticInterfaceImplement/*a*/<ISpriteAssembler>/*b*/()
53+
export class SimpleSpriteAssembler {}
54+
`)
55+
);
56+
});
4857
test('class / method / params / properties decorators', () => {
4958
rewriteRun(
5059
//language=typescript

openrewrite/test/javascript/parser/do-while.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,16 @@ describe('do-while mapping', () => {
3838
`)
3939
);
4040
});
41+
42+
test.skip('do-while with labeled statement', () => {
43+
rewriteRun(
44+
//language=typescript
45+
typeScript(`
46+
partition: do {
47+
break partition;
48+
} while (from < to)/*a*/;/*b*/
49+
`)
50+
);
51+
});
52+
4153
});

0 commit comments

Comments
 (0)