@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
|
@@ -10,7 +10,8 @@ const type_predicate_1 = require("./type-predicate");
|
|
|
10
10
|
const dispatch_all_1 = require("./dispatch-all");
|
|
11
11
|
const checker_1 = require("../checker");
|
|
12
12
|
const service_2 = require("@lcap/nasl-concepts/service");
|
|
13
|
-
const
|
|
13
|
+
const symbol_type_1 = require("../reference-manager/symbol-type");
|
|
14
|
+
const def_key_helpers_1 = require("../reference-manager/def-key-helpers");
|
|
14
15
|
const reference_manager_1 = require("../reference-manager/reference-manager");
|
|
15
16
|
const collect_q_name_1 = require("../reference-manager/collect-q-name");
|
|
16
17
|
const remove_q_name_1 = require("../reference-manager/remove-q-name");
|
|
@@ -18,10 +19,97 @@ const rename_q_name_1 = require("../reference-manager/rename-q-name");
|
|
|
18
19
|
const dispatch_def_1 = require("./dispatch-def");
|
|
19
20
|
const type_manager_1 = require("./type-manager");
|
|
20
21
|
const helper_1 = require("./helper");
|
|
22
|
+
const topo_sort_1 = require("./topo-sort");
|
|
21
23
|
const helper_2 = require("../reference-manager/helper");
|
|
22
24
|
const misc_1 = require("../utils/misc");
|
|
23
25
|
const get_oql_files_1 = require("./get-oql-files");
|
|
24
26
|
const asserts_1 = require("@lcap/nasl-concepts/asserts");
|
|
27
|
+
/**
|
|
28
|
+
* 祖先节点重新验证规则配置
|
|
29
|
+
* 当子节点的特定字段变更时,会触发祖先节点的重新验证
|
|
30
|
+
* 通过配置驱动的方式,可以轻松添加新的验证规则,避免硬编码
|
|
31
|
+
*
|
|
32
|
+
* 默认会向上查找整个祖先链,找到所有匹配类型的祖先节点进行验证
|
|
33
|
+
* 如果设置了 directParentOnly: true,则只查找直接父节点
|
|
34
|
+
*/
|
|
35
|
+
const ANCESTOR_REVALIDATION_RULES = [
|
|
36
|
+
{
|
|
37
|
+
childNodeType: 'View',
|
|
38
|
+
triggerFields: ['isIndex'],
|
|
39
|
+
ancestorNodeTypes: ['View', 'Frontend'],
|
|
40
|
+
directParentOnly: true,
|
|
41
|
+
validationFn: (ancestorNode, env) => {
|
|
42
|
+
// 类型检查:确保 ancestorNode 是 View 或 Frontend 类型
|
|
43
|
+
if ((0, asserts_1.isView)(ancestorNode) || (0, asserts_1.isFrontend)(ancestorNode)) {
|
|
44
|
+
env.errorDiagnoser.checkViewIndexPageSetting(ancestorNode);
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
errorFilter: (err) => !err.isIndex,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
childNodeType: 'ProcessElementV2',
|
|
51
|
+
triggerFields: ['subProcessKey'],
|
|
52
|
+
ancestorNodeTypes: ['App'],
|
|
53
|
+
directParentOnly: false,
|
|
54
|
+
validationFn: (ancestorNode, env) => {
|
|
55
|
+
// 类型检查:确保 ancestorNode 是 App 类型
|
|
56
|
+
if (ancestorNode.concept === 'App') {
|
|
57
|
+
// 检测所有流程的循环引用(在 App 级别,因为流程的变更会影响兄弟级别的流程)
|
|
58
|
+
env.errorDiagnoser.checkAllProcessCircularReferences(ancestorNode);
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
errorFilter: (err) => {
|
|
62
|
+
// 过滤掉流程循环引用相关的错误,以便重新检测
|
|
63
|
+
return !err.message?.includes('流程存在循环引用');
|
|
64
|
+
},
|
|
65
|
+
siblingNodeTypes: ['ProcessV2'],
|
|
66
|
+
getSiblingNodes: (ancestorNode) => {
|
|
67
|
+
// 从 App 节点获取所有 ProcessV2 兄弟节点
|
|
68
|
+
if (ancestorNode.concept === 'App') {
|
|
69
|
+
const appNode = ancestorNode;
|
|
70
|
+
return appNode.processV2s || [];
|
|
71
|
+
}
|
|
72
|
+
return [];
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
/**
|
|
77
|
+
* 检查节点类型是否匹配规则
|
|
78
|
+
*/
|
|
79
|
+
function matchesChildNodeType(rule, nodeConcept) {
|
|
80
|
+
if (Array.isArray(rule.childNodeType)) {
|
|
81
|
+
return rule.childNodeType.includes(nodeConcept);
|
|
82
|
+
}
|
|
83
|
+
return rule.childNodeType === nodeConcept;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 查找匹配的祖先节点
|
|
87
|
+
* @param startNode 起始节点
|
|
88
|
+
* @param ancestorNodeTypes 要查找的祖先节点类型列表
|
|
89
|
+
* @param directParentOnly 是否只查找直接父节点
|
|
90
|
+
* @returns 匹配的祖先节点列表(从近到远)
|
|
91
|
+
*/
|
|
92
|
+
function findMatchingAncestors(startNode, ancestorNodeTypes, directParentOnly = false) {
|
|
93
|
+
const matchingAncestors = [];
|
|
94
|
+
if (directParentOnly) {
|
|
95
|
+
// 只查找直接父节点
|
|
96
|
+
const parentNode = startNode.parentNode;
|
|
97
|
+
if (parentNode && ancestorNodeTypes.includes(parentNode.concept)) {
|
|
98
|
+
matchingAncestors.push(parentNode);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
// 向上遍历整个祖先链
|
|
103
|
+
let currentNode = startNode.parentNode;
|
|
104
|
+
while (currentNode) {
|
|
105
|
+
if (ancestorNodeTypes.includes(currentNode.concept)) {
|
|
106
|
+
matchingAncestors.push(currentNode);
|
|
107
|
+
}
|
|
108
|
+
currentNode = currentNode.parentNode;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return matchingAncestors;
|
|
112
|
+
}
|
|
25
113
|
/**
|
|
26
114
|
* @warning 改动这个文件中的逻辑时很容易引发增量检查问题、查找引用问题、内存泄漏,请谨慎;如单元测试 UT 发生错误,更要谨慎
|
|
27
115
|
* 为了增加效率,直接往 params 的 Set 里加东西
|
|
@@ -42,14 +130,11 @@ const preProcessOther = (env, nd, typerCheckFiles) => {
|
|
|
42
130
|
};
|
|
43
131
|
exports.preProcessOther = preProcessOther;
|
|
44
132
|
/**
|
|
45
|
-
*
|
|
133
|
+
* 重命名定义节点:
|
|
46
134
|
* 1 获取要删除的旧的 qNames1
|
|
47
135
|
* 2 获取引用旧的 qNames1 的待检查项 ys
|
|
48
136
|
* 3 获取要增加的新的 qNames2
|
|
49
|
-
* 4
|
|
50
|
-
* 5 尝试 'relink':改名后,如果新名字已经存在一些存量 refs,也要加进去
|
|
51
|
-
* 6 根据转移的 symbolRefs,获取引用新的 qNames2 的待检查项 zs(比如可能一个以前找不到的名字碰巧连接上了)
|
|
52
|
-
* 7 类型检查 ys 和 zs
|
|
137
|
+
* 4 删除旧的 qNames1,清空旧引用(根据 mode 决定是否缓存引用)
|
|
53
138
|
*/
|
|
54
139
|
/**
|
|
55
140
|
* @warning 改动这个文件中的逻辑时很容易引发增量检查问题、查找引用问题、内存泄漏,请谨慎;如单元测试 UT 发生错误,更要谨慎
|
|
@@ -62,8 +147,8 @@ const preProcessDefRename = (env, nd, typerCheckFiles, oldName, mode, oqlRemoveN
|
|
|
62
147
|
env.refMgr.invalidateLocalSymCache();
|
|
63
148
|
return true;
|
|
64
149
|
}
|
|
65
|
-
const qName = (0,
|
|
66
|
-
// 2.
|
|
150
|
+
const qName = (0, def_key_helpers_1.getGlobalDefKey)(nd);
|
|
151
|
+
// 2. 获取引用旧的 qNames1 的待检查项
|
|
67
152
|
const oldQName = easyGetOldQName(qName, oldName);
|
|
68
153
|
try {
|
|
69
154
|
const filePath = nd.getEmbeddedFilePath();
|
|
@@ -80,20 +165,27 @@ const preProcessDefRename = (env, nd, typerCheckFiles, oldName, mode, oqlRemoveN
|
|
|
80
165
|
typerCheckFiles.add(refFileNode);
|
|
81
166
|
});
|
|
82
167
|
}
|
|
83
|
-
// 3.
|
|
168
|
+
// 3. 获取要增加的新的 qNames2
|
|
84
169
|
const nsp = (0, helper_2.getNamespaceWithoutLast)(nd);
|
|
85
|
-
const qNamesToRename = (0, rename_q_name_1.
|
|
86
|
-
// 4.
|
|
87
|
-
//
|
|
170
|
+
const qNamesToRename = (0, rename_q_name_1.getDefKeysForRename)(oldName, nsp, nd);
|
|
171
|
+
// 4. 删除旧的 qNames1 并清空旧引用
|
|
172
|
+
// 注意:新的 qNames2 会在 batchPreProcessAllCreateNodes 阶段统一设置(通过 typerCreateNodes.add 调用)
|
|
173
|
+
// 这确保了统一性:所有新的 qName 都通过相同的代码路径设置
|
|
174
|
+
// 所有引用会在类型检查阶段通过 addRefsForGlobalSym 重新建立
|
|
88
175
|
qNamesToRename.forEach(([oldQName, newQName]) => {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
env.refMgr.
|
|
176
|
+
if (!oldQName || !newQName)
|
|
177
|
+
return;
|
|
178
|
+
const oldDef = env.refMgr.gQNameDefs.get(oldQName);
|
|
179
|
+
if (!oldDef)
|
|
180
|
+
return;
|
|
181
|
+
// 缓存引用(用于撤销/重做,重命名回旧名字/创建同名节点建立关联)
|
|
182
|
+
env.refMgr.cacheRefsForRecreation(oldQName, oldDef);
|
|
183
|
+
// 从 gQNameDefs 中删除旧的 qName
|
|
184
|
+
// 注意:新的 qName 会在 batchPreProcessAllCreateNodes 阶段设置
|
|
185
|
+
env.refMgr.gQNameDefs.delete(oldQName);
|
|
186
|
+
// 清空旧定义的引用:引用会在类型检查阶段重新建立
|
|
187
|
+
env.refMgr.deleteSymbolRefs(oldDef);
|
|
92
188
|
});
|
|
93
|
-
// 6. Based on transferred symbolRefs, get items to check that reference new qNames2
|
|
94
|
-
// getDirectRefFileNodes(env, nd as DefConcept).forEach((refFileNode) => {
|
|
95
|
-
// typerCheckFiles.add(refFileNode);
|
|
96
|
-
// });
|
|
97
189
|
return true;
|
|
98
190
|
};
|
|
99
191
|
exports.preProcessDefRename = preProcessDefRename;
|
|
@@ -123,6 +215,61 @@ const pushRefFilesToChkFiles = (env, chkFiles, qNames) => {
|
|
|
123
215
|
}
|
|
124
216
|
}
|
|
125
217
|
};
|
|
218
|
+
/**
|
|
219
|
+
* 清理节点内部引用的所有定义
|
|
220
|
+
* @param env 语义环境
|
|
221
|
+
* @param sourceNode 源节点(可以是完整节点或临时节点)
|
|
222
|
+
* @param targetNode 目标节点(用于判断引用节点是否属于它)
|
|
223
|
+
* @param errorContext 错误上下文,用于日志
|
|
224
|
+
*/
|
|
225
|
+
const clearRefsFromNode = (env, sourceNode, targetNode, errorContext) => {
|
|
226
|
+
try {
|
|
227
|
+
// 遍历源节点,收集所有引用的 qName
|
|
228
|
+
const refQNames = new Set();
|
|
229
|
+
if (sourceNode.traverseStrictChildren) {
|
|
230
|
+
sourceNode.traverseStrictChildren((nd) => {
|
|
231
|
+
if (reference_manager_1.ReferenceManager.refConcept.includes(nd.concept)) {
|
|
232
|
+
const qName = (0, def_key_helpers_1.getGlobalDefKey)(nd);
|
|
233
|
+
if (qName) {
|
|
234
|
+
refQNames.add(qName);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
// 对于每个被引用的定义,清理属于目标节点的引用
|
|
240
|
+
for (const qName of refQNames) {
|
|
241
|
+
const def = env.refMgr.gQNameDefs.get(qName);
|
|
242
|
+
if (!def) {
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
const refs = env.refMgr.getSymbolRefs(def);
|
|
246
|
+
if (!refs) {
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
// 找出属于目标节点的引用节点并清理
|
|
250
|
+
// 通过 parentNode 链判断:从引用节点向上遍历,看是否能到达 targetNode
|
|
251
|
+
const refsToRemove = [];
|
|
252
|
+
for (const ref of refs) {
|
|
253
|
+
let currentNode = ref;
|
|
254
|
+
while (currentNode) {
|
|
255
|
+
if (currentNode === targetNode) {
|
|
256
|
+
// 找到了,说明 ref 是 targetNode 的子节点,需要清理
|
|
257
|
+
refsToRemove.push(ref);
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
currentNode = currentNode.parentNode;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// 清理这些引用
|
|
264
|
+
for (const ref of refsToRemove) {
|
|
265
|
+
env.refMgr.getSymbolRefs(def)?.delete(ref);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
catch (err) {
|
|
270
|
+
nasl_utils_1.isDebugMode && console.warn(`Failed to clear refs from ${errorContext}:`, targetNode.nodePath, err);
|
|
271
|
+
}
|
|
272
|
+
};
|
|
126
273
|
const batchPreProcessAllRemoveNodes = (env, removeNodes, chkFiles, removedFiles) => {
|
|
127
274
|
// 首先需要删除所有引用,后面移除定义后,删除引用时要么符号找不到,要么要去缓存里找,更麻烦,不如多一次遍历
|
|
128
275
|
const allQNameDefs = new Set();
|
|
@@ -141,9 +288,12 @@ const batchPreProcessAllRemoveNodes = (env, removeNodes, chkFiles, removedFiles)
|
|
|
141
288
|
if (!reference_manager_1.ReferenceManager.globalDefConcept.includes(rmNd.concept)) {
|
|
142
289
|
env.removeTypes(rmNd);
|
|
143
290
|
}
|
|
291
|
+
// 对于被删除的节点,清理它内部引用的所有定义
|
|
292
|
+
const rawNode = (0, misc_1.toRaw)(rmNd);
|
|
293
|
+
clearRefsFromNode(env, rawNode, rawNode, 'removed node');
|
|
144
294
|
const nsp = (0, helper_2.getNamespaceWithoutLast)(rmNd) ?? '';
|
|
145
295
|
// Including entity logics if nd.concept === 'Entity'
|
|
146
|
-
const qNames = (0, remove_q_name_1.
|
|
296
|
+
const qNames = (0, remove_q_name_1.getDefKeysForRemove)(nsp, rmNd);
|
|
147
297
|
for (const [qName, def] of qNames) {
|
|
148
298
|
allQNameDefs.add([qName, def]);
|
|
149
299
|
}
|
|
@@ -199,10 +349,18 @@ const batchPreProcessAllCreateNodes = (env, createNodes, chkFiles) => {
|
|
|
199
349
|
// TODO:之后再整理代码
|
|
200
350
|
for (const nd of createNodes) {
|
|
201
351
|
if (reference_manager_1.ReferenceManager.localDefConcept.includes(nd.concept)) {
|
|
352
|
+
// 新增的 Logic/View 参数:注册到 gQNameDefs 并对调用处重新收集参数引用,否则「查找引用」查不到
|
|
353
|
+
const raw = (0, misc_1.toRaw)(nd);
|
|
354
|
+
if ((raw.concept === 'Param' || raw.concept === 'ParamWithGroup') && raw.parentNode) {
|
|
355
|
+
const parent = (0, misc_1.toRaw)(raw.parentNode);
|
|
356
|
+
if ((0, symbol_type_1.isLogicViewLike)(parent)) {
|
|
357
|
+
env.refMgr.registerNewParamAndRecollectRefs(env, raw);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
202
360
|
continue;
|
|
203
361
|
}
|
|
204
362
|
const nsp = (0, helper_2.getNamespaceWithoutLast)(nd);
|
|
205
|
-
const createdQNames = (0, collect_q_name_1.
|
|
363
|
+
const createdQNames = (0, collect_q_name_1.getDefKeysForCreate)(nsp, nd);
|
|
206
364
|
// Try to 'relink' to old defs,仅 relink refs,和建立 QNames,新的 refs 需要检查后再收集
|
|
207
365
|
for (const [qName, def] of createdQNames) {
|
|
208
366
|
env.refMgr.handleDefOp("create" /* Operation.Create */, def, qName);
|
|
@@ -215,6 +373,46 @@ const batchPreProcessAllCreateNodes = (env, createNodes, chkFiles) => {
|
|
|
215
373
|
pushRefFilesToChkFiles(env, chkFiles, createdQNames.map(([qName]) => qName));
|
|
216
374
|
}
|
|
217
375
|
};
|
|
376
|
+
const batchPreProcessAllUpdatedNodes = (env, updatedNodes, chkFiles) => {
|
|
377
|
+
const updatedQNames = [];
|
|
378
|
+
// 基于 oldObject 清理旧的引用关系;所有改动都需将所在文件加入 chkFiles,使关联节点重新计算类型
|
|
379
|
+
for (const [updatedNode, { oldObject }] of updatedNodes.entries()) {
|
|
380
|
+
const rawNode = (0, misc_1.toRaw)(updatedNode);
|
|
381
|
+
// 任一更新节点所在文件都加入 chkFiles,保证该文件被重新类型检查
|
|
382
|
+
const fileNode = (0, service_1.getFileNode)(rawNode);
|
|
383
|
+
if (fileNode) {
|
|
384
|
+
chkFiles.add(fileNode);
|
|
385
|
+
}
|
|
386
|
+
try {
|
|
387
|
+
const restoredJSON = {
|
|
388
|
+
...oldObject,
|
|
389
|
+
concept: oldObject.concept || rawNode.concept
|
|
390
|
+
};
|
|
391
|
+
// 基于 oldObject 创建临时节点(只包含 oldObject 中的字段)
|
|
392
|
+
const tempNode = nasl_concepts_1.BaseNode.from(restoredJSON);
|
|
393
|
+
clearRefsFromNode(env, tempNode, rawNode, 'oldObject');
|
|
394
|
+
// 逻辑/页面参数变更时同步 gQNameDefs,新加参数才能被「查找引用」查到
|
|
395
|
+
if ((0, symbol_type_1.isLogicViewLike)(rawNode)) {
|
|
396
|
+
env.refMgr.syncParamsOfLogicOrView(env, rawNode, tempNode);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
catch (err) {
|
|
400
|
+
// 如果处理失败,记录错误但继续处理
|
|
401
|
+
nasl_utils_1.isDebugMode && console.warn('Failed to clear old refs from oldObject:', rawNode.nodePath, err);
|
|
402
|
+
}
|
|
403
|
+
// 收集更新节点对应的 qNames,用于将引用这些定义的文件加入 chkFiles,使关联节点重新计算类型
|
|
404
|
+
if (!reference_manager_1.ReferenceManager.localDefConcept.includes(rawNode.concept)) {
|
|
405
|
+
const nsp = (0, helper_2.getNamespaceWithoutLast)(rawNode) ?? '';
|
|
406
|
+
const qNames = (0, collect_q_name_1.getDefKeysForCreate)(nsp, rawNode);
|
|
407
|
+
for (const [qName] of qNames) {
|
|
408
|
+
updatedQNames.push(qName);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
if (updatedQNames.length > 0) {
|
|
413
|
+
pushRefFilesToChkFiles(env, chkFiles, updatedQNames);
|
|
414
|
+
}
|
|
415
|
+
};
|
|
218
416
|
/**
|
|
219
417
|
* 增量更新诊断信息
|
|
220
418
|
* @param params 包含所有参数的对象
|
|
@@ -224,7 +422,7 @@ const batchPreProcessAllCreateNodes = (env, createNodes, chkFiles) => {
|
|
|
224
422
|
* @warning 改动这个文件中的逻辑时很容易引发增量检查问题、查找引用问题、内存泄漏,请谨慎;如单元测试 UT 发生错误,更要谨慎
|
|
225
423
|
*/
|
|
226
424
|
async function checkUpdateRefsDiag(params) {
|
|
227
|
-
const { env, diagMgr: diagnosticManager, removeNodes, createNodes, tsDiagnostics, removedConnectors = new Set(), checkedFiles = new Set() } = params;
|
|
425
|
+
const { env, diagMgr: diagnosticManager, removeNodes, createNodes, tsDiagnostics, removedConnectors = new Set(), checkedFiles = new Set(), updatedNodes = new Map() } = params;
|
|
228
426
|
// Integration-specific diagnostics accumulator
|
|
229
427
|
let diagRecs = [];
|
|
230
428
|
// 将 removeNodes、createNodes、removeNodes 根据是否在 integration 下分成两类
|
|
@@ -233,8 +431,9 @@ async function checkUpdateRefsDiag(params) {
|
|
|
233
431
|
nasl_utils_1.isDebugMode && console.time('\x1b[44m\x1b[97m 1: 按原有类型删除符号引用和类型 \x1b[0m');
|
|
234
432
|
batchPreProcessAllRemoveNodes(env, removeNodes, chkFiles, removedFiles);
|
|
235
433
|
batchPreProcessAllCreateNodes(env, createNodes, chkFiles);
|
|
434
|
+
batchPreProcessAllUpdatedNodes(env, updatedNodes, chkFiles);
|
|
236
435
|
for (const file of removedFiles) {
|
|
237
|
-
clearSemInfoDiags(env, diagnosticManager, file);
|
|
436
|
+
clearSemInfoDiags(env, diagnosticManager, file, false); // 删除的整棵子树都清(含 localSymBindings)
|
|
238
437
|
}
|
|
239
438
|
nasl_utils_1.isDebugMode && console.timeEnd('\x1b[44m\x1b[97m 1: 按原有类型删除符号引用和类型 \x1b[0m');
|
|
240
439
|
// 合并两段过滤:先排除已删除文件和不合法路径(包含 '[-1]'),
|
|
@@ -267,8 +466,58 @@ async function checkUpdateRefsDiag(params) {
|
|
|
267
466
|
return processRelatedConcepts.includes(v?.concept);
|
|
268
467
|
});
|
|
269
468
|
// 拆分 BusinessComponent 和 View,先处理 BusinessComponent
|
|
270
|
-
const [
|
|
271
|
-
const [viewNodes,
|
|
469
|
+
const [bsNodesRaw, otherNodes3] = (0, helper_1.divideBy)(otherNodes2, (v) => v?.concept === 'BusinessComponent');
|
|
470
|
+
const [viewNodes, otherNodes4] = (0, helper_1.divideBy)(otherNodes3, (v) => v?.concept === 'View');
|
|
471
|
+
const [frontendNodes, defNodes] = (0, helper_1.divideBy)(otherNodes4, (v) => ['FrontendType', 'Frontend'].includes(v?.concept));
|
|
472
|
+
// 对 BusinessComponent 做局部拓扑排序:
|
|
473
|
+
// 若同一个 FrontendType 下的业务组件 A 模板中引用了业务组件 B(通过 bs-XXX 实例),
|
|
474
|
+
// 则 B 需要先于 A 处理。
|
|
475
|
+
//
|
|
476
|
+
// 环的处理:
|
|
477
|
+
// topoSortBusinessComponentsByAst 会对环内节点做"展开"处理,
|
|
478
|
+
// 例如 A↔B 时返回 [A, B, A],使 A 在 B 定型后获得第二次类型检查。
|
|
479
|
+
//
|
|
480
|
+
// 因此这里构造两个列表:
|
|
481
|
+
// - bsNodesForTyping:保留环展开的重复节点,用于 dispatchAsyncDef 类型检查阶段。
|
|
482
|
+
// 环内首节点会被多次 dispatchAsyncDef,第二次时其依赖已就绪,可正确解析。
|
|
483
|
+
// - bsNodesUnique:去重版本,用于 removeRefs / addRefs / 签名比较等,
|
|
484
|
+
// 这些操作具有幂等性或不应重复执行,每个组件只需跑一遍。
|
|
485
|
+
const bsNodesForTyping = (() => {
|
|
486
|
+
if (!bsNodesRaw.length)
|
|
487
|
+
return bsNodesRaw;
|
|
488
|
+
// 分组:按 FrontendType 归类业务组件,仅在同一 FrontendType 内部建图并排序
|
|
489
|
+
const groupByFrontend = new Map();
|
|
490
|
+
for (const nd of bsNodesRaw) {
|
|
491
|
+
const bc = nd;
|
|
492
|
+
const fe = bc.frontendType;
|
|
493
|
+
if (!groupByFrontend.has(fe)) {
|
|
494
|
+
groupByFrontend.set(fe, []);
|
|
495
|
+
}
|
|
496
|
+
groupByFrontend.get(fe).push(bc);
|
|
497
|
+
}
|
|
498
|
+
const result = [];
|
|
499
|
+
for (const [, list] of groupByFrontend) {
|
|
500
|
+
const ordered = (0, topo_sort_1.topoSortBusinessComponentsByAst)(list);
|
|
501
|
+
// 不去重,保留环展开产生的重复节点(例如 [A, B, A])
|
|
502
|
+
ordered.forEach(bc => {
|
|
503
|
+
result.push(bc);
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
return result;
|
|
507
|
+
})();
|
|
508
|
+
// 去重版本:用于 removeRefs / addRefs / 参数签名比较等,只需要每个 BusinessComponent 跑一遍完整管线
|
|
509
|
+
const bsNodesUnique = (() => {
|
|
510
|
+
const seen = new Set();
|
|
511
|
+
const res = [];
|
|
512
|
+
for (const nd of bsNodesForTyping) {
|
|
513
|
+
const bc = nd;
|
|
514
|
+
if (seen.has(bc))
|
|
515
|
+
continue;
|
|
516
|
+
seen.add(bc);
|
|
517
|
+
res.push(nd);
|
|
518
|
+
}
|
|
519
|
+
return res;
|
|
520
|
+
})();
|
|
272
521
|
/**
|
|
273
522
|
* @warning 这个需要先做,因为下面的 topoSortLogicAndSetTypes 会根据逻辑的最新 NASL 更新逻辑的类型
|
|
274
523
|
* 找到页面变量,集合,判断类型有无变化
|
|
@@ -276,26 +525,45 @@ async function checkUpdateRefsDiag(params) {
|
|
|
276
525
|
*/
|
|
277
526
|
const [oldLogicRetTys, oldLogicParamTys] = getLogicSigs(env, logicNodes);
|
|
278
527
|
// 收集页面和业务组件的参数类型(它们没有返回值)
|
|
279
|
-
const oldViewParamTys = getViewComponentSigs(env, [...viewNodes, ...
|
|
528
|
+
const oldViewParamTys = getViewComponentSigs(env, [...viewNodes, ...bsNodesUnique]);
|
|
280
529
|
(0, dispatch_def_1.setParamOptionalFlags)([...itfcNodes, ...logicNodes]);
|
|
281
530
|
const logicTasks = (0, dispatch_all_1.topoSortLogicAndSetTypes)(env, logicNodes);
|
|
282
531
|
// 处理类型检查 - 改为顺序处理,确保正确的等待异步操作
|
|
283
532
|
nasl_utils_1.isDebugMode && console.time('\x1b[44m\x1b[97m 2: 类型检查 \x1b[0m');
|
|
284
533
|
// 先处理 BusinessComponent,再处理 View
|
|
285
|
-
const
|
|
286
|
-
|
|
534
|
+
const filesForRefs = [...defNodes, ...itfcNodes, ...logicTasks, ...processNodes, ...bsNodesUnique, ...viewNodes, ...frontendNodes];
|
|
535
|
+
const filesForTyping = [...defNodes, ...itfcNodes, ...logicTasks, ...processNodes, ...bsNodesForTyping, ...viewNodes, ...frontendNodes];
|
|
536
|
+
// 1) 先按「唯一集合」移除引用 & 旧诊断
|
|
537
|
+
for (const file of filesForRefs) {
|
|
287
538
|
env.refMgr.removeRefsForGlobalSym(env, file);
|
|
288
539
|
clearSemInfoDiags(env, diagnosticManager, file);
|
|
289
|
-
|
|
540
|
+
}
|
|
541
|
+
// 2) 再按「拓扑 + 环展开」的顺序跑类型检查(每个 BusinessComponent 可能多次出现,如 A,B,A)
|
|
542
|
+
// 重复出现的节点(环展开重启节点)非最后一次时抑制报错,避免依赖未就绪时产生不准确的诊断
|
|
543
|
+
const errorGuard = env.createDuplicateErrorGuard(filesForTyping);
|
|
544
|
+
for (const file of filesForTyping) {
|
|
545
|
+
errorGuard.before(file);
|
|
546
|
+
try {
|
|
547
|
+
await (0, dispatch_all_1.dispatchAsyncDef)(env, file, true);
|
|
548
|
+
}
|
|
549
|
+
finally {
|
|
550
|
+
errorGuard.after(file);
|
|
551
|
+
}
|
|
290
552
|
}
|
|
291
553
|
nasl_utils_1.isDebugMode && console.timeEnd('\x1b[44m\x1b[97m 2: 类型检查 \x1b[0m');
|
|
292
554
|
// 按新类型添加符号
|
|
293
555
|
nasl_utils_1.isDebugMode && console.time('\x1b[44m\x1b[97m 3: 按新类型添加符号 \x1b[0m');
|
|
294
|
-
for (const file of
|
|
556
|
+
for (const file of filesForRefs) {
|
|
295
557
|
if (reference_manager_1.ReferenceManager.defConcept.includes(file.concept)) {
|
|
296
558
|
env.refMgr.addRefsForGlobalSym(env, file);
|
|
297
559
|
}
|
|
298
560
|
}
|
|
561
|
+
// View/Logic 的 callers(Destination/CallLogic)已就绪,再对每个 View/Logic 重收参数引用,页面参数才能对应到页面跳转
|
|
562
|
+
for (const file of filesForRefs) {
|
|
563
|
+
if ((0, symbol_type_1.isLogicViewLike)(file)) {
|
|
564
|
+
env.refMgr.recollectParamRefsForDef(env, file);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
299
567
|
nasl_utils_1.isDebugMode && console.timeEnd('\x1b[44m\x1b[97m 3: 按新类型添加符号 \x1b[0m');
|
|
300
568
|
nasl_utils_1.isDebugMode && console.time('\x1b[44m\x1b[97m 4: 错误诊断 \x1b[0m');
|
|
301
569
|
// 对OQL节点加载来自TS的错误
|
|
@@ -307,8 +575,80 @@ async function checkUpdateRefsDiag(params) {
|
|
|
307
575
|
node.errorsFromTSServer = [{ message }];
|
|
308
576
|
}
|
|
309
577
|
});
|
|
310
|
-
//
|
|
311
|
-
|
|
578
|
+
// 配置驱动的祖先节点重新验证机制
|
|
579
|
+
// 当子节点的特定字段变更时,根据配置的规则向上查找祖先节点并触发重新验证
|
|
580
|
+
for (const [updatedNode, { object }] of updatedNodes.entries()) {
|
|
581
|
+
const nodeConcept = updatedNode.concept;
|
|
582
|
+
// 查找匹配的验证规则
|
|
583
|
+
const matchingRules = ANCESTOR_REVALIDATION_RULES.filter(rule => matchesChildNodeType(rule, nodeConcept) &&
|
|
584
|
+
rule.triggerFields.some(field => object.hasOwnProperty(field)));
|
|
585
|
+
// 对每个匹配的规则执行祖先节点重新验证
|
|
586
|
+
for (const rule of matchingRules) {
|
|
587
|
+
// 查找所有匹配的祖先节点(从近到远)
|
|
588
|
+
const matchingAncestors = findMatchingAncestors(updatedNode, rule.ancestorNodeTypes, rule.directParentOnly ?? false);
|
|
589
|
+
// 对每个匹配的祖先节点执行重新验证
|
|
590
|
+
for (const ancestorNode of matchingAncestors) {
|
|
591
|
+
// 如果祖先节点已经在已排序的文件列表中,则跳过(会在后续统一处理)
|
|
592
|
+
if (filesForRefs.includes(ancestorNode)) {
|
|
593
|
+
continue;
|
|
594
|
+
}
|
|
595
|
+
// 调用 checker 的重新验证方法
|
|
596
|
+
const nodeDiagnosticsMap = env.errorDiagnoser.revalidateAncestorNode(ancestorNode, rule.validationFn, rule.errorFilter, rule.siblingNodeTypes, rule.getSiblingNodes);
|
|
597
|
+
// 收集新的诊断信息
|
|
598
|
+
// 注意:nodeDiagnosticsMap 可能包含多个文件节点的诊断信息(如 App 和 ProcessV2)
|
|
599
|
+
// 需要按文件节点分组处理
|
|
600
|
+
// 同时,即使兄弟节点没有诊断信息,也需要为它们生成空的 DiagnosticRecord,以便 pushAll 能清除它们的错误
|
|
601
|
+
const processedFileNodes = new Set();
|
|
602
|
+
if (nodeDiagnosticsMap) {
|
|
603
|
+
// 按文件节点分组诊断信息
|
|
604
|
+
const diagnosticsByFileNode = new Map();
|
|
605
|
+
nodeDiagnosticsMap.forEach((errs, node) => {
|
|
606
|
+
const fileNode = (0, service_1.getFileNode)(node);
|
|
607
|
+
if (fileNode) {
|
|
608
|
+
processedFileNodes.add(fileNode);
|
|
609
|
+
let fileDiagnostics = diagnosticsByFileNode.get(fileNode);
|
|
610
|
+
if (!fileDiagnostics) {
|
|
611
|
+
fileDiagnostics = new Map();
|
|
612
|
+
diagnosticsByFileNode.set(fileNode, fileDiagnostics);
|
|
613
|
+
}
|
|
614
|
+
fileDiagnostics.set(node, errs);
|
|
615
|
+
}
|
|
616
|
+
});
|
|
617
|
+
// 为每个文件节点生成 DiagnosticRecord
|
|
618
|
+
diagnosticsByFileNode.forEach((fileDiagnostics, fileNode) => {
|
|
619
|
+
diagRecs.push(...(0, checker_1.transformDiagnosticsToRecords)(fileNode, fileDiagnostics));
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
// 为兄弟节点生成 DiagnosticRecord(即使它们没有诊断信息,也要生成空的,以便 pushAll 能清除它们的错误)
|
|
623
|
+
if (rule.getSiblingNodes) {
|
|
624
|
+
const siblings = rule.getSiblingNodes(ancestorNode);
|
|
625
|
+
for (const siblingNode of siblings) {
|
|
626
|
+
// 如果指定了 siblingNodeTypes,则只处理匹配类型的兄弟节点
|
|
627
|
+
if (rule.siblingNodeTypes && rule.siblingNodeTypes.length > 0) {
|
|
628
|
+
if (!rule.siblingNodeTypes.includes(siblingNode.concept)) {
|
|
629
|
+
continue;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
// 如果已经处理过这个文件节点,跳过
|
|
633
|
+
if (processedFileNodes.has(siblingNode)) {
|
|
634
|
+
continue;
|
|
635
|
+
}
|
|
636
|
+
// 为兄弟节点生成空的 DiagnosticRecord
|
|
637
|
+
const siblingDiagnostics = env.errorDiagnoser.getDiagnostics(siblingNode);
|
|
638
|
+
if (siblingDiagnostics) {
|
|
639
|
+
diagRecs.push(...(0, checker_1.transformDiagnosticsToRecords)(siblingNode, siblingDiagnostics));
|
|
640
|
+
}
|
|
641
|
+
else {
|
|
642
|
+
// 即使没有诊断信息,也要生成一个空的 DiagnosticRecord,以便 pushAll 能清除错误
|
|
643
|
+
diagRecs.push(...(0, checker_1.transformDiagnosticsToRecords)(siblingNode, new Map()));
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
// 处理错误诊断:仅对每个文件节点执行一次
|
|
651
|
+
for (const file of filesForRefs) {
|
|
312
652
|
await (0, nasl_utils_1.timeSlicingWithGenerator)(env.errorDiagnoser.checkNode(file));
|
|
313
653
|
const nodeDiagnosticsMap = env.errorDiagnoser.getDiagnostics(file);
|
|
314
654
|
nodeDiagnosticsMap && diagRecs.push(...(0, checker_1.transformDiagnosticsToRecords)(file, nodeDiagnosticsMap));
|
|
@@ -342,7 +682,7 @@ async function checkUpdateRefsDiag(params) {
|
|
|
342
682
|
oldLogicRetTys,
|
|
343
683
|
oldLogicParamTys,
|
|
344
684
|
viewNodes: [...viewNodes],
|
|
345
|
-
bsNodes: [...
|
|
685
|
+
bsNodes: [...bsNodesUnique],
|
|
346
686
|
oldViewParamTys,
|
|
347
687
|
});
|
|
348
688
|
if (nextChkFiles.size) {
|
|
@@ -355,7 +695,8 @@ async function checkUpdateRefsDiag(params) {
|
|
|
355
695
|
createNodes: new Set(),
|
|
356
696
|
tsDiagnostics: [],
|
|
357
697
|
removedConnectors,
|
|
358
|
-
checkedFiles
|
|
698
|
+
checkedFiles,
|
|
699
|
+
updatedNodes: new Map() // 递归调用时不需要处理更新的节点
|
|
359
700
|
}));
|
|
360
701
|
}
|
|
361
702
|
return diagRecs;
|
|
@@ -467,17 +808,22 @@ const removeNodeDiagnostics = (errorDiagnoser, diagnosticManager, file) => {
|
|
|
467
808
|
diagnosticManager && diagnosticManager.deleteOwn(file.id);
|
|
468
809
|
};
|
|
469
810
|
/**
|
|
470
|
-
*
|
|
811
|
+
* 清除节点的语义信息和诊断,为重新类型检查做准备
|
|
812
|
+
* @param skipSubView true 时遇到子 View 剪枝,并顺带清除 start 的 localSymBindings(不深入子文件,子 View 等保留供 checker 使用);false 时整棵子树都清(含 localSymBindings)
|
|
471
813
|
*/
|
|
472
814
|
const clearSemInfoDiags = (env, diagnosticManager, start, skipSubView = true) => {
|
|
473
815
|
const fileNodes = new Array;
|
|
474
|
-
//
|
|
816
|
+
// 遍历包含自身;skipSubView 时遇到子 View 剪枝且不收集、不删该节点,避免误清子 View 的 typeBindings/allocatedVirtualNodes 等
|
|
475
817
|
start.traverseStrictChildrenWithPruning((nd) => {
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
818
|
+
const prune = skipSubView && nd !== start && nd.concept === 'View';
|
|
819
|
+
if (!prune) {
|
|
820
|
+
(0, file_node_cache_1.checkNodeIsFileModuleInIdeWithCache)(nd) && fileNodes.push(nd);
|
|
821
|
+
env.typeBindings.delete(nd);
|
|
822
|
+
(0, service_2.isNaslCallExpr)(nd) && env.resolvedCallInfo.delete(nd);
|
|
823
|
+
}
|
|
824
|
+
return prune;
|
|
480
825
|
});
|
|
826
|
+
// fileNodes 在 skipSubView 时已排除子 View,故以下均不会碰到子 View
|
|
481
827
|
for (const fileNode of fileNodes) {
|
|
482
828
|
removeNodeDiagnostics(env.errorDiagnoser, diagnosticManager, fileNode);
|
|
483
829
|
env.allocatedVirtualNodes.get(fileNode)?.forEach(virtualNd => {
|
|
@@ -486,13 +832,20 @@ const clearSemInfoDiags = (env, diagnosticManager, start, skipSubView = true) =>
|
|
|
486
832
|
});
|
|
487
833
|
env.allocatedVirtualNodes.delete(fileNode);
|
|
488
834
|
if (fileNode.concept === 'MetadataType') {
|
|
489
|
-
env.typeAlias.delete((0,
|
|
835
|
+
env.typeAlias.delete((0, def_key_helpers_1.getGlobalDefKey)(fileNode));
|
|
490
836
|
}
|
|
491
837
|
else if (fileNode.concept === 'BusinessComponent') {
|
|
492
838
|
env.refMgr.compDefMgr.removeBusinessComponentDef(fileNode);
|
|
493
839
|
}
|
|
494
|
-
|
|
495
|
-
|
|
840
|
+
}
|
|
841
|
+
if (skipSubView) {
|
|
842
|
+
env.refMgr.clearLocalSymBindingsForFile(start, {
|
|
843
|
+
skipDescendantFileNodes: true,
|
|
844
|
+
isFileNode: file_node_cache_1.checkNodeIsFileModuleInIdeWithCache,
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
else {
|
|
848
|
+
env.refMgr.clearLocalSymBindingsForFile(start);
|
|
496
849
|
}
|
|
497
850
|
};
|
|
498
851
|
/**
|