mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-06-04 14:41:11 +00:00
141 lines
3.5 KiB
TypeScript
141 lines
3.5 KiB
TypeScript
import * as _ from 'lodash';
|
|
import {
|
|
JSExpression,
|
|
NodeData,
|
|
NodeSchema,
|
|
isJSExpression,
|
|
isJSSlot,
|
|
isDOMText,
|
|
ContainerSchema,
|
|
NpmInfo,
|
|
CompositeValue,
|
|
isNodeSchema,
|
|
isJSFunction,
|
|
} from '@alilc/lowcode-types';
|
|
import { CodeGeneratorError } from '../types/error';
|
|
|
|
export function isContainerSchema(x: any): x is ContainerSchema {
|
|
return (
|
|
typeof x === 'object' &&
|
|
x &&
|
|
typeof x.componentName === 'string' &&
|
|
typeof x.fileName === 'string'
|
|
);
|
|
}
|
|
|
|
export function isNpmInfo(x: any): x is NpmInfo {
|
|
return typeof x === 'object' && x && typeof x.package === 'string';
|
|
}
|
|
|
|
const noop = () => undefined;
|
|
|
|
const handleChildrenDefaultOptions = {
|
|
rerun: false,
|
|
};
|
|
|
|
const DEFAULT_MAX_DEPTH = 100000;
|
|
|
|
/**
|
|
* 遍历并处理所有的子节点
|
|
* @param children
|
|
* @param handlers
|
|
* @param options
|
|
* @returns
|
|
*/
|
|
export function handleSubNodes<T>(
|
|
children: NodeSchema['children'],
|
|
handlers: {
|
|
string?: (i: string) => T;
|
|
expression?: (i: JSExpression) => T;
|
|
node?: (i: NodeSchema) => T;
|
|
},
|
|
options?: {
|
|
rerun?: boolean;
|
|
maxDepth?: number; // 防止出现死循环无穷递归
|
|
},
|
|
): T[] {
|
|
const opt = {
|
|
...handleChildrenDefaultOptions,
|
|
...(options || {}),
|
|
};
|
|
const maxDepth = opt.maxDepth ?? DEFAULT_MAX_DEPTH;
|
|
if (maxDepth <= 0) {
|
|
throw new Error('handleSubNodes maxDepth reached');
|
|
}
|
|
|
|
if (Array.isArray(children)) {
|
|
const list: NodeData[] = children as NodeData[];
|
|
return list
|
|
.map((child) => handleSubNodes(child, handlers, { ...opt, maxDepth: maxDepth - 1 }))
|
|
.reduce((p, c) => p.concat(c), []);
|
|
}
|
|
|
|
let result: T | undefined;
|
|
const childrenRes: T[] = [];
|
|
if (children === null || children === undefined) {
|
|
return [];
|
|
} else if (isDOMText(children)) {
|
|
const handler = handlers.string || noop;
|
|
result = handler(children);
|
|
} else if (isJSExpression(children)) {
|
|
const handler = handlers.expression || noop;
|
|
result = handler(children);
|
|
} else if (isJSSlot(children)) {
|
|
return handleSubNodes(children.value, handlers, { ...opt, maxDepth: maxDepth - 1 });
|
|
} else if (isNodeSchema(children)) {
|
|
const handler = handlers.node || noop;
|
|
const child = children as NodeSchema;
|
|
result = handler(child);
|
|
|
|
if (child.children) {
|
|
const childRes = handleSubNodes(child.children, handlers, opt);
|
|
childrenRes.push(...childRes);
|
|
}
|
|
|
|
if (child.props) {
|
|
if (Array.isArray(child.props)) {
|
|
child.props.forEach(({ value }) => {
|
|
const childRes = handleCompositeValueInProps(value);
|
|
childrenRes.push(...childRes);
|
|
});
|
|
} else {
|
|
Object.values(child.props).forEach((value) => {
|
|
const childRes = handleCompositeValueInProps(value);
|
|
childrenRes.push(...childRes);
|
|
});
|
|
}
|
|
}
|
|
} else {
|
|
throw new CodeGeneratorError('handleSubNodes got invalid NodeData', children);
|
|
}
|
|
|
|
if (result !== undefined) {
|
|
childrenRes.unshift(result);
|
|
}
|
|
|
|
return childrenRes;
|
|
|
|
function handleCompositeValueInProps(value: CompositeValue): T[] {
|
|
if (isJSSlot(value)) {
|
|
return handleSubNodes(value.value, handlers, { ...opt, maxDepth: maxDepth - 1 });
|
|
}
|
|
|
|
// CompositeArray
|
|
if (Array.isArray(value)) {
|
|
return _.flatMap(value, (v) => handleCompositeValueInProps(v));
|
|
}
|
|
|
|
// CompositeObject
|
|
if (
|
|
!isJSExpression(value) &&
|
|
!isJSFunction(value) &&
|
|
typeof value === 'object' &&
|
|
value !== null
|
|
) {
|
|
return _.flatMap(Object.values(value), (v) => handleCompositeValueInProps(v));
|
|
}
|
|
|
|
return [];
|
|
}
|
|
}
|