mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-01-30 15:28:18 +00:00
129 lines
3.4 KiB
TypeScript
129 lines
3.4 KiB
TypeScript
import * as parser from '@babel/parser';
|
|
import generate from '@babel/generator';
|
|
import traverse from '@babel/traverse';
|
|
import * as t from '@babel/types';
|
|
import { JSExpression, JSFunction, isJSExpression, isJSFunction } from '@alilc/lowcode-types';
|
|
import { CodeGeneratorError, IScope } from '../types';
|
|
import { transformExpressionLocalRef, ParseError } from './expressionParser';
|
|
|
|
function parseFunction(content: string): t.FunctionExpression | null {
|
|
try {
|
|
const ast = parser.parse(`(${content});`);
|
|
let resultNode: t.FunctionExpression | null = null;
|
|
traverse(ast, {
|
|
FunctionExpression(path) {
|
|
resultNode = path.node;
|
|
path.stop();
|
|
},
|
|
});
|
|
return resultNode;
|
|
} catch (e) {
|
|
throw new ParseError(content, e);
|
|
}
|
|
}
|
|
|
|
function transformFuncExpr2MethodMember(methodName: string, content: string): string {
|
|
const funcNode = parseFunction(content);
|
|
if (funcNode) {
|
|
const targetNode = t.classMethod(
|
|
'method',
|
|
(methodName && t.identifier(methodName)) || funcNode.id || t.identifier('notDefineName'),
|
|
funcNode.params,
|
|
funcNode.body,
|
|
undefined,
|
|
undefined,
|
|
undefined,
|
|
funcNode.async || undefined,
|
|
);
|
|
|
|
const { code: resultCode } = generate(targetNode, { sourceMaps: false });
|
|
return resultCode;
|
|
}
|
|
|
|
throw new Error('Can not find Function Statement');
|
|
}
|
|
|
|
function getArrowFunction(content: string) {
|
|
const funcNode = parseFunction(content);
|
|
if (funcNode) {
|
|
const targetNode = t.arrowFunctionExpression(
|
|
funcNode.params,
|
|
funcNode.body,
|
|
funcNode.async || undefined,
|
|
);
|
|
|
|
const { code: resultCode } = generate(targetNode, { sourceMaps: false });
|
|
return resultCode;
|
|
}
|
|
|
|
throw new Error('Can not find Function Statement');
|
|
}
|
|
|
|
function getBodyStatements(content: string) {
|
|
const funcNode = parseFunction(content);
|
|
if (funcNode) {
|
|
const statements: t.Statement[] = funcNode.body.body;
|
|
|
|
const targetNode = t.program(statements, undefined, 'module', undefined);
|
|
|
|
const { code: resultCode } = generate(targetNode, { sourceMaps: false });
|
|
return resultCode;
|
|
}
|
|
|
|
throw new Error('Can not find Function Statement');
|
|
}
|
|
|
|
export function isJsCode(value: unknown): boolean {
|
|
return isJSExpression(value) || isJSFunction(value);
|
|
}
|
|
|
|
export function generateExpression(value: any, scope: IScope): string {
|
|
if (isJSExpression(value)) {
|
|
const exprVal = (value as JSExpression).value.trim();
|
|
if (!exprVal) {
|
|
return 'null';
|
|
}
|
|
|
|
const afterProcessWithLocals = transformExpressionLocalRef(exprVal, scope);
|
|
return afterProcessWithLocals;
|
|
}
|
|
|
|
throw new CodeGeneratorError('Not a JSExpression');
|
|
}
|
|
|
|
export function generateFunction(
|
|
value: any,
|
|
config: {
|
|
name?: string;
|
|
isMember?: boolean;
|
|
isBlock?: boolean;
|
|
isArrow?: boolean;
|
|
isBindExpr?: boolean;
|
|
} = {
|
|
name: undefined,
|
|
isMember: false,
|
|
isBlock: false,
|
|
isArrow: false,
|
|
isBindExpr: false,
|
|
},
|
|
) {
|
|
if (isJsCode(value)) {
|
|
const functionCfg = value as JSFunction;
|
|
if (config.isMember) {
|
|
return transformFuncExpr2MethodMember(config.name || '', functionCfg.value);
|
|
}
|
|
if (config.isBlock) {
|
|
return getBodyStatements(functionCfg.value);
|
|
}
|
|
if (config.isArrow) {
|
|
return getArrowFunction(functionCfg.value);
|
|
}
|
|
if (config.isBindExpr) {
|
|
return `(${functionCfg.value}).bind(this)`;
|
|
}
|
|
return functionCfg.value;
|
|
}
|
|
|
|
throw new CodeGeneratorError('Not a JSFunction or JSExpression');
|
|
}
|