forked from alibaba/lowcode-engine
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathschema.ts
More file actions
156 lines (138 loc) · 4.05 KB
/
schema.ts
File metadata and controls
156 lines (138 loc) · 4.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import * as _ from 'lodash';
import {
IPublicTypeJSExpression,
IPublicTypeNodeData,
IPublicTypeNodeSchema,
isJSExpression,
isJSSlot,
isDOMText,
IPublicTypeContainerSchema,
IPublicTypeNpmInfo,
IPublicTypeCompositeValue,
isNodeSchema,
isJSFunction,
} from '@alilc/lowcode-types';
import { CodeGeneratorError } from '../types/error';
import { isJSExpressionFn } from './common';
export function isContainerSchema(x: any): x is IPublicTypeContainerSchema {
return (
typeof x === 'object' &&
x &&
typeof x.componentName === 'string' &&
typeof x.fileName === 'string'
);
}
export function isNpmInfo(x: any): x is IPublicTypeNpmInfo {
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: IPublicTypeNodeSchema['children'],
handlers: {
string?: (i: string) => T;
expression?: (i: IPublicTypeJSExpression) => T;
node?: (i: IPublicTypeNodeSchema) => 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: IPublicTypeNodeData[] = children as IPublicTypeNodeData[];
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 IPublicTypeNodeSchema;
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 as IPublicTypeCompositeValue);
childrenRes.push(...childRes);
});
}
}
} else {
throw new CodeGeneratorError('handleSubNodes got invalid NodeData', children);
}
if (result !== undefined) {
childrenRes.unshift(result);
}
return childrenRes;
function handleCompositeValueInProps(value: IPublicTypeCompositeValue): T[] {
if (isJSSlot(value)) {
return handleSubNodes(value.value, handlers, { ...opt, maxDepth: maxDepth - 1 });
}
// CompositeArray
if (Array.isArray(value)) {
return _.flatMap(value, (v) => handleCompositeValueInProps(v));
}
// IPublicTypeCompositeObject
if (
!isJSExpression(value) &&
!isJSExpressionFn(value) &&
!isJSFunction(value) &&
typeof value === 'object' &&
value !== null
) {
return _.flatMap(Object.values(value), (v) => handleCompositeValueInProps(v));
}
return [];
}
}
export function isValidContainerType(schema: IPublicTypeNodeSchema) {
return [
'Page',
'Component',
'Block',
].includes(schema.componentName);
}
export const enum ContainerType {
Page = 'Page',
Component = 'Component',
Block = 'Block',
}