@lcap/nasl 4.4.0-rc.2 → 4.4.1-rc.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.
Files changed (143) hide show
  1. package/out/generator/genBundleFiles.d.ts +2 -0
  2. package/out/generator/genBundleFiles.d.ts.map +1 -1
  3. package/out/generator/genBundleFiles.js +46 -10
  4. package/out/generator/genBundleFiles.js.map +1 -1
  5. package/out/generator/icestark.d.ts +1 -1
  6. package/out/generator/icestark.d.ts.map +1 -1
  7. package/out/generator/icestark.js +6 -1
  8. package/out/generator/icestark.js.map +1 -1
  9. package/out/generator/qiankun.d.ts +1 -1
  10. package/out/generator/qiankun.d.ts.map +1 -1
  11. package/out/generator/qiankun.js +5 -3
  12. package/out/generator/qiankun.js.map +1 -1
  13. package/out/generator/release-body/data.d.ts.map +1 -1
  14. package/out/generator/release-body/data.js +30 -0
  15. package/out/generator/release-body/data.js.map +1 -1
  16. package/out/generator/release-body/share-content.js +1 -1
  17. package/out/generator/release-body/share-content.js.map +1 -1
  18. package/out/generator/release-body/types.d.ts +1 -0
  19. package/out/generator/release-body/types.d.ts.map +1 -1
  20. package/out/generator/wujie.d.ts +1 -1
  21. package/out/generator/wujie.d.ts.map +1 -1
  22. package/out/generator/wujie.js +6 -1
  23. package/out/generator/wujie.js.map +1 -1
  24. package/out/natural/exports/nasl2Files.d.ts +18 -1
  25. package/out/natural/exports/nasl2Files.d.ts.map +1 -1
  26. package/out/natural/exports/nasl2Files.js +162 -3
  27. package/out/natural/exports/nasl2Files.js.map +1 -1
  28. package/out/natural/exports/transform2BatchActions.d.ts +3 -1
  29. package/out/natural/exports/transform2BatchActions.d.ts.map +1 -1
  30. package/out/natural/exports/transform2BatchActions.js +767 -101
  31. package/out/natural/exports/transform2BatchActions.js.map +1 -1
  32. package/out/natural/old/parser/transformTS2UI.js +1 -1
  33. package/out/natural/old/parser/transformTS2UI.js.map +1 -1
  34. package/out/natural/old/parser/transformTSCode.d.ts.map +1 -1
  35. package/out/natural/old/parser/transformTSCode.js +26 -2
  36. package/out/natural/old/parser/transformTSCode.js.map +1 -1
  37. package/out/natural/parser/parseNaturalTS.d.ts.map +1 -1
  38. package/out/natural/parser/parseNaturalTS.js +97 -26
  39. package/out/natural/parser/parseNaturalTS.js.map +1 -1
  40. package/out/natural/parser/parseNaturalTSXView.d.ts.map +1 -1
  41. package/out/natural/parser/parseNaturalTSXView.js +106 -87
  42. package/out/natural/parser/parseNaturalTSXView.js.map +1 -1
  43. package/out/natural/transforms/checker/checkDefaultValue.d.ts +2 -1
  44. package/out/natural/transforms/checker/checkDefaultValue.d.ts.map +1 -1
  45. package/out/natural/transforms/checker/checkDefaultValue.js +7 -1
  46. package/out/natural/transforms/checker/checkDefaultValue.js.map +1 -1
  47. package/out/natural/transforms/checker/checkLcapEntity.d.ts +16 -0
  48. package/out/natural/transforms/checker/checkLcapEntity.d.ts.map +1 -0
  49. package/out/natural/transforms/checker/checkLcapEntity.js +337 -0
  50. package/out/natural/transforms/checker/checkLcapEntity.js.map +1 -0
  51. package/out/natural/transforms/checker/checkValidationCalleeName.d.ts +3 -0
  52. package/out/natural/transforms/checker/checkValidationCalleeName.d.ts.map +1 -0
  53. package/out/natural/transforms/checker/checkValidationCalleeName.js +88 -0
  54. package/out/natural/transforms/checker/checkValidationCalleeName.js.map +1 -0
  55. package/out/natural/transforms/checker/checkViewElement.d.ts.map +1 -1
  56. package/out/natural/transforms/checker/checkViewElement.js +175 -9
  57. package/out/natural/transforms/checker/checkViewElement.js.map +1 -1
  58. package/out/natural/transforms/checker/index.d.ts +2 -0
  59. package/out/natural/transforms/checker/index.d.ts.map +1 -1
  60. package/out/natural/transforms/checker/index.js +5 -1
  61. package/out/natural/transforms/checker/index.js.map +1 -1
  62. package/out/natural/transforms/transform2Entity.d.ts +5 -0
  63. package/out/natural/transforms/transform2Entity.d.ts.map +1 -1
  64. package/out/natural/transforms/transform2Entity.js +84 -4
  65. package/out/natural/transforms/transform2Entity.js.map +1 -1
  66. package/out/natural/transforms/transform2GlobalLogicDeclaration.d.ts +1 -1
  67. package/out/natural/transforms/transform2GlobalLogicDeclaration.d.ts.map +1 -1
  68. package/out/natural/transforms/transform2GlobalLogicDeclaration.js +15 -1
  69. package/out/natural/transforms/transform2GlobalLogicDeclaration.js.map +1 -1
  70. package/out/natural/transforms/transform2Logic.d.ts +3 -3
  71. package/out/natural/transforms/transform2Logic.d.ts.map +1 -1
  72. package/out/natural/transforms/transform2Logic.js +54 -13
  73. package/out/natural/transforms/transform2Logic.js.map +1 -1
  74. package/out/natural/transforms/transform2LogicItem.d.ts +4 -0
  75. package/out/natural/transforms/transform2LogicItem.d.ts.map +1 -1
  76. package/out/natural/transforms/transform2LogicItem.js +82 -18
  77. package/out/natural/transforms/transform2LogicItem.js.map +1 -1
  78. package/out/natural/transforms/transform2ValidationRule.d.ts +1 -1
  79. package/out/natural/transforms/transform2ValidationRule.d.ts.map +1 -1
  80. package/out/natural/transforms/transform2ValidationRule.js +5 -0
  81. package/out/natural/transforms/transform2ValidationRule.js.map +1 -1
  82. package/out/natural/transforms/transform2Variable.d.ts +3 -3
  83. package/out/natural/transforms/transform2Variable.d.ts.map +1 -1
  84. package/out/natural/transforms/transform2Variable.js +36 -5
  85. package/out/natural/transforms/transform2Variable.js.map +1 -1
  86. package/out/natural/transforms/transformThemeAndStyle.d.ts +4 -1
  87. package/out/natural/transforms/transformThemeAndStyle.d.ts.map +1 -1
  88. package/out/natural/transforms/transformThemeAndStyle.js +25 -12
  89. package/out/natural/transforms/transformThemeAndStyle.js.map +1 -1
  90. package/out/natural/transforms/utils/createComponentLookupMap.d.ts +32 -0
  91. package/out/natural/transforms/utils/createComponentLookupMap.d.ts.map +1 -0
  92. package/out/natural/transforms/utils/createComponentLookupMap.js +57 -0
  93. package/out/natural/transforms/utils/createComponentLookupMap.js.map +1 -0
  94. package/out/natural/transforms/utils/iconNames.d.ts +2 -0
  95. package/out/natural/transforms/utils/iconNames.d.ts.map +1 -0
  96. package/out/natural/transforms/utils/iconNames.js +299 -0
  97. package/out/natural/transforms/utils/iconNames.js.map +1 -0
  98. package/out/natural/transforms/utils/normalizeNode.d.ts +3 -0
  99. package/out/natural/transforms/utils/normalizeNode.d.ts.map +1 -0
  100. package/out/natural/transforms/utils/normalizeNode.js +15 -0
  101. package/out/natural/transforms/utils/normalizeNode.js.map +1 -0
  102. package/out/natural/transforms/utils/parseDecorator.d.ts +32 -4
  103. package/out/natural/transforms/utils/parseDecorator.d.ts.map +1 -1
  104. package/out/natural/transforms/utils/parseDecorator.js +81 -9
  105. package/out/natural/transforms/utils/parseDecorator.js.map +1 -1
  106. package/out/natural/transforms/utils/transform2Directory.d.ts +59 -0
  107. package/out/natural/transforms/utils/transform2Directory.d.ts.map +1 -0
  108. package/out/natural/transforms/utils/transform2Directory.js +229 -0
  109. package/out/natural/transforms/utils/transform2Directory.js.map +1 -0
  110. package/out/natural/utils/index.d.ts +17 -0
  111. package/out/natural/utils/index.d.ts.map +1 -1
  112. package/out/natural/utils/index.js +38 -2
  113. package/out/natural/utils/index.js.map +1 -1
  114. package/out/natural/utils/nasl-file-types.d.ts +45 -0
  115. package/out/natural/utils/nasl-file-types.d.ts.map +1 -0
  116. package/out/natural/utils/nasl-file-types.js +131 -0
  117. package/out/natural/utils/nasl-file-types.js.map +1 -0
  118. package/out/server/OQL/sqlDbTypes.json +717 -0
  119. package/out/server/createUiTs.d.ts +0 -1
  120. package/out/server/createUiTs.d.ts.map +1 -1
  121. package/out/server/createUiTs.js +1 -118
  122. package/out/server/createUiTs.js.map +1 -1
  123. package/out/server/extendBaseNode.d.ts.map +1 -1
  124. package/out/server/extendBaseNode.js +3 -0
  125. package/out/server/extendBaseNode.js.map +1 -1
  126. package/out/server/naslServer.d.ts.map +1 -1
  127. package/out/server/naslServer.js +14 -21
  128. package/out/server/naslServer.js.map +1 -1
  129. package/out/service/storage/init.d.ts +1 -1
  130. package/out/service/storage/init.d.ts.map +1 -1
  131. package/out/service/storage/init.js +17 -7
  132. package/out/service/storage/init.js.map +1 -1
  133. package/out/service/storage/specTools.d.ts +20 -8
  134. package/out/service/storage/specTools.d.ts.map +1 -1
  135. package/out/service/storage/specTools.js +124 -5
  136. package/out/service/storage/specTools.js.map +1 -1
  137. package/package.json +9 -9
  138. package/sandbox/stdlib/nasl.util.ts +1 -1
  139. package/sandbox/stdlib/nasl.validation.ts +50 -14
  140. package/out/natural/transforms/utils/fetchFromComments.d.ts +0 -3
  141. package/out/natural/transforms/utils/fetchFromComments.d.ts.map +0 -1
  142. package/out/natural/transforms/utils/fetchFromComments.js +0 -10
  143. package/out/natural/transforms/utils/fetchFromComments.js.map +0 -1
@@ -17,6 +17,8 @@
17
17
  * - enum: 枚举类型
18
18
  * - logic: 业务逻辑
19
19
  * - view: 视图组件
20
+ * - backendVariables: 后端变量
21
+ * - frontendVariables: 前端类型变量
20
22
  */
21
23
  Object.defineProperty(exports, "__esModule", { value: true });
22
24
  exports.applyBatchActions = exports.transform2BatchActions = exports.generateRouterContainerTemplate = void 0;
@@ -24,6 +26,13 @@ const uuid_1 = require("uuid");
24
26
  const concepts_1 = require("../../concepts");
25
27
  const index_1 = require("../../index");
26
28
  const utils_1 = require("../../utils");
29
+ const nasl_file_types_1 = require("../utils/nasl-file-types");
30
+ /**
31
+ * 检查项目类型是否允许空名称
32
+ */
33
+ const isNameOptional = (itemType) => {
34
+ return ['backendVariables', 'frontendVariables', 'theme'].includes(itemType);
35
+ };
27
36
  /**
28
37
  * 生成空的路由容器模板
29
38
  * 用于为嵌套视图创建父级容器视图
@@ -62,6 +71,14 @@ const getItemType = (namespace) => {
62
71
  return 'logic';
63
72
  if (namespace.includes('views'))
64
73
  return 'view';
74
+ if (namespace.includes('extensions'))
75
+ return 'extensions';
76
+ if (namespace.includes('app.backend.variables'))
77
+ return 'backendVariables';
78
+ if (namespace.includes('theme.css'))
79
+ return 'theme';
80
+ if (/app\.frontendTypes\.[^.]+\.frontends\.[^.]+\.variables/.test(namespace))
81
+ return 'frontendVariables';
65
82
  return 'unknown';
66
83
  };
67
84
  /**
@@ -141,74 +158,400 @@ const buildNestedViewPath = (parentViewNames, viewName) => {
141
158
  * @param parentViewNames - 可选的父级视图名称数组
142
159
  * @returns 找到的视图节点或 undefined
143
160
  */
144
- const createViewFinder = (instance) => (name, parentViewNames) => {
145
- if (parentViewNames && parentViewNames.length > 0) {
146
- // 对于嵌套视图,使用路径查找
147
- const viewPath = buildNestedViewPath(parentViewNames, name);
148
- return instance?.findNodeByPath(viewPath);
149
- }
161
+ const createViewFinder = (instance) => (name, parentViewNames = []) => {
162
+ // if (parentViewNames && parentViewNames.length > 0) {
163
+ // // 对于嵌套视图,使用路径查找
164
+ // }
165
+ const viewPath = buildNestedViewPath(parentViewNames, name);
166
+ return instance?.findNodeByPath(viewPath);
150
167
  // 顶级视图使用 findViewByName
151
- return instance?.frontendTypes?.[0]?.frontends?.[0]?.findViewByName(name);
168
+ // return instance?.frontendTypes?.[0]?.frontends?.[0]?.findViewByName(name);
169
+ };
170
+ /**
171
+ * 类型守卫:判断是否为单节点处理器
172
+ */
173
+ const isSingleNodeHandler = (handler) => {
174
+ return ['entity', 'structure', 'enum', 'logic'].includes(handler.type);
175
+ };
176
+ /**
177
+ * 类型守卫:判断是否为视图处理器
178
+ */
179
+ const isViewHandler = (handler) => {
180
+ return handler.type === 'view';
181
+ };
182
+ /**
183
+ * 类型守卫:判断是否为全局变量处理器
184
+ */
185
+ const isGlobalVariablesHandler = (handler) => {
186
+ return ['backendVariables', 'frontendVariables'].includes(handler.type);
187
+ };
188
+ /**
189
+ * 类型守卫:判断是否为主题处理器
190
+ */
191
+ const isThemeHandler = (handler) => {
192
+ return handler.type === 'theme';
152
193
  };
153
194
  /**
154
195
  * 创建不同类型处理器的工厂函数
155
- * 为每种类型(entity、structure、enum、logic、view)提供统一的操作接口
196
+ * 为每种类型(entity、structure、enum、logic、view、backendVariables、frontendVariables)提供统一的操作接口
156
197
  * @param appInstance - 解析后的应用实例,用于查找新创建的对象
157
198
  * @param app - 目前已有的应用实例,用于查找已存在的对象和添加新对象
158
199
  * @returns 包含各种类型处理器的对象
159
200
  */
160
201
  const createTypeHandlers = (appInstance, app) => ({
161
202
  entity: {
203
+ type: 'entity',
162
204
  /** 实体在应用中的路径模板 */
163
205
  path: 'app.dataSources[name=defaultDS].entities[0]',
164
206
  /** 从解析实例中查找实体的方法 */
165
207
  findMethod: (name) => appInstance?.dataSources?.[0]?.findEntityByName(name),
166
208
  /** 从目标应用中查找已存在实体的方法 */
167
209
  findExisting: (name) => app.dataSources?.[0]?.findEntityByName(name),
168
- /** 向目标应用添加实体的方法 */
169
- addMethod: (json) => app.dataSources[0].addEntity(json),
170
210
  },
171
211
  structure: {
212
+ type: 'structure',
172
213
  /** 结构体在应用中的路径模板 */
173
214
  path: 'app.structures[0]',
174
215
  /** 从解析实例中查找结构体的方法 */
175
216
  findMethod: (name) => appInstance?.findStructureByName(name),
176
217
  /** 从目标应用中查找已存在结构体的方法 */
177
218
  findExisting: (name) => app.findStructureByName(name),
178
- /** 向目标应用添加结构体的方法 */
179
- addMethod: (json) => app.addStructure(json),
180
219
  },
181
220
  enum: {
221
+ type: 'enum',
182
222
  /** 枚举在应用中的路径模板 */
183
223
  path: 'app.enums[0]',
184
224
  /** 从解析实例中查找枚举的方法 */
185
225
  findMethod: (name) => appInstance?.findEnumByName(name),
186
226
  /** 从目标应用中查找已存在枚举的方法 */
187
227
  findExisting: (name) => app.findEnumByName(name),
188
- /** 向目标应用添加枚举的方法 */
189
- addMethod: (json) => app.addEnum(json),
190
228
  },
191
229
  logic: {
230
+ type: 'logic',
192
231
  /** 逻辑在应用中的路径模板 */
193
232
  path: 'app.logics[0]',
194
233
  /** 从解析实例中查找逻辑的方法 */
195
234
  findMethod: (name) => appInstance?.findLogicByName(name),
196
235
  /** 从目标应用中查找已存在逻辑的方法 */
197
236
  findExisting: (name) => app.findLogicByName(name),
198
- /** 向目标应用添加逻辑的方法 */
199
- addMethod: (json) => app.addLogic(json),
200
237
  },
201
238
  view: {
239
+ type: 'view',
202
240
  /** 视图在应用中的路径模板 */
203
241
  path: 'app.frontendTypes[name=pc].frontends[name=pc].views[0]',
204
242
  /** 从解析实例中查找视图的方法 */
205
243
  findMethod: createViewFinder(appInstance),
206
244
  /** 从目标应用中查找已存在视图的方法 */
207
245
  findExisting: createViewFinder(app),
208
- /** 向目标应用添加视图的方法 */
209
- addMethod: (json) => app.frontendTypes[0].frontends[0].addView(json),
210
246
  },
247
+ backendVariables: {
248
+ type: 'backendVariables',
249
+ /** 后端全局变量在应用中的路径 */
250
+ path: 'app.backend.variables[0]',
251
+ /** 从解析实例中查找后端变量 */
252
+ findMethod: (name) => {
253
+ if (!name)
254
+ return appInstance?.backend;
255
+ const path = `app.backend.variables[name=${name}]`;
256
+ return appInstance?.findNodeByPath(path);
257
+ },
258
+ /** 从目标应用中查找已存在的后端变量 */
259
+ findExisting: (name) => {
260
+ if (!name)
261
+ return app.backend;
262
+ const path = `app.backend.variables[name=${name}]`;
263
+ return app.findNodeByPath(path);
264
+ },
265
+ },
266
+ frontendVariables: {
267
+ type: 'frontendVariables',
268
+ /** 前端全局变量在应用中的路径 */
269
+ path: 'app.frontendTypes[name=pc].frontends[name=pc].variables[0]',
270
+ /** 从解析实例中查找前端变量 */
271
+ findMethod: (name) => {
272
+ if (!name)
273
+ return appInstance?.frontendTypes?.[0]?.frontends?.[0];
274
+ const path = `app.frontendTypes[name=pc].frontends[name=pc].variables[name=${name}]`;
275
+ return appInstance?.findNodeByPath(path);
276
+ },
277
+ /** 从目标应用中查找已存在的前端变量 */
278
+ findExisting: (name) => {
279
+ if (!name)
280
+ return app.frontendTypes?.[0]?.frontends?.[0];
281
+ const path = `app.frontendTypes[name=pc].frontends[name=pc].variables[name=${name}]`;
282
+ return app.findNodeByPath(path);
283
+ },
284
+ },
285
+ theme: {
286
+ type: 'theme',
287
+ /** 主题在应用中的路径 */
288
+ path: 'app.frontendTypes[name=pc].frontends[name=pc].theme',
289
+ /** 从解析实例中查找主题 */
290
+ findMethod: () => appInstance?.frontendTypes?.[0]?.frontends?.[0]?.theme,
291
+ /** 从目标应用中查找已存在的主题 */
292
+ findExisting: () => app.frontendTypes?.[0]?.frontends?.[0]?.theme,
293
+ },
294
+ // 后续需要扩展 extensions 的
211
295
  });
296
+ /**
297
+ * 通用删除操作处理
298
+ * @param params - 删除操作参数
299
+ */
300
+ const handleDeleteOperation = (params) => {
301
+ const { handler, itemName, itemType, batchActions, errors, parentViewNames, errorMessageTemplate = `要删除的对象不存在: ${itemName}`, } = params;
302
+ // 根据 handler 类型调用不同的 findExisting 方法
303
+ let existingNode;
304
+ if (isViewHandler(handler)) {
305
+ existingNode = handler.findExisting(itemName, parentViewNames);
306
+ }
307
+ else if (isSingleNodeHandler(handler)) {
308
+ existingNode = handler.findExisting(itemName);
309
+ }
310
+ else if (isGlobalVariablesHandler(handler)) {
311
+ existingNode = handler.findExisting(itemName);
312
+ }
313
+ if (existingNode) {
314
+ batchActions.actions.push({
315
+ action: 'delete',
316
+ path: existingNode.nodePath,
317
+ object: null,
318
+ });
319
+ }
320
+ else {
321
+ errors.push({
322
+ item: itemName,
323
+ type: itemType,
324
+ error: new Error(errorMessageTemplate),
325
+ level: 1,
326
+ });
327
+ }
328
+ };
329
+ /**
330
+ * 处理变量创建或更新操作
331
+ */
332
+ const handleVariableCreateOrUpdate = (handler, variable, variableName, batchActions) => {
333
+ const existingVar = handler.findExisting(variableName);
334
+ const variableObject = variable.toJSON();
335
+ if (existingVar) {
336
+ // 更新操作
337
+ batchActions.actions.push({
338
+ action: 'update',
339
+ path: existingVar.nodePath,
340
+ object: variableObject,
341
+ });
342
+ }
343
+ else {
344
+ // 创建操作
345
+ batchActions.actions.push({
346
+ action: 'create',
347
+ path: handler.path,
348
+ object: variableObject,
349
+ });
350
+ }
351
+ };
352
+ /**
353
+ * 处理全局变量类型(一个文件对应多个节点)
354
+ */
355
+ const processGlobalVariables = (params) => {
356
+ const { handler, action, itemType, batchActions, errors } = params;
357
+ // 系统保留变量,不允许删除、创建或更新
358
+ const RESERVED_VARIABLES = new Set(['httpRequest', 'httpResponse', 'currentUser']);
359
+ // 获取容器节点(backend 或 frontend)
360
+ const container = handler.findMethod();
361
+ if (!container || !container.variables) {
362
+ errors.push({
363
+ item: itemType,
364
+ type: itemType,
365
+ error: new Error(`未找到${itemType}容器或variables属性`),
366
+ level: 2,
367
+ });
368
+ return;
369
+ }
370
+ // 处理删除操作的特殊情况
371
+ if (action === 'delete') {
372
+ for (const variable of container.variables) {
373
+ const variableName = variable.name;
374
+ if (!variableName || RESERVED_VARIABLES.has(variableName))
375
+ continue;
376
+ try {
377
+ handleDeleteOperation({
378
+ handler,
379
+ itemName: variableName,
380
+ itemType,
381
+ batchActions,
382
+ errors,
383
+ errorMessageTemplate: `要删除的变量不存在: ${variableName}`,
384
+ });
385
+ }
386
+ catch (error) {
387
+ errors.push({
388
+ item: variableName,
389
+ type: itemType,
390
+ error: error,
391
+ level: 3,
392
+ });
393
+ }
394
+ }
395
+ return;
396
+ }
397
+ // 处理创建和更新操作
398
+ // 一次性获取现有容器,避免重复调用
399
+ const existingContainer = handler.findExisting();
400
+ // 构建新变量名的 Set(只在有现有容器时才需要)
401
+ const newVariableNames = existingContainer?.variables ? new Set() : null;
402
+ // 第一遍:处理新变量的创建/更新
403
+ for (const variable of container.variables) {
404
+ const variableName = variable.name;
405
+ if (!variableName || RESERVED_VARIABLES.has(variableName))
406
+ continue;
407
+ // 同时收集变量名(避免额外的 map 操作)
408
+ newVariableNames?.add(variableName);
409
+ try {
410
+ handleVariableCreateOrUpdate(handler, variable, variableName, batchActions);
411
+ }
412
+ catch (error) {
413
+ errors.push({
414
+ item: variableName,
415
+ type: itemType,
416
+ error: error,
417
+ level: 3,
418
+ });
419
+ }
420
+ }
421
+ // 第二遍:处理需要删除的旧变量(app 中有但 appInstance 中没有的,目前以 spec 生成为准,如果后续不需要,这块可以隐藏)
422
+ if (existingContainer?.variables && newVariableNames) {
423
+ for (const existingVariable of existingContainer.variables) {
424
+ const existingVariableName = existingVariable.name;
425
+ if (!existingVariableName ||
426
+ RESERVED_VARIABLES.has(existingVariableName) ||
427
+ newVariableNames.has(existingVariableName)) {
428
+ continue;
429
+ }
430
+ // 变量在 appInstance 中不存在,按 delete 处理
431
+ try {
432
+ handleDeleteOperation({
433
+ handler,
434
+ itemName: existingVariableName,
435
+ itemType,
436
+ batchActions,
437
+ errors,
438
+ errorMessageTemplate: `要删除的变量不存在: ${existingVariableName}`,
439
+ });
440
+ }
441
+ catch (error) {
442
+ errors.push({
443
+ item: existingVariableName,
444
+ type: itemType,
445
+ error: error,
446
+ level: 3,
447
+ });
448
+ }
449
+ }
450
+ }
451
+ };
452
+ /**
453
+ * 计算 view 类型的路径
454
+ */
455
+ const calculateViewPath = (naslObject) => {
456
+ let type = 'views';
457
+ if (naslObject.parentNode?.concept === 'View') {
458
+ type = 'children';
459
+ }
460
+ const parentChildren = naslObject.parentNode?.[type] || [];
461
+ const childIndex = parentChildren.findIndex((child) => child === naslObject);
462
+ const index = childIndex !== -1 ? childIndex : 0;
463
+ return `${naslObject.parentNode.nodePath}.${type}[${index}]`;
464
+ };
465
+ /**
466
+ * 处理 view 类型的 children 属性
467
+ */
468
+ const handleViewChildren = (object, action) => {
469
+ if (action === 'create') {
470
+ // 对于创建操作,需要将 children 数组转换为空数组
471
+ object.children = [];
472
+ }
473
+ else if (action === 'update') {
474
+ // 对于更新操作,删除 children 属性
475
+ if (object.children) {
476
+ delete object.children;
477
+ }
478
+ }
479
+ };
480
+ /**
481
+ * 处理单节点创建或更新操作
482
+ */
483
+ const handleSingleNodeCreateOrUpdate = (handler, itemName, itemType, parentViewNames, batchActions, errors) => {
484
+ // 从解析的实例中获取 NASL 对象
485
+ let naslObject;
486
+ // 根据 handler 类型调用不同的 findMethod
487
+ if (isViewHandler(handler)) {
488
+ naslObject = handler.findMethod(itemName, parentViewNames);
489
+ }
490
+ else {
491
+ naslObject = handler.findMethod(itemName);
492
+ }
493
+ if (!naslObject) {
494
+ errors.push({
495
+ item: itemName,
496
+ type: itemType,
497
+ error: new Error(`未找到对应的 NASL 对象: ${handler.path} - ${itemName}`),
498
+ level: 2,
499
+ });
500
+ return;
501
+ }
502
+ let finalAction = 'create';
503
+ let path = '';
504
+ let object = naslObject.toJSON();
505
+ // 特殊处理:对于 view 类型,计算正确的路径
506
+ if (itemType === 'view' && naslObject.parentNode) {
507
+ path = calculateViewPath(naslObject);
508
+ }
509
+ // 检查目标应用中是否已存在同名对象
510
+ let existingNode;
511
+ if (isViewHandler(handler)) {
512
+ existingNode = handler.findExisting(itemName, parentViewNames);
513
+ }
514
+ else {
515
+ existingNode = handler.findExisting(itemName);
516
+ }
517
+ if (existingNode) {
518
+ // 存在同名对象,标记为更新操作
519
+ finalAction = 'update';
520
+ path = existingNode.nodePath;
521
+ }
522
+ // 特殊处理 view 类型的 children 属性
523
+ if (itemType === 'view') {
524
+ handleViewChildren(object, finalAction);
525
+ }
526
+ // 添加创建或更新操作到批量操作列表
527
+ batchActions.actions.push({
528
+ action: finalAction,
529
+ path: path || handler.path,
530
+ object,
531
+ });
532
+ };
533
+ /**
534
+ * 处理单节点类型(一个文件对应一个节点)
535
+ */
536
+ const processSingleNode = (params) => {
537
+ const { handler, itemName, itemType, action, parentViewNames, batchActions, errors } = params;
538
+ if (action === 'delete') {
539
+ // 删除操作:使用通用删除方法
540
+ handleDeleteOperation({
541
+ handler,
542
+ itemName,
543
+ itemType,
544
+ batchActions,
545
+ errors,
546
+ parentViewNames,
547
+ errorMessageTemplate: `要删除的对象不存在: ${handler.path} - ${itemName}`,
548
+ });
549
+ }
550
+ else {
551
+ // 创建或更新操作
552
+ handleSingleNodeCreateOrUpdate(handler, itemName, itemType, parentViewNames, batchActions, errors);
553
+ }
554
+ };
212
555
  /**
213
556
  * 检测并生成缺失的父级视图模板
214
557
  * @param path - 当前项的路径
@@ -255,14 +598,37 @@ const transformCodeAction = ({ path, content, action, }) => {
255
598
  // 移除路径前缀 'src/',并解析命名空间
256
599
  const namespace = path.replace(/^src\//, '');
257
600
  const namespaceParts = namespace.split('.');
258
- // 提取项目名称和父命名空间
259
- const itemName = namespaceParts.length >= 2 ? namespaceParts[namespaceParts.length - 2] : '';
260
- const parentNamespace = namespaceParts.slice(0, -2).join('.');
261
- // 根据命名空间确定项目类型
601
+ // 根据命名空间确定项目类型(需要先确定类型)
262
602
  const itemType = getItemType(namespace);
603
+ // 提取项目名称和父命名空间,对于变量类型需要特殊处理
604
+ let itemName;
605
+ let parentNamespace;
606
+ if (itemType === 'backendVariables' || itemType === 'frontendVariables') {
607
+ // 对于变量类型,路径格式为: app.backend.variables.ts 或 app.frontendTypes.pc.frontends.pc.variables.ts
608
+ // itemName 设为空字符串(因为这是整个 variables 文件)
609
+ // parentNamespace 为去掉 .ts 的部分,即保留到 variables
610
+ itemName = '';
611
+ parentNamespace = namespaceParts.slice(0, -1).join('.');
612
+ }
613
+ else if (itemType === 'theme') {
614
+ // 对于主题类型,路径格式为: app.frontendTypes.pc.frontends.pc.theme.css
615
+ itemName = '';
616
+ parentNamespace = namespaceParts.slice(0, -1).join('.');
617
+ }
618
+ else if (itemType === 'extensions') {
619
+ parentNamespace = namespaceParts.slice(0, -1).join('.');
620
+ }
621
+ else {
622
+ // 其他类型使用原有逻辑,即单文件模式(例如一个实体对应一个文件)
623
+ itemName = namespaceParts.length >= 2 ? namespaceParts[namespaceParts.length - 2] : '';
624
+ parentNamespace = namespaceParts.slice(0, -2).join('.');
625
+ }
263
626
  // 生成转换后的代码,为非未知类型添加命名空间包装
264
627
  let transformedCode = content;
265
- if (itemType !== 'unknown' && parentNamespace) {
628
+ if (itemType === 'theme') {
629
+ transformedCode = `namespace ${parentNamespace} {\n $theme\`${content}\`;\n}\n`;
630
+ }
631
+ else if (itemType !== 'unknown' && parentNamespace) {
266
632
  // 对于视图类型,需要额外的缩进
267
633
  const indent = itemType === 'view' ? ' ' : '';
268
634
  transformedCode = `namespace ${parentNamespace} {\n${indent}${content}\n}\n`;
@@ -310,8 +676,13 @@ const transform2BatchActions = ({ codeActions, app, sessionId, type = 'normal',
310
676
  // 第一阶段:转换所有codeAction
311
677
  for (const item of codeActions) {
312
678
  try {
313
- // 检查文件后缀,目前一期只处理 .ts 和 .tsx 文件
314
- if (!item.path.endsWith('.ts') && !item.path.endsWith('.tsx')) {
679
+ // 检查文件后缀,目前只处理 .ts、.tsx 和 .css 文件
680
+ if (!item.path.endsWith('.ts') &&
681
+ !item.path.endsWith('.tsx') &&
682
+ !item.path.endsWith('.css')) {
683
+ continue;
684
+ }
685
+ if (!(0, nasl_file_types_1.isKnownFileType)(item.path)) {
315
686
  continue;
316
687
  }
317
688
  // 检测并生成缺失的父级视图
@@ -320,6 +691,9 @@ const transform2BatchActions = ({ codeActions, app, sessionId, type = 'normal',
320
691
  }
321
692
  // 处理当前项
322
693
  const { transformedCode, itemType, itemName, action, parentViewNames } = transformCodeAction(item);
694
+ // 跳过未知类型的 codeAction/暂时禁用 extensions
695
+ if (itemType === 'unknown' || itemType === 'extensions')
696
+ continue;
323
697
  // 只有非删除操作才需要累积代码用于解析,因为删除操作不需要解析新的 NASL 对象
324
698
  if (action !== 'delete') {
325
699
  codeArray.push(transformedCode);
@@ -370,86 +744,73 @@ const transform2BatchActions = ({ codeActions, app, sessionId, type = 'normal',
370
744
  // 第三阶段:生成批量操作
371
745
  // 获取不同类型的处理器
372
746
  const typeHandlers = createTypeHandlers(appInstance, app);
747
+ // 收集所有要删除的视图名称,用于跳过冗余的子视图删除操作
748
+ const deletedViewNames = new Set(itemTypes
749
+ .filter(({ type, action }) => type === 'view' && action === 'delete')
750
+ .map(({ name }) => name));
373
751
  // 遍历每个项目,生成对应的批量操作
374
752
  for (const { type: itemType, name: itemName, action, parentViewNames } of itemTypes) {
375
- // 跳过未知类型或无名称的项目
376
- if (itemType === 'unknown' || !itemName)
753
+ // 跳过未知类型,或者非可选名称但无名称的项目
754
+ if (itemType === 'unknown' || (!isNameOptional(itemType) && !itemName))
377
755
  continue;
756
+ // 如果父级视图已在删除列表中,子视图无需单独删除(父视图删除时会级联删除子视图)
757
+ if (itemType === 'view' && action === 'delete' && parentViewNames?.some((p) => deletedViewNames.has(p))) {
758
+ continue;
759
+ }
378
760
  try {
379
761
  const handler = typeHandlers[itemType];
380
762
  if (!handler)
381
763
  continue;
382
- // 根据操作类型执行不同的处理逻辑
383
- if (action === 'delete') {
384
- // 删除操作:查找已存在的对象并删除
385
- const existingNode = handler.findExisting(itemName, parentViewNames);
386
- if (existingNode) {
387
- // 添加删除操作到批量操作列表
764
+ // 使用类型守卫进行精确的类型判断和处理
765
+ if (isThemeHandler(handler)) {
766
+ // 主题类型:无需参数
767
+ const naslObject = handler.findMethod();
768
+ if (naslObject) {
769
+ const existingNode = handler.findExisting();
388
770
  batchActions.actions.push({
389
- action: 'delete',
390
- path: existingNode.nodePath,
391
- object: null,
392
- });
393
- }
394
- else {
395
- // 要删除的对象不存在,记录错误
396
- errors.push({
397
- item: itemName,
398
- type: itemType,
399
- error: new Error(`要删除的对象不存在: ${handler.path} - ${itemName}`),
400
- level: 1,
771
+ action: 'update',
772
+ path: existingNode?.nodePath || handler.path,
773
+ object: {
774
+ // 暂时只支持 scopeVariableMap + cssRules
775
+ ...existingNode.toJSON(),
776
+ scopeVariableMap: naslObject.scopeVariableMap,
777
+ cssRules: naslObject.cssRules,
778
+ },
401
779
  });
402
780
  }
403
781
  }
404
- else {
405
- // 创建或更新操作:从解析的实例中获取 NASL 对象
406
- const naslObject = handler.findMethod(itemName, parentViewNames);
407
- if (!naslObject) {
408
- errors.push({
409
- item: itemName,
410
- type: itemType,
411
- error: new Error(`未找到对应的 NASL 对象: ${handler.path} - ${itemName}`),
412
- level: 2,
413
- });
414
- continue;
415
- }
416
- let finalAction = 'create';
417
- let path = '';
418
- let object = naslObject.toJSON();
419
- // 特殊处理:对于 view 类型,判断父级 view 是否存在于 itemTypes 中
420
- if (itemType === 'view' && naslObject.parentNode) {
421
- // 找到当前节点在父节点 children 中的实际索引
422
- let type = 'views';
423
- if (naslObject.parentNode?.concept === 'View') {
424
- type = 'children';
425
- }
426
- const parentChildren = naslObject.parentNode?.[type] || [];
427
- const childIndex = parentChildren.findIndex((child) => child === naslObject);
428
- const index = childIndex !== -1 ? childIndex : 0;
429
- path = `${naslObject.parentNode.nodePath}.${type}[${index}]`;
430
- }
431
- // 检查目标应用中是否已存在同名对象
432
- const existingNode = handler.findExisting(itemName, parentViewNames);
433
- if (existingNode) {
434
- // 存在同名对象,标记为更新操作
435
- finalAction = 'update';
436
- path = existingNode.nodePath;
437
- }
438
- if (itemType === 'view') {
439
- if (finalAction === 'create') {
440
- // 对于创建操作,需要将 children 数组转换为对象
441
- object.children = [];
442
- }
443
- if (finalAction === 'update') {
444
- if (object.children)
445
- delete object.children;
446
- }
447
- }
448
- // 添加创建或更新操作到批量操作列表
449
- batchActions.actions.push({
450
- action: finalAction,
451
- path: path || handler.path,
452
- object,
782
+ else if (isGlobalVariablesHandler(handler)) {
783
+ // 全局变量类型:一个文件对应多个节点
784
+ processGlobalVariables({
785
+ handler,
786
+ action,
787
+ itemType,
788
+ batchActions,
789
+ errors,
790
+ });
791
+ }
792
+ else if (isViewHandler(handler)) {
793
+ // 视图类型:一个文件对应一个节点,支持嵌套视图
794
+ processSingleNode({
795
+ handler,
796
+ itemName,
797
+ itemType,
798
+ action,
799
+ parentViewNames,
800
+ batchActions,
801
+ errors,
802
+ });
803
+ }
804
+ else if (isSingleNodeHandler(handler)) {
805
+ // 单节点类型:entity, structure, enum, logic
806
+ processSingleNode({
807
+ handler,
808
+ itemName,
809
+ itemType,
810
+ action,
811
+ parentViewNames,
812
+ batchActions,
813
+ errors,
453
814
  });
454
815
  }
455
816
  }
@@ -463,6 +824,10 @@ const transform2BatchActions = ({ codeActions, app, sessionId, type = 'normal',
463
824
  });
464
825
  }
465
826
  }
827
+ // 第五阶段:同步 directories(只处理 appInstance 中已存在的)
828
+ if (appInstance && app) {
829
+ handleAppDirectories(appInstance, app, batchActions, errors);
830
+ }
466
831
  // 第四阶段:错误处理和结果返回
467
832
  // 如果有错误发生,在控制台输出错误信息(但不中断执行)
468
833
  if (errors.length > 0) {
@@ -471,12 +836,12 @@ const transform2BatchActions = ({ codeActions, app, sessionId, type = 'normal',
471
836
  // 构建返回结果,基础结果包含批量操作
472
837
  let result = {
473
838
  batchActions,
839
+ accumulatedTsCode, // 累积的 TypeScript 代码
474
840
  };
475
841
  // 调试模式下返回额外的调试信息
476
842
  if (type === 'debug') {
477
843
  result = {
478
844
  ...result,
479
- accumulatedTsCode, // 累积的 TypeScript 代码
480
845
  parseJSON, // 解析后的 JSON 对象
481
846
  errors, // 错误列表
482
847
  };
@@ -487,6 +852,307 @@ const transform2BatchActions = ({ codeActions, app, sessionId, type = 'normal',
487
852
  return result;
488
853
  };
489
854
  exports.transform2BatchActions = transform2BatchActions;
855
+ /**
856
+ * 构建全局 definition 索引
857
+ * 一次性构建,避免重复遍历
858
+ * @param allDirs - 所有目录数组
859
+ * @returns 全局索引对象
860
+ */
861
+ const buildGlobalDefIndex = (allDirs) => {
862
+ const defMap = new Map();
863
+ const dirDefMap = new Map();
864
+ for (const dir of allDirs) {
865
+ if (!dir?.definitions || !dir.name)
866
+ continue;
867
+ const defKeys = new Set();
868
+ for (const def of dir.definitions) {
869
+ if (!def)
870
+ continue;
871
+ const key = `${def.namespace}:${def.name}`;
872
+ defMap.set(key, {
873
+ def,
874
+ dirName: dir.name,
875
+ dirPath: dir.nodePath,
876
+ });
877
+ defKeys.add(key);
878
+ }
879
+ if (defKeys.size > 0) {
880
+ dirDefMap.set(dir.name, defKeys);
881
+ }
882
+ }
883
+ return { defMap, dirDefMap };
884
+ };
885
+ /**
886
+ * 深度比较两个 definition 是否需要更新
887
+ * 只比较关键属性,避免不必要的序列化
888
+ * @param appDef - app 中的 definition
889
+ * @param instanceDef - appInstance 中的 definition
890
+ * @returns 是否需要更新
891
+ */
892
+ const needsDefinitionUpdate = (appDef, instanceDef) => {
893
+ // 快速检查:引用相等
894
+ if (appDef === instanceDef)
895
+ return false;
896
+ // 关键属性比较
897
+ return (appDef.referredConcept !== instanceDef.referredConcept ||
898
+ appDef.namespace !== instanceDef.namespace ||
899
+ appDef.name !== instanceDef.name);
900
+ };
901
+ /**
902
+ * 同步目录的 definitions
903
+ * 使用 Map 替代数组查找,使用全局索引避免重复遍历
904
+ * @param instanceDir - appInstance 中的目录
905
+ * @param appDir - app 中对应的目录
906
+ * @param globalDefIndex - 全局 definition 索引
907
+ * @param pendingActions - 待添加的批量操作数组
908
+ * @param errors - 错误收集数组
909
+ */
910
+ const syncDirectoryDefinitions = (instanceDir, appDir, globalDefIndex, pendingActions, errors) => {
911
+ try {
912
+ // 快速检查
913
+ if (!instanceDir?.definitions || instanceDir.definitions.length === 0) {
914
+ return;
915
+ }
916
+ // 构建当前目录的 definition Map
917
+ const appDefMap = new Map((appDir?.definitions || []).map((def) => [`${def.namespace}:${def.name}`, def]));
918
+ for (const instanceDef of instanceDir.definitions) {
919
+ if (!instanceDef)
920
+ continue;
921
+ const key = `${instanceDef.namespace}:${instanceDef.name}`;
922
+ const defObject = instanceDef.toJSON();
923
+ // 第一步:在当前目录查找
924
+ const appDefInCurrentDir = appDefMap.get(key);
925
+ if (appDefInCurrentDir) {
926
+ // 在当前目录找到了,检查是否需要更新
927
+ if (needsDefinitionUpdate(appDefInCurrentDir, instanceDef)) {
928
+ // 内容不同,更新(先删除再创建)
929
+ pendingActions.push({
930
+ action: 'delete',
931
+ path: appDefInCurrentDir.nodePath,
932
+ object: null,
933
+ }, {
934
+ action: 'create',
935
+ path: `${appDir.nodePath}.definitions[0]`,
936
+ object: defObject,
937
+ });
938
+ }
939
+ // 内容相同则跳过
940
+ }
941
+ else {
942
+ // 第二步:使用全局索引查找其他目录
943
+ const defInOtherDir = globalDefIndex.defMap.get(key);
944
+ if (defInOtherDir && defInOtherDir.dirName !== appDir.name) {
945
+ // 在其他文件夹找到了 → 文件移动场景
946
+ // 先删除旧位置的引用
947
+ pendingActions.push({
948
+ action: 'delete',
949
+ path: defInOtherDir.def.nodePath,
950
+ object: null,
951
+ });
952
+ }
953
+ // 然后在当前目录创建新引用(无论是移动还是新建)
954
+ pendingActions.push({
955
+ action: 'create',
956
+ path: `${appDir.nodePath}.definitions[0]`,
957
+ object: defObject,
958
+ });
959
+ }
960
+ }
961
+ }
962
+ catch (error) {
963
+ errors.push({
964
+ item: instanceDir?.name || 'unknown',
965
+ type: 'definitionSync',
966
+ error: error,
967
+ level: 4,
968
+ });
969
+ }
970
+ };
971
+ /**
972
+ * 删除新目录中的 definitions 在其他目录中的旧引用
973
+ * 使用全局索引,避免重复构建 Map
974
+ * @param instanceDir - 新目录
975
+ * @param globalDefIndex - 全局 definition 索引
976
+ * @param pendingActions - 待添加的批量操作数组
977
+ */
978
+ const deleteOldDefinitionReferences = (instanceDir, globalDefIndex, pendingActions) => {
979
+ if (!instanceDir?.definitions || instanceDir.definitions.length === 0) {
980
+ return;
981
+ }
982
+ // 直接使用全局索引查找
983
+ for (const instanceDef of instanceDir.definitions) {
984
+ if (!instanceDef)
985
+ continue;
986
+ const key = `${instanceDef.namespace}:${instanceDef.name}`;
987
+ const oldDef = globalDefIndex.defMap.get(key);
988
+ if (oldDef) {
989
+ // 找到了旧引用,删除它
990
+ pendingActions.push({
991
+ action: 'delete',
992
+ path: oldDef.def.nodePath,
993
+ object: null,
994
+ });
995
+ }
996
+ }
997
+ };
998
+ /**
999
+ * 同步单个目录
1000
+ * 通用的目录同步逻辑,适用于所有类型的目录
1001
+ * @param instanceDir - appInstance 中的目录
1002
+ * @param appDir - app 中对应的目录(可能不存在)
1003
+ * @param globalDefIndex - 全局 definition 索引
1004
+ * @param parentPath - 父级路径
1005
+ * @param pendingActions - 待添加的批量操作数组
1006
+ * @param errors - 错误收集数组
1007
+ * @param errorType - 错误类型标识
1008
+ */
1009
+ const syncSingleDirectory = (instanceDir, appDir, globalDefIndex, parentPath, pendingActions, errors, errorType) => {
1010
+ try {
1011
+ if (!appDir) {
1012
+ // 目录不存在,需要创建
1013
+ // 先删除该目录中 definitions 在其他目录的旧引用
1014
+ deleteOldDefinitionReferences(instanceDir, globalDefIndex, pendingActions);
1015
+ // 然后创建完整的新目录
1016
+ const dirObject = instanceDir.toJSON();
1017
+ pendingActions.push({
1018
+ action: 'create',
1019
+ path: parentPath,
1020
+ object: dirObject,
1021
+ });
1022
+ }
1023
+ else {
1024
+ // 目录存在,同步 definitions
1025
+ syncDirectoryDefinitions(instanceDir, appDir, globalDefIndex, pendingActions, errors);
1026
+ }
1027
+ }
1028
+ catch (error) {
1029
+ errors.push({
1030
+ item: instanceDir?.name || 'unknown',
1031
+ type: errorType,
1032
+ error: error,
1033
+ level: 4,
1034
+ });
1035
+ }
1036
+ };
1037
+ /**
1038
+ * 处理 app directories 同步
1039
+ * 处理四种 directories: 'LOGICS', 'ENUMS', 'STRUCTURES' 以及 appInstance.dataSources[0] 的 directories
1040
+ * 比对 directories 及引用 definitions,最小粒度是 definition,唯一标识是 namespace+name
1041
+ * 文件夹只做新增更新,definition 如果在同一领域的文件夹下,需要先删除原引用,再创建新引用
1042
+ *
1043
+ * 性能优化:
1044
+ * 1. 全局 definition 索引缓存 - 避免重复构建
1045
+ * 3. 批量操作收集 - 减少数组扩容
1046
+ * 4. 提前验证和快速退出 - 避免无效处理
1047
+ * 5. 优化的 definition 比较 - 只比较关键属性
1048
+ */
1049
+ const handleAppDirectories = (appInstance, app, batchActions, errors) => {
1050
+ // 性能计时开始
1051
+ const startTime = performance.now();
1052
+ // 1. 边界检查和快速退出
1053
+ if (!appInstance || !app) {
1054
+ errors.push({
1055
+ item: 'handleAppDirectories',
1056
+ type: 'invalidParams',
1057
+ error: new Error('appInstance 或 app 参数无效'),
1058
+ level: 5,
1059
+ });
1060
+ return;
1061
+ }
1062
+ try {
1063
+ // 2. 快速检查是否有需要处理的目录
1064
+ const hasInstanceDirs = appInstance.directories?.some((dir) => ['LOGICS', 'ENUMS', 'STRUCTURES'].includes(dir?.name) && dir.children?.length > 0);
1065
+ const hasDataSourceDirs = appInstance.dataSources?.[0]?.directories?.length > 0;
1066
+ if (!hasInstanceDirs && !hasDataSourceDirs) {
1067
+ console.log('[handleAppDirectories] 无需处理目录同步');
1068
+ return; // 无需处理
1069
+ }
1070
+ // 3. 批量操作收集器(减少数组扩容)
1071
+ const pendingActions = [];
1072
+ // 4. 处理根目录类型 (LOGICS, ENUMS, STRUCTURES)
1073
+ const rootDirectoryTypes = ['LOGICS', 'ENUMS', 'STRUCTURES'];
1074
+ for (const rootType of rootDirectoryTypes) {
1075
+ try {
1076
+ const instanceRootDir = appInstance.directories?.find((dir) => dir?.name === rootType);
1077
+ if (!instanceRootDir?.children?.length) {
1078
+ continue;
1079
+ }
1080
+ let appRootDir = app.directories?.find((dir) => dir?.name === rootType);
1081
+ if (!appRootDir) {
1082
+ // 根目录不存在,直接创建
1083
+ pendingActions.push({
1084
+ action: 'create',
1085
+ path: 'app.directories[0]',
1086
+ object: instanceRootDir.toJSON(),
1087
+ });
1088
+ continue;
1089
+ }
1090
+ // 5. 构建子目录 Map(O(1) 查找,替代数组遍历)
1091
+ const allAppChildDirs = appRootDir.children || [];
1092
+ const appChildDirMap = new Map(allAppChildDirs.filter((dir) => dir?.name).map((dir) => [dir.name, dir]));
1093
+ // 6. 构建全局 definition 索引(一次性构建)
1094
+ const globalDefIndex = buildGlobalDefIndex(allAppChildDirs);
1095
+ // 7. 遍历子目录
1096
+ for (const instanceChildDir of instanceRootDir.children) {
1097
+ if (!instanceChildDir?.name)
1098
+ continue;
1099
+ const appChildDir = appChildDirMap.get(instanceChildDir.name);
1100
+ syncSingleDirectory(instanceChildDir, appChildDir, globalDefIndex, `${appRootDir.nodePath}.children[0]`, pendingActions, errors, 'directorySync');
1101
+ }
1102
+ }
1103
+ catch (error) {
1104
+ errors.push({
1105
+ item: rootType,
1106
+ type: 'rootDirectorySync',
1107
+ error: error,
1108
+ level: 4,
1109
+ });
1110
+ }
1111
+ }
1112
+ // 8. 处理数据源 (Entity) directories
1113
+ if (appInstance.dataSources?.[0]?.directories && app.dataSources?.[0]) {
1114
+ try {
1115
+ const instanceDataSource = appInstance.dataSources[0];
1116
+ const appDataSource = app.dataSources[0];
1117
+ const allAppEntityDirs = appDataSource.directories || [];
1118
+ // 构建目录 Map(O(1) 查找)
1119
+ const entityDirMap = new Map(allAppEntityDirs.filter((dir) => dir?.name).map((dir) => [dir.name, dir]));
1120
+ // 构建全局 definition 索引
1121
+ const globalDefIndex = buildGlobalDefIndex(allAppEntityDirs);
1122
+ for (const instanceDir of instanceDataSource.directories) {
1123
+ if (!instanceDir?.name)
1124
+ continue;
1125
+ const appDir = entityDirMap.get(instanceDir.name);
1126
+ syncSingleDirectory(instanceDir, appDir, globalDefIndex, `${appDataSource.nodePath}.directories[0]`, pendingActions, errors, 'entityDirectorySync');
1127
+ }
1128
+ }
1129
+ catch (error) {
1130
+ errors.push({
1131
+ item: 'dataSources',
1132
+ type: 'dataSourceDirectorySync',
1133
+ error: error,
1134
+ level: 4,
1135
+ });
1136
+ }
1137
+ }
1138
+ // 9. 批量添加所有操作(一次性 push,减少数组扩容)
1139
+ if (pendingActions.length > 0) {
1140
+ batchActions.actions.push(...pendingActions);
1141
+ console.log(`[handleAppDirectories] 生成 ${pendingActions.length} 个批量操作`);
1142
+ }
1143
+ // 性能计时结束
1144
+ const endTime = performance.now();
1145
+ console.log(`[handleAppDirectories] 执行时间: ${(endTime - startTime).toFixed(2)}ms`);
1146
+ }
1147
+ catch (error) {
1148
+ errors.push({
1149
+ item: 'handleAppDirectories',
1150
+ type: 'directorySync',
1151
+ error: error,
1152
+ level: 4,
1153
+ });
1154
+ }
1155
+ };
490
1156
  /**
491
1157
  * 辅助函数:从路径项中提取索引
492
1158
  * @param pathItem - 路径项,如 'entities[0]'
@@ -556,12 +1222,12 @@ const applyBatchActions = (app, batchActions) => {
556
1222
  }
557
1223
  }
558
1224
  app.emit('collect:end');
559
- return new Promise((resolve, reject) => {
560
- app.on('save-nasl-success', resolve);
561
- app.on('save-nasl-error', (error) => {
562
- reject(error);
563
- });
564
- });
1225
+ // return new Promise((resolve, reject) => {
1226
+ // app.on('save-nasl-success', resolve);
1227
+ // app.on('save-nasl-error', (error: any) => {
1228
+ // reject(error);
1229
+ // });
1230
+ // });
565
1231
  };
566
1232
  exports.applyBatchActions = applyBatchActions;
567
1233
  //# sourceMappingURL=transform2BatchActions.js.map