@lcap/nasl-language-server-core 4.4.0-beta.3 → 4.4.0-beta.31

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 (142) hide show
  1. package/out/checker.d.ts +4 -1
  2. package/out/checker.d.ts.map +1 -1
  3. package/out/checker.js +996 -96
  4. package/out/checker.js.map +1 -1
  5. package/out/index.d.ts +1 -1
  6. package/out/index.d.ts.map +1 -1
  7. package/out/index.js +5 -3
  8. package/out/index.js.map +1 -1
  9. package/out/reference-manager/build-q-name-def.d.ts.map +1 -1
  10. package/out/reference-manager/build-q-name-def.js +11 -0
  11. package/out/reference-manager/build-q-name-def.js.map +1 -1
  12. package/out/reference-manager/builtin-q-name.js +2 -2
  13. package/out/reference-manager/builtin-q-name.js.map +1 -1
  14. package/out/reference-manager/collect-q-name.d.ts +1 -1
  15. package/out/reference-manager/collect-q-name.d.ts.map +1 -1
  16. package/out/reference-manager/collect-q-name.js +64 -27
  17. package/out/reference-manager/collect-q-name.js.map +1 -1
  18. package/out/reference-manager/def-key-helpers.d.ts +38 -0
  19. package/out/reference-manager/def-key-helpers.d.ts.map +1 -0
  20. package/out/reference-manager/{get-q-name.js → def-key-helpers.js} +195 -23
  21. package/out/reference-manager/def-key-helpers.js.map +1 -0
  22. package/out/reference-manager/helper.js +2 -2
  23. package/out/reference-manager/helper.js.map +1 -1
  24. package/out/reference-manager/reference-manager.d.ts +146 -47
  25. package/out/reference-manager/reference-manager.d.ts.map +1 -1
  26. package/out/reference-manager/reference-manager.js +632 -204
  27. package/out/reference-manager/reference-manager.js.map +1 -1
  28. package/out/reference-manager/remove-q-name.d.ts +1 -1
  29. package/out/reference-manager/remove-q-name.d.ts.map +1 -1
  30. package/out/reference-manager/remove-q-name.js +14 -14
  31. package/out/reference-manager/remove-q-name.js.map +1 -1
  32. package/out/reference-manager/rename-q-name.d.ts +26 -26
  33. package/out/reference-manager/rename-q-name.d.ts.map +1 -1
  34. package/out/reference-manager/rename-q-name.js +48 -167
  35. package/out/reference-manager/rename-q-name.js.map +1 -1
  36. package/out/reference-manager/symbol-type.d.ts +8 -3
  37. package/out/reference-manager/symbol-type.d.ts.map +1 -1
  38. package/out/reference-manager/symbol-type.js +9 -2
  39. package/out/reference-manager/symbol-type.js.map +1 -1
  40. package/out/reference-manager/update-nasl-fragment.d.ts +2 -2
  41. package/out/reference-manager/update-nasl-fragment.d.ts.map +1 -1
  42. package/out/reference-manager/update-nasl-fragment.js +33 -28
  43. package/out/reference-manager/update-nasl-fragment.js.map +1 -1
  44. package/out/services/bindable-logic-service.js.map +1 -1
  45. package/out/symbol/traverse/concepts/index.d.ts +1 -1
  46. package/out/symbol/traverse/concepts/index.d.ts.map +1 -1
  47. package/out/symbol/traverse/concepts/logic/expression/member-expression.js.map +1 -1
  48. package/out/typer/collectGlobalDefs.d.ts +8 -0
  49. package/out/typer/collectGlobalDefs.d.ts.map +1 -1
  50. package/out/typer/collectGlobalDefs.js +102 -54
  51. package/out/typer/collectGlobalDefs.js.map +1 -1
  52. package/out/typer/component-def-manager/component-def-manager.d.ts +16 -0
  53. package/out/typer/component-def-manager/component-def-manager.d.ts.map +1 -1
  54. package/out/typer/component-def-manager/component-def-manager.js +63 -2
  55. package/out/typer/component-def-manager/component-def-manager.js.map +1 -1
  56. package/out/typer/component-def-manager/utils.d.ts.map +1 -1
  57. package/out/typer/component-def-manager/utils.js +26 -0
  58. package/out/typer/component-def-manager/utils.js.map +1 -1
  59. package/out/typer/dispatch-all.d.ts +3 -1
  60. package/out/typer/dispatch-all.d.ts.map +1 -1
  61. package/out/typer/dispatch-all.js +51 -6
  62. package/out/typer/dispatch-all.js.map +1 -1
  63. package/out/typer/dispatch-call.d.ts +27 -1
  64. package/out/typer/dispatch-call.d.ts.map +1 -1
  65. package/out/typer/dispatch-call.js +151 -107
  66. package/out/typer/dispatch-call.js.map +1 -1
  67. package/out/typer/dispatch-def.d.ts.map +1 -1
  68. package/out/typer/dispatch-def.js +51 -23
  69. package/out/typer/dispatch-def.js.map +1 -1
  70. package/out/typer/dispatch-expr.d.ts +2 -1
  71. package/out/typer/dispatch-expr.d.ts.map +1 -1
  72. package/out/typer/dispatch-expr.js +240 -199
  73. package/out/typer/dispatch-expr.js.map +1 -1
  74. package/out/typer/dispatch-process.d.ts +8 -1
  75. package/out/typer/dispatch-process.d.ts.map +1 -1
  76. package/out/typer/dispatch-process.js +37 -4
  77. package/out/typer/dispatch-process.js.map +1 -1
  78. package/out/typer/dispatch-stmt.d.ts.map +1 -1
  79. package/out/typer/dispatch-stmt.js +39 -25
  80. package/out/typer/dispatch-stmt.js.map +1 -1
  81. package/out/typer/dispatch-view.d.ts +1 -1
  82. package/out/typer/dispatch-view.d.ts.map +1 -1
  83. package/out/typer/dispatch-view.js +87 -48
  84. package/out/typer/dispatch-view.js.map +1 -1
  85. package/out/typer/fix-use-before-assign.js.map +1 -1
  86. package/out/typer/get-oql-files.d.ts.map +1 -1
  87. package/out/typer/get-oql-files.js +3 -9
  88. package/out/typer/get-oql-files.js.map +1 -1
  89. package/out/typer/incremental-update.d.ts +14 -7
  90. package/out/typer/incremental-update.d.ts.map +1 -1
  91. package/out/typer/incremental-update.js +396 -43
  92. package/out/typer/incremental-update.js.map +1 -1
  93. package/out/typer/oql-checker/chain-call-transformer.d.ts.map +1 -1
  94. package/out/typer/oql-checker/chain-call-transformer.js +17 -4
  95. package/out/typer/oql-checker/chain-call-transformer.js.map +1 -1
  96. package/out/typer/oql-checker/ts-parser.d.ts.map +1 -1
  97. package/out/typer/oql-checker/ts-parser.js +252 -37
  98. package/out/typer/oql-checker/ts-parser.js.map +1 -1
  99. package/out/typer/overload-helper.d.ts.map +1 -1
  100. package/out/typer/overload-helper.js +190 -23
  101. package/out/typer/overload-helper.js.map +1 -1
  102. package/out/typer/solver.d.ts +8 -9
  103. package/out/typer/solver.d.ts.map +1 -1
  104. package/out/typer/solver.js +54 -31
  105. package/out/typer/solver.js.map +1 -1
  106. package/out/typer/subster.d.ts +1 -1
  107. package/out/typer/subster.d.ts.map +1 -1
  108. package/out/typer/subster.js +251 -57
  109. package/out/typer/subster.js.map +1 -1
  110. package/out/typer/topo-sort.d.ts +38 -0
  111. package/out/typer/topo-sort.d.ts.map +1 -1
  112. package/out/typer/topo-sort.js +272 -3
  113. package/out/typer/topo-sort.js.map +1 -1
  114. package/out/typer/type-manager.d.ts +1 -0
  115. package/out/typer/type-manager.d.ts.map +1 -1
  116. package/out/typer/type-manager.js +14 -11
  117. package/out/typer/type-manager.js.map +1 -1
  118. package/out/typer/type-predicate.d.ts +1 -0
  119. package/out/typer/type-predicate.d.ts.map +1 -1
  120. package/out/typer/type-predicate.js +83 -14
  121. package/out/typer/type-predicate.js.map +1 -1
  122. package/out/typer/typer.d.ts +51 -6
  123. package/out/typer/typer.d.ts.map +1 -1
  124. package/out/typer/typer.js +248 -46
  125. package/out/typer/typer.js.map +1 -1
  126. package/out/typer/unifier.d.ts +12 -1
  127. package/out/typer/unifier.d.ts.map +1 -1
  128. package/out/typer/unifier.js +110 -37
  129. package/out/typer/unifier.js.map +1 -1
  130. package/out/utils/debug.js.map +1 -1
  131. package/out/utils/type-operator.d.ts +15 -0
  132. package/out/utils/type-operator.d.ts.map +1 -1
  133. package/out/utils/type-operator.js +65 -3
  134. package/out/utils/type-operator.js.map +1 -1
  135. package/package.json +5 -5
  136. package/out/reference-manager/get-q-name.d.ts +0 -9
  137. package/out/reference-manager/get-q-name.d.ts.map +0 -1
  138. package/out/reference-manager/get-q-name.js.map +0 -1
  139. package/out/reference-manager/view-elem-logic.d.ts +0 -44
  140. package/out/reference-manager/view-elem-logic.d.ts.map +0 -1
  141. package/out/reference-manager/view-elem-logic.js +0 -164
  142. package/out/reference-manager/view-elem-logic.js.map +0 -1
@@ -7,7 +7,7 @@ const fp_macros_1 = require("../utils/fp-macros");
7
7
  const console_1 = require("console");
8
8
  const builtin_q_name_1 = require("./builtin-q-name");
9
9
  const build_q_name_def_1 = require("./build-q-name-def");
10
- const get_q_name_1 = require("./get-q-name");
10
+ const def_key_helpers_1 = require("./def-key-helpers");
11
11
  const typer_1 = require("../typer");
12
12
  const type_predicate_1 = require("../typer/type-predicate");
13
13
  const helper_1 = require("../typer/helper");
@@ -21,7 +21,6 @@ const type_manager_1 = require("../typer/type-manager");
21
21
  const oql_1 = require("../utils/oql");
22
22
  const string_2 = require("../utils/string");
23
23
  const traverse_util_1 = require("../utils/traverse-util");
24
- const view_elem_logic_1 = require("./view-elem-logic");
25
24
  const helper_2 = require("./helper");
26
25
  const misc_1 = require("../utils/misc");
27
26
  const asserts_1 = require("@lcap/nasl-concepts/asserts");
@@ -46,7 +45,7 @@ class ReferenceManager {
46
45
  static { this.defConcept = symbol_type_1.defConcept; } /** imported */
47
46
  static { this.compositeNodeConcept = symbol_type_1.compositeNodeConcept; } /** imported */
48
47
  static { this.connectionNsp = 'app.connections'; }
49
- // gQNameDefs 和 symbolRefs 的构建时机不一样,所以不放在构造器中
48
+ // gQNameDefs 和 globalRefs 的构建时机不一样,所以不放在构造器中
50
49
  constructor() {
51
50
  // qualified names to definition memory address for GLOBAL DEFINITIONS
52
51
  this.gQNameDefs = new Map();
@@ -65,33 +64,26 @@ class ReferenceManager {
65
64
  *
66
65
  * 将实体看成 namespace,所有引用实体逻辑的地方也算引用了实体?
67
66
  */
68
- this.gSymbolRefs = new Map; // 手动管理,小心内存泄漏
69
- // Accessor methods for symbolRefs to normalize input later
67
+ this.globalRefs = new Map; // 手动管理,小心内存泄漏
68
+ // Accessor methods for globalRefs to normalize input later
70
69
  this.getSymbolRefs = (__def) => {
71
70
  const def = this.normaliseEntityLogic(__def);
72
- return this.gSymbolRefs.get(def);
71
+ return this.globalRefs.get(def);
73
72
  };
74
73
  this.setSymbolRefs = (__def, refs) => {
75
74
  const def = this.normaliseEntityLogic(__def);
76
- this.gSymbolRefs.set(def, refs);
75
+ this.globalRefs.set(def, refs);
77
76
  };
78
77
  this.deleteSymbolRefs = (__def) => {
79
78
  const def = this.normaliseEntityLogic(__def);
80
- return this.gSymbolRefs.delete(def);
79
+ return this.globalRefs.delete(def);
81
80
  };
82
- this.clearSymbolRefs = () => {
83
- this.gSymbolRefs.clear();
81
+ this.clearGlobalRefs = () => {
82
+ this.globalRefs.clear();
84
83
  };
85
- this.getSymbolRefsSize = () => {
86
- return this.gSymbolRefs.size;
84
+ this.getGlobalRefsSize = () => {
85
+ return this.globalRefs.size;
87
86
  };
88
- // 辅助 map
89
- this.veQNameDefs = new Map();
90
- /**
91
- * @warning ViewElement 和 Logic 都是局部符号,可以重名,qName 重复时会出错,不要搞这种例子谢谢
92
- * key 是 memory addr 而不是 string 的原因:点查找引用时,不好高效获取 qName(如 Logic 没有 namespace 但调用处其实有,对的就是 elements.)
93
- */
94
- this.veRefs = new Map();
95
87
  // 当前的 collectRefs 是增加还是删除引用。先这样吧,没时间重构了……
96
88
  this.modeForCollect = null;
97
89
  /**
@@ -115,14 +107,26 @@ class ReferenceManager {
115
107
  // 暂无"局部类型",所以简化处理:
116
108
  return this.gSymbolImplicitRefs.get(nd) ?? emptySet;
117
109
  };
118
- // 删除一个 def 时,缓存其 qName 到引用符号的关系,为了方便之后还能 relink 恢复
119
- this.gCachedQNameSymbolRefs = new Map();
110
+ /**
111
+ * 待恢复引用缓存:删除节点时保存引用,创建同名节点时恢复引用后立即删除
112
+ * key: qName, value: Set<PendingRefInfo>
113
+ * 只在删除和创建之间临时使用,使用后立即清除,避免内存泄漏
114
+ *
115
+ * 使用场景:
116
+ * 1. 删除节点时:通过 cacheRefsForRecreation 保存引用节点
117
+ * 2. 创建同名节点时:通过 restoreRefsFromCache 恢复引用并清除缓存
118
+ *
119
+ * 设计说明:
120
+ * - 只存储引用节点本身
121
+ * - 恢复时会检查引用节点是否仍在 app 树上且仍引用原来的 qName
122
+ */
123
+ this.pendingRefsForRecreation = new Map();
120
124
  this.compDefMgr = new component_def_manager_1.ComponentDefManager();
121
125
  // 上一次查找引用局部符号建立的 cache
122
126
  this.lastBoundary = undefined;
123
127
  this.isLocalCacheValid = true;
124
- /** local qName refs 局部符号的引用 */
125
- this.lQNameRefs = new Map();
128
+ /** 局部符号的引用,key getLocalDefKey 返回值(作用域内简单名或完整路径) */
129
+ this.localRefs = new Map();
126
130
  // 当前文件节点
127
131
  this.curFileNode = undefined;
128
132
  /**
@@ -146,14 +150,26 @@ class ReferenceManager {
146
150
  /**
147
151
  * Remove all recorded local scope variable bindings under a file node.
148
152
  * Used by incremental type checking to invalidate stale scope allocations.
153
+ * @param options.skipDescendantFileNodes 为 true 时遇到子级「文件节点」则不再向下遍历,避免误清子 View 等,增量阶段 2 重算前用此选项
154
+ * @param options.isFileNode 与 skipDescendantFileNodes 搭配使用,用于判断某节点是否为文件节点(如 checkNodeIsFileModuleInIdeWithCache)
149
155
  */
150
- this.clearLocalSymBindingsForFile = (file) => {
156
+ this.clearLocalSymBindingsForFile = (file, options) => {
151
157
  if (!file)
152
158
  return;
153
- file.traverseStrictChildren((nd) => {
154
- this.localSymBindings.delete(nd);
155
- });
156
- // also clear the file node itself
159
+ const { skipDescendantFileNodes, isFileNode } = options ?? {};
160
+ if (skipDescendantFileNodes && isFileNode) {
161
+ file.traverseStrictChildrenWithPruning?.((nd) => {
162
+ const prune = nd !== file && isFileNode(nd);
163
+ if (!prune)
164
+ this.localSymBindings.delete(nd);
165
+ return prune;
166
+ });
167
+ }
168
+ else {
169
+ file.traverseStrictChildren((nd) => {
170
+ this.localSymBindings.delete(nd);
171
+ });
172
+ }
157
173
  this.localSymBindings.delete(file);
158
174
  };
159
175
  this.clearAllLocalSymBindings = () => {
@@ -167,7 +183,7 @@ class ReferenceManager {
167
183
  * declaration for each variable name is returned (nearest-first ordering).
168
184
  *
169
185
  * Implementation notes:
170
- * - We intentionally DO NOT depend on the (ephemeral) lexicalVarStacks in SemEnv so
186
+ * - We intentionally DO NOT depend on the (ephemeral) localDefStacks in SemEnv so
171
187
  * this works post-typing (e.g. in reference / rename / hover providers) without
172
188
  * re-running the typer.
173
189
  * - Order:
@@ -194,20 +210,21 @@ class ReferenceManager {
194
210
  const localSyms = this.getVisibleLocalSyms(node, options);
195
211
  const localVars = localSyms.filter(service_1.isLocalVar);
196
212
  const collected = Array.from(localVars);
197
- const seen = new Set(localSyms.map(v => (0, get_q_name_1.getTokenQualifiedName)(v)));
213
+ // 用于 shadowing 去重,需用 getLocalDefKey 与引用时的 key 一致
214
+ const seen = new Set(localSyms.map(v => (0, def_key_helpers_1.getLocalDefKey)(v) ?? (0, def_key_helpers_1.getGlobalDefKey)(v)));
198
215
  const seenNames = new Set(localVars.map(v => v?.name).filter(Boolean));
199
216
  // View-specific: stitch in process variables allocated during typing
200
217
  this.stitchProcessVarsForView(node, env, includeShadowed, predicate, collected, seenNames);
201
218
  this.stitchValidationVarsForView(node, env, includeShadowed, predicate, collected, seenNames);
202
219
  const feVars = getNearestFrontendVars(node);
203
220
  for (const v of feVars) {
204
- const vQName = (0, get_q_name_1.getTokenQualifiedName)(v);
205
- if (!vQName)
221
+ const vKey = (0, def_key_helpers_1.getLocalDefKey)(v) ?? (0, def_key_helpers_1.getGlobalDefKey)(v);
222
+ if (!vKey)
206
223
  continue;
207
224
  if (!includeShadowed) {
208
- if (seen.has(vQName))
225
+ if (seen.has(vKey))
209
226
  continue;
210
- seen.add(vQName);
227
+ seen.add(vKey);
211
228
  }
212
229
  if (predicate && !predicate(v))
213
230
  continue;
@@ -266,7 +283,7 @@ class ReferenceManager {
266
283
  const vars = this.localSymBindings.get(cur);
267
284
  if (vars && vars.length > 0) {
268
285
  for (const v of vars) {
269
- const vQName = (0, get_q_name_1.getTokenQualifiedName)(v);
286
+ const vQName = (0, def_key_helpers_1.getGlobalDefKey)(v);
270
287
  if (!vQName)
271
288
  continue;
272
289
  if (!includeShadowed) {
@@ -332,8 +349,10 @@ class ReferenceManager {
332
349
  for (const triggerLauncher of app.triggerLaunchers) {
333
350
  allRefs.push(...this.collectRefs(env, triggerLauncher));
334
351
  }
335
- for (const metadataType of app.metadataTypes) {
336
- allRefs.push(...this.collectRefs(env, metadataType));
352
+ if (String(app?.preferenceMap?.metadataTypeEnable) === 'true') {
353
+ for (const metadataType of app.metadataTypes) {
354
+ allRefs.push(...this.collectRefs(env, metadataType));
355
+ }
337
356
  }
338
357
  // for (const preference of app.preferenceMap) {
339
358
  // allRefs.push(...this.collectRefs(env, preference as any as ValidExtInp));
@@ -347,13 +366,13 @@ class ReferenceManager {
347
366
  const def = this.gQNameDefs.get(qName);
348
367
  if (def) {
349
368
  // Add reference to existing definition
350
- (0, helper_1.createSetOnPush)(this.gSymbolRefs, def, ref);
369
+ (0, helper_1.createSetOnPush)(this.globalRefs, def, ref);
351
370
  }
352
371
  else {
353
372
  // Cache reference for future relinking
354
373
  // FIXME:这里有问题,脏脏的,比如局部变量、入参等都扔到这里面了,虽然暂时可能没有太大的正确性问题,但有内存泄漏
355
374
  if (!(0, helper_2.cheapTestLocalSymbol)(qName)) {
356
- (0, helper_1.createSetOnPush)(this.gCachedQNameSymbolRefs, qName, ref);
375
+ this.addRefToPendingCache(qName, ref);
357
376
  }
358
377
  }
359
378
  });
@@ -385,10 +404,6 @@ class ReferenceManager {
385
404
  this.modeForCollect = null;
386
405
  };
387
406
  this.addQNameDefs = (0, build_q_name_def_1.mkAddQNameDefs)(this.gQNameDefs, this.compDefMgr);
388
- /** 注释见具体实现 */
389
- this.addViewElementLogicQNameDefs = (0, view_elem_logic_1.mkAddViewElementLogicQNameDefs)(this.veQNameDefs, this.gQNameDefs);
390
- /** 注释见具体实现 */
391
- this.addViewElementLogicRefs = (0, view_elem_logic_1.mkAddViewElementBindLogicRefs)(this.veQNameDefs, this.veRefs);
392
407
  this.queryQNameDef = (qName) => {
393
408
  const res = this.gQNameDefs.get(qName);
394
409
  if (!res) {
@@ -448,12 +463,10 @@ class ReferenceManager {
448
463
  }
449
464
  };
450
465
  /**
451
- * 重要对外接口,查找符号的定义
452
- * @param ref
453
- * @returns
466
+ * 查找符号的定义(含全局符号、View/BC 内 logics 等,均已在 gQNameDefs 中注册)
454
467
  */
455
468
  this.getNodeDef = (ref) => {
456
- const qName = (0, get_q_name_1.getTokenQualifiedName)(ref);
469
+ const qName = (0, def_key_helpers_1.getGlobalDefKey)(ref);
457
470
  return qName ? this.gQNameDefs.get(qName) : undefined;
458
471
  };
459
472
  /**
@@ -464,9 +477,25 @@ class ReferenceManager {
464
477
  this.getReferences = (env, __nd) => {
465
478
  let nd = this.normaliseEntityLogic((0, misc_1.toRaw)(__nd));
466
479
  let res = new Set();
480
+ // 逻辑/页面参数:外部引用在 globalRefs(CallLogic 实参),内部引用在 localRefs(Logic 体内同名标识符)
481
+ if (nd.concept === 'Param' || nd.concept === 'ParamWithGroup') {
482
+ const paramQName = (0, def_key_helpers_1.getGlobalDefKey)(nd);
483
+ const isParamOfLogicOrView = (0, symbol_type_1.isLogicViewLike)(nd.parentNode);
484
+ const def = isParamOfLogicOrView && paramQName ? this.gQNameDefs.get(paramQName) : undefined;
485
+ const externalRefs = def ? this.getSymbolRefs(def) ?? new Set() : new Set();
486
+ const boundary = (0, helper_2.getBoundary)(nd);
487
+ if (boundary && (this.lastBoundary !== boundary || !this.isLocalCacheValid)) {
488
+ this.localRefs.clear();
489
+ this.timeAndLog('Get reference: collect local refs for Param', this.buildLocalRefs, env, nd);
490
+ }
491
+ const localKey = (0, def_key_helpers_1.getLocalDefKey)(nd) ?? nd.name;
492
+ const internalRefs = (localKey && this.localRefs.get(localKey)) ?? new Set();
493
+ res = mnemonist_1.set.union(externalRefs, internalRefs);
494
+ return Array.from(res);
495
+ }
467
496
  // 比如 OverriddenLogic 和对应的 Logic 名字一样,但引用挂在 Logic 上
468
497
  // 比如 实体对应的实体逻辑可能有多份内存地址,归结到现存的一份上
469
- // nd = this.gQNameDefs.get(getTokenQualifiedName(nd)!)!;
498
+ // nd = this.gQNameDefs.get(getGlobalDefKey(nd)!)!;
470
499
  // ==> 好像也不行,很多依赖库逻辑调用又挂了
471
500
  const boundary = (0, helper_2.getBoundary)(nd);
472
501
  // 全局符号直接查找
@@ -477,7 +506,7 @@ class ReferenceManager {
477
506
  if (pConn && boundary) {
478
507
  // 那么它也就是个连接器下的局部符号
479
508
  const qNameRefs = this.collectRefs(env, boundary); // 注意,从 boundary 开始就行,不是从 connector 开始
480
- const ndQName = (0, get_q_name_1.getTokenQualifiedName)(nd);
509
+ const ndQName = (0, def_key_helpers_1.getGlobalDefKey)(nd);
481
510
  for (const [ref, qName] of qNameRefs) {
482
511
  qName === ndQName && res.add(ref);
483
512
  }
@@ -488,27 +517,28 @@ class ReferenceManager {
488
517
  // 局部符号需要即时获取
489
518
  // 从缓存中获取
490
519
  if (this.lastBoundary === boundary && this.isLocalCacheValid) {
491
- res = this.lQNameRefs.get((0, get_q_name_1.getTokenQualifiedName)(nd)) ?? new Set();
492
- // 此处的 Logic 必然不是全局逻辑
493
- // @ts-expect-error 目前的 AST 设计,ViewElement 既是引用又是定义
494
- if (nd.concept === 'ViewElement' || nd.concept === 'Logic' || nd.concept === 'BusinessLogic') {
495
- res = mnemonist_1.set.union(res, this.getViewElementRefs(nd));
520
+ const localKey = (0, def_key_helpers_1.getLocalDefKey)(nd) ?? (0, def_key_helpers_1.getGlobalDefKey)(nd);
521
+ const lRefs = localKey ? (this.localRefs.get(localKey) ?? new Set()) : new Set();
522
+ const gRefs = this.getSymbolRefs(nd) ?? new Set();
523
+ if (nd.concept === 'ViewElement' || nd.concept === 'Logic' || nd.concept === 'BusinessLogic' || nd.concept === 'Event') {
524
+ res = mnemonist_1.set.union(lRefs, gRefs);
525
+ }
526
+ else {
527
+ res = lRefs;
496
528
  }
497
529
  }
498
530
  else {
499
531
  // 局部扫描,建立所有局部引用
500
- this.lQNameRefs.clear();
501
- this.veQNameDefs.clear();
502
- this.veRefs.clear();
503
- this.timeAndLog('Get reference: collect local refs', this.buildMinimalLocalQNameRefs, env, nd);
504
- res = mnemonist_1.set.union(res, this.lQNameRefs.get((0, get_q_name_1.getTokenQualifiedName)(nd)) ?? new Set());
505
- // @ts-expect-error 同上,并且虽然 BindEvent 本身没引用但是要触发对 view 建立引用
506
- if (nd.concept === 'ViewElement' || nd.concept === 'Logic' || nd.concept === 'BusinessLogic' || nd.concept === 'BindEvent') {
532
+ this.localRefs.clear();
533
+ this.timeAndLog('Get reference: collect local refs', this.buildLocalRefs, env, nd);
534
+ const localKey = (0, def_key_helpers_1.getLocalDefKey)(nd) ?? (0, def_key_helpers_1.getGlobalDefKey)(nd);
535
+ res = mnemonist_1.set.union(res, (localKey ? (this.localRefs.get(localKey) ?? new Set()) : new Set()));
536
+ if (nd.concept === 'ViewElement' || nd.concept === 'Logic' || nd.concept === 'BusinessLogic' || nd.concept === 'BindEvent' || nd.concept === 'Event') {
507
537
  const ctxViewLike = (0, misc_1.toRaw)((0, nasl_concepts_1.getCtxViewLike)(nd));
508
- this.timeAndLog('Get reference: build view element logic qName defs cache', this.addViewElementLogicQNameDefs, ctxViewLike);
509
- this.timeAndLog('Get reference: build view element refs cache', this.addViewElementLogicRefs, ctxViewLike);
510
- // @ts-expect-error get 出来一个 undefined 无所谓
511
- res = mnemonist_1.set.union(res ?? new Set(), this.getViewElementRefs(nd));
538
+ if (ctxViewLike) {
539
+ this.timeAndLog('Get reference: build view element refs cache', this.buildLocalRefs, env, ctxViewLike);
540
+ }
541
+ res = mnemonist_1.set.union(res ?? new Set(), this.getSymbolRefs(nd) ?? new Set());
512
542
  }
513
543
  }
514
544
  }
@@ -518,25 +548,24 @@ class ReferenceManager {
518
548
  * 业务逻辑在页面调用的时候,名字前缀是随着业务组件实例名字而变化的,几乎是全应用查找……
519
549
  */
520
550
  if (nd.concept === 'BusinessLogic') {
521
- // 上面已经找到了业务组件内部对业务组件逻辑的内用
551
+ // 上面已经找到了业务组件内部对业务组件逻辑的引用(localRefs)
522
552
  // 现在再找出所有 业务组件逻辑 所属的业务组件的外部引用
553
+ // buildLocalRefs 会把页面中 elements.bs-xxx.logics.myLogic 的调用写入 globalRefs(BusinessLogic)
523
554
  const bs = (0, misc_1.toRaw)((0, nasl_concepts_1.getCtxViewLike)(nd));
524
555
  if (bs?.concept === 'BusinessComponent') {
525
556
  const bsRefs = this.getSymbolRefs(bs) ?? new Set();
526
- let bsRefsRefs = new Array(); // 业务组件(在页面的引用)的引用
527
557
  /**
528
- * 再对每个实例找到所有引用
558
+ * 对每个 BC 实例所在的页面扫描,buildLocalRefs 会把外部引用写入 globalRefs(nd)
529
559
  * @warning 造孽,引用业务组件的每个 view 都要扫描一遍,应该很慢
530
560
  */
531
561
  const startTime = Date.now();
532
562
  for (const bsInst of bsRefs) {
533
563
  const ctxViewLike = (0, misc_1.toRaw)((0, nasl_concepts_1.getCtxViewLike)(bsInst));
534
- this.addViewElementLogicQNameDefs(ctxViewLike);
535
- this.addViewElementLogicRefs(ctxViewLike);
536
- bsRefsRefs.push(...this.getViewElementRefs(bsInst));
564
+ if (ctxViewLike)
565
+ this.buildLocalRefs(env, ctxViewLike);
537
566
  }
538
- // 再从引用中过滤出找到当前业务逻辑的调用
539
- res = mnemonist_1.set.union(res, new Set(bsRefsRefs.filter(r => r.concept === 'CallLogic' && r.calleeName === nd.name))); // amazing!
567
+ // 外部引用已写入 globalRefs(BusinessLogic),直接取
568
+ res = mnemonist_1.set.union(res, this.getSymbolRefs(nd) ?? new Set());
540
569
  const endTime = Date.now();
541
570
  if (endTime - startTime > 200) {
542
571
  console.log(`Get reference: complex business logic took ${endTime - startTime}ms`);
@@ -549,7 +578,7 @@ class ReferenceManager {
549
578
  const allLogics = [...conn.logics, ...conn.namespaces.flatMap(nsp => nsp.logics)];
550
579
  for (const l of allLogics) {
551
580
  // ConnectorLogic,发布态的连接器里外都有调用,真是里外不是人啊。
552
- res = mnemonist_1.set.union(res, this.gSymbolRefs.get(l) ?? new Set());
581
+ res = mnemonist_1.set.union(res, this.globalRefs.get(l) ?? new Set());
553
582
  }
554
583
  }
555
584
  // 加上所有实体逻辑调用的引用(实体逻辑可看做无定义,但要修改调用处的 namespace:实体名是 namespace 的一部分)
@@ -570,17 +599,15 @@ class ReferenceManager {
570
599
  };
571
600
  /**
572
601
  * 给类似 FileNode 级别的定义建立局部引用记录
573
- * @warning 不包括 ViewElement、BindEvent 相关的引用,那个在 @link addViewElementLogicRefs
602
+ * @warning 不包括 ViewElement、BindEvent 相关的引用,已合并到 getLocalDefKeys 与 collectedRefs 处理
574
603
  * @warning 需要包括 SubLogics
575
604
  */
576
- this.buildMinimalLocalQNameRefs = (env, __nd) => {
605
+ this.buildLocalRefs = (env, __nd) => {
577
606
  this.modeForCollect = "create" /* Operation.Create */;
578
607
  const nd = (0, misc_1.toRaw)(__nd);
579
608
  let logicVars = new Array();
580
609
  let viewVars = new Array();
581
610
  let processVars = new Array();
582
- /** @warning v4.1 开始,view logics 不在这里处理,在 @link veQNameRefs 那里处理 */
583
- let isViewLike = false;
584
611
  const boundary = (0, helper_2.getBoundary)(nd);
585
612
  if (!boundary) {
586
613
  return new Set();
@@ -591,7 +618,33 @@ class ReferenceManager {
591
618
  if (ctxLogic && 'variables' in ctxLogic) {
592
619
  logicVars.push(...ctxLogic.variables?.map(misc_1.toRaw) ?? []);
593
620
  }
594
- isViewLike = true;
621
+ // View/BC 内 logics、events、elements 的引用走 localRefs,需预先初始化 key
622
+ const viewLike = boundary;
623
+ const viewQ = (0, def_key_helpers_1.getGlobalDefKey)(viewLike);
624
+ (viewLike.logics ?? []).forEach((l) => {
625
+ const q = (0, def_key_helpers_1.getLocalDefKey)(l) ?? (0, def_key_helpers_1.getGlobalDefKey)(l);
626
+ q && this.localRefs.set(q, new Set());
627
+ });
628
+ (viewLike.events ?? []).forEach((e) => {
629
+ const q = (0, def_key_helpers_1.getLocalDefKey)(e) ?? (0, def_key_helpers_1.getGlobalDefKey)(e);
630
+ q && this.localRefs.set(q, new Set());
631
+ });
632
+ for (const be of viewLike.bindEvents ?? []) {
633
+ for (const l of be.logics ?? []) {
634
+ this.localRefs.set(`${viewQ}.bindEvents.${be.name}.logics.${l.name}`, new Set());
635
+ }
636
+ }
637
+ const initElemKeys = (ve, parentNsp, parentKey = 'elements') => {
638
+ const elemKey = `${parentNsp}.${parentKey}.${ve.name}`;
639
+ this.localRefs.set(elemKey, new Set());
640
+ for (const be of ve.bindEvents ?? []) {
641
+ for (const l of be.logics ?? []) {
642
+ this.localRefs.set(`${elemKey}.bindEvents.${be.name}.logics.${l.name}`, new Set());
643
+ }
644
+ }
645
+ ve.children?.forEach((c) => initElemKeys(c, elemKey, 'children'));
646
+ };
647
+ (viewLike.elements ?? []).forEach((ve) => initElemKeys(ve, viewQ, 'elements'));
595
648
  }
596
649
  else if (boundary.concept === 'ProcessDefinitionV2') {
597
650
  processVars = (0, nasl_concepts_1.getProcessVars)(nd).map(misc_1.toRaw);
@@ -604,34 +657,47 @@ class ReferenceManager {
604
657
  logicVars = (0, nasl_concepts_1.getLogicVars)(nd).map(misc_1.toRaw);
605
658
  }
606
659
  let allVars = logicVars.concat(processVars).concat(viewVars);
607
- // initialize local cache
660
+ let collectedRefs = this.collectRefs(env, boundary, true);
661
+ this.lastBoundary = boundary;
662
+ // initialize local cache: 局部变量用 getLocalDefKey;Entity/Structure 属性用 collectRefs 返回的 qName(全局 key)
608
663
  allVars.forEach(def => {
609
- const qName = (0, get_q_name_1.getTokenQualifiedName)(def);
664
+ const qName = (0, def_key_helpers_1.getLocalDefKey)(def) ?? (0, def_key_helpers_1.getGlobalDefKey)(def);
610
665
  if (qName) {
611
- this.lQNameRefs.set(qName, new Set());
666
+ this.localRefs.set(qName, new Set());
612
667
  }
613
668
  });
614
- let subRefs = this.collectRefs(env, boundary, true);
615
- this.lastBoundary = boundary;
616
- subRefs?.forEach(([rf, qName]) => {
617
- // 不存在则表示不是局部符号
618
- this.lQNameRefs.get(qName)?.add(rf);
669
+ collectedRefs?.forEach(([rf, qName]) => {
670
+ if (rf.concept === 'Identifier' && qName.includes('.properties.')) {
671
+ this.localRefs.set(qName, this.localRefs.get(qName) ?? new Set());
672
+ }
673
+ });
674
+ collectedRefs?.forEach(([rf, qName]) => {
675
+ const isEntityOrStructPropRef = rf.concept === 'Identifier' && qName.includes('.properties.');
676
+ const keys = (0, def_key_helpers_1.getLocalDefKeys)(rf);
677
+ const keysToUse = isEntityOrStructPropRef ? [qName] : (keys.length > 0 ? keys : [qName]);
678
+ for (const key of keysToUse) {
679
+ // 简单名 key 不加入属性名 Identifier(NewComposite/BatchAssignment 等)
680
+ if (!key.includes('.') && (0, def_key_helpers_1.isIdentifierAsPropertyName)(rf))
681
+ continue;
682
+ this.localRefs.get(key)?.add(rf);
683
+ }
684
+ // 页面调用 BC 逻辑:外部引用 -> globalRefs
685
+ if (rf.concept === 'CallLogic' && rf.calleeNamespace?.startsWith('elements.') && rf.calleeNamespace?.endsWith('.logics')) {
686
+ const def = this.gQNameDefs.get(qName);
687
+ def && (0, fp_macros_1.createOnAdd)(this.globalRefs, def, rf);
688
+ }
689
+ // Entity/Structure 属性引用 -> globalRefs
690
+ if (isEntityOrStructPropRef) {
691
+ const def = this.gQNameDefs.get(qName);
692
+ def && (0, fp_macros_1.createOnAdd)(this.globalRefs, def, rf);
693
+ }
619
694
  });
620
695
  // Note: 暂不支持 BindAttr、BindDirective 里的变量的查找引用
621
696
  this.isLocalCacheValid = true;
622
697
  this.modeForCollect = null;
623
698
  };
624
- /**
625
- * References to view elements are calls of component logic and access of properties
626
- * 'elements.uLinearLayout1.logics.openLoading'
627
- *
628
- * 'elements.uLinearLayout1.property.uLinearLayout1._if._if'
629
- * "concept": "Identifier",
630
- * "namespace": "elements.uLinearLayout1.property",
631
- * "name": "uLinearLayout1",
632
- *
633
- */
634
- this.getViewElementRefs = (nd) => !nd ? new Set() : this.veRefs.get(nd) ?? new Set();
699
+ /** @deprecated 使用 getSymbolRefs,保留仅为兼容 */
700
+ this.getViewElementRefs = (nd) => !nd ? new Set() : this.getSymbolRefs(nd) ?? new Set();
635
701
  /**
636
702
  * 非常危险,但是先这样吧
637
703
  */
@@ -662,55 +728,399 @@ class ReferenceManager {
662
728
  // 重命名时不需要处理 sourceRef targetRef,好像其他逻辑已经处理掉了
663
729
  return result;
664
730
  };
731
+ this.updateRefsInNaslFragment = update_nasl_fragment_1.updateRefsInNaslFragment;
732
+ /**
733
+ * 添加引用到缓存(内部方法,统一管理 pendingRefsForRecreation)
734
+ * @param qName 节点的 qName
735
+ * @param ref 要缓存的引用
736
+ */
737
+ this.addRefToPendingCache = (qName, ref) => {
738
+ if (!this.pendingRefsForRecreation.has(qName)) {
739
+ this.pendingRefsForRecreation.set(qName, new Set());
740
+ }
741
+ // 只记录引用节点本身
742
+ const refInfo = {
743
+ ref,
744
+ };
745
+ this.pendingRefsForRecreation.get(qName).add(refInfo);
746
+ };
665
747
  /**
666
- * qNameDef 中删除 oldQName ==> def
667
- * qNameDef 中建立 newQName ==> def
668
- * def 内存地址相同
669
- * 如果 mode 是 'update',则 newQName 的引用集合是 oldQName 在 symbolRefs 中的既存引用
670
- * 合并上 新名字在 cachedQNameSymbolRefs 中的既存引用。
671
- * 新名字在 cachedQNameSymbolRefs 中的引用将被删除。
748
+ * 缓存引用以备后续恢复(在删除节点时调用)
749
+ * @param qName 节点的 qName
750
+ * @param defNode 要删除的节点
672
751
  *
673
- * 如果 mode 是其他,则 newQName 的引用集合是 newQName 在 cachedQNameSymbolRefs 中的既存引用。
674
- * oldQName 的引用将被放入 cachedQNameSymbolRefs
675
- * 删除 newQName 的缓存引用
752
+ * 使用场景:删除节点时,保存引用节点本身到 pendingRefsForRecreation,以便后续创建同名节点时恢复引用
753
+ *
754
+ * 设计说明:
755
+ * - 只存储引用节点本身(因为需要它来建立引用关系)
756
+ * - 恢复时会检查引用节点是否仍在 app 树上且仍引用原来的 qName
757
+ */
758
+ this.cacheRefsForRecreation = (qName, defNode) => {
759
+ if (!(0, symbol_type_1.isGlobalDef)(defNode)) {
760
+ return;
761
+ }
762
+ const refs = this.getSymbolRefs(defNode);
763
+ if (refs && refs.size > 0) {
764
+ // 只记录引用节点本身
765
+ const refInfos = new Set();
766
+ for (const ref of refs) {
767
+ const refInfo = {
768
+ ref,
769
+ };
770
+ refInfos.add(refInfo);
771
+ }
772
+ this.pendingRefsForRecreation.set(qName, refInfos);
773
+ }
774
+ };
775
+ /**
776
+ * 检查引用是否仍在 app 树上
777
+ *
778
+ * 方法:
779
+ * 向上遍历 parentNode 链,检查每个节点是否在其父节点的子节点集合中
780
+ * (因为删除节点时可能不会把 parentNode 设置为 null,但会从父节点的子节点集合中移除)
781
+ *
782
+ * 如果链上的任何节点不在其父节点的子节点集合中,说明已被删除,不在 app 树上
783
+ * 如果能到达 App 节点,说明引用仍在 app 树上
784
+ */
785
+ this.isRefStillInAppTree = (ref) => {
786
+ try {
787
+ if (!ref || !ref.concept) {
788
+ return false;
789
+ }
790
+ let currentNode = ref;
791
+ let depth = 0;
792
+ const maxDepth = 100; // 防止无限循环
793
+ // 向上遍历 parentNode 链,查找 App 节点
794
+ while (currentNode && depth < maxDepth) {
795
+ if (currentNode.concept === 'App') {
796
+ // 找到了 App 节点,说明引用仍在 app 树上
797
+ return true;
798
+ }
799
+ // 检查当前节点是否在其父节点的子节点集合中
800
+ // 如果节点被删除了,即使 parentNode 还存在,节点也不会在父节点的子节点集合中
801
+ const parentNode = currentNode.parentNode;
802
+ if (parentNode && currentNode.parentKey) {
803
+ const parentProperty = parentNode[currentNode.parentKey];
804
+ if (Array.isArray(parentProperty)) {
805
+ // 如果是数组,检查节点是否在数组中
806
+ if (parentProperty.indexOf(currentNode) === -1) {
807
+ // 节点不在父节点的子节点集合中,说明已被删除
808
+ return false;
809
+ }
810
+ }
811
+ else if (parentProperty !== currentNode) {
812
+ // 如果是单个属性,检查是否指向当前节点
813
+ // 节点不在父节点的子节点集合中,说明已被删除
814
+ return false;
815
+ }
816
+ }
817
+ currentNode = parentNode;
818
+ depth++;
819
+ }
820
+ // 无法到达 App 节点,说明引用已不在 app 树上(节点已被删除)
821
+ return false;
822
+ }
823
+ catch {
824
+ // 如果访问节点属性时出错,说明节点已被删除
825
+ return false;
826
+ }
827
+ };
828
+ /**
829
+ * 检查引用节点是否仍引用指定的 qName
830
+ * @param ref 引用节点
831
+ * @param qName 要检查的 qName
832
+ * @returns 如果引用节点仍引用指定的 qName,返回 true;否则返回 false
833
+ */
834
+ this.isRefStillReferencingQName = (ref, qName) => {
835
+ try {
836
+ // 通过 getGlobalDefKey 获取引用节点当前引用的 qName
837
+ const currentQName = (0, def_key_helpers_1.getGlobalDefKey)(ref);
838
+ // 检查是否还引用原来的 qName
839
+ return currentQName === qName;
840
+ }
841
+ catch {
842
+ // 如果获取失败,返回 false
843
+ return false;
844
+ }
845
+ };
846
+ /**
847
+ * 从缓存恢复引用(在创建节点时调用)
848
+ * @param qName 节点的 qName
849
+ * @param defNode 新创建的节点
850
+ * @returns 是否成功恢复引用
851
+ *
852
+ * 使用场景:创建节点时,如果有缓存的引用信息(来自删除操作),则恢复引用关系
853
+ *
854
+ * 恢复策略:
855
+ * 1. 使用引用节点本身(如果节点仍然有效)
856
+ * 2. 检查引用节点是否仍在 app 树上(过滤掉已删除的引用)
857
+ * 3. **关键**:检查引用节点是否仍引用原来的 qName(如果引用内容已改变,则不恢复)
858
+ * 4. 重新建立引用关系
859
+ */
860
+ this.restoreRefsFromCache = (qName, defNode) => {
861
+ if (!(0, symbol_type_1.isGlobalDef)(defNode)) {
862
+ return false;
863
+ }
864
+ const cachedRefInfos = this.pendingRefsForRecreation.get(qName);
865
+ if (!cachedRefInfos || cachedRefInfos.size === 0) {
866
+ return false;
867
+ }
868
+ const validRefs = new Set();
869
+ for (const refInfo of cachedRefInfos) {
870
+ // 检查引用节点是否仍在 app 树上
871
+ if (!this.isRefStillInAppTree(refInfo.ref)) {
872
+ continue;
873
+ }
874
+ // 检查引用节点是否仍引用原来的 qName
875
+ if (this.isRefStillReferencingQName(refInfo.ref, qName)) {
876
+ // 引用节点仍然有效且仍引用原来的 qName,添加到恢复集合中
877
+ validRefs.add(refInfo.ref);
878
+ }
879
+ }
880
+ // 如果有有效的引用,恢复它们
881
+ if (validRefs.size > 0) {
882
+ this.setSymbolRefs(defNode, validRefs);
883
+ }
884
+ // 使用后立即删除缓存,避免内存泄漏
885
+ this.pendingRefsForRecreation.delete(qName);
886
+ return validRefs.size > 0;
887
+ };
888
+ /**
889
+ * 获取待恢复引用缓存中的引用(用于查询场景,如 getOqlFiles)
890
+ * @param qName 节点的 qName
891
+ * @param app 可选的 App 实例(保留参数以保持向后兼容,但不再使用)
892
+ * @returns 缓存的引用集合,如果没有则返回 undefined
893
+ *
894
+ * 注意:只使用引用节点本身,检查引用节点是否仍在 app 树上且仍引用原来的 qName
895
+ */
896
+ this.getPendingRefsForRecreation = (qName, app) => {
897
+ const refInfos = this.pendingRefsForRecreation.get(qName);
898
+ if (!refInfos) {
899
+ return undefined;
900
+ }
901
+ const refs = new Set();
902
+ for (const refInfo of refInfos) {
903
+ // 检查引用节点是否仍在 app 树上
904
+ if (!this.isRefStillInAppTree(refInfo.ref)) {
905
+ continue;
906
+ }
907
+ // 检查引用节点是否仍引用原来的 qName
908
+ if (this.isRefStillReferencingQName(refInfo.ref, qName)) {
909
+ refs.add(refInfo.ref);
910
+ }
911
+ }
912
+ return refs;
913
+ };
914
+ /**
915
+ * 获取待恢复引用缓存的大小(用于测试和调试)
916
+ * @returns 缓存中 qName 的数量
917
+ */
918
+ this.getPendingRefsForRecreationSize = () => {
919
+ return this.pendingRefsForRecreation.size;
920
+ };
921
+ /**
922
+ * 清除所有待恢复引用缓存
923
+ * 用于清理操作,避免内存泄漏
924
+ */
925
+ this.clearPendingRefsCache = () => {
926
+ this.pendingRefsForRecreation.clear();
927
+ };
928
+ /**
929
+ * 注册 Logic/View/BusinessLogic 的 params 到 gQNameDefs,便于建立「调用逻辑的参数」到「逻辑的参数」的引用
930
+ */
931
+ this.registerParamsOfLogicOrView = (defNode) => {
932
+ const nd = defNode;
933
+ if (!(0, symbol_type_1.isLogicViewLike)(nd) || !nd.params?.length) {
934
+ return;
935
+ }
936
+ for (const p of nd.params) {
937
+ const pq = (0, def_key_helpers_1.getGlobalDefKey)(p);
938
+ if (pq) {
939
+ this.gQNameDefs.set(pq, p);
940
+ }
941
+ }
942
+ };
943
+ /**
944
+ * 移除 Logic/View/BusinessLogic 的 params 在 gQNameDefs 的注册及其引用
945
+ */
946
+ this.unregisterParamsOfLogicOrView = (defNode) => {
947
+ const nd = defNode;
948
+ if (!(0, symbol_type_1.isLogicViewLike)(nd) || !nd.params?.length) {
949
+ return;
950
+ }
951
+ for (const p of nd.params) {
952
+ const pq = (0, def_key_helpers_1.getGlobalDefKey)(p);
953
+ if (pq) {
954
+ this.gQNameDefs.delete(pq);
955
+ this.deleteSymbolRefs(p);
956
+ }
957
+ }
958
+ };
959
+ /**
960
+ * 对「调用该 Logic/View/BusinessComponent 的所有 CallLogic/Destination/ViewElement」重新收集参数引用,把参数引用加进 globalRefs。
961
+ * syncParamsOfLogicOrView 与 registerNewParamAndRecollectRefs 共用,避免重复逻辑。
962
+ * 所有 callers 均在 globalRefs。
963
+ */
964
+ this.recollectParamRefsForCallers = (env, logicQName) => {
965
+ const logicDef = this.gQNameDefs.get(logicQName);
966
+ const callers = logicDef ? this.getSymbolRefs(logicDef) : undefined;
967
+ if (!callers?.size)
968
+ return;
969
+ const prevMode = this.modeForCollect;
970
+ this.modeForCollect = "create" /* Operation.Create */;
971
+ try {
972
+ for (const ref of callers) {
973
+ if (ref.concept === 'CallLogic' || ref.concept === 'Destination'
974
+ || (ref.concept === 'ViewElement' && ref.tag?.startsWith('bs-'))) {
975
+ this.handleCallerParamRefs(env, ref);
976
+ }
977
+ }
978
+ }
979
+ finally {
980
+ this.modeForCollect = prevMode;
981
+ }
982
+ };
983
+ /**
984
+ * 对指定 Logic/View/BusinessLogic 重新收集参数引用(CallLogic 实参、Destination 实参 → params)。
985
+ * 增量更新「3: 按新类型添加符号」之后调用,此时 View 的 callers(Destination)已就绪,页面参数才能对应到页面跳转。
986
+ */
987
+ this.recollectParamRefsForDef = (env, defNode) => {
988
+ if (!(0, symbol_type_1.isLogicViewLike)(defNode))
989
+ return;
990
+ const qName = (0, def_key_helpers_1.getGlobalDefKey)(defNode);
991
+ if (qName)
992
+ this.recollectParamRefsForCallers(env, qName);
993
+ };
994
+ /**
995
+ * Logic/View/BusinessLogic 参数列表变更时同步 gQNameDefs 与 globalRefs。
996
+ * - 仅卸载「已删除」的参数,避免把内部引用清空。
997
+ * - 仍存在的参数:把 refs 从旧 def 迁移到新 def,并更新 gQNameDefs。
998
+ * - 新加参数:只做注册。
999
+ * - 最后对「调用该 Logic/View 的所有 CallLogic」重新收集参数引用,把新参数的引用加进 globalRefs。
1000
+ */
1001
+ this.syncParamsOfLogicOrView = (env, updatedDefNode, oldDefNode) => {
1002
+ const updated = updatedDefNode;
1003
+ const old = oldDefNode;
1004
+ if (!(0, symbol_type_1.isLogicViewLike)(updated))
1005
+ return;
1006
+ const logicQName = (0, def_key_helpers_1.getGlobalDefKey)(updatedDefNode);
1007
+ if (!logicQName)
1008
+ return;
1009
+ const oldParams = old.params ?? [];
1010
+ const newParams = updated.params ?? [];
1011
+ const newParamNames = new Set(newParams.map((p) => p?.name));
1012
+ const oldParamNames = new Set(oldParams.map((p) => p?.name));
1013
+ // 只卸载已删除的参数,用 getGlobalDefKey(p) 与注册时 key 一致
1014
+ for (const p of oldParams) {
1015
+ const name = p?.name;
1016
+ if (newParamNames.has(name))
1017
+ continue;
1018
+ const pq = (0, def_key_helpers_1.getGlobalDefKey)(p);
1019
+ if (!pq)
1020
+ continue;
1021
+ const def = this.gQNameDefs.get(pq);
1022
+ if (def)
1023
+ this.deleteSymbolRefs(def);
1024
+ this.gQNameDefs.delete(pq);
1025
+ }
1026
+ // 对新参数:存在的迁移 refs,新增的只注册,用 getGlobalDefKey(p) 与注册时 key 一致
1027
+ for (const p of newParams) {
1028
+ const pq = (0, def_key_helpers_1.getGlobalDefKey)(p);
1029
+ if (!pq)
1030
+ continue;
1031
+ const name = p?.name;
1032
+ if (oldParamNames.has(name)) {
1033
+ const oldDef = this.gQNameDefs.get(pq);
1034
+ const refs = oldDef ? this.globalRefs.get(oldDef) : undefined;
1035
+ if (oldDef)
1036
+ this.globalRefs.delete(oldDef);
1037
+ this.gQNameDefs.set(pq, p);
1038
+ if (refs?.size)
1039
+ this.globalRefs.set(p, refs);
1040
+ }
1041
+ else {
1042
+ this.gQNameDefs.set(pq, p);
1043
+ }
1044
+ }
1045
+ this.recollectParamRefsForCallers(env, logicQName);
1046
+ };
1047
+ /**
1048
+ * 新增参数进入 createNodes 时(Param create 事件):注册该参数并对调用该 Logic/View 的 CallLogic 重新收集参数引用。
1049
+ * 与 syncParamsOfLogicOrView 互补:后者处理 Logic update;本方法处理 Param create。
676
1050
  */
677
- this.transferQNameDef = (oldQName, newQName, mode) => {
678
- if (!oldQName || !newQName)
1051
+ this.registerNewParamAndRecollectRefs = (env, paramNode) => {
1052
+ const nd = paramNode;
1053
+ if (nd.concept !== 'Param' && nd.concept !== 'ParamWithGroup')
1054
+ return;
1055
+ const parent = nd.parentNode;
1056
+ if (!(0, symbol_type_1.isLogicViewLike)(parent))
1057
+ return;
1058
+ const logicQName = (0, def_key_helpers_1.getGlobalDefKey)(parent);
1059
+ if (!logicQName)
679
1060
  return;
680
- const oldDef = this.gQNameDefs.get(oldQName);
681
- if (!oldDef)
1061
+ const pq = (0, def_key_helpers_1.getGlobalDefKey)(nd);
1062
+ if (!pq)
682
1063
  return;
683
- // 1. 删除 oldQName,建立 newQName,def 地址不变
684
- this.gQNameDefs.delete(oldQName);
685
- this.gQNameDefs.set(newQName, oldDef);
686
- // 2. 处理引用集合
687
- if (mode === 'update') {
688
- // 获取 oldQName 的既存引用
689
- const oldRefs = this.gSymbolRefs.get(oldDef) ?? new Set();
690
- // 获取 newQName 在缓存中的引用
691
- const newCachedRefs = this.gCachedQNameSymbolRefs.get(newQName) ?? new Set();
692
- // 合并引用集合
693
- const mergedRefs = mnemonist_1.set.union(oldRefs, newCachedRefs);
694
- // 设置新名字的引用集合
695
- mergedRefs.size > 0 && this.setSymbolRefs(oldDef, mergedRefs);
696
- // 删除 newQName 在缓存中的引用
697
- this.gCachedQNameSymbolRefs.delete(newQName);
1064
+ this.gQNameDefs.set(pq, nd);
1065
+ this.recollectParamRefsForCallers(env, logicQName);
1066
+ };
1067
+ /**
1068
+ * 建立「调用处实参」到「Logic/View/BusinessComponent 形参」的引用。
1069
+ * 支持 CallLogic(调用逻辑)、Destination(页面跳转)、ViewElement(业务组件 bindAttrs)等。
1070
+ * 扩充新类型时只需在此处增加分支。
1071
+ */
1072
+ this.handleCallerParamRefs = (env, nd) => {
1073
+ if (!this.modeForCollect)
1074
+ return;
1075
+ let callee;
1076
+ let bindings;
1077
+ if (nd.concept === 'CallLogic' || nd.concept === 'Destination') {
1078
+ const calleeQName = (0, def_key_helpers_1.getGlobalDefKey)(nd);
1079
+ if (!calleeQName)
1080
+ return;
1081
+ callee = this.gQNameDefs.get(calleeQName);
1082
+ if (!callee?.params?.length)
1083
+ return;
1084
+ const args = nd.arguments ?? [];
1085
+ bindings = args
1086
+ .map((arg, i) => {
1087
+ const param = callee.params.find((p) => p.name === arg.keyword)
1088
+ ?? callee.params[i];
1089
+ return param ? { refNode: arg, param } : null;
1090
+ })
1091
+ .filter((x) => !!x);
1092
+ }
1093
+ else if (nd.concept === 'ViewElement' && nd.tag.startsWith('bs-')) {
1094
+ // 无 bindAttrs 则无需注册实参→形参引用,直接跳过,避免 frontendType/businessComponents 查找
1095
+ if (!nd.bindAttrs?.length)
1096
+ return;
1097
+ const bsName = nd.tag.split('bs-')[1];
1098
+ const fet = nd.frontendType;
1099
+ const bsDef = fet?.businessComponents?.find((bc) => bc.name === bsName);
1100
+ if (!bsDef?.params?.length)
1101
+ return;
1102
+ callee = bsDef;
1103
+ bindings = nd.bindAttrs
1104
+ .map((attr) => {
1105
+ const param = bsDef.params.find((p) => p.name === attr.name);
1106
+ return param ? { refNode: attr, param } : null;
1107
+ })
1108
+ .filter((x) => !!x);
698
1109
  }
699
1110
  else {
700
- // 不是 update,直接取 newQName 在缓存中的引用
701
- const newCachedRefs = this.gCachedQNameSymbolRefs.get(newQName) ?? new Set();
702
- this.setSymbolRefs(oldDef, newCachedRefs);
703
- // oldQName 的引用集合被放入 cachedQNameSymbolRefs
704
- const oldRefs = this.gSymbolRefs.get(oldDef) ?? new Set();
705
- oldRefs.size > 0 && this.gCachedQNameSymbolRefs.set(oldQName, oldRefs);
706
- // 删除 newQName 在缓存中的引用
707
- this.gCachedQNameSymbolRefs.delete(newQName);
1111
+ return;
1112
+ }
1113
+ for (const { refNode, param } of bindings) {
1114
+ const paramQName = (0, def_key_helpers_1.getGlobalDefKey)(param);
1115
+ if (paramQName) {
1116
+ this.handleRefOp(this.modeForCollect, refNode, paramQName);
1117
+ }
708
1118
  }
709
1119
  };
710
- this.updateRefsInNaslFragment = update_nasl_fragment_1.updateRefsInNaslFragment;
711
1120
  /**
712
- * @warning Only handle global symbols
713
- */
1121
+ * 处理「定义」的增删
1122
+ * @warning Only handle global symbols
1123
+ **/
714
1124
  this.handleDefOp = (mode, defNode, qName) => {
715
1125
  switch (mode) {
716
1126
  // 目前的策略是 re-link:删除 logic1 后,不会删除引用。新建一个 logic1 后,自动关联到老的引用上
@@ -719,16 +1129,16 @@ class ReferenceManager {
719
1129
  this.isLocalCacheValid = false;
720
1130
  }
721
1131
  else {
722
- // 可以链接回旧的引用,类似于 rename
723
- const oldRefs = this.gCachedQNameSymbolRefs.get(qName);
724
- oldRefs && this.setSymbolRefs(defNode, oldRefs);
725
1132
  // qName 链接到新的 defNode 的 mem addr
726
1133
  this.gQNameDefs.set(qName, defNode);
1134
+ // 逻辑/页面参数一并注册,便于建立「调用逻辑的参数」到「逻辑的参数」的引用
1135
+ this.registerParamsOfLogicOrView(defNode);
727
1136
  if ((0, component_def_manager_1.isGeneralViewElementDefinition)(defNode)) {
728
1137
  this.compDefMgr.add(defNode, 'handleDefOp');
729
1138
  }
730
- // 删除缓存
731
- this.gCachedQNameSymbolRefs.delete(qName);
1139
+ // 尝试从缓存恢复引用(来自删除操作)
1140
+ // 如果恢复成功,缓存会被自动清除;如果失败,引用会在类型检查时自动重新建立
1141
+ this.restoreRefsFromCache(qName, defNode);
732
1142
  }
733
1143
  break;
734
1144
  }
@@ -737,17 +1147,11 @@ class ReferenceManager {
737
1147
  this.isLocalCacheValid = false;
738
1148
  }
739
1149
  else {
740
- const refs = this.getSymbolRefs(defNode);
741
- if (refs) {
742
- if (refs.size > 0) {
743
- // 过滤掉 BindAttribute 的引用,因为 BindAttribute 的引用很容易冗余
744
- // 使用类型断言因为 BindAttribute 是特殊的引用类型,未包含在 RefConcept 中
745
- this.gCachedQNameSymbolRefs.set(qName, new Set(Array.from(refs).filter(ref => ref.concept !== 'BindAttribute')));
746
- }
747
- else {
748
- this.gCachedQNameSymbolRefs.set(qName, refs);
749
- }
750
- }
1150
+ // 先移除逻辑/页面参数的注册及其引用
1151
+ this.unregisterParamsOfLogicOrView(defNode);
1152
+ // 缓存引用以备后续恢复(在删除引用之前调用)
1153
+ this.cacheRefsForRecreation(qName, defNode);
1154
+ // 删除 qName 和引用
751
1155
  this.gQNameDefs.delete(qName);
752
1156
  if ((0, component_def_manager_1.isGeneralViewElementDefinition)(defNode)) {
753
1157
  this.compDefMgr.removeComponentGroup(defNode);
@@ -759,16 +1163,17 @@ class ReferenceManager {
759
1163
  }
760
1164
  };
761
1165
  /**
1166
+ * 处理「引用」的增删
762
1167
  * @warning Only handle global symbols
763
- */
1168
+ **/
764
1169
  this.handleRefOp = (mode, refNd, qName) => {
765
1170
  const def = this.gQNameDefs.get(qName);
766
1171
  if (def) {
767
1172
  switch (mode) {
768
1173
  case "create" /* Operation.Create */: {
769
1174
  // Route reference to the appropriate map based on whether it's explicit or implicit
770
- // Explicit references go to symbolRefs
771
- (0, fp_macros_1.createOnAdd)(this.gSymbolRefs, def, refNd);
1175
+ // Explicit references go to globalRefs
1176
+ (0, fp_macros_1.createOnAdd)(this.globalRefs, def, refNd);
772
1177
  break;
773
1178
  }
774
1179
  case "delete" /* Operation.Remove */: {
@@ -778,19 +1183,8 @@ class ReferenceManager {
778
1183
  }
779
1184
  }
780
1185
  }
781
- else {
782
- // cache 里的也要处理……
783
- switch (mode) {
784
- case "create" /* Operation.Create */: {
785
- (0, fp_macros_1.createOnAdd)(this.gCachedQNameSymbolRefs, qName, refNd);
786
- break;
787
- }
788
- case "delete" /* Operation.Remove */: {
789
- this.gCachedQNameSymbolRefs.get(qName)?.delete(refNd);
790
- break;
791
- }
792
- }
793
- }
1186
+ // 注意:如果定义不存在,引用会被忽略
1187
+ // 类型检查时会重新建立引用关系
794
1188
  };
795
1189
  this.handleSymbolImplicitRefs = (nd) => {
796
1190
  if (!nd)
@@ -847,7 +1241,7 @@ class ReferenceManager {
847
1241
  if (!(0, type_predicate_1.isEntityTy)(typeAnnotation) && !(0, type_predicate_1.isStructureTy)(typeAnnotation)) {
848
1242
  return;
849
1243
  }
850
- const tyQName = (0, get_q_name_1.getTokenQualifiedName)(typeAnnotation);
1244
+ const tyQName = (0, def_key_helpers_1.getGlobalDefKey)(typeAnnotation);
851
1245
  if (!tyQName) {
852
1246
  return;
853
1247
  }
@@ -882,7 +1276,7 @@ class ReferenceManager {
882
1276
  if (!bsDef) {
883
1277
  return;
884
1278
  }
885
- this.handleRefOp(this.modeForCollect, nd, (0, get_q_name_1.getTokenQualifiedName)(bsDef));
1279
+ this.handleRefOp(this.modeForCollect, nd, (0, def_key_helpers_1.getGlobalDefKey)(bsDef));
886
1280
  };
887
1281
  this.handleBindRoles = (env, nd) => {
888
1282
  for (const roleName of nd.bindRoles ?? nd.roles) {
@@ -909,11 +1303,11 @@ class ReferenceManager {
909
1303
  parent?.interfaceDependencies?.forEach(dep => {
910
1304
  dep.interfaces.forEach(itfc => {
911
1305
  if (itfc.concept === 'AuthInterface' && itfc.name === nd.calleeName) {
912
- // this.handleRefOp(this.modeForCollect!, nd, getTokenQualifiedName(itfc)!);
1306
+ // this.handleRefOp(this.modeForCollect!, nd, getGlobalDefKey(itfc)!);
913
1307
  const authName = itfc.authLogic;
914
1308
  parent?.authLogicsForCallInterface?.forEach(l => {
915
1309
  if (l.name === authName) {
916
- this.handleRefOp(this.modeForCollect, nd, (0, get_q_name_1.getTokenQualifiedName)(l));
1310
+ this.handleRefOp(this.modeForCollect, nd, (0, def_key_helpers_1.getGlobalDefKey)(l));
917
1311
  }
918
1312
  });
919
1313
  }
@@ -921,17 +1315,29 @@ class ReferenceManager {
921
1315
  });
922
1316
  parent.interfaces?.forEach(itfc => {
923
1317
  if (itfc.concept === 'AuthInterface' && itfc.name === nd.calleeName) {
924
- // this.handleRefOp(this.modeForCollect!, nd, getTokenQualifiedName(itfc)!);
925
- // this.handleRefOp(this.modeForCollect!, nd, getTokenQualifiedName(itfc)!);
1318
+ // this.handleRefOp(this.modeForCollect!, nd, getGlobalDefKey(itfc)!);
1319
+ // this.handleRefOp(this.modeForCollect!, nd, getGlobalDefKey(itfc)!);
926
1320
  const authName = itfc.authLogic;
927
1321
  parent?.authLogics?.forEach(l => {
928
1322
  if (l.name === authName) {
929
- this.handleRefOp(this.modeForCollect, nd, (0, get_q_name_1.getTokenQualifiedName)(l));
1323
+ this.handleRefOp(this.modeForCollect, nd, (0, def_key_helpers_1.getGlobalDefKey)(l));
930
1324
  }
931
1325
  });
932
1326
  }
933
1327
  });
934
1328
  };
1329
+ /**
1330
+ * 处理 ProcessElementV2 的 CallSubProcess 类型对 ProcessV2 的引用
1331
+ * 当 ProcessElementV2 的 type === 'CallSubProcess' 时,subProcessKey 字段引用另一个 ProcessV2 的 uniqueKey
1332
+ */
1333
+ this.handleProcessSubProcessRef = (env, nd) => {
1334
+ if (nd.type !== 'CallSubProcess' || !nd.subProcessKey) {
1335
+ return;
1336
+ }
1337
+ // subProcessKey 就是 ProcessV2 的 uniqueKey,直接作为 qName 使用
1338
+ const subProcessQName = nd.subProcessKey;
1339
+ this.handleRefOp(this.modeForCollect, nd, subProcessQName);
1340
+ };
935
1341
  /**
936
1342
  * 无论根节点是 ref 还是 def,都要递归收集下层所有的引用节点
937
1343
  * 会打散 a.b.c、A | B、x.a.b 等结构,并记录必要的信息
@@ -959,7 +1365,7 @@ class ReferenceManager {
959
1365
  !skipSubView && views.push(...(0, misc_1.getSubViews)(nd));
960
1366
  if (nd.concept === 'View' || nd.concept === 'BusinessComponent') {
961
1367
  this.curFileNode = nd;
962
- env.viewAssocProcess = env.processV2ViewBindings.get((0, get_q_name_1.getTokenQualifiedName)(nd)) ?? null;
1368
+ env.viewAssocProcess = env.processV2ViewBindings.get((0, def_key_helpers_1.getGlobalDefKey)(nd)) ?? null;
963
1369
  }
964
1370
  const res = new Array(); // 使用数组而不是 Map
965
1371
  // specialization for speeding up
@@ -974,10 +1380,16 @@ class ReferenceManager {
974
1380
  n.concept === 'EntityProperty' && this.handleForeignKeyRef(env, n);
975
1381
  n.concept === 'AssigneeV2' && this.handleBindRoles(env, n);
976
1382
  n.concept === 'CallAuthInterface' && this.handleAuthLogicRef(env, n);
1383
+ // 处理流程子流程引用
1384
+ n.concept === 'ProcessElementV2' && this.handleProcessSubProcessRef(env, n);
1385
+ // 处理 CallLogic、Destination、ViewElement 的调用处实参到形参的引用
1386
+ if (['CallLogic', 'Destination', 'ViewElement'].includes(n.concept)) {
1387
+ this.handleCallerParamRefs(env, n);
1388
+ }
977
1389
  if (!symbol_type_1.refConcept.includes(n.concept)) {
978
1390
  return;
979
1391
  }
980
- const qName = (0, get_q_name_1.getTokenQualifiedName)(n); // 太慢,后续应该需要优化速度
1392
+ const qName = (0, def_key_helpers_1.getGlobalDefKey)(n); // 太慢,后续应该需要优化速度
981
1393
  if (!qName) {
982
1394
  return;
983
1395
  }
@@ -1004,7 +1416,7 @@ class ReferenceManager {
1004
1416
  case 'TypeAnnotation':
1005
1417
  const refs = this.splitPolyType(n);
1006
1418
  for (const ref of refs) {
1007
- const qName = (0, get_q_name_1.getTokenQualifiedName)(ref);
1419
+ const qName = (0, def_key_helpers_1.getGlobalDefKey)(ref);
1008
1420
  qName && qNameRefs.push([ref, qName]);
1009
1421
  }
1010
1422
  break;
@@ -1039,7 +1451,7 @@ class ReferenceManager {
1039
1451
  for (const v of views) {
1040
1452
  v.bindRoles.length && this.handleBindRoles(env, v);
1041
1453
  const lastViewAssocProcess = env.viewAssocProcess;
1042
- env.viewAssocProcess = env.processV2ViewBindings.get((0, get_q_name_1.getTokenQualifiedName)(v)) ?? null;
1454
+ env.viewAssocProcess = env.processV2ViewBindings.get((0, def_key_helpers_1.getGlobalDefKey)(v)) ?? null;
1043
1455
  const lastCurFileNode = this.curFileNode;
1044
1456
  this.curFileNode = v;
1045
1457
  // @ts-expect-error contra-variance errors
@@ -1054,7 +1466,7 @@ class ReferenceManager {
1054
1466
  (0, traverse_util_1.visitChildrenWith)(nd, normalCb, compositeNodePred, compositeNodeCb);
1055
1467
  }
1056
1468
  if (nd.concept === 'McpInterface') {
1057
- const qName = nd.originLogic && (0, get_q_name_1.getTokenQualifiedName)(nd.originLogic);
1469
+ const qName = nd.originLogic && (0, def_key_helpers_1.getGlobalDefKey)(nd.originLogic);
1058
1470
  qName && res.push([nd, qName]);
1059
1471
  }
1060
1472
  else if (nd.concept !== 'QueryFieldExpression') {
@@ -1116,7 +1528,7 @@ class ReferenceManager {
1116
1528
  const visibleLocalSyms = this.getVisibleLocalSyms(nd);
1117
1529
  const localQNameSet = new Set();
1118
1530
  for (const s of visibleLocalSyms) {
1119
- const q = (0, get_q_name_1.getTokenQualifiedName)(s);
1531
+ const q = (0, def_key_helpers_1.getGlobalDefKey)(s);
1120
1532
  q && localQNameSet.add(q);
1121
1533
  }
1122
1534
  for (const [ref, qName] of refAndQNames) {
@@ -1187,8 +1599,16 @@ class ReferenceManager {
1187
1599
  processVar = (0, typer_1.createProcessVariable)(env, proc);
1188
1600
  (0, helper_1.createOnPush)(env.allocatedVirtualNodes, this.curFileNode, processVar);
1189
1601
  });
1190
- if (symbol_type_1.refConcept.includes(id0.concept)) {
1191
- const qName = (0, get_q_name_1.getTokenQualifiedName)(id0);
1602
+ // 处理 processVariable.variable1 的情况
1603
+ // processVariable 是虚拟变量,不需要添加引用,只需要设置类型以便后续处理
1604
+ if (processVar && id0.name === 'processVariable') {
1605
+ const procVarTy = env.getType(processVar);
1606
+ if (procVarTy) {
1607
+ env.setType(id0, procVarTy);
1608
+ }
1609
+ }
1610
+ else if (symbol_type_1.refConcept.includes(id0.concept)) {
1611
+ const qName = (0, def_key_helpers_1.getGlobalDefKey)(id0);
1192
1612
  let isProcessRef = false;
1193
1613
  if (qName) {
1194
1614
  // Handle process reference in view
@@ -1207,7 +1627,7 @@ class ReferenceManager {
1207
1627
  }
1208
1628
  if (isProcessRef) {
1209
1629
  const processDef = env.viewAssocProcess;
1210
- const pId = (0, get_q_name_1.getTokenQualifiedName)(processDef);
1630
+ const pId = (0, def_key_helpers_1.getGlobalDefKey)(processDef);
1211
1631
  res.push([ids[0], pId]);
1212
1632
  const processBindDataTy = (0, type_manager_1.createTypeofBindData)(pId, env);
1213
1633
  env.setType(ids[0], processBindDataTy);
@@ -1231,7 +1651,17 @@ class ReferenceManager {
1231
1651
  }
1232
1652
  // 是这样的,为了兼容 processVariable.variable1,前面的是匿名数据结构,只需要 variable1 的引用就行了
1233
1653
  let ndDef = this.getNodeDef(ty);
1234
- if (ndDef && (ndDef.concept === 'Entity' || ndDef.concept === 'Structure' || ndDef.concept === 'Enum')) {
1654
+ // 处理 processVariable.variable1 的情况:匿名结构类型,需要添加 processVariable.variable1 的引用
1655
+ if (ty.typeKind === 'anonymousStructure' && ids[0].name === 'processVariable' && processVar) {
1656
+ const procDef = processVar.parentNode;
1657
+ if (procDef && procDef.concept === 'ProcessDefinitionV2') {
1658
+ const procVar = procDef.variables?.find((v) => v.name === ids[i + 1].name);
1659
+ if (procVar) {
1660
+ res.push([ids[i + 1], `processVariable.${ids[i + 1].name}`]);
1661
+ }
1662
+ }
1663
+ }
1664
+ else if (ndDef && (ndDef.concept === 'Entity' || ndDef.concept === 'Structure' || ndDef.concept === 'Enum')) {
1235
1665
  const propQName = (0, string_2.getPropQName)(`${ty.typeNamespace}.${ty.typeName}`, ids[i + 1].name, 'Entity');
1236
1666
  res.push([ids[i + 1], propQName]); // type reference
1237
1667
  }
@@ -1344,8 +1774,8 @@ class ReferenceManager {
1344
1774
  return res;
1345
1775
  }
1346
1776
  const entityQName = nd.propertyName === 'data'
1347
- ? (0, get_q_name_1.getTokenQualifiedName)(entityRef.typeAnnotation) // data 是 Entity
1348
- : (0, get_q_name_1.getTokenQualifiedName)(entityRef.typeAnnotation.typeArguments[0]); // relation_data 是 List<Entity>
1777
+ ? (0, def_key_helpers_1.getGlobalDefKey)(entityRef.typeAnnotation) // data 是 Entity
1778
+ : (0, def_key_helpers_1.getGlobalDefKey)(entityRef.typeAnnotation.typeArguments[0]); // relation_data 是 List<Entity>
1349
1779
  for (const sub of nd.subFieldPermissions) {
1350
1780
  res.push([sub, (0, string_2.getPropQName)(entityQName, sub.propertyName, 'Entity')]);
1351
1781
  }
@@ -1357,9 +1787,9 @@ class ReferenceManager {
1357
1787
  this.getMemoryStats = () => {
1358
1788
  const stats = {
1359
1789
  gQNameDefs: this.gQNameDefs,
1360
- symbolRefs: this.gSymbolRefs, // Exporting private map for serialization
1361
- cachedQNameSymbolRefs: this.gCachedQNameSymbolRefs,
1362
- localQNameRefs: this.lQNameRefs,
1790
+ globalRefs: this.globalRefs, // Exporting private map for serialization
1791
+ pendingRefsForRecreation: this.pendingRefsForRecreation, // Exporting private map for serialization
1792
+ localRefs: this.localRefs,
1363
1793
  compDefMgr: this.compDefMgr,
1364
1794
  };
1365
1795
  const result = {
@@ -1411,7 +1841,7 @@ class ReferenceManager {
1411
1841
  if (!(0, helper_2.isEntityLogic)(nd)) {
1412
1842
  return nd;
1413
1843
  }
1414
- const qName = (0, get_q_name_1.getTokenQualifiedName)(nd);
1844
+ const qName = (0, def_key_helpers_1.getGlobalDefKey)(nd);
1415
1845
  if (!qName) {
1416
1846
  throw new Error('The entity logic does not have namespace');
1417
1847
  }
@@ -1422,8 +1852,8 @@ class ReferenceManager {
1422
1852
  // 同步跟新引用管理器,跟上实体逻辑内存地址变化的节奏
1423
1853
  if (nd !== def) {
1424
1854
  this.gQNameDefs.set(qName, nd);
1425
- const refs = mnemonist_1.set.union(this.gSymbolRefs.get(def) ?? new Set(), this.gSymbolRefs.get(nd) ?? new Set());
1426
- refs.size > 0 && this.gSymbolRefs.set(nd, refs);
1855
+ const refs = mnemonist_1.set.union(this.globalRefs.get(def) ?? new Set(), this.globalRefs.get(nd) ?? new Set());
1856
+ refs.size > 0 && this.globalRefs.set(nd, refs);
1427
1857
  }
1428
1858
  return nd;
1429
1859
  };
@@ -1442,7 +1872,7 @@ class ReferenceManager {
1442
1872
  if (!(ctxViewLike && (ctxViewLike.concept === 'View' || ctxViewLike.concept === 'BusinessComponent'))) {
1443
1873
  return;
1444
1874
  }
1445
- const ctxQName = (0, get_q_name_1.getTokenQualifiedName)(ctxViewLike);
1875
+ const ctxQName = (0, def_key_helpers_1.getGlobalDefKey)(ctxViewLike);
1446
1876
  if (!ctxQName)
1447
1877
  return;
1448
1878
  const assocProc = env.processV2ViewBindings.get(ctxQName);
@@ -1479,9 +1909,9 @@ class ReferenceManager {
1479
1909
  if (!ctxViewElement) {
1480
1910
  return;
1481
1911
  }
1482
- const macthed = node.concept === 'BindAttribute';
1483
- const ancestor = !macthed && node.getAncestorRaw('BindAttribute');
1484
- const boundary = (macthed ? node : ancestor);
1912
+ const matched = node.concept === 'BindAttribute';
1913
+ const ancestor = !matched && node.getAncestorRaw('BindAttribute');
1914
+ const boundary = (matched ? node : ancestor);
1485
1915
  if (boundary?.name !== 'rules') {
1486
1916
  return;
1487
1917
  }
@@ -1521,7 +1951,7 @@ class ReferenceManager {
1521
1951
  }
1522
1952
  }; }
1523
1953
  static getEntityLogicQNames(nd) {
1524
- const qName = (0, get_q_name_1.getTokenQualifiedName)(nd);
1954
+ const qName = (0, def_key_helpers_1.getGlobalDefKey)(nd);
1525
1955
  const res = new Array();
1526
1956
  for (const l of nd.logics) {
1527
1957
  res.push(`${qName}.logics.${l.name}`);
@@ -1529,13 +1959,11 @@ class ReferenceManager {
1529
1959
  return res;
1530
1960
  }
1531
1961
  clearAll() {
1532
- this.clearSymbolRefs();
1962
+ this.clearGlobalRefs();
1533
1963
  this.gQNameDefs.clear();
1534
- this.gCachedQNameSymbolRefs.clear();
1535
- this.lQNameRefs.clear();
1536
- this.veQNameDefs.clear();
1537
- this.veRefs.clear();
1964
+ this.localRefs.clear();
1538
1965
  this.compDefMgr.clearAll();
1966
+ this.clearPendingRefsCache(); // 清除待恢复引用缓存
1539
1967
  this.gSymbolImplicitRefs = new WeakMap();
1540
1968
  }
1541
1969
  }