@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.
- package/out/checker.d.ts +4 -1
- package/out/checker.d.ts.map +1 -1
- package/out/checker.js +996 -96
- package/out/checker.js.map +1 -1
- package/out/index.d.ts +1 -1
- package/out/index.d.ts.map +1 -1
- package/out/index.js +5 -3
- package/out/index.js.map +1 -1
- package/out/reference-manager/build-q-name-def.d.ts.map +1 -1
- package/out/reference-manager/build-q-name-def.js +11 -0
- package/out/reference-manager/build-q-name-def.js.map +1 -1
- package/out/reference-manager/builtin-q-name.js +2 -2
- package/out/reference-manager/builtin-q-name.js.map +1 -1
- package/out/reference-manager/collect-q-name.d.ts +1 -1
- package/out/reference-manager/collect-q-name.d.ts.map +1 -1
- package/out/reference-manager/collect-q-name.js +64 -27
- package/out/reference-manager/collect-q-name.js.map +1 -1
- package/out/reference-manager/def-key-helpers.d.ts +38 -0
- package/out/reference-manager/def-key-helpers.d.ts.map +1 -0
- package/out/reference-manager/{get-q-name.js → def-key-helpers.js} +195 -23
- package/out/reference-manager/def-key-helpers.js.map +1 -0
- package/out/reference-manager/helper.js +2 -2
- package/out/reference-manager/helper.js.map +1 -1
- package/out/reference-manager/reference-manager.d.ts +146 -47
- package/out/reference-manager/reference-manager.d.ts.map +1 -1
- package/out/reference-manager/reference-manager.js +632 -204
- package/out/reference-manager/reference-manager.js.map +1 -1
- package/out/reference-manager/remove-q-name.d.ts +1 -1
- package/out/reference-manager/remove-q-name.d.ts.map +1 -1
- package/out/reference-manager/remove-q-name.js +14 -14
- package/out/reference-manager/remove-q-name.js.map +1 -1
- package/out/reference-manager/rename-q-name.d.ts +26 -26
- package/out/reference-manager/rename-q-name.d.ts.map +1 -1
- package/out/reference-manager/rename-q-name.js +48 -167
- package/out/reference-manager/rename-q-name.js.map +1 -1
- package/out/reference-manager/symbol-type.d.ts +8 -3
- package/out/reference-manager/symbol-type.d.ts.map +1 -1
- package/out/reference-manager/symbol-type.js +9 -2
- package/out/reference-manager/symbol-type.js.map +1 -1
- package/out/reference-manager/update-nasl-fragment.d.ts +2 -2
- package/out/reference-manager/update-nasl-fragment.d.ts.map +1 -1
- package/out/reference-manager/update-nasl-fragment.js +33 -28
- package/out/reference-manager/update-nasl-fragment.js.map +1 -1
- package/out/services/bindable-logic-service.js.map +1 -1
- package/out/symbol/traverse/concepts/index.d.ts +1 -1
- package/out/symbol/traverse/concepts/index.d.ts.map +1 -1
- package/out/symbol/traverse/concepts/logic/expression/member-expression.js.map +1 -1
- package/out/typer/collectGlobalDefs.d.ts +8 -0
- package/out/typer/collectGlobalDefs.d.ts.map +1 -1
- package/out/typer/collectGlobalDefs.js +102 -54
- package/out/typer/collectGlobalDefs.js.map +1 -1
- package/out/typer/component-def-manager/component-def-manager.d.ts +16 -0
- package/out/typer/component-def-manager/component-def-manager.d.ts.map +1 -1
- package/out/typer/component-def-manager/component-def-manager.js +63 -2
- package/out/typer/component-def-manager/component-def-manager.js.map +1 -1
- package/out/typer/component-def-manager/utils.d.ts.map +1 -1
- package/out/typer/component-def-manager/utils.js +26 -0
- package/out/typer/component-def-manager/utils.js.map +1 -1
- package/out/typer/dispatch-all.d.ts +3 -1
- package/out/typer/dispatch-all.d.ts.map +1 -1
- package/out/typer/dispatch-all.js +51 -6
- package/out/typer/dispatch-all.js.map +1 -1
- package/out/typer/dispatch-call.d.ts +27 -1
- package/out/typer/dispatch-call.d.ts.map +1 -1
- package/out/typer/dispatch-call.js +151 -107
- package/out/typer/dispatch-call.js.map +1 -1
- package/out/typer/dispatch-def.d.ts.map +1 -1
- package/out/typer/dispatch-def.js +51 -23
- package/out/typer/dispatch-def.js.map +1 -1
- package/out/typer/dispatch-expr.d.ts +2 -1
- package/out/typer/dispatch-expr.d.ts.map +1 -1
- package/out/typer/dispatch-expr.js +240 -199
- package/out/typer/dispatch-expr.js.map +1 -1
- package/out/typer/dispatch-process.d.ts +8 -1
- package/out/typer/dispatch-process.d.ts.map +1 -1
- package/out/typer/dispatch-process.js +37 -4
- package/out/typer/dispatch-process.js.map +1 -1
- package/out/typer/dispatch-stmt.d.ts.map +1 -1
- package/out/typer/dispatch-stmt.js +39 -25
- package/out/typer/dispatch-stmt.js.map +1 -1
- package/out/typer/dispatch-view.d.ts +1 -1
- package/out/typer/dispatch-view.d.ts.map +1 -1
- package/out/typer/dispatch-view.js +87 -48
- package/out/typer/dispatch-view.js.map +1 -1
- package/out/typer/fix-use-before-assign.js.map +1 -1
- package/out/typer/get-oql-files.d.ts.map +1 -1
- package/out/typer/get-oql-files.js +3 -9
- package/out/typer/get-oql-files.js.map +1 -1
- package/out/typer/incremental-update.d.ts +14 -7
- package/out/typer/incremental-update.d.ts.map +1 -1
- package/out/typer/incremental-update.js +396 -43
- package/out/typer/incremental-update.js.map +1 -1
- package/out/typer/oql-checker/chain-call-transformer.d.ts.map +1 -1
- package/out/typer/oql-checker/chain-call-transformer.js +17 -4
- package/out/typer/oql-checker/chain-call-transformer.js.map +1 -1
- package/out/typer/oql-checker/ts-parser.d.ts.map +1 -1
- package/out/typer/oql-checker/ts-parser.js +252 -37
- package/out/typer/oql-checker/ts-parser.js.map +1 -1
- package/out/typer/overload-helper.d.ts.map +1 -1
- package/out/typer/overload-helper.js +190 -23
- package/out/typer/overload-helper.js.map +1 -1
- package/out/typer/solver.d.ts +8 -9
- package/out/typer/solver.d.ts.map +1 -1
- package/out/typer/solver.js +54 -31
- package/out/typer/solver.js.map +1 -1
- package/out/typer/subster.d.ts +1 -1
- package/out/typer/subster.d.ts.map +1 -1
- package/out/typer/subster.js +251 -57
- package/out/typer/subster.js.map +1 -1
- package/out/typer/topo-sort.d.ts +38 -0
- package/out/typer/topo-sort.d.ts.map +1 -1
- package/out/typer/topo-sort.js +272 -3
- package/out/typer/topo-sort.js.map +1 -1
- package/out/typer/type-manager.d.ts +1 -0
- package/out/typer/type-manager.d.ts.map +1 -1
- package/out/typer/type-manager.js +14 -11
- package/out/typer/type-manager.js.map +1 -1
- package/out/typer/type-predicate.d.ts +1 -0
- package/out/typer/type-predicate.d.ts.map +1 -1
- package/out/typer/type-predicate.js +83 -14
- package/out/typer/type-predicate.js.map +1 -1
- package/out/typer/typer.d.ts +51 -6
- package/out/typer/typer.d.ts.map +1 -1
- package/out/typer/typer.js +248 -46
- package/out/typer/typer.js.map +1 -1
- package/out/typer/unifier.d.ts +12 -1
- package/out/typer/unifier.d.ts.map +1 -1
- package/out/typer/unifier.js +110 -37
- package/out/typer/unifier.js.map +1 -1
- package/out/utils/debug.js.map +1 -1
- package/out/utils/type-operator.d.ts +15 -0
- package/out/utils/type-operator.d.ts.map +1 -1
- package/out/utils/type-operator.js +65 -3
- package/out/utils/type-operator.js.map +1 -1
- package/package.json +5 -5
- package/out/reference-manager/get-q-name.d.ts +0 -9
- package/out/reference-manager/get-q-name.d.ts.map +0 -1
- package/out/reference-manager/get-q-name.js.map +0 -1
- package/out/reference-manager/view-elem-logic.d.ts +0 -44
- package/out/reference-manager/view-elem-logic.d.ts.map +0 -1
- package/out/reference-manager/view-elem-logic.js +0 -164
- 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
|
|
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 和
|
|
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.
|
|
69
|
-
// Accessor methods for
|
|
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.
|
|
71
|
+
return this.globalRefs.get(def);
|
|
73
72
|
};
|
|
74
73
|
this.setSymbolRefs = (__def, refs) => {
|
|
75
74
|
const def = this.normaliseEntityLogic(__def);
|
|
76
|
-
this.
|
|
75
|
+
this.globalRefs.set(def, refs);
|
|
77
76
|
};
|
|
78
77
|
this.deleteSymbolRefs = (__def) => {
|
|
79
78
|
const def = this.normaliseEntityLogic(__def);
|
|
80
|
-
return this.
|
|
79
|
+
return this.globalRefs.delete(def);
|
|
81
80
|
};
|
|
82
|
-
this.
|
|
83
|
-
this.
|
|
81
|
+
this.clearGlobalRefs = () => {
|
|
82
|
+
this.globalRefs.clear();
|
|
84
83
|
};
|
|
85
|
-
this.
|
|
86
|
-
return this.
|
|
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
|
-
|
|
119
|
-
|
|
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
|
-
/**
|
|
125
|
-
this.
|
|
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
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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)
|
|
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
|
-
|
|
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
|
|
205
|
-
if (!
|
|
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(
|
|
225
|
+
if (seen.has(vKey))
|
|
209
226
|
continue;
|
|
210
|
-
seen.add(
|
|
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,
|
|
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
|
-
|
|
336
|
-
|
|
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.
|
|
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
|
-
|
|
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,
|
|
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(
|
|
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,
|
|
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
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
if (nd.concept === 'ViewElement' || nd.concept === 'Logic' || nd.concept === 'BusinessLogic') {
|
|
495
|
-
res = mnemonist_1.set.union(
|
|
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.
|
|
501
|
-
this.
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
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
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
res = mnemonist_1.set.union(res ?? new Set(), this.
|
|
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
|
-
|
|
535
|
-
|
|
536
|
-
bsRefsRefs.push(...this.getViewElementRefs(bsInst));
|
|
564
|
+
if (ctxViewLike)
|
|
565
|
+
this.buildLocalRefs(env, ctxViewLike);
|
|
537
566
|
}
|
|
538
|
-
//
|
|
539
|
-
res = mnemonist_1.set.union(res,
|
|
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.
|
|
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
|
|
602
|
+
* @warning 不包括 ViewElement、BindEvent 相关的引用,已合并到 getLocalDefKeys 与 collectedRefs 处理
|
|
574
603
|
* @warning 需要包括 SubLogics
|
|
575
604
|
*/
|
|
576
|
-
this.
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
664
|
+
const qName = (0, def_key_helpers_1.getLocalDefKey)(def) ?? (0, def_key_helpers_1.getGlobalDefKey)(def);
|
|
610
665
|
if (qName) {
|
|
611
|
-
this.
|
|
666
|
+
this.localRefs.set(qName, new Set());
|
|
612
667
|
}
|
|
613
668
|
});
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
667
|
-
*
|
|
668
|
-
*
|
|
669
|
-
* 如果 mode 是 'update',则 newQName 的引用集合是 oldQName 在 symbolRefs 中的既存引用
|
|
670
|
-
* 合并上 新名字在 cachedQNameSymbolRefs 中的既存引用。
|
|
671
|
-
* 新名字在 cachedQNameSymbolRefs 中的引用将被删除。
|
|
748
|
+
* 缓存引用以备后续恢复(在删除节点时调用)
|
|
749
|
+
* @param qName 节点的 qName
|
|
750
|
+
* @param defNode 要删除的节点
|
|
672
751
|
*
|
|
673
|
-
*
|
|
674
|
-
*
|
|
675
|
-
*
|
|
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.
|
|
678
|
-
|
|
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
|
|
681
|
-
if (!
|
|
1061
|
+
const pq = (0, def_key_helpers_1.getGlobalDefKey)(nd);
|
|
1062
|
+
if (!pq)
|
|
682
1063
|
return;
|
|
683
|
-
|
|
684
|
-
this.
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
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
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
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
|
|
771
|
-
(0, fp_macros_1.createOnAdd)(this.
|
|
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
|
-
|
|
782
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
925
|
-
// this.handleRefOp(this.modeForCollect!, nd,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
1191
|
-
|
|
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,
|
|
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
|
-
|
|
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,
|
|
1348
|
-
: (0,
|
|
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
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
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,
|
|
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.
|
|
1426
|
-
refs.size > 0 && this.
|
|
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,
|
|
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
|
|
1483
|
-
const ancestor = !
|
|
1484
|
-
const boundary = (
|
|
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,
|
|
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.
|
|
1962
|
+
this.clearGlobalRefs();
|
|
1533
1963
|
this.gQNameDefs.clear();
|
|
1534
|
-
this.
|
|
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
|
}
|