mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-01-13 01:21:58 +00:00
194 lines
5.1 KiB
TypeScript
194 lines
5.1 KiB
TypeScript
import {
|
|
ChildNodeType,
|
|
IComponentNodeItem,
|
|
IJSExpression,
|
|
ChildNodeItem,
|
|
CodeGeneratorError,
|
|
PIECE_TYPE,
|
|
CodePiece,
|
|
HandlerSet,
|
|
ExtGeneratorPlugin,
|
|
} from '../types';
|
|
import { generateCompositeType } from './compositeType';
|
|
import { generateExpression } from './jsExpression';
|
|
|
|
// tslint:disable-next-line: no-empty
|
|
const noop = () => [];
|
|
|
|
export function handleChildren<T>(
|
|
children: ChildNodeType,
|
|
handlers: HandlerSet<T>,
|
|
): T[] {
|
|
if (Array.isArray(children)) {
|
|
const list: ChildNodeItem[] = children as ChildNodeItem[];
|
|
return list
|
|
.map(child => handleChildren(child, handlers))
|
|
.reduce((p, c) => p.concat(c), []);
|
|
} else if (typeof children === 'string') {
|
|
const handler = handlers.string || handlers.common || noop;
|
|
return handler(children as string);
|
|
} else if ((children as IJSExpression).type === 'JSExpression') {
|
|
const handler = handlers.expression || handlers.common || noop;
|
|
return handler(children as IJSExpression);
|
|
} else {
|
|
const handler = handlers.node || handlers.common || noop;
|
|
return handler(children as IComponentNodeItem);
|
|
}
|
|
}
|
|
|
|
export function generateAttr(attrName: string, attrValue: any): CodePiece[] {
|
|
if (attrName === 'initValue' || attrName === 'labelCol') {
|
|
return [];
|
|
}
|
|
const [isString, valueStr] = generateCompositeType(attrValue);
|
|
return [{
|
|
value: `${attrName}=${isString ? `"${valueStr}"` : `{${valueStr}}`}`,
|
|
type: PIECE_TYPE.ATTR,
|
|
}];
|
|
}
|
|
|
|
export function generateAttrs(nodeItem: IComponentNodeItem): CodePiece[] {
|
|
const { props } = nodeItem;
|
|
let pieces: CodePiece[] = [];
|
|
|
|
Object.keys(props).forEach((propName: string) =>
|
|
pieces = pieces.concat(generateAttr(propName, props[propName])),
|
|
);
|
|
|
|
return pieces;
|
|
}
|
|
|
|
export function mapNodeName(src: string): string {
|
|
if (src === 'Div') {
|
|
return 'div';
|
|
}
|
|
return src;
|
|
}
|
|
|
|
export function generateBasicNode(nodeItem: IComponentNodeItem): CodePiece[] {
|
|
const pieces: CodePiece[] = [];
|
|
pieces.push({
|
|
value: mapNodeName(nodeItem.componentName),
|
|
type: PIECE_TYPE.TAG,
|
|
});
|
|
|
|
return pieces;
|
|
}
|
|
|
|
export function generateReactCtrlLine(nodeItem: IComponentNodeItem): CodePiece[] {
|
|
const pieces: CodePiece[] = [];
|
|
|
|
if (nodeItem.loop && nodeItem.loopArgs) {
|
|
let loopDataExp;
|
|
if ((nodeItem.loop as IJSExpression).type === 'JSExpression') {
|
|
loopDataExp = `(${(nodeItem.loop as IJSExpression).value})`;
|
|
} else {
|
|
loopDataExp = JSON.stringify(nodeItem.loop);
|
|
}
|
|
pieces.unshift({
|
|
value: `${loopDataExp}.map((${nodeItem.loopArgs[0]}, ${nodeItem.loopArgs[1]}) => (`,
|
|
type: PIECE_TYPE.BEFORE,
|
|
});
|
|
pieces.push({
|
|
value: '))',
|
|
type: PIECE_TYPE.AFTER,
|
|
});
|
|
}
|
|
|
|
if (nodeItem.condition) {
|
|
const [isString, value] = generateCompositeType(nodeItem.condition);
|
|
|
|
pieces.unshift({
|
|
value: `(${isString ? `'${value}'` : value}) && (`,
|
|
type: PIECE_TYPE.BEFORE,
|
|
});
|
|
pieces.push({
|
|
value: ')',
|
|
type: PIECE_TYPE.AFTER,
|
|
});
|
|
}
|
|
|
|
if (nodeItem.condition || (nodeItem.loop && nodeItem.loopArgs)) {
|
|
pieces.unshift({
|
|
value: '{',
|
|
type: PIECE_TYPE.BEFORE,
|
|
});
|
|
pieces.push({
|
|
value: '}',
|
|
type: PIECE_TYPE.AFTER,
|
|
});
|
|
}
|
|
|
|
return pieces;
|
|
}
|
|
|
|
export function linkPieces(pieces: CodePiece[]): string {
|
|
if (pieces.filter(p => p.type === PIECE_TYPE.TAG).length !== 1) {
|
|
throw new CodeGeneratorError('One node only need one tag define');
|
|
}
|
|
const tagName = pieces.filter(p => p.type === PIECE_TYPE.TAG)[0].value;
|
|
|
|
const beforeParts = pieces
|
|
.filter(p => p.type === PIECE_TYPE.BEFORE)
|
|
.map(p => p.value)
|
|
.join('');
|
|
|
|
const afterParts = pieces
|
|
.filter(p => p.type === PIECE_TYPE.AFTER)
|
|
.map(p => p.value)
|
|
.join('');
|
|
|
|
const childrenParts = pieces
|
|
.filter(p => p.type === PIECE_TYPE.CHILDREN)
|
|
.map(p => p.value)
|
|
.join('');
|
|
|
|
let attrsParts = pieces
|
|
.filter(p => p.type === PIECE_TYPE.ATTR)
|
|
.map(p => p.value)
|
|
.join(' ');
|
|
|
|
attrsParts = !!attrsParts ? ` ${attrsParts}` : '';
|
|
|
|
if (childrenParts) {
|
|
return `${beforeParts}<${tagName}${attrsParts}>${childrenParts}</${tagName}>${afterParts}`;
|
|
}
|
|
|
|
return `${beforeParts}<${tagName}${attrsParts} />${afterParts}`;
|
|
}
|
|
|
|
export function createNodeGenerator(handlers: HandlerSet<string>, plugins: ExtGeneratorPlugin[]) {
|
|
const generateNode = (nodeItem: IComponentNodeItem): string => {
|
|
let pieces: CodePiece[] = [];
|
|
|
|
plugins.forEach(p => {
|
|
pieces = pieces.concat(p(nodeItem));
|
|
});
|
|
pieces = pieces.concat(generateBasicNode(nodeItem));
|
|
pieces = pieces.concat(generateAttrs(nodeItem));
|
|
if (nodeItem.children && (nodeItem.children as unknown[]).length > 0) {
|
|
pieces = pieces.concat(handleChildren<string>(nodeItem.children, handlers).map(l => ({
|
|
type: PIECE_TYPE.CHILDREN,
|
|
value: l,
|
|
})));
|
|
}
|
|
|
|
return linkPieces(pieces);
|
|
};
|
|
|
|
handlers.node = (input: IComponentNodeItem) => [generateNode(input)];
|
|
|
|
return generateNode;
|
|
}
|
|
|
|
export const generateString = (input: string) => [input];
|
|
|
|
export function createReactNodeGenerator() {
|
|
return createNodeGenerator({
|
|
string: generateString,
|
|
expression: (input) => [generateExpression(input)],
|
|
}, [
|
|
generateReactCtrlLine,
|
|
]);
|
|
}
|