Skip to content

Commit

Permalink
Merge pull request #12 from pcriadoperez/callback-function
Browse files Browse the repository at this point in the history
feat: support functionExpresions annd allow passing function as argument un function call
  • Loading branch information
carlosmiei authored Sep 12, 2024
2 parents 8f2f960 + a917edc commit a72d71c
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 11 deletions.
25 changes: 18 additions & 7 deletions src/baseTranspiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ class BaseTranspiler {
requiresParameterType;
supportsFalsyOrTruthyValues;
requiresCallExpressionCast;
removeVariableDeclarationForFunctionExpression;
includeFunctionNameInFunctionExpressionDeclaration;
id;

constructor(config) {
Expand All @@ -198,6 +200,8 @@ class BaseTranspiler {
this.requiresParameterType = false;
this.supportsFalsyOrTruthyValues = true;
this.requiresCallExpressionCast = false;
this.removeVariableDeclarationForFunctionExpression = true;
this.includeFunctionNameInFunctionExpressionDeclaration = true;
this.initOperators();
}

Expand Down Expand Up @@ -390,7 +394,7 @@ class BaseTranspiler {
return name;
}

transformIdentifier(identifier) {
transformIdentifier(node, identifier) {
return this.unCamelCaseIfNeeded(identifier);
}

Expand All @@ -404,7 +408,7 @@ class BaseTranspiler {
if (idValue === "undefined") {
return this.UNDEFINED_TOKEN;
}
return this.transformIdentifier(idValue); // check this later
return this.transformIdentifier(node, idValue); // check this later
}

shouldRemoveParenthesisFromCallExpression(node) {
Expand Down Expand Up @@ -818,7 +822,7 @@ class BaseTranspiler {
}

printFunctionDefinition(node, identation) {
let name = node.name.escapedText;
let name = node.name?.escapedText ?? "";
name = this.transformFunctionNameIfNeeded(name);

const parsedArgs = node.parameters.map(param => this.printParameter(param)).join(", ");
Expand All @@ -830,11 +834,14 @@ class BaseTranspiler {
returnType = returnType ? returnType + " " : returnType;

const fnKeyword = this.FUNCTION_TOKEN ? this.FUNCTION_TOKEN + " " : "";
if (!fnKeyword){
if (!fnKeyword && ts.isFunctionDeclaration(node)){
modifiers = modifiers + "public ";
}
const functionDef = this.getIden(identation) + modifiers + returnType + fnKeyword + name
+ "(" + parsedArgs + ")";
let functionDef = this.getIden(identation) + modifiers + returnType + fnKeyword;
if (this.includeFunctionNameInFunctionExpressionDeclaration || !ts.isFunctionExpression(node)) {
functionDef += name;
}
functionDef += "(" + parsedArgs + ")";

return functionDef;
}
Expand Down Expand Up @@ -926,6 +933,10 @@ class BaseTranspiler {
printVariableDeclarationList(node,identation) {
const declaration = node.declarations[0];
const varToken = this.VAR_TOKEN ? this.VAR_TOKEN + " ": "";

if (this.removeVariableDeclarationForFunctionExpression && (ts.isFunctionExpression(declaration.initializer) || ts.isArrowFunction(declaration.initializer))) {
return this.printNode(declaration.initializer, identation).trimEnd();
}
// const name = declaration.name.escapedText;
const parsedValue = (declaration.initializer) ? this.printNode(declaration.initializer, identation) : this.NULL_TOKEN;
return this.getIden(identation) + varToken + this.printNode(declaration.name) + " = " + parsedValue.trim();
Expand Down Expand Up @@ -1680,7 +1691,7 @@ class BaseTranspiler {
return this.printExpressionStatement(node, identation);
} else if(ts.isBlock(node)) {
return this.printBlock(node, identation);
} else if (ts.isFunctionDeclaration(node)){
} else if (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node)){
return this.printFunctionDeclaration(node, identation);
} else if (ts.isClassDeclaration(node)) {
return this.printClass(node, identation);
Expand Down
5 changes: 4 additions & 1 deletion src/csharpTranspiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ export class CSharpTranspiler extends BaseTranspiler {
}
}

return this.transformIdentifier(idValue); // check this later
return this.transformIdentifier(node, idValue); // check this later
}

printConstructorDeclaration (node, identation) {
Expand Down Expand Up @@ -511,6 +511,9 @@ export class CSharpTranspiler extends BaseTranspiler {
const declaration = node.declarations[0];
// const name = declaration.name.escapedText;

if (this.removeVariableDeclarationForFunctionExpression && ts.isFunctionExpression(declaration.initializer)) {
return this.printNode(declaration.initializer, identation).trimEnd();
}
// handle array binding : input: const [a,b] = this.method()
// output: var abVar = this.method; var a = abVar[0]; var b = abVar[1];
if (declaration?.name.kind === ts.SyntaxKind.ArrayBindingPattern) {
Expand Down
32 changes: 29 additions & 3 deletions src/phpTranspiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ export class PhpTranspiler extends BaseTranspiler {
this.id = "php";
this.asyncTranspiling = config['async'] ?? true;
this.uncamelcaseIdentifiers = config['uncamelcaseIdentifiers'] ?? false;
this.removeVariableDeclarationForFunctionExpression = config['removeFunctionAssignToVariable'] ?? false;
this.includeFunctionNameInFunctionExpressionDeclaration = config['includeFunctionNameInFunctionExpressionDeclaration'] ?? false;

this.propRequiresScopeResolutionOperator = ['super'] + (config['ScopeResolutionProps'] ?? []);

Expand All @@ -78,17 +80,41 @@ export class PhpTranspiler extends BaseTranspiler {
return this.AWAIT_WRAPPER_OPEN + expression + this.AWAIT_WRAPPER_CLOSE;
}

transformIdentifier(identifier) {

transformIdentifier(node, identifier) {
if (this.uncamelcaseIdentifiers) {
identifier = this.unCamelCaseIfNeeded(identifier);
}

// Get the symbol for the identifier
const symbol = global.checker.getSymbolAtLocation(node);

// Check if the symbol references a function declaration or expression
if (symbol && symbol.valueDeclaration) {
const valueDecl = symbol.valueDeclaration;

// Check if it's a function (FunctionDeclaration, FunctionExpression, ArrowFunction)
if (ts.isFunctionDeclaration(valueDecl) || ts.isFunctionExpression(valueDecl) || ts.isArrowFunction(valueDecl)) {
// Check if the identifier is passed as an argument in a function call
if (node.parent && ts.isCallExpression(node.parent) && node.parent.arguments.includes(node)) {
return `'${identifier}'`; // Transpile function reference as string
}
}
}

// If the identifier is a function parameter (callback), it should remain a variable with `$` prefix
if (node.parent && ts.isParameter(node.parent) || (node.parent && ts.isCallExpression(node.parent) && ts.isIdentifier(node))) {
return "$" + identifier;
}

// Default case: prepend $ for variables (non-functions), unless it's a class or constant
if (!this.startsWithUpperCase(identifier)) {
return "$" + identifier; // avoid adding $ to constants, and classes
return "$" + identifier; // Prepend $ for variable names
}

return identifier;
}


getCustomOperatorIfAny(left, right, operator) {
const STRING_CONCAT = '.';
const PLUS_EQUALS_TOKEN = '.=';
Expand Down
2 changes: 2 additions & 0 deletions src/pythonTranspiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ export class PythonTranspiler extends BaseTranspiler {
this.initConfig();
this.asyncTranspiling = config['async'] ?? true;
this.uncamelcaseIdentifiers = config['uncamelcaseIdentifiers'] ?? true;
this.removeVariableDeclarationForFunctionExpression = config['removeVariableDeclarationForFunctionExpression'] ?? true;
this.includeFunctionNameInFunctionExpressionDeclaration = config['includeFunctionNameInFunctionExpressionDeclaration'] ?? true;

// user overrides
this.applyUserOverrides(config);
Expand Down
27 changes: 27 additions & 0 deletions tests/csharpTranspiler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,33 @@ describe('csharp transpiling tests', () => {
// transpiler.setPhpAsyncTranspiling(true);
// expect(output).toBe(csharp);
// });
test('callback function transpilation', () => {
const ts =
"function printResult(result) {\n" +
" return;\n" +
"}\n" +
"processNumbers(5, 10, printResult);";
const cs =
"public void printResult(object result)\n{\n" +
" return;\n" +
"}\n" +
"processNumbers(5, 10, printResult);";
const output = transpiler.transpileCSharp(ts).content;
expect(output).toBe(cs);
});
test('function expression transpilation', () => {
const ts =
"const consumer = function consumer(a) {\n" +
" return;\n" +
"};";
const csharp =
"void consumer(object a)\n" +
"{\n" +
" return;\n" +
"};";
const output = transpiler.transpileCSharp(ts).content;
expect(output).toBe(csharp);
});
test('basic class with constructor', () => {
const ts =
"class teste extends Test {\n" +
Expand Down
38 changes: 38 additions & 0 deletions tests/phpTranspiler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,44 @@ describe('php transpiling tests', () => {
const output = transpiler.transpilePhp(ts).content;
expect(output).toBe(php);
});
test('callback function transpilation', () => {
const ts =
"function printResult(result) {\n" +
" return;\n" +
"}\n" +
"processNumbers(5, 10, printResult);";
const php =
"function printResult($result) {\n" +
" return;\n" +
"}\n" +
"processNumbers(5, 10, 'printResult');";
const output = transpiler.transpilePhp(ts).content;
expect(output).toBe(php);
});
test('function expression transpilation', () => {
const ts =
"const consumer = function consumer (a) {\n" +
" return a;\n" +
"};";
const php =
"$consumer = function ($a) {\n" +
" return $a;\n" +
"};"
const output = transpiler.transpilePhp(ts).content;
expect(output).toBe(php);
});
test('arrow function', () => {
const ts =
"const consumer = (a) => {\n" +
" return a;\n" +
"};";
const php =
"$consumer = function ($a) {\n" +
" return $a;\n" +
"};"
const output = transpiler.transpilePhp(ts).content;
expect(output).toBe(php);
});
test('basic identation check [nested if]', () => {
const ts =
"if (1) {\n" +
Expand Down
24 changes: 24 additions & 0 deletions tests/pythonTranspiler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,30 @@ describe('python tests', () => {
const output = transpiler.transpilePython(ts).content;
expect(output).toBe(python);
});
test('callback function transpilation', () => {
const ts =
"function printResult(result) {\n" +
" return;\n" +
"}\n" +
"processNumbers(5, 10, printResult);";
const py =
"def printResult(result):\n" +
" return\n" +
"processNumbers(5, 10, printResult)";
const output = transpiler.transpilePython(ts).content;
expect(output).toBe(py);
});
test('function expression transpilation', () => {
const ts =
"const consumer = function consumer(a) {\n" +
" return a + 1;\n" +
"};\n";
const python =
"def consumer(a):\n" +
" return a + 1";
const output = transpiler.transpilePython(ts).content;
expect(output).toBe(python);
});
test('basic identation test [nested if]', () => {
const ts =
"if (1) {\n" +
Expand Down

0 comments on commit a72d71c

Please sign in to comment.