Skip to content

Commit

Permalink
Fixed trailing comma in TypeParameters, updated decorators (#179)
Browse files Browse the repository at this point in the history
Co-authored-by: Andrii Rodionov <[email protected]>
  • Loading branch information
arodionov and Andrii Rodionov authored Dec 24, 2024
1 parent 0e88045 commit 8373432
Show file tree
Hide file tree
Showing 18 changed files with 191 additions and 44 deletions.
61 changes: 46 additions & 15 deletions openrewrite/src/javascript/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -771,7 +771,14 @@ export class JavaScriptParserVisitor {
let _arguments: JContainer<J.Expression> | null = null;

if (ts.isCallExpression(node.expression)) {
annotationType = this.convert(node.expression.expression);
annotationType = new JS.ExpressionWithTypeArguments(
randomId(),
Space.EMPTY,
Markers.EMPTY,
this.convert(node.expression.expression),
node.expression.typeArguments ? this.mapTypeArguments(this.suffix(node.expression.expression), node.expression.typeArguments) : null,
null
);
_arguments = this.mapCommaSeparatedList(node.expression.getChildren(this.sourceFile).slice(-3))
} else if (ts.isIdentifier(node.expression)) {
annotationType = this.convert(node.expression);
Expand Down Expand Up @@ -1146,7 +1153,7 @@ export class JavaScriptParserVisitor {
randomId(),
this.prefix(node),
Markers.EMPTY,
[],
this.mapDecorators(node),
this.mapModifiers(node),
null,
this.mapTypeInfo(node),
Expand All @@ -1163,7 +1170,7 @@ export class JavaScriptParserVisitor {
randomId(),
this.prefix(node),
Markers.EMPTY,
[],
this.mapDecorators(node),
this.mapModifiers(node),
null,
this.mapTypeInfo(node),
Expand All @@ -1186,7 +1193,7 @@ export class JavaScriptParserVisitor {
randomId(),
this.prefix(node),
Markers.EMPTY,
[],
this.mapDecorators(node),
this.mapModifiers(node),
null,
null,
Expand All @@ -1203,7 +1210,7 @@ export class JavaScriptParserVisitor {
randomId(),
this.prefix(node),
Markers.EMPTY,
[],
this.mapDecorators(node),
this.mapModifiers(node),
null,
null,
Expand Down Expand Up @@ -2615,7 +2622,7 @@ export class JavaScriptParserVisitor {
Markers.EMPTY,
[node.initializer ?
(ts.isVariableDeclarationList(node.initializer) ? this.rightPadded(this.visit(node.initializer), Space.EMPTY) :
this.rightPadded(new ExpressionStatement(randomId(), this.visit(node.initializer)), this.suffix(node.initializer.getLastToken()!))) :
this.rightPadded(new ExpressionStatement(randomId(), this.visit(node.initializer)), this.suffix(node.initializer))) :
this.rightPadded(this.newJEmpty(), this.suffix(this.findChildNode(node, ts.SyntaxKind.OpenParenToken)!))], // to handle for (/*_*/; ; );
node.condition ? this.rightPadded(ts.isStatement(node.condition) ? this.visit(node.condition) : new ExpressionStatement(randomId(), this.visit(node.condition)), this.suffix(node.condition)) :
this.rightPadded(this.newJEmpty(), this.suffix(this.findChildNode(node, ts.SyntaxKind.SemicolonToken)!)), // to handle for ( ;/*_*/; );
Expand Down Expand Up @@ -2758,7 +2765,7 @@ export class JavaScriptParserVisitor {
visitVariableDeclaration(node: ts.VariableDeclaration) {
const nameExpression = this.visit(node.name);

if (nameExpression instanceof J.Identifier) {
if (nameExpression instanceof J.Identifier && !node.exclamationToken) {
return new J.VariableDeclarations.NamedVariable(
randomId(),
this.prefix(node),
Expand All @@ -2774,7 +2781,17 @@ export class JavaScriptParserVisitor {
randomId(),
this.prefix(node),
Markers.EMPTY,
nameExpression,
node.exclamationToken ? new JS.Unary(
randomId(),
Space.EMPTY,
Markers.EMPTY,
this.leftPadded(
this.suffix(node.name),
JS.Unary.Type.Exclamation
),
nameExpression,
this.mapType(node)
) : nameExpression,
[],
node.initializer ? this.leftPadded(this.prefix(node.getChildAt(node.getChildCount(this.sourceFile) - 2)), this.visit(node.initializer)) : null,
this.mapVariableType(node)
Expand Down Expand Up @@ -2945,9 +2962,15 @@ export class JavaScriptParserVisitor {
visitModuleDeclaration(node: ts.ModuleDeclaration) {
const body = node.body ? this.visit(node.body as ts.Node) : null;

let namespaceKeyword = this.findChildNode(node, ts.SyntaxKind.NamespaceKeyword);
const keywordType = namespaceKeyword ? JS.NamespaceDeclaration.KeywordType.Namespace : JS.NamespaceDeclaration.KeywordType.Module
namespaceKeyword ??= this.findChildNode(node, ts.SyntaxKind.ModuleKeyword);
let namespaceKeyword = this.findChildNode(node, ts.SyntaxKind.NamespaceKeyword) ?? this.findChildNode(node, ts.SyntaxKind.ModuleKeyword);
let keywordType: JS.NamespaceDeclaration.KeywordType;
if (namespaceKeyword == undefined) {
keywordType = JS.NamespaceDeclaration.KeywordType.Empty;
} else if (namespaceKeyword?.kind === ts.SyntaxKind.NamespaceKeyword) {
keywordType = JS.NamespaceDeclaration.KeywordType.Namespace;
} else {
keywordType = JS.NamespaceDeclaration.KeywordType.Module;
}
if (body instanceof JS.NamespaceDeclaration) {
return new JS.NamespaceDeclaration(
randomId(),
Expand Down Expand Up @@ -3368,6 +3391,7 @@ export class JavaScriptParserVisitor {
this.prefix(node),
Markers.EMPTY,
this.rightPadded(this.visit(node.name), this.suffix(node.name)),
JS.PropertyAssignment.AssigmentToken.Colon,
this.visit(node.initializer)
);
}
Expand All @@ -3378,7 +3402,8 @@ export class JavaScriptParserVisitor {
this.prefix(node),
Markers.EMPTY,
this.rightPadded(this.visit(node.name), this.suffix(node.name)),
null
JS.PropertyAssignment.AssigmentToken.Equals,
node.objectAssignmentInitializer ? this.visit(node.objectAssignmentInitializer) : null
);
}

Expand All @@ -3401,6 +3426,7 @@ export class JavaScriptParserVisitor {
),
this.suffix(node.expression)
),
JS.PropertyAssignment.AssigmentToken.Empty,
null
);
}
Expand Down Expand Up @@ -3740,15 +3766,18 @@ export class JavaScriptParserVisitor {
return args;
}

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

private mapTypeParametersAsJContainer(node: ts.ClassDeclaration | ts.InterfaceDeclaration | ts.ClassExpression): JContainer<J.TypeParameter> | null {
return node.typeParameters
? JContainer.build(
this.suffix(this.findChildNode(node, ts.SyntaxKind.Identifier)!),
this.mapTypeParametersList(node.typeParameters),
this.mapTypeParametersList(node.typeParameters)
.concat(node.typeParameters.hasTrailingComma ? this.rightPadded(
new J.TypeParameter(randomId(), Space.EMPTY, Markers.EMPTY, [], [], this.newJEmpty(), null),
this.prefix(this.findChildNode(node, ts.SyntaxKind.GreaterThanToken)!)) : []),
Markers.EMPTY
)
: null;
Expand All @@ -3765,7 +3794,9 @@ export class JavaScriptParserVisitor {
Markers.EMPTY,
[],
typeParameters.map(tp => this.rightPadded(this.visit(tp), this.suffix(tp)))
.concat(typeParameters.hasTrailingComma ? this.rightPadded(this.newJEmpty(), this.prefix(this.findChildNode(node, ts.SyntaxKind.GreaterThanToken)!)) : []),
.concat(typeParameters.hasTrailingComma ? this.rightPadded(
new J.TypeParameter(randomId(), Space.EMPTY, Markers.EMPTY, [], [], this.newJEmpty(), null),
this.prefix(this.findChildNode(node, ts.SyntaxKind.GreaterThanToken)!)) : []),
);
}

Expand Down
4 changes: 3 additions & 1 deletion openrewrite/src/javascript/remote/receiver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ class Visitor extends JavaScriptVisitor<ReceiverContext> {
propertyAssignment = propertyAssignment.withPrefix(ctx.receiveNode(propertyAssignment.prefix, receiveSpace)!);
propertyAssignment = propertyAssignment.withMarkers(ctx.receiveNode(propertyAssignment.markers, ctx.receiveMarkers)!);
propertyAssignment = propertyAssignment.padding.withName(ctx.receiveNode(propertyAssignment.padding.name, receiveRightPaddedTree)!);
propertyAssignment = propertyAssignment.withAssigmentToken(ctx.receiveValue(propertyAssignment.assigmentToken, ValueType.Enum)!);
propertyAssignment = propertyAssignment.withInitializer(ctx.receiveNode(propertyAssignment.initializer, ctx.receiveTree));
return propertyAssignment;
}
Expand Down Expand Up @@ -1575,6 +1576,7 @@ class Factory implements ReceiverFactory {
ctx.receiveNode(null, receiveSpace)!,
ctx.receiveNode(null, ctx.receiveMarkers)!,
ctx.receiveNode<JRightPadded<Expression>>(null, receiveRightPaddedTree)!,
ctx.receiveValue(null, ValueType.Enum)!,
ctx.receiveNode<Expression>(null, ctx.receiveTree)
);
}
Expand Down Expand Up @@ -1941,7 +1943,7 @@ class Factory implements ReceiverFactory {
ctx.receiveValue(null, ValueType.UUID)!,
ctx.receiveNode(null, receiveSpace)!,
ctx.receiveNode(null, ctx.receiveMarkers)!,
ctx.receiveNode<JContainer<ExportSpecifier>>(null, receiveContainer)!,
ctx.receiveNode<JContainer<Expression>>(null, receiveContainer)!,
ctx.receiveValue(null, ValueType.Object)
);
}
Expand Down
1 change: 1 addition & 0 deletions openrewrite/src/javascript/remote/sender.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ class Visitor extends JavaScriptVisitor<SenderContext> {
ctx.sendNode(propertyAssignment, v => v.prefix, Visitor.sendSpace);
ctx.sendNode(propertyAssignment, v => v.markers, ctx.sendMarkers);
ctx.sendNode(propertyAssignment, v => v.padding.name, Visitor.sendRightPadded(ValueType.Tree));
ctx.sendValue(propertyAssignment, v => v.assigmentToken, ValueType.Enum);
ctx.sendNode(propertyAssignment, v => v.initializer, ctx.sendTree);
return propertyAssignment;
}
Expand Down
46 changes: 34 additions & 12 deletions openrewrite/src/javascript/tree/tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2101,12 +2101,13 @@ export class ObjectBindingDeclarations extends JSMixin(Object) implements Expres

@LstType("org.openrewrite.javascript.tree.JS$PropertyAssignment")
export class PropertyAssignment extends JSMixin(Object) implements Statement, TypedTree {
public constructor(id: UUID, prefix: Space, markers: Markers, name: JRightPadded<Expression>, initializer: Expression | null) {
public constructor(id: UUID, prefix: Space, markers: Markers, name: JRightPadded<Expression>, assigmentToken: PropertyAssignment.AssigmentToken, initializer: Expression | null) {
super();
this._id = id;
this._prefix = prefix;
this._markers = markers;
this._name = name;
this._assigmentToken = assigmentToken;
this._initializer = initializer;
}

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

public withId(id: UUID): PropertyAssignment {
return id === this._id ? this : new PropertyAssignment(id, this._prefix, this._markers, this._name, this._initializer);
return id === this._id ? this : new PropertyAssignment(id, this._prefix, this._markers, this._name, this._assigmentToken, this._initializer);
}

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

public withPrefix(prefix: Space): PropertyAssignment {
return prefix === this._prefix ? this : new PropertyAssignment(this._id, prefix, this._markers, this._name, this._initializer);
return prefix === this._prefix ? this : new PropertyAssignment(this._id, prefix, this._markers, this._name, this._assigmentToken, this._initializer);
}

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

public withMarkers(markers: Markers): PropertyAssignment {
return markers === this._markers ? this : new PropertyAssignment(this._id, this._prefix, markers, this._name, this._initializer);
return markers === this._markers ? this : new PropertyAssignment(this._id, this._prefix, markers, this._name, this._assigmentToken, this._initializer);
}

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

private readonly _assigmentToken: PropertyAssignment.AssigmentToken;

public get assigmentToken(): PropertyAssignment.AssigmentToken {
return this._assigmentToken;
}

public withAssigmentToken(assigmentToken: PropertyAssignment.AssigmentToken): PropertyAssignment {
return assigmentToken === this._assigmentToken ? this : new PropertyAssignment(this._id, this._prefix, this._markers, this._name, assigmentToken, this._initializer);
}

private readonly _initializer: Expression | null;

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

public withInitializer(initializer: Expression | null): PropertyAssignment {
return initializer === this._initializer ? this : new PropertyAssignment(this._id, this._prefix, this._markers, this._name, initializer);
return initializer === this._initializer ? this : new PropertyAssignment(this._id, this._prefix, this._markers, this._name, this._assigmentToken, initializer);
}

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

}

export namespace PropertyAssignment {
export enum AssigmentToken {
Colon = 0,
Equals = 1,
Empty = 2,

}

}

@LstType("org.openrewrite.javascript.tree.JS$SatisfiesExpression")
export class SatisfiesExpression extends JSMixin(Object) implements Expression {
public constructor(id: UUID, prefix: Space, markers: Markers, expression: J, satisfiesType: JLeftPadded<Expression>, _type: JavaType | null) {
Expand Down Expand Up @@ -4482,6 +4503,7 @@ export namespace NamespaceDeclaration {
export enum KeywordType {
Namespace = 0,
Module = 1,
Empty = 2,

}

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

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

private readonly _elements: JContainer<ExportSpecifier>;
private readonly _elements: JContainer<Expression>;

public get elements(): ExportSpecifier[] {
public get elements(): Expression[] {
return this._elements.elements;
}

public withElements(elements: ExportSpecifier[]): NamedExports {
public withElements(elements: Expression[]): NamedExports {
return this.padding.withElements(JContainer.withElements(this._elements, elements));
}

Expand All @@ -5277,10 +5299,10 @@ export class NamedExports extends JSMixin(Object) implements Expression {
get padding() {
const t = this;
return new class {
public get elements(): JContainer<ExportSpecifier> {
public get elements(): JContainer<Expression> {
return t._elements;
}
public withElements(elements: JContainer<ExportSpecifier>): NamedExports {
public withElements(elements: JContainer<Expression>): NamedExports {
return t._elements === elements ? t : new NamedExports(t._id, t._prefix, t._markers, elements, t._type);
}
}
Expand Down
1 change: 1 addition & 0 deletions openrewrite/test/javascript/parser/call.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ describe('call mapping', () => {
//language=typescript
typeScript(`
var d = (new Date).getTime()
// use marker omit
`)
);
});
Expand Down
11 changes: 11 additions & 0 deletions openrewrite/test/javascript/parser/class.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -542,4 +542,15 @@ describe('class mapping', () => {
);
});

test('class with type param with trailing comma', () => {
rewriteRun(
//language=typescript
typeScript(`
export class APIError<
TData extends null | object = { [key: string]: unknown } | null,
> extends ExtendableError<TData> {}
`)
);
});

});
9 changes: 9 additions & 0 deletions openrewrite/test/javascript/parser/decorator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ describe('class decorator mapping', () => {
`)
);
});
test('decorator with type params', () => {
rewriteRun(
//language=typescript
typeScript(`
@StaticInterfaceImplement/*a*/<ISpriteAssembler>/*b*/()
export class SimpleSpriteAssembler {}
`)
);
});
test('class / method / params / properties decorators', () => {
rewriteRun(
//language=typescript
Expand Down
12 changes: 12 additions & 0 deletions openrewrite/test/javascript/parser/do-while.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,16 @@ describe('do-while mapping', () => {
`)
);
});

test.skip('do-while with labeled statement', () => {
rewriteRun(
//language=typescript
typeScript(`
partition: do {
break partition;
} while (from < to)/*a*/;/*b*/
`)
);
});

});
Loading

0 comments on commit 8373432

Please sign in to comment.