@mybricks/plugin-ai 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +7 -2
- package/src/agents/app.ts +188 -60
- package/src/agents/common.ts +428 -68
- package/src/agents/custom.ts +14 -0
- package/src/agents/index.ts +31 -1
- package/src/agents/knowledges/README.md +614 -0
- package/src/agents/knowledges/SUMMARY.md +527 -0
- package/src/agents/knowledges/index.ts +8 -0
- package/src/agents/knowledges/knowledge-base.ts +565 -0
- package/src/agents/knowledges/knowledge-node.ts +266 -0
- package/src/agents/knowledges/types.ts +208 -0
- package/src/agents/utils/config.ts +427 -0
- package/src/agents/workspace/coding-manager.ts +31 -0
- package/src/agents/workspace/components-manager.ts +124 -0
- package/src/agents/workspace/outline-focus.ts +188 -0
- package/src/agents/workspace/outline-info.ts +520 -0
- package/src/agents/workspace/page-tree-generator.ts +83 -0
- package/src/agents/workspace/workspace.ts +319 -0
- package/src/agents/workspace-by-knowledges/MIGRATION.md +568 -0
- package/src/agents/workspace-by-knowledges/README.md +521 -0
- package/src/agents/workspace-by-knowledges/index.ts +11 -0
- package/src/agents/workspace-by-knowledges/providers/component-docs-provider.ts +92 -0
- package/src/agents/workspace-by-knowledges/providers/focus-info-provider.ts +131 -0
- package/src/agents/workspace-by-knowledges/providers/index.ts +8 -0
- package/src/agents/workspace-by-knowledges/providers/project-info-provider.ts +151 -0
- package/src/agents/workspace-by-knowledges/test.ts +240 -0
- package/src/agents/workspace-by-knowledges/types.ts +56 -0
- package/src/agents/workspace-by-knowledges/utils/components-manager.ts +145 -0
- package/src/agents/workspace-by-knowledges/utils/index.ts +8 -0
- package/src/agents/workspace-by-knowledges/utils/outline-focus.ts +178 -0
- package/src/agents/workspace-by-knowledges/utils/outline-info.ts +521 -0
- package/src/agents/workspace-by-knowledges/workspace.ts +166 -0
- package/src/api/cloud-components.ts +129 -0
- package/src/api-record-replay/README.md +187 -0
- package/src/api-record-replay/index.ts +11 -0
- package/src/api-record-replay/manager.ts +168 -0
- package/src/api-record-replay/recorder.ts +117 -0
- package/src/api-record-replay/replayer.ts +148 -0
- package/src/components/attachments/index.less +117 -0
- package/src/components/attachments/index.tsx +136 -0
- package/src/components/icons/index.tsx +21 -1
- package/src/components/index.less +34 -0
- package/src/components/mention/index.less +23 -0
- package/src/components/mention/index.tsx +19 -0
- package/src/components/messages/index.less +444 -237
- package/src/components/messages/index.tsx +371 -88
- package/src/components/sender/index.less +203 -0
- package/src/components/sender/index.tsx +298 -0
- package/src/components/types.ts +31 -0
- package/src/constants/index.ts +8 -0
- package/src/context/RequestStatusTracker.ts +50 -0
- package/src/context/index.ts +68 -6
- package/src/{types.d.ts → global.d.ts} +40 -5
- package/src/index.tsx +212 -32
- package/src/preset/agents.ts +380 -0
- package/src/preset/createTemplates.ts +25 -0
- package/src/preset/index.ts +12 -0
- package/src/preset/prompts.ts +235 -0
- package/src/preset/requestAsStream.ts +246 -0
- package/src/preset/user.ts +6 -0
- package/src/startView/components/header/header.less +17 -0
- package/src/startView/components/header/header.tsx +15 -0
- package/src/startView/components/index.ts +1 -0
- package/src/startView/index.less +22 -204
- package/src/startView/index.tsx +35 -203
- package/src/tools/analyze-and-expand-prd.ts +192 -86
- package/src/tools/analyze-requirement-and-components.ts +589 -0
- package/src/tools/answer.ts +59 -0
- package/src/tools/build-process.ts +1174 -0
- package/src/tools/coding-subagent-as-tool.ts +119 -0
- package/src/tools/generate-ui-content.ts +1083 -0
- package/src/tools/index.ts +22 -19
- package/src/tools/open-dsl.ts +69 -0
- package/src/tools/refactor-ui-content.ts +801 -0
- package/src/tools/utils.ts +880 -28
- package/src/types/index.ts +4 -0
- package/src/view/components/header/header.less +36 -2
- package/src/view/components/header/header.tsx +47 -2
- package/src/view/components/index.ts +0 -2
- package/src/view/index.tsx +158 -8
- package/src/tools/answer-user.ts +0 -35
- package/src/tools/focus-element.ts +0 -47
- package/src/tools/generate-page.ts +0 -750
- package/src/tools/get-component-info-by-ids.ts +0 -166
- package/src/tools/get-component-info.ts +0 -53
- package/src/tools/get-components-doc-and-prd.ts +0 -137
- package/src/tools/get-focus-mybricks-dsl.ts +0 -26
- package/src/tools/get-mybricks-dsl.ts +0 -73
- package/src/tools/modify-component.ts +0 -385
- package/src/view/components/messages/messages.less +0 -228
- package/src/view/components/messages/messages.tsx +0 -172
- package/src/view/components/sender/sender.less +0 -44
- package/src/view/components/sender/sender.tsx +0 -62
package/src/tools/utils.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { jsonrepair } from 'jsonrepair'
|
|
2
|
+
import { ComponentsManager } from './../agents/workspace/components-manager'
|
|
3
|
+
|
|
1
4
|
export function getFiles(files: RxFiles, {
|
|
2
5
|
extName
|
|
3
6
|
}: {
|
|
@@ -13,50 +16,899 @@ export function getFiles(files: RxFiles, {
|
|
|
13
16
|
return result
|
|
14
17
|
}
|
|
15
18
|
|
|
16
|
-
function
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
+
export function getComponentOperationSummary(operations = [], componentIdToTitleMap = new Map()) {
|
|
20
|
+
const componentActions: any = {};
|
|
21
|
+
const results: any = [];
|
|
22
|
+
|
|
23
|
+
// 收集组件title信息(补充传入映射中没有的新组件)
|
|
24
|
+
operations.forEach(operation => {
|
|
25
|
+
if (operation.type === 'addChild' && operation.params.title) {
|
|
26
|
+
componentIdToTitleMap.set(operation.params.comId, operation.params.title)
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
operations.forEach(operation => {
|
|
31
|
+
const { comId, type, target, params } = operation;
|
|
32
|
+
|
|
33
|
+
switch (type) {
|
|
34
|
+
case 'doConfig':
|
|
35
|
+
const configTitle = componentIdToTitleMap.get(comId) || comId;
|
|
36
|
+
if (!componentActions[configTitle]) {
|
|
37
|
+
componentActions[configTitle] = { configs: [] };
|
|
38
|
+
}
|
|
39
|
+
const simplifiedPath = params.path?.split?.('/')?.pop?.();
|
|
40
|
+
componentActions[configTitle].configs.push(simplifiedPath);
|
|
41
|
+
break;
|
|
42
|
+
|
|
43
|
+
case 'addChild':
|
|
44
|
+
const parentTitle = componentIdToTitleMap.get(comId) || comId;
|
|
45
|
+
|
|
46
|
+
// 1. 先记录添加组件的操作
|
|
47
|
+
results.push(`• 在【${parentTitle}】的 ${target} 插槽中新增了「${params.title}」`);
|
|
48
|
+
|
|
49
|
+
// 2. 如果新组件有配置,单独记录配置操作
|
|
50
|
+
if (params.configs && params.configs.length > 0) {
|
|
51
|
+
const childConfigs = params.configs.map(config => config.path?.split?.('/')?.pop?.());
|
|
52
|
+
results.push(`• 配置【${params.title}】:设置了 ${childConfigs.join('、')} 等属性`);
|
|
53
|
+
}
|
|
54
|
+
break;
|
|
55
|
+
|
|
56
|
+
case 'move':
|
|
57
|
+
const moveTitle = componentIdToTitleMap.get(comId);
|
|
58
|
+
const targetTitle = componentIdToTitleMap.get(params.to?.comId);
|
|
59
|
+
const slotId = params.to?.slotId;
|
|
60
|
+
|
|
61
|
+
if (moveTitle && targetTitle) {
|
|
62
|
+
results.push(`• 将【${moveTitle}】移动至【${targetTitle}】的 ${slotId} 插槽中`);
|
|
63
|
+
}
|
|
64
|
+
break;
|
|
65
|
+
|
|
66
|
+
case 'delete':
|
|
67
|
+
const deleteTitle = componentIdToTitleMap.get(comId);
|
|
68
|
+
if (deleteTitle) {
|
|
69
|
+
results.push(`• 删除了【${deleteTitle}】组件`);
|
|
70
|
+
} else {
|
|
71
|
+
// 如果没有title,可能是删除了一个没有被记录的组件
|
|
72
|
+
results.push(`• 删除了组件 ${comId}`);
|
|
73
|
+
}
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// 处理独立的配置操作(doConfig类型)
|
|
79
|
+
Object.keys(componentActions).forEach(title => {
|
|
80
|
+
const actions = componentActions[title];
|
|
81
|
+
if (actions.configs.length > 0) {
|
|
82
|
+
results.push(`• 配置【${title}】:调整了 ${actions.configs.join('、')} 等属性`);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
return results.join('\n');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
interface Config {
|
|
90
|
+
path: string;
|
|
91
|
+
value: any;
|
|
92
|
+
style: any;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
interface AddChildActionParams {
|
|
96
|
+
namespace?: string;
|
|
97
|
+
ns?: string;
|
|
98
|
+
layout?: any;
|
|
99
|
+
configs: Config[];
|
|
100
|
+
ignore?: boolean;
|
|
101
|
+
enhance?: boolean;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
interface DoConfigActionParams {
|
|
105
|
+
path: string;
|
|
106
|
+
value: any;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
type ActionParams = AddChildActionParams | DoConfigActionParams;
|
|
110
|
+
|
|
111
|
+
interface Action {
|
|
112
|
+
comId: string;
|
|
113
|
+
type: string;
|
|
114
|
+
target: string;
|
|
115
|
+
params: ActionParams;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// 第二个参数用于透传当前解析器实例内的 comId -> params 映射,方便后续 O(1) 快查
|
|
119
|
+
const formatAction = (
|
|
120
|
+
_action: string,
|
|
121
|
+
comIdToParamsMap?: Map<string, AddChildActionParams>,
|
|
122
|
+
options?: { enabledActionTags?: boolean }
|
|
123
|
+
) => {
|
|
124
|
+
const { enabledActionTags } = options ?? {};
|
|
125
|
+
let action;
|
|
126
|
+
try {
|
|
127
|
+
// TODO,后面要提示词处理的,这样replace不合理
|
|
128
|
+
const fixActionString = _action.replaceAll('{":parent/', '{"path":":parent/')
|
|
129
|
+
action = JSON.parse(fixActionString);
|
|
130
|
+
} catch (error) {
|
|
131
|
+
try {
|
|
132
|
+
const repairedAction = jsonrepair(_action)
|
|
133
|
+
action = JSON.parse(repairedAction)
|
|
134
|
+
} catch (error) {
|
|
135
|
+
console.error("repair action error", error);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
19
138
|
|
|
20
|
-
if (!
|
|
21
|
-
return
|
|
139
|
+
if (!Array.isArray(action)) {
|
|
140
|
+
return action;
|
|
22
141
|
}
|
|
23
142
|
|
|
24
|
-
|
|
25
|
-
|
|
143
|
+
const [comId, target, type, params] = action;
|
|
144
|
+
const newAct: Action = {
|
|
145
|
+
comId,
|
|
146
|
+
type,
|
|
147
|
+
target,
|
|
148
|
+
params,
|
|
149
|
+
};
|
|
26
150
|
|
|
27
|
-
|
|
28
|
-
|
|
151
|
+
if (newAct.type === "delete") {
|
|
152
|
+
if (!newAct.params) {
|
|
153
|
+
return {
|
|
154
|
+
...newAct,
|
|
155
|
+
params: {}
|
|
156
|
+
}
|
|
29
157
|
}
|
|
158
|
+
}
|
|
30
159
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
160
|
+
if (newAct.type === 'move') {
|
|
161
|
+
if (newAct.params) {
|
|
162
|
+
return {
|
|
163
|
+
...newAct,
|
|
164
|
+
params: {
|
|
165
|
+
to: newAct.params
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
35
169
|
}
|
|
36
170
|
|
|
37
|
-
//
|
|
38
|
-
if (
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
171
|
+
// ns => namespace
|
|
172
|
+
if (newAct.type === "addChild") {
|
|
173
|
+
if (newAct.params?.ns) {
|
|
174
|
+
newAct.params.namespace = ComponentsManager.getFullNamespace(newAct.params.ns);
|
|
175
|
+
delete newAct.params.ns;
|
|
176
|
+
}
|
|
43
177
|
}
|
|
44
178
|
|
|
45
|
-
//
|
|
46
|
-
if (
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
})
|
|
179
|
+
// 标记使用
|
|
180
|
+
if (newAct.type === 'addChild') {
|
|
181
|
+
if (enabledActionTags) {
|
|
182
|
+
|
|
183
|
+
if (newAct.params?.ignore) {
|
|
184
|
+
// TODO:标记的兼容,对于配置了ignore,但是有padding的组件,直接替换成enhance,因为直接去掉,底层的100%组件宽高会失效。
|
|
185
|
+
if (newAct?.params?.configs?.some(config => Object.keys(config?.style ?? {}).some(key => key.startsWith('padding')))) {
|
|
186
|
+
newAct.params.enhance = true;
|
|
187
|
+
delete newAct.params.ignore;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// TODO:标记的兼容,如果配置了enhance或者ignore的不是布局组件,需要删除该标记
|
|
191
|
+
if (!ComponentsManager.isLayoutComponent(newAct.params.namespace)) {
|
|
192
|
+
delete newAct.params.enhance;
|
|
193
|
+
delete newAct.params.ignore;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// TODO:标记的兼容,关注配置了ignore的父级元素是否为布局组件,如果不是,需要改成enhance而不是ignore,因为其他组件没有setLayout函数
|
|
197
|
+
if (comIdToParamsMap) {
|
|
198
|
+
const parentParams = comIdToParamsMap.get(newAct.comId);
|
|
199
|
+
if (!parentParams) { // 没有父级组件,直接删除标记
|
|
200
|
+
delete newAct.params.enhance;
|
|
201
|
+
delete newAct.params.ignore;
|
|
202
|
+
} else {
|
|
203
|
+
// 有父级组件,判断父级组件是否为布局组件
|
|
204
|
+
const parentNamespace = parentParams?.namespace;
|
|
205
|
+
if (parentNamespace && !ComponentsManager.isLayoutComponent(parentNamespace)) {
|
|
206
|
+
newAct.params.enhance = true;
|
|
207
|
+
delete newAct.params.ignore;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
} else {
|
|
213
|
+
if (newAct.params.enhance || newAct.params.ignore) {
|
|
214
|
+
delete newAct.params.enhance;
|
|
215
|
+
delete newAct.params.ignore;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// absolute 布局的转化
|
|
221
|
+
if (newAct.params?.value?.display === "absolute") {
|
|
222
|
+
newAct.params.value.position = "smart";
|
|
223
|
+
delete newAct.params.value.display;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// flexDirection 的兼容
|
|
227
|
+
if (newAct.params?.value && newAct.params.value.display === "flex" && !newAct.params.value.flexDirection) {
|
|
228
|
+
newAct.params.value.flexDirection = "row";
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// addChild兼容
|
|
232
|
+
if (newAct.type === "addChild" && Array.isArray(newAct.params?.configs)) {
|
|
233
|
+
newAct.params.configs.forEach((config) => {
|
|
234
|
+
|
|
235
|
+
// path value幻觉,直接用key value的情况
|
|
236
|
+
if (!config?.path && Object.keys(config).length === 1) {
|
|
237
|
+
const firstKey = Object.keys(config)[0];
|
|
238
|
+
const value = config[firstKey]
|
|
239
|
+
delete config[firstKey];
|
|
240
|
+
config.path = firstKey
|
|
241
|
+
config.value = value
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (config.parent) {
|
|
245
|
+
config.path = `:parent/${config.path}`;
|
|
246
|
+
delete config.parent;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// absolute 布局的转化
|
|
250
|
+
if (config?.value?.display === "absolute") {
|
|
251
|
+
config.value.position = "smart";
|
|
252
|
+
delete config.value.display;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// flexDirection 的兼容
|
|
256
|
+
if (config.value && config.value?.display === "flex" && !config.value?.flexDirection) {
|
|
257
|
+
config.value.flexDirection = "row";
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (config?.style) {
|
|
261
|
+
// 兼容background
|
|
262
|
+
transformToValidBackground(config?.style);
|
|
52
263
|
}
|
|
53
264
|
});
|
|
54
265
|
}
|
|
55
266
|
|
|
267
|
+
// flex布局幻觉的兼容
|
|
268
|
+
if (newAct.type === "doConfig") {
|
|
269
|
+
if (newAct.params?.display === 'flex' && !newAct.params?.flexDirection) {
|
|
270
|
+
newAct.params.flexDirection = 'column';
|
|
271
|
+
}
|
|
272
|
+
if (newAct.params?.flexDirection && !newAct.params?.display) {
|
|
273
|
+
newAct.params.display = 'flex';
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// 对样式幻觉的兼容
|
|
278
|
+
if (newAct.type === "doConfig" && newAct.params?.style) {
|
|
279
|
+
// 兼容background
|
|
280
|
+
transformToValidBackground(newAct.params?.style);
|
|
281
|
+
}
|
|
282
|
+
if (newAct.type === "addChild" && newAct.params?.layout) {
|
|
283
|
+
// 兼容margin
|
|
284
|
+
transformToValidMargins(newAct.params?.layout);
|
|
285
|
+
|
|
286
|
+
// 支持width=auto
|
|
287
|
+
if (newAct.params?.layout?.width === 'auto') {
|
|
288
|
+
newAct.params.layout.width = '100%';
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// 在所有兼容性处理之后,再记录 addChild 的配置,保证 namespace / layout 等信息已经就绪
|
|
293
|
+
if (comIdToParamsMap && newAct.type === "addChild") {
|
|
294
|
+
comIdToParamsMap.set(newAct.params.comId, JSON.parse(JSON.stringify(newAct.params)) as AddChildActionParams);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return newAct;
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* 将background转换为有效的backgroundColor和backgroundImage
|
|
302
|
+
* @param styles 需要转换的样式对象
|
|
303
|
+
*/
|
|
304
|
+
function transformToValidBackground(styles: any): void {
|
|
305
|
+
// 兼容下把渐变色配置到backgroundColor的情况
|
|
306
|
+
if (
|
|
307
|
+
styles?.backgroundColor &&
|
|
308
|
+
styles?.backgroundColor?.indexOf("gradient") > -1
|
|
309
|
+
) {
|
|
310
|
+
const imageRegex =
|
|
311
|
+
/(url\([^)]+\)|linear-gradient\([^)]+\)|radial-gradient\([^)]+\)|conic-gradient\([^)]+\))/;
|
|
312
|
+
const imageMatch = styles.backgroundColor.match(imageRegex);
|
|
313
|
+
|
|
314
|
+
if (imageMatch && !styles.backgroundImage) {
|
|
315
|
+
styles.backgroundImage = imageMatch[0];
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
delete styles.backgroundColor;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// 兼容,配置backgroundColor的话记得去除渐变色
|
|
322
|
+
if (styles.backgroundColor && !styles.backgroundImage) {
|
|
323
|
+
styles.backgroundColor = styles.backgroundColor
|
|
324
|
+
styles.backgroundImage = 'none'
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// 如果没有background属性,直接返回
|
|
328
|
+
if (!styles.background) {
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const background = styles.background.toString().trim();
|
|
333
|
+
|
|
334
|
+
// 删除原有的background属性
|
|
335
|
+
delete styles.background;
|
|
336
|
+
|
|
337
|
+
// 处理特殊值
|
|
338
|
+
if (background === 'transparent' || background === 'none') {
|
|
339
|
+
styles.backgroundColor = 'transparent';
|
|
340
|
+
styles.backgroundImage = 'none';
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// 解析复合背景
|
|
345
|
+
const parsedBackground = parseComplexBackground(background);
|
|
346
|
+
|
|
347
|
+
if (parsedBackground.hasImages && !styles.backgroundImage) {
|
|
348
|
+
styles.backgroundColor = 'transparent';
|
|
349
|
+
styles.backgroundImage = parsedBackground.images.join(', ');
|
|
350
|
+
|
|
351
|
+
// 设置背景位置和尺寸
|
|
352
|
+
if (parsedBackground.position && !styles.backgroundPosition) {
|
|
353
|
+
styles.backgroundPosition = parsedBackground.position;
|
|
354
|
+
}
|
|
355
|
+
if (parsedBackground.size && !styles.backgroundSize) {
|
|
356
|
+
styles.backgroundSize = parsedBackground.size;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// 如果只有颜色
|
|
363
|
+
if (parsedBackground.color && !styles.backgroundColor) {
|
|
364
|
+
styles.backgroundColor = parsedBackground.color;
|
|
365
|
+
if (!styles.backgroundImage) {
|
|
366
|
+
styles.backgroundImage = 'none';
|
|
367
|
+
}
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// 如果没有找到颜色,但有backgroundImage,设置透明背景色
|
|
372
|
+
if (styles.backgroundImage && !styles.backgroundColor) {
|
|
373
|
+
styles.backgroundColor = 'transparent';
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* 解析复杂的background值
|
|
379
|
+
* @param background 原始background字符串
|
|
380
|
+
* @returns 解析后的对象
|
|
381
|
+
*/
|
|
382
|
+
function parseComplexBackground(background: string) {
|
|
383
|
+
const result = {
|
|
384
|
+
images: [] as string[],
|
|
385
|
+
color: '',
|
|
386
|
+
position: '',
|
|
387
|
+
size: '',
|
|
388
|
+
hasImages: false
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
// 使用更精确的方法来提取图片和渐变
|
|
392
|
+
const images = extractBackgroundImages(background);
|
|
393
|
+
|
|
394
|
+
if (images.length > 0) {
|
|
395
|
+
result.hasImages = true;
|
|
396
|
+
result.images = images;
|
|
397
|
+
|
|
398
|
+
// 提取位置和尺寸信息
|
|
399
|
+
const positionSizeInfo = extractPositionAndSize(background, images);
|
|
400
|
+
result.position = positionSizeInfo.position;
|
|
401
|
+
result.size = positionSizeInfo.size;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// 提取颜色值
|
|
405
|
+
const color = extractBackgroundColor(background, images);
|
|
406
|
+
if (color) {
|
|
407
|
+
result.color = color;
|
|
408
|
+
}
|
|
409
|
+
|
|
56
410
|
return result;
|
|
57
411
|
}
|
|
58
412
|
|
|
413
|
+
/**
|
|
414
|
+
* 提取背景图片和渐变
|
|
415
|
+
*/
|
|
416
|
+
function extractBackgroundImages(background: string): string[] {
|
|
417
|
+
const images: string[] = [];
|
|
418
|
+
let remaining = background;
|
|
419
|
+
|
|
420
|
+
while (remaining.length > 0) {
|
|
421
|
+
// 查找下一个函数的开始
|
|
422
|
+
const urlMatch = remaining.match(/url\s*\(/);
|
|
423
|
+
const gradientMatch = remaining.match(/(linear-gradient|radial-gradient|conic-gradient)\s*\(/);
|
|
424
|
+
|
|
425
|
+
let nextMatch = null;
|
|
426
|
+
let matchType = '';
|
|
427
|
+
|
|
428
|
+
if (urlMatch && gradientMatch) {
|
|
429
|
+
// 选择更早出现的匹配
|
|
430
|
+
if (urlMatch.index! < gradientMatch.index!) {
|
|
431
|
+
nextMatch = urlMatch;
|
|
432
|
+
matchType = 'url';
|
|
433
|
+
} else {
|
|
434
|
+
nextMatch = gradientMatch;
|
|
435
|
+
matchType = 'gradient';
|
|
436
|
+
}
|
|
437
|
+
} else if (urlMatch) {
|
|
438
|
+
nextMatch = urlMatch;
|
|
439
|
+
matchType = 'url';
|
|
440
|
+
} else if (gradientMatch) {
|
|
441
|
+
nextMatch = gradientMatch;
|
|
442
|
+
matchType = 'gradient';
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if (!nextMatch) {
|
|
446
|
+
break;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
const startIndex = nextMatch.index!;
|
|
450
|
+
const functionStart = remaining.indexOf('(', startIndex) + 1;
|
|
451
|
+
|
|
452
|
+
// 找到匹配的右括号
|
|
453
|
+
let parenCount = 1;
|
|
454
|
+
let endIndex = functionStart;
|
|
455
|
+
|
|
456
|
+
while (endIndex < remaining.length && parenCount > 0) {
|
|
457
|
+
if (remaining[endIndex] === '(') {
|
|
458
|
+
parenCount++;
|
|
459
|
+
} else if (remaining[endIndex] === ')') {
|
|
460
|
+
parenCount--;
|
|
461
|
+
}
|
|
462
|
+
endIndex++;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
if (parenCount === 0) {
|
|
466
|
+
// 提取完整的函数
|
|
467
|
+
const fullFunction = remaining.substring(startIndex, endIndex);
|
|
468
|
+
images.push(fullFunction);
|
|
469
|
+
|
|
470
|
+
// 移除已处理的部分
|
|
471
|
+
remaining = remaining.substring(endIndex);
|
|
472
|
+
} else {
|
|
473
|
+
// 如果括号不匹配,跳过这个匹配
|
|
474
|
+
remaining = remaining.substring(startIndex + 1);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
return images;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* 提取位置和尺寸信息
|
|
483
|
+
*/
|
|
484
|
+
function extractPositionAndSize(background: string, images: string[]): { position: string; size: string } {
|
|
485
|
+
let cleanBackground = background;
|
|
486
|
+
|
|
487
|
+
// 移除所有图片和渐变
|
|
488
|
+
images.forEach(image => {
|
|
489
|
+
cleanBackground = cleanBackground.replace(image, '');
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
// 清理多余的逗号和空格
|
|
493
|
+
cleanBackground = cleanBackground.replace(/,\s*,/g, ',').replace(/^\s*,\s*|\s*,\s*$/g, '').trim();
|
|
494
|
+
|
|
495
|
+
// 匹配位置/尺寸模式 (如: center/cover, top left/contain)
|
|
496
|
+
const positionSizeMatch = cleanBackground.match(/([^\/,]*?)\/([^\/,]*)/);
|
|
497
|
+
|
|
498
|
+
let position = '';
|
|
499
|
+
let size = '';
|
|
500
|
+
|
|
501
|
+
if (positionSizeMatch) {
|
|
502
|
+
const positionPart = positionSizeMatch[1]?.trim();
|
|
503
|
+
const sizePart = positionSizeMatch[2]?.trim();
|
|
504
|
+
|
|
505
|
+
if (positionPart && isValidBackgroundPosition(positionPart)) {
|
|
506
|
+
position = positionPart;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
if (sizePart && isValidBackgroundSize(sizePart)) {
|
|
510
|
+
size = sizePart;
|
|
511
|
+
}
|
|
512
|
+
} else {
|
|
513
|
+
// 如果没有找到 / 分隔符,尝试单独匹配位置或尺寸
|
|
514
|
+
const parts = cleanBackground.split(/\s+/).filter(part => part.length > 0);
|
|
515
|
+
|
|
516
|
+
for (const part of parts) {
|
|
517
|
+
if (!position && isValidBackgroundPosition(part)) {
|
|
518
|
+
position = part;
|
|
519
|
+
} else if (!size && isValidBackgroundSize(part)) {
|
|
520
|
+
size = part;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
return { position, size };
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* 提取背景颜色
|
|
530
|
+
*/
|
|
531
|
+
function extractBackgroundColor(background: string, images: string[]): string {
|
|
532
|
+
let cleanBackground = background;
|
|
533
|
+
|
|
534
|
+
// 移除所有图片和渐变
|
|
535
|
+
images.forEach(image => {
|
|
536
|
+
cleanBackground = cleanBackground.replace(image, '');
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
// 移除位置和尺寸信息
|
|
540
|
+
cleanBackground = cleanBackground.replace(/\s*(center|top|bottom|left|right|\d+%|\d+px)\s*/g, ' ');
|
|
541
|
+
cleanBackground = cleanBackground.replace(/\s*\/\s*(cover|contain|auto|\d+%|\d+px)\s*/g, ' ');
|
|
542
|
+
cleanBackground = cleanBackground.replace(/,\s*,/g, ',').replace(/^\s*,\s*|\s*,\s*$/g, '').trim();
|
|
543
|
+
|
|
544
|
+
// 匹配颜色格式
|
|
545
|
+
const colorRegex = /(#[0-9A-Fa-f]{3,6}|rgb\([^)]+\)|rgba\([^)]+\)|hsl\([^)]+\)|hsla\([^)]+\)|[a-zA-Z]+)/;
|
|
546
|
+
const colorMatch = cleanBackground.match(colorRegex);
|
|
547
|
+
|
|
548
|
+
return colorMatch ? colorMatch[0] : '';
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* 检查是否是有效的背景位置值
|
|
553
|
+
*/
|
|
554
|
+
function isValidBackgroundPosition(value: string): boolean {
|
|
555
|
+
const positionKeywords = ['center', 'top', 'bottom', 'left', 'right'];
|
|
556
|
+
const parts = value.split(/\s+/);
|
|
557
|
+
|
|
558
|
+
return parts.every(part =>
|
|
559
|
+
positionKeywords.includes(part) ||
|
|
560
|
+
/^\d+%$/.test(part) ||
|
|
561
|
+
/^\d+px$/.test(part) ||
|
|
562
|
+
/^-?\d+(\.\d+)?(px|em|rem|%)$/.test(part)
|
|
563
|
+
);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* 检查是否是有效的背景尺寸值
|
|
568
|
+
*/
|
|
569
|
+
function isValidBackgroundSize(value: string): boolean {
|
|
570
|
+
const sizeKeywords = ['cover', 'contain', 'auto'];
|
|
571
|
+
|
|
572
|
+
if (sizeKeywords.includes(value)) {
|
|
573
|
+
return true;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
const parts = value.split(/\s+/);
|
|
577
|
+
return parts.every(part =>
|
|
578
|
+
part === 'auto' ||
|
|
579
|
+
/^\d+%$/.test(part) ||
|
|
580
|
+
/^\d+px$/.test(part) ||
|
|
581
|
+
/^-?\d+(\.\d+)?(px|em|rem|%)$/.test(part)
|
|
582
|
+
);
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* 将margin简写转换为marginTop/Right/Bottom/Left
|
|
587
|
+
* @param styles 需要转换的样式对象
|
|
588
|
+
*/
|
|
589
|
+
function transformToValidMargins(styles: any): void {
|
|
590
|
+
// 如果没有margin属性,直接返回
|
|
591
|
+
if (!styles.margin) {
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
const margin = styles.margin.toString().trim();
|
|
596
|
+
const values = margin.split(/\s+/); // 按空格分割
|
|
597
|
+
|
|
598
|
+
// 根据值的数量设置不同方向的margin
|
|
599
|
+
switch (values.length) {
|
|
600
|
+
case 1: // margin: 10px;
|
|
601
|
+
styles.marginTop = values[0];
|
|
602
|
+
styles.marginRight = values[0];
|
|
603
|
+
styles.marginBottom = values[0];
|
|
604
|
+
styles.marginLeft = values[0];
|
|
605
|
+
break;
|
|
606
|
+
case 2: // margin: 10px 20px;
|
|
607
|
+
styles.marginTop = values[0];
|
|
608
|
+
styles.marginRight = values[1];
|
|
609
|
+
styles.marginBottom = values[0];
|
|
610
|
+
styles.marginLeft = values[1];
|
|
611
|
+
break;
|
|
612
|
+
case 3: // margin: 10px 20px 30px;
|
|
613
|
+
styles.marginTop = values[0];
|
|
614
|
+
styles.marginRight = values[1];
|
|
615
|
+
styles.marginBottom = values[2];
|
|
616
|
+
styles.marginLeft = values[1];
|
|
617
|
+
break;
|
|
618
|
+
case 4: // margin: 10px 20px 30px 40px;
|
|
619
|
+
styles.marginTop = values[0];
|
|
620
|
+
styles.marginRight = values[1];
|
|
621
|
+
styles.marginBottom = values[2];
|
|
622
|
+
styles.marginLeft = values[3];
|
|
623
|
+
break;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// 删除原有的margin属性
|
|
627
|
+
delete styles.margin;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* 将解析出的一条 action 推入列表,若为 addChild 且带 index 则追加对应 move
|
|
632
|
+
*/
|
|
633
|
+
function pushParsedAction(
|
|
634
|
+
newActions: any[],
|
|
635
|
+
parsedAction: any,
|
|
636
|
+
processedLines: Set<string>,
|
|
637
|
+
trimmedLine: string
|
|
638
|
+
) {
|
|
639
|
+
if (!parsedAction.comId) return;
|
|
640
|
+
newActions.push(parsedAction);
|
|
641
|
+
if (parsedAction.type === 'addChild' && parsedAction.params.index !== undefined) {
|
|
642
|
+
newActions.push({
|
|
643
|
+
comId: parsedAction.params.comId,
|
|
644
|
+
target: ':root',
|
|
645
|
+
type: 'move',
|
|
646
|
+
params: {
|
|
647
|
+
to: {
|
|
648
|
+
comId: parsedAction.comId,
|
|
649
|
+
slotId: parsedAction.target,
|
|
650
|
+
index: parsedAction.params.index,
|
|
651
|
+
},
|
|
652
|
+
}
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
processedLines.add(trimmedLine);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* 创建actions解析器
|
|
660
|
+
* @param options.enabledActionTags 是否启用 action tags
|
|
661
|
+
* @returns 解析函数 parseActions(text, isEnd?)
|
|
662
|
+
* - text: 待解析的 actions 文本(可流式追加)
|
|
663
|
+
* - isEnd: 是否为结束标记;为 true 时最后一行即使没有回车符也会被当作完整行解析
|
|
664
|
+
*/
|
|
665
|
+
export function createActionsParser({ enabledActionTags }: { enabledActionTags?: boolean }) {
|
|
666
|
+
const processedLines = new Set<string>();
|
|
667
|
+
const comIdToParamsMap = new Map<string, AddChildActionParams>();
|
|
668
|
+
|
|
669
|
+
return function parseActions(text: string, isEnd?: boolean) {
|
|
670
|
+
const newActions: any[] = [];
|
|
671
|
+
const lines = text.split("\n").filter(line => line.trim() !== '');
|
|
672
|
+
|
|
673
|
+
const linesToProcess = lines.slice(0, -1);
|
|
674
|
+
const lastLine = lines[lines.length - 1];
|
|
675
|
+
const lastLineComplete = lines.length === 0 || text.endsWith("\n") || isEnd === true;
|
|
676
|
+
|
|
677
|
+
for (const line of linesToProcess) {
|
|
678
|
+
const trimmedLine = line.trim();
|
|
679
|
+
if (!trimmedLine || processedLines.has(trimmedLine)) continue;
|
|
680
|
+
try {
|
|
681
|
+
const parsedAction = formatAction(trimmedLine, comIdToParamsMap, { enabledActionTags });
|
|
682
|
+
pushParsedAction(newActions, parsedAction, processedLines, trimmedLine);
|
|
683
|
+
} catch {
|
|
684
|
+
processedLines.add(trimmedLine);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
if (lastLine && lastLine.trim() && lastLineComplete && !processedLines.has(lastLine.trim())) {
|
|
689
|
+
const trimmedLastLine = lastLine.trim();
|
|
690
|
+
try {
|
|
691
|
+
const parsedAction = formatAction(trimmedLastLine, comIdToParamsMap, { enabledActionTags });
|
|
692
|
+
pushParsedAction(newActions, parsedAction, processedLines, trimmedLastLine);
|
|
693
|
+
} catch {
|
|
694
|
+
processedLines.add(trimmedLastLine);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
return newActions;
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
export function stripFileBlocks(raw: string) {
|
|
703
|
+
if (typeof raw !== "string") {
|
|
704
|
+
return ""
|
|
705
|
+
}
|
|
706
|
+
const fileBlockRegex = /```[^\n]*title\s*=\s*"[^"\n]*"?[\s\S]*?```/g;
|
|
707
|
+
let cleaned = raw.replace(fileBlockRegex, '');
|
|
708
|
+
|
|
709
|
+
// 去掉多余空行:连续空白行压缩为单个换行,再首尾 trim
|
|
710
|
+
cleaned = cleaned
|
|
711
|
+
.replace(/\n{2,}/g, '\n') // 多个换行压缩为一个
|
|
712
|
+
.trim();
|
|
713
|
+
|
|
714
|
+
return cleaned;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
export function jsonSafeParse(input: string): any {
|
|
718
|
+
let finalError
|
|
719
|
+
try {
|
|
720
|
+
return JSON.parse(input);
|
|
721
|
+
} catch (error) {
|
|
722
|
+
finalError = error
|
|
723
|
+
try {
|
|
724
|
+
const repairedJson = jsonrepair(input);
|
|
725
|
+
return JSON.parse(repairedJson);
|
|
726
|
+
} catch (repairError) {
|
|
727
|
+
// 修复也失败了,抛出错误
|
|
728
|
+
throw finalError
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
/** PC */
|
|
734
|
+
type PageInfoSPA = {
|
|
735
|
+
id: string;
|
|
736
|
+
title: string;
|
|
737
|
+
inputs: {id: string; title: string}[];
|
|
738
|
+
outputs: {id: string; title: string}[];
|
|
739
|
+
}[]
|
|
740
|
+
|
|
741
|
+
/** 鸿蒙 */
|
|
742
|
+
type PageInfoMPA = {
|
|
743
|
+
pageAry: PageInfoSPA;
|
|
744
|
+
}[]
|
|
745
|
+
|
|
746
|
+
/** 获取pages,兼容spa和mpa */
|
|
747
|
+
export const transformPageInfo = (pageInfo: PageInfoSPA | PageInfoMPA) => {
|
|
748
|
+
const pages: PageInfoSPA[number][] = [];
|
|
749
|
+
pageInfo?.forEach((page) => {
|
|
750
|
+
if ("pageAry" in page) {
|
|
751
|
+
pages.push(...page.pageAry);
|
|
752
|
+
} else {
|
|
753
|
+
pages.push(page)
|
|
754
|
+
}
|
|
755
|
+
})
|
|
756
|
+
return pages;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
const formatVarAction = (
|
|
760
|
+
_action: string,
|
|
761
|
+
) => {
|
|
762
|
+
let action;
|
|
763
|
+
try {
|
|
764
|
+
// TODO,后面要提示词处理的,这样replace不合理
|
|
765
|
+
const fixActionString = _action.replaceAll('{":parent/', '{"path":":parent/')
|
|
766
|
+
action = JSON.parse(fixActionString);
|
|
767
|
+
} catch (error) {
|
|
768
|
+
try {
|
|
769
|
+
const repairedAction = jsonrepair(_action)
|
|
770
|
+
action = JSON.parse(repairedAction)
|
|
771
|
+
console.log("[action]", action)
|
|
772
|
+
} catch (error) {
|
|
773
|
+
console.error("repair action error", error);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
if (!Array.isArray(action)) {
|
|
778
|
+
return action;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
return action;
|
|
782
|
+
};
|
|
59
783
|
|
|
60
|
-
export
|
|
61
|
-
|
|
784
|
+
export function createVarActionsParser() {
|
|
785
|
+
const processedLines = new Set<string>();
|
|
786
|
+
|
|
787
|
+
return function parseActions(text: string) {
|
|
788
|
+
const newActions = [];
|
|
789
|
+
const lines = text.split("\n").filter(line => line.trim() !== '');
|
|
790
|
+
|
|
791
|
+
// 只处理除了最后一行之外的所有行(最后一行可能不完整)
|
|
792
|
+
const linesToProcess = lines.slice(0, -1);
|
|
793
|
+
const lastLine = lines[lines.length - 1];
|
|
794
|
+
|
|
795
|
+
// 处理完整的行
|
|
796
|
+
for (const line of linesToProcess) {
|
|
797
|
+
const trimmedLine = line.trim();
|
|
798
|
+
|
|
799
|
+
// 跳过空行和已处理的行
|
|
800
|
+
if (!trimmedLine || processedLines.has(trimmedLine)) {
|
|
801
|
+
continue;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
try {
|
|
805
|
+
const parsedAction = formatVarAction(trimmedLine);
|
|
806
|
+
newActions.push(parsedAction);
|
|
807
|
+
processedLines.add(trimmedLine);
|
|
808
|
+
} catch (error) {
|
|
809
|
+
// 这是真正的解析错误(完整的行但格式错误)
|
|
810
|
+
processedLines.add(trimmedLine); // 标记为已处理,避免重复尝试
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
// 处理最后一行
|
|
815
|
+
if (lastLine && lastLine.trim()) {
|
|
816
|
+
const trimmedLastLine = lastLine.trim();
|
|
817
|
+
|
|
818
|
+
// 如果文本以换行符结尾,说明最后一行是完整的
|
|
819
|
+
if ((text.endsWith("\n")) && !processedLines.has(trimmedLastLine)) {
|
|
820
|
+
try {
|
|
821
|
+
const parsedAction = formatVarAction(trimmedLastLine);
|
|
822
|
+
newActions.push(parsedAction);
|
|
823
|
+
processedLines.add(trimmedLastLine);
|
|
824
|
+
} catch (error) {
|
|
825
|
+
processedLines.add(trimmedLastLine);
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
// processedLines.clear();
|
|
831
|
+
|
|
832
|
+
return newActions;
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
const UUID_SEED = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
837
|
+
export const uuid = (len = 5) => {
|
|
838
|
+
const maxPos = UUID_SEED.length;
|
|
839
|
+
let rtn = '';
|
|
840
|
+
for (let i = 0; i < len; i++) {
|
|
841
|
+
rtn += UUID_SEED.charAt(Math.floor(Math.random() * maxPos));
|
|
842
|
+
}
|
|
843
|
+
return 'u_' + rtn;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
export class ComIdTransform {
|
|
847
|
+
comIdMap: Record<string, string[]> = {};
|
|
848
|
+
|
|
849
|
+
constructor(comIds: string[]) {
|
|
850
|
+
const { comIdMap } = this;
|
|
851
|
+
comIds.forEach((comId) => {
|
|
852
|
+
comIdMap[comId] = [comId];
|
|
853
|
+
})
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
getComId(comId: string) {
|
|
857
|
+
if (!this.comIdMap[comId] || this.comIdMap[comId].length === 0) {
|
|
858
|
+
const newComId = uuid();
|
|
859
|
+
this.comIdMap[comId] = [newComId];
|
|
860
|
+
return newComId;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
// 返回最近添加的comId(数组的最后一个)
|
|
864
|
+
return this.comIdMap[comId][this.comIdMap[comId].length - 1];
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
// 添加新的comId映射,用于addChild操作
|
|
868
|
+
addComId(comId: string): string {
|
|
869
|
+
const newComId = uuid();
|
|
870
|
+
if (!this.comIdMap[comId]) {
|
|
871
|
+
this.comIdMap[comId] = [];
|
|
872
|
+
}
|
|
873
|
+
this.comIdMap[comId].push(newComId);
|
|
874
|
+
return newComId;
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
export class PromiseStack {
|
|
879
|
+
stack: any[] = [];
|
|
880
|
+
currentPromise: any = null;
|
|
881
|
+
|
|
882
|
+
add(promiseFn: any) {
|
|
883
|
+
this.stack.push(promiseFn);
|
|
884
|
+
this.run();
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
async run() {
|
|
888
|
+
let catchNext = false;
|
|
889
|
+
try {
|
|
890
|
+
if (this.currentPromise) {
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
const promiseFn = this.stack.shift();
|
|
894
|
+
if (promiseFn) {
|
|
895
|
+
const promise = promiseFn();
|
|
896
|
+
if (Object.prototype.toString.call(promise) === "[object Promise]") {
|
|
897
|
+
this.currentPromise = promise;
|
|
898
|
+
catchNext = true;
|
|
899
|
+
await promise;
|
|
900
|
+
this.currentPromise = null;
|
|
901
|
+
this.run();
|
|
902
|
+
} else {
|
|
903
|
+
this.run();
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
} catch (e) {
|
|
907
|
+
console.error(e)
|
|
908
|
+
if (catchNext) {
|
|
909
|
+
this.currentPromise = null;
|
|
910
|
+
this.run();
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
}
|
|
62
914
|
}
|