Skip to content

Commit

Permalink
Implemented support for FunctionExpression (#145)
Browse files Browse the repository at this point in the history
Created new JS.FunctionDeclaration to represent ts.FunctionExpression and ts.FunctionDeclaration.
Refactored visitFunctionDeclaration from J.MethodDeclaration to JS.FunctionDeclaration

Co-authored-by: Andrii Rodionov <[email protected]>
  • Loading branch information
arodionov and Andrii Rodionov authored Nov 15, 2024
1 parent e89418f commit e5249c2
Show file tree
Hide file tree
Showing 15 changed files with 502 additions and 62 deletions.
69 changes: 40 additions & 29 deletions openrewrite/src/javascript/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,9 +249,21 @@ 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 | ts.ModuleDeclaration | ts.GetAccessorDeclaration | ts.SetAccessorDeclaration) {
if (ts.isVariableStatement(node) || ts.isModuleDeclaration(node) || ts.isClassDeclaration(node) || ts.isEnumDeclaration(node) || ts.isInterfaceDeclaration(node) || ts.isPropertyDeclaration(node) || ts.isPropertySignature(node) || ts.isFunctionDeclaration(node) || ts.isParameter(node) || ts.isMethodDeclaration(node) || ts.isConstructorDeclaration(node)) {
if (ts.isVariableStatement(node) || ts.isModuleDeclaration(node) || ts.isClassDeclaration(node) || ts.isEnumDeclaration(node) || ts.isInterfaceDeclaration(node) || ts.isPropertyDeclaration(node) || ts.isPropertySignature(node) || ts.isParameter(node) || ts.isMethodDeclaration(node) || ts.isConstructorDeclaration(node)) {
return node.modifiers ? node.modifiers?.filter(ts.isModifier).map(this.mapModifier) : [];
} else if (ts.isVariableDeclarationList(node)) {
} else if (ts.isFunctionDeclaration(node)) {
return [...node.modifiers ? node.modifiers?.filter(ts.isModifier).map(this.mapModifier) : [],
// empty modifier is used to capture spaces before FunctionKeyword
new J.Modifier(
randomId(),
this.prefix(this.findChildNode(node, ts.SyntaxKind.FunctionKeyword)!),
Markers.EMPTY,
null,
J.Modifier.Type.LanguageExtension,
[]
)]
}
else if (ts.isVariableDeclarationList(node)) {
let modifier: string | undefined;
if ((node.flags & ts.NodeFlags.Let) !== 0) {
modifier = "let";
Expand All @@ -271,7 +283,7 @@ export class JavaScriptParserVisitor {
} else if (ts.isGetAccessorDeclaration(node)) {
return (node.modifiers ? node.modifiers?.filter(ts.isModifier).map(this.mapModifier) : []).concat(new J.Modifier(
randomId(),
this.prefix(node.getChildren().find(c => c.getText() === 'get')!),
this.prefix(this.findChildNode(node, ts.SyntaxKind.GetKeyword)!),
Markers.EMPTY,
'get',
J.Modifier.Type.LanguageExtension,
Expand All @@ -280,7 +292,7 @@ export class JavaScriptParserVisitor {
} else if (ts.isSetAccessorDeclaration(node)) {
return (node.modifiers ? node.modifiers?.filter(ts.isModifier).map(this.mapModifier) : []).concat(new J.Modifier(
randomId(),
this.prefix(node.getChildren().find(c => c.getText() === 'set')!),
this.prefix(this.findChildNode(node, ts.SyntaxKind.SetKeyword)!),
Markers.EMPTY,
'set',
J.Modifier.Type.LanguageExtension,
Expand Down Expand Up @@ -858,9 +870,7 @@ export class JavaScriptParserVisitor {
Markers.EMPTY,
this.mapDecorators(node),
this.mapModifiers(node),
node.typeParameters
? new J.TypeParameters(randomId(), this.suffix(node.name), Markers.EMPTY, [], node.typeParameters.map(tp => this.rightPadded(this.visit(tp), this.suffix(tp))))
: null,
this.mapTypeParametersAsObject(node),
this.mapTypeInfo(node),
this.getOptionalUnary(node),
this.mapCommaSeparatedList(this.getParameterListNodes(node)),
Expand Down Expand Up @@ -1301,7 +1311,18 @@ export class JavaScriptParserVisitor {
}

visitFunctionExpression(node: ts.FunctionExpression) {
return this.visitUnknown(node);
return new JS.FunctionDeclaration(
randomId(),
this.prefix(node),
Markers.EMPTY,
[],
null,
this.mapTypeParametersAsObject(node),
this.mapCommaSeparatedList(this.getParameterListNodes(node)),
this.mapTypeInfo(node),
this.convert(node.body),
this.mapMethodType(node)
);
}

visitArrowFunction(node: ts.ArrowFunction) {
Expand Down Expand Up @@ -1887,29 +1908,16 @@ export class JavaScriptParserVisitor {
}

visitFunctionDeclaration(node: ts.FunctionDeclaration) {
return new J.MethodDeclaration(
return new JS.FunctionDeclaration(
randomId(),
this.prefix(node),
Markers.EMPTY,
this.mapDecorators(node),
[new J.Modifier(
randomId(),
this.prefix(this.findChildNode(node, ts.SyntaxKind.FunctionKeyword)!),
Markers.EMPTY,
node.getChildAt(1, this.sourceFile).kind == ts.SyntaxKind.AsteriskToken ? "function*" : "function",
J.Modifier.Type.LanguageExtension,
[]
), ...this.mapModifiers(node)],
this.mapTypeParametersAsObject(node), // FIXME type parameters
this.mapTypeInfo(node),
new J.MethodDeclaration.IdentifierWithAnnotations(
node.name ? this.visit(node.name) : this.mapIdentifier(node, ""),
[]
),
this.mapModifiers(node),
this.visit(node.name!),
this.mapTypeParametersAsObject(node),
this.mapCommaSeparatedList(this.getParameterListNodes(node)),
null,
node.body ? this.convert<J.Block>(node.body) : null,
null,
this.mapTypeInfo(node),
this.convert(node.body!),
this.mapMethodType(node)
);
}
Expand Down Expand Up @@ -2613,12 +2621,15 @@ export class JavaScriptParserVisitor {
: null;
}

private mapTypeParametersAsObject(node: ts.MethodDeclaration | ts.MethodSignature | ts.FunctionDeclaration | ts.CallSignatureDeclaration | ts.ConstructSignatureDeclaration) : J.TypeParameters | null {
private mapTypeParametersAsObject(node: ts.MethodDeclaration | ts.MethodSignature | ts.FunctionDeclaration
| ts.CallSignatureDeclaration | ts.ConstructSignatureDeclaration | ts.FunctionExpression) : J.TypeParameters | null {
if (!node.typeParameters) return null;

let ts_prefix;
let ts_prefix: Space;
if (ts.isConstructSignatureDeclaration(node)) {
ts_prefix = this.suffix(this.findChildNode(node, ts.SyntaxKind.NewKeyword)!);
} else if (ts.isFunctionExpression(node)) {
ts_prefix = this.suffix(this.findChildNode(node, ts.SyntaxKind.FunctionKeyword)!);
} else {
ts_prefix = node.questionToken ? this.suffix(node.questionToken) : node.name ? this.suffix(node.name) : Space.EMPTY;
}
Expand Down
31 changes: 30 additions & 1 deletion openrewrite/src/javascript/remote/receiver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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, JSVariableDeclarations, JSMethodDeclaration, NamespaceDeclaration} from '../tree';
import {JS, JsLeftPadded, JsRightPadded, JsContainer, JsSpace, CompilationUnit, Alias, ArrowFunction, Await, DefaultType, Delete, Export, ExpressionStatement, FunctionType, JsImport, JsBinary, ObjectBindingDeclarations, PropertyAssignment, ScopedVariableDeclarations, StatementExpression, TemplateExpression, Tuple, TypeDeclaration, TypeOf, TypeOperator, Unary, Union, Void, Yield, TypeInfo, JSVariableDeclarations, JSMethodDeclaration, NamespaceDeclaration, FunctionDeclaration} from '../tree';
import {Expression, J, JContainer, JLeftPadded, JRightPadded, NameTree, Space, Statement, TypeTree, TypedTree} from "../../java";
import * as Java from "../../java/tree";

Expand Down Expand Up @@ -352,6 +352,20 @@ class Visitor extends JavaScriptVisitor<ReceiverContext> {
return namespaceDeclaration;
}

public visitFunctionDeclaration(functionDeclaration: FunctionDeclaration, ctx: ReceiverContext): J {
functionDeclaration = functionDeclaration.withId(ctx.receiveValue(functionDeclaration.id, ValueType.UUID)!);
functionDeclaration = functionDeclaration.withPrefix(ctx.receiveNode(functionDeclaration.prefix, receiveSpace)!);
functionDeclaration = functionDeclaration.withMarkers(ctx.receiveNode(functionDeclaration.markers, ctx.receiveMarkers)!);
functionDeclaration = functionDeclaration.withModifiers(ctx.receiveNodes(functionDeclaration.modifiers, ctx.receiveTree)!);
functionDeclaration = functionDeclaration.withName(ctx.receiveNode(functionDeclaration.name, ctx.receiveTree));
functionDeclaration = functionDeclaration.withTypeParameters(ctx.receiveNode(functionDeclaration.typeParameters, ctx.receiveTree));
functionDeclaration = functionDeclaration.padding.withParameters(ctx.receiveNode(functionDeclaration.padding.parameters, receiveContainer)!);
functionDeclaration = functionDeclaration.withReturnTypeExpression(ctx.receiveNode(functionDeclaration.returnTypeExpression, ctx.receiveTree));
functionDeclaration = functionDeclaration.withBody(ctx.receiveNode(functionDeclaration.body, ctx.receiveTree)!);
functionDeclaration = functionDeclaration.withType(ctx.receiveValue(functionDeclaration.type, ValueType.Object));
return functionDeclaration;
}

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)!);
Expand Down Expand Up @@ -1378,6 +1392,21 @@ class Factory implements ReceiverFactory {
);
}

if (type === "org.openrewrite.javascript.tree.JS$FunctionDeclaration") {
return new FunctionDeclaration(
ctx.receiveValue(null, ValueType.UUID)!,
ctx.receiveNode(null, receiveSpace)!,
ctx.receiveNode(null, ctx.receiveMarkers)!,
ctx.receiveNodes<Java.Modifier>(null, ctx.receiveTree)!,
ctx.receiveNode<Java.Identifier>(null, ctx.receiveTree),
ctx.receiveNode<Java.TypeParameters>(null, ctx.receiveTree),
ctx.receiveNode<JContainer<Statement>>(null, receiveContainer)!,
ctx.receiveNode<TypeTree>(null, ctx.receiveTree),
ctx.receiveNode<J>(null, ctx.receiveTree)!,
ctx.receiveValue(null, ValueType.Object)
);
}

if (type === "org.openrewrite.java.tree.J$AnnotatedType") {
return new Java.AnnotatedType(
ctx.receiveValue(null, ValueType.UUID)!,
Expand Down
16 changes: 15 additions & 1 deletion openrewrite/src/javascript/remote/sender.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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, JSVariableDeclarations, JSMethodDeclaration, NamespaceDeclaration} from '../tree';
import {JS, JsLeftPadded, JsRightPadded, JsContainer, JsSpace, CompilationUnit, Alias, ArrowFunction, Await, DefaultType, Delete, Export, ExpressionStatement, FunctionType, JsImport, JsBinary, ObjectBindingDeclarations, PropertyAssignment, ScopedVariableDeclarations, StatementExpression, TemplateExpression, Tuple, TypeDeclaration, TypeOf, TypeOperator, Unary, Union, Void, Yield, TypeInfo, JSVariableDeclarations, JSMethodDeclaration, NamespaceDeclaration, FunctionDeclaration} from '../tree';
import {Expression, J, JContainer, JLeftPadded, JRightPadded, Space, Statement} from "../../java";
import * as Java from "../../java/tree";

Expand Down Expand Up @@ -347,6 +347,20 @@ class Visitor extends JavaScriptVisitor<SenderContext> {
return namespaceDeclaration;
}

public visitFunctionDeclaration(functionDeclaration: FunctionDeclaration, ctx: SenderContext): J {
ctx.sendValue(functionDeclaration, v => v.id, ValueType.UUID);
ctx.sendNode(functionDeclaration, v => v.prefix, Visitor.sendSpace);
ctx.sendNode(functionDeclaration, v => v.markers, ctx.sendMarkers);
ctx.sendNodes(functionDeclaration, v => v.modifiers, ctx.sendTree, t => t.id);
ctx.sendNode(functionDeclaration, v => v.name, ctx.sendTree);
ctx.sendNode(functionDeclaration, v => v.typeParameters, ctx.sendTree);
ctx.sendNode(functionDeclaration, v => v.padding.parameters, Visitor.sendContainer(ValueType.Tree));
ctx.sendNode(functionDeclaration, v => v.returnTypeExpression, ctx.sendTree);
ctx.sendNode(functionDeclaration, v => v.body, ctx.sendTree);
ctx.sendTypedValue(functionDeclaration, v => v.type, ValueType.Object);
return functionDeclaration;
}

public visitAnnotatedType(annotatedType: Java.AnnotatedType, ctx: SenderContext): J {
ctx.sendValue(annotatedType, v => v.id, ValueType.UUID);
ctx.sendNode(annotatedType, v => v.prefix, Visitor.sendSpace);
Expand Down
6 changes: 4 additions & 2 deletions openrewrite/src/javascript/tree/support_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,8 @@ export namespace JsSpace {
JSVARIABLE_DECLARATIONS_JSNAMED_VARIABLE_PREFIX,
NAMESPACE_DECLARATION_PREFIX,
NAMESPACE_DECLARATION_KEYWORD_PREFIX,
JSMETHOD_DECLARATION_PREFIX
JSMETHOD_DECLARATION_PREFIX,
FUNCTION_DECLARATION_PREFIX
}
}
export namespace JsLeftPadded {
Expand Down Expand Up @@ -263,6 +264,7 @@ export namespace JsContainer {
OBJECT_BINDING_DECLARATIONS_BINDINGS,
TUPLE_ELEMENTS,
JSMETHOD_DECLARATION_PARAMETERS,
JSMETHOD_DECLARATION_THROWZ
JSMETHOD_DECLARATION_THROWZ,
FUNCTION_DECLARATION_PARAMETERS
}
}
Loading

0 comments on commit e5249c2

Please sign in to comment.