@lcap/nasl-language-server-core 4.4.0-beta.9 → 4.4.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/out/checker.d.ts +2 -1
  2. package/out/checker.d.ts.map +1 -1
  3. package/out/checker.js +613 -92
  4. package/out/checker.js.map +1 -1
  5. package/out/reference-manager/collect-q-name.d.ts.map +1 -1
  6. package/out/reference-manager/collect-q-name.js +6 -3
  7. package/out/reference-manager/collect-q-name.js.map +1 -1
  8. package/out/reference-manager/get-q-name.d.ts.map +1 -1
  9. package/out/reference-manager/get-q-name.js +12 -4
  10. package/out/reference-manager/get-q-name.js.map +1 -1
  11. package/out/reference-manager/reference-manager.d.ts +94 -12
  12. package/out/reference-manager/reference-manager.d.ts.map +1 -1
  13. package/out/reference-manager/reference-manager.js +270 -77
  14. package/out/reference-manager/reference-manager.js.map +1 -1
  15. package/out/reference-manager/remove-q-name.d.ts.map +1 -1
  16. package/out/reference-manager/remove-q-name.js +7 -4
  17. package/out/reference-manager/remove-q-name.js.map +1 -1
  18. package/out/reference-manager/symbol-type.d.ts +1 -1
  19. package/out/reference-manager/symbol-type.d.ts.map +1 -1
  20. package/out/reference-manager/symbol-type.js +1 -0
  21. package/out/reference-manager/symbol-type.js.map +1 -1
  22. package/out/reference-manager/update-nasl-fragment.d.ts +2 -2
  23. package/out/reference-manager/update-nasl-fragment.d.ts.map +1 -1
  24. package/out/reference-manager/update-nasl-fragment.js +29 -24
  25. package/out/reference-manager/update-nasl-fragment.js.map +1 -1
  26. package/out/reference-manager/view-elem-logic.js.map +1 -1
  27. package/out/services/bindable-logic-service.js.map +1 -1
  28. package/out/symbol/traverse/concepts/index.d.ts +1 -1
  29. package/out/symbol/traverse/concepts/index.d.ts.map +1 -1
  30. package/out/symbol/traverse/concepts/logic/expression/member-expression.js.map +1 -1
  31. package/out/typer/collectGlobalDefs.d.ts +8 -0
  32. package/out/typer/collectGlobalDefs.d.ts.map +1 -1
  33. package/out/typer/collectGlobalDefs.js +74 -49
  34. package/out/typer/collectGlobalDefs.js.map +1 -1
  35. package/out/typer/dispatch-all.d.ts.map +1 -1
  36. package/out/typer/dispatch-all.js +3 -1
  37. package/out/typer/dispatch-all.js.map +1 -1
  38. package/out/typer/dispatch-call.d.ts.map +1 -1
  39. package/out/typer/dispatch-call.js +4 -0
  40. package/out/typer/dispatch-call.js.map +1 -1
  41. package/out/typer/dispatch-def.d.ts.map +1 -1
  42. package/out/typer/dispatch-def.js +45 -19
  43. package/out/typer/dispatch-def.js.map +1 -1
  44. package/out/typer/dispatch-expr.d.ts.map +1 -1
  45. package/out/typer/dispatch-expr.js +69 -60
  46. package/out/typer/dispatch-expr.js.map +1 -1
  47. package/out/typer/dispatch-process.d.ts +8 -1
  48. package/out/typer/dispatch-process.d.ts.map +1 -1
  49. package/out/typer/dispatch-process.js +34 -1
  50. package/out/typer/dispatch-process.js.map +1 -1
  51. package/out/typer/dispatch-stmt.js.map +1 -1
  52. package/out/typer/dispatch-view.d.ts.map +1 -1
  53. package/out/typer/dispatch-view.js +56 -20
  54. package/out/typer/dispatch-view.js.map +1 -1
  55. package/out/typer/fix-use-before-assign.js.map +1 -1
  56. package/out/typer/get-oql-files.d.ts.map +1 -1
  57. package/out/typer/get-oql-files.js +2 -8
  58. package/out/typer/get-oql-files.js.map +1 -1
  59. package/out/typer/incremental-update.d.ts +2 -5
  60. package/out/typer/incremental-update.d.ts.map +1 -1
  61. package/out/typer/incremental-update.js +95 -19
  62. package/out/typer/incremental-update.js.map +1 -1
  63. package/out/typer/oql-checker/ts-parser.d.ts.map +1 -1
  64. package/out/typer/oql-checker/ts-parser.js +99 -20
  65. package/out/typer/oql-checker/ts-parser.js.map +1 -1
  66. package/out/typer/overload-helper.d.ts.map +1 -1
  67. package/out/typer/overload-helper.js +185 -23
  68. package/out/typer/overload-helper.js.map +1 -1
  69. package/out/typer/solver.d.ts +1 -1
  70. package/out/typer/solver.d.ts.map +1 -1
  71. package/out/typer/solver.js +16 -4
  72. package/out/typer/solver.js.map +1 -1
  73. package/out/typer/subster.d.ts.map +1 -1
  74. package/out/typer/subster.js +32 -5
  75. package/out/typer/subster.js.map +1 -1
  76. package/out/typer/topo-sort.d.ts +1 -0
  77. package/out/typer/topo-sort.d.ts.map +1 -1
  78. package/out/typer/topo-sort.js +15 -5
  79. package/out/typer/topo-sort.js.map +1 -1
  80. package/out/typer/type-predicate.d.ts.map +1 -1
  81. package/out/typer/type-predicate.js +11 -3
  82. package/out/typer/type-predicate.js.map +1 -1
  83. package/out/typer/typer.d.ts +1 -1
  84. package/out/typer/typer.d.ts.map +1 -1
  85. package/out/typer/typer.js +14 -3
  86. package/out/typer/typer.js.map +1 -1
  87. package/out/typer/unifier.d.ts.map +1 -1
  88. package/out/typer/unifier.js +9 -7
  89. package/out/typer/unifier.js.map +1 -1
  90. package/out/utils/debug.js.map +1 -1
  91. package/out/utils/type-operator.d.ts +15 -0
  92. package/out/utils/type-operator.d.ts.map +1 -1
  93. package/out/utils/type-operator.js +65 -3
  94. package/out/utils/type-operator.js.map +1 -1
  95. package/package.json +5 -5
@@ -115,8 +115,20 @@ class ReferenceManager {
115
115
  // 暂无"局部类型",所以简化处理:
116
116
  return this.gSymbolImplicitRefs.get(nd) ?? emptySet;
117
117
  };
118
- // 删除一个 def 时,缓存其 qName 到引用符号的关系,为了方便之后还能 relink 恢复
119
- this.gCachedQNameSymbolRefs = new Map();
118
+ /**
119
+ * 待恢复引用缓存:删除节点时保存引用,创建同名节点时恢复引用后立即删除
120
+ * key: qName, value: Set<PendingRefInfo>
121
+ * 只在删除和创建之间临时使用,使用后立即清除,避免内存泄漏
122
+ *
123
+ * 使用场景:
124
+ * 1. 删除节点时:通过 cacheRefsForRecreation 保存引用节点
125
+ * 2. 创建同名节点时:通过 restoreRefsFromCache 恢复引用并清除缓存
126
+ *
127
+ * 设计说明:
128
+ * - 只存储引用节点本身
129
+ * - 恢复时会检查引用节点是否仍在 app 树上且仍引用原来的 qName
130
+ */
131
+ this.pendingRefsForRecreation = new Map();
120
132
  this.compDefMgr = new component_def_manager_1.ComponentDefManager();
121
133
  // 上一次查找引用局部符号建立的 cache
122
134
  this.lastBoundary = undefined;
@@ -332,8 +344,10 @@ class ReferenceManager {
332
344
  for (const triggerLauncher of app.triggerLaunchers) {
333
345
  allRefs.push(...this.collectRefs(env, triggerLauncher));
334
346
  }
335
- for (const metadataType of app.metadataTypes) {
336
- allRefs.push(...this.collectRefs(env, metadataType));
347
+ if (String(app?.preferenceMap?.metadataTypeEnable) === 'true') {
348
+ for (const metadataType of app.metadataTypes) {
349
+ allRefs.push(...this.collectRefs(env, metadataType));
350
+ }
337
351
  }
338
352
  // for (const preference of app.preferenceMap) {
339
353
  // allRefs.push(...this.collectRefs(env, preference as any as ValidExtInp));
@@ -353,7 +367,7 @@ class ReferenceManager {
353
367
  // Cache reference for future relinking
354
368
  // FIXME:这里有问题,脏脏的,比如局部变量、入参等都扔到这里面了,虽然暂时可能没有太大的正确性问题,但有内存泄漏
355
369
  if (!(0, helper_2.cheapTestLocalSymbol)(qName)) {
356
- (0, helper_1.createSetOnPush)(this.gCachedQNameSymbolRefs, qName, ref);
370
+ this.addRefToPendingCache(qName, ref);
357
371
  }
358
372
  }
359
373
  });
@@ -456,6 +470,23 @@ class ReferenceManager {
456
470
  const qName = (0, get_q_name_1.getTokenQualifiedName)(ref);
457
471
  return qName ? this.gQNameDefs.get(qName) : undefined;
458
472
  };
473
+ /**
474
+ * 查找符号的定义,同时查找全局定义和 View 级别的定义
475
+ * 用于构建调用图时查找 View 级别的 logics
476
+ * @param ref
477
+ * @returns
478
+ */
479
+ this.getNodeDefIncludingView = (ref) => {
480
+ const qName = (0, get_q_name_1.getTokenQualifiedName)(ref);
481
+ if (!qName)
482
+ return undefined;
483
+ // 先查找全局定义
484
+ const globalDef = this.gQNameDefs.get(qName);
485
+ if (globalDef)
486
+ return globalDef;
487
+ // 再查找 View 级别的定义
488
+ return this.veQNameDefs.get(qName);
489
+ };
459
490
  /**
460
491
  * @warning 对外接口,指用户点击 "查找引用",只返回用户手动指定的引用
461
492
  * @param __nd 要查找引用的定义
@@ -662,52 +693,203 @@ class ReferenceManager {
662
693
  // 重命名时不需要处理 sourceRef targetRef,好像其他逻辑已经处理掉了
663
694
  return result;
664
695
  };
696
+ this.updateRefsInNaslFragment = update_nasl_fragment_1.updateRefsInNaslFragment;
697
+ /**
698
+ * 添加引用到缓存(内部方法,统一管理 pendingRefsForRecreation)
699
+ * @param qName 节点的 qName
700
+ * @param ref 要缓存的引用
701
+ */
702
+ this.addRefToPendingCache = (qName, ref) => {
703
+ if (!this.pendingRefsForRecreation.has(qName)) {
704
+ this.pendingRefsForRecreation.set(qName, new Set());
705
+ }
706
+ // 只记录引用节点本身
707
+ const refInfo = {
708
+ ref,
709
+ };
710
+ this.pendingRefsForRecreation.get(qName).add(refInfo);
711
+ };
665
712
  /**
666
- * qNameDef 中删除 oldQName ==> def
667
- * qNameDef 中建立 newQName ==> def
668
- * def 内存地址相同
669
- * 如果 mode 是 'update',则 newQName 的引用集合是 oldQName 在 symbolRefs 中的既存引用
670
- * 合并上 新名字在 cachedQNameSymbolRefs 中的既存引用。
671
- * 新名字在 cachedQNameSymbolRefs 中的引用将被删除。
713
+ * 缓存引用以备后续恢复(在删除节点时调用)
714
+ * @param qName 节点的 qName
715
+ * @param defNode 要删除的节点
672
716
  *
673
- * 如果 mode 是其他,则 newQName 的引用集合是 newQName 在 cachedQNameSymbolRefs 中的既存引用。
674
- * oldQName 的引用将被放入 cachedQNameSymbolRefs
675
- * 删除 newQName 的缓存引用
717
+ * 使用场景:删除节点时,保存引用节点本身到 pendingRefsForRecreation,以便后续创建同名节点时恢复引用
718
+ *
719
+ * 设计说明:
720
+ * - 只存储引用节点本身(因为需要它来建立引用关系)
721
+ * - 恢复时会检查引用节点是否仍在 app 树上且仍引用原来的 qName
676
722
  */
677
- this.transferQNameDef = (oldQName, newQName, mode) => {
678
- if (!oldQName || !newQName)
679
- return;
680
- const oldDef = this.gQNameDefs.get(oldQName);
681
- if (!oldDef)
723
+ this.cacheRefsForRecreation = (qName, defNode) => {
724
+ if (!(0, symbol_type_1.isGlobalDef)(defNode)) {
682
725
  return;
683
- // 1. 删除 oldQName,建立 newQName,def 地址不变
684
- this.gQNameDefs.delete(oldQName);
685
- this.gQNameDefs.set(newQName, oldDef);
686
- // 2. 处理引用集合
687
- if (mode === 'update') {
688
- // 获取 oldQName 的既存引用
689
- const oldRefs = this.gSymbolRefs.get(oldDef) ?? new Set();
690
- // 获取 newQName 在缓存中的引用
691
- const newCachedRefs = this.gCachedQNameSymbolRefs.get(newQName) ?? new Set();
692
- // 合并引用集合
693
- const mergedRefs = mnemonist_1.set.union(oldRefs, newCachedRefs);
694
- // 设置新名字的引用集合
695
- mergedRefs.size > 0 && this.setSymbolRefs(oldDef, mergedRefs);
696
- // 删除 newQName 在缓存中的引用
697
- this.gCachedQNameSymbolRefs.delete(newQName);
698
726
  }
699
- else {
700
- // 不是 update,直接取 newQName 在缓存中的引用
701
- const newCachedRefs = this.gCachedQNameSymbolRefs.get(newQName) ?? new Set();
702
- this.setSymbolRefs(oldDef, newCachedRefs);
703
- // oldQName 的引用集合被放入 cachedQNameSymbolRefs
704
- const oldRefs = this.gSymbolRefs.get(oldDef) ?? new Set();
705
- oldRefs.size > 0 && this.gCachedQNameSymbolRefs.set(oldQName, oldRefs);
706
- // 删除 newQName 在缓存中的引用
707
- this.gCachedQNameSymbolRefs.delete(newQName);
727
+ const refs = this.getSymbolRefs(defNode);
728
+ if (refs && refs.size > 0) {
729
+ // 只记录引用节点本身
730
+ const refInfos = new Set();
731
+ for (const ref of refs) {
732
+ const refInfo = {
733
+ ref,
734
+ };
735
+ refInfos.add(refInfo);
736
+ }
737
+ this.pendingRefsForRecreation.set(qName, refInfos);
708
738
  }
709
739
  };
710
- this.updateRefsInNaslFragment = update_nasl_fragment_1.updateRefsInNaslFragment;
740
+ /**
741
+ * 检查引用是否仍在 app 树上
742
+ *
743
+ * 方法:
744
+ * 向上遍历 parentNode 链,检查每个节点是否在其父节点的子节点集合中
745
+ * (因为删除节点时可能不会把 parentNode 设置为 null,但会从父节点的子节点集合中移除)
746
+ *
747
+ * 如果链上的任何节点不在其父节点的子节点集合中,说明已被删除,不在 app 树上
748
+ * 如果能到达 App 节点,说明引用仍在 app 树上
749
+ */
750
+ this.isRefStillInAppTree = (ref) => {
751
+ try {
752
+ if (!ref || !ref.concept) {
753
+ return false;
754
+ }
755
+ let currentNode = ref;
756
+ let depth = 0;
757
+ const maxDepth = 100; // 防止无限循环
758
+ // 向上遍历 parentNode 链,查找 App 节点
759
+ while (currentNode && depth < maxDepth) {
760
+ if (currentNode.concept === 'App') {
761
+ // 找到了 App 节点,说明引用仍在 app 树上
762
+ return true;
763
+ }
764
+ // 检查当前节点是否在其父节点的子节点集合中
765
+ // 如果节点被删除了,即使 parentNode 还存在,节点也不会在父节点的子节点集合中
766
+ const parentNode = currentNode.parentNode;
767
+ if (parentNode && currentNode.parentKey) {
768
+ const parentProperty = parentNode[currentNode.parentKey];
769
+ if (Array.isArray(parentProperty)) {
770
+ // 如果是数组,检查节点是否在数组中
771
+ if (parentProperty.indexOf(currentNode) === -1) {
772
+ // 节点不在父节点的子节点集合中,说明已被删除
773
+ return false;
774
+ }
775
+ }
776
+ else if (parentProperty !== currentNode) {
777
+ // 如果是单个属性,检查是否指向当前节点
778
+ // 节点不在父节点的子节点集合中,说明已被删除
779
+ return false;
780
+ }
781
+ }
782
+ currentNode = parentNode;
783
+ depth++;
784
+ }
785
+ // 无法到达 App 节点,说明引用已不在 app 树上(节点已被删除)
786
+ return false;
787
+ }
788
+ catch {
789
+ // 如果访问节点属性时出错,说明节点已被删除
790
+ return false;
791
+ }
792
+ };
793
+ /**
794
+ * 检查引用节点是否仍引用指定的 qName
795
+ * @param ref 引用节点
796
+ * @param qName 要检查的 qName
797
+ * @returns 如果引用节点仍引用指定的 qName,返回 true;否则返回 false
798
+ */
799
+ this.isRefStillReferencingQName = (ref, qName) => {
800
+ try {
801
+ // 通过 getTokenQualifiedName 获取引用节点当前引用的 qName
802
+ const currentQName = (0, get_q_name_1.getTokenQualifiedName)(ref);
803
+ // 检查是否还引用原来的 qName
804
+ return currentQName === qName;
805
+ }
806
+ catch {
807
+ // 如果获取失败,返回 false
808
+ return false;
809
+ }
810
+ };
811
+ /**
812
+ * 从缓存恢复引用(在创建节点时调用)
813
+ * @param qName 节点的 qName
814
+ * @param defNode 新创建的节点
815
+ * @returns 是否成功恢复引用
816
+ *
817
+ * 使用场景:创建节点时,如果有缓存的引用信息(来自删除操作),则恢复引用关系
818
+ *
819
+ * 恢复策略:
820
+ * 1. 使用引用节点本身(如果节点仍然有效)
821
+ * 2. 检查引用节点是否仍在 app 树上(过滤掉已删除的引用)
822
+ * 3. **关键**:检查引用节点是否仍引用原来的 qName(如果引用内容已改变,则不恢复)
823
+ * 4. 重新建立引用关系
824
+ */
825
+ this.restoreRefsFromCache = (qName, defNode) => {
826
+ if (!(0, symbol_type_1.isGlobalDef)(defNode)) {
827
+ return false;
828
+ }
829
+ const cachedRefInfos = this.pendingRefsForRecreation.get(qName);
830
+ if (!cachedRefInfos || cachedRefInfos.size === 0) {
831
+ return false;
832
+ }
833
+ const validRefs = new Set();
834
+ for (const refInfo of cachedRefInfos) {
835
+ // 检查引用节点是否仍在 app 树上
836
+ if (!this.isRefStillInAppTree(refInfo.ref)) {
837
+ continue;
838
+ }
839
+ // 检查引用节点是否仍引用原来的 qName
840
+ if (this.isRefStillReferencingQName(refInfo.ref, qName)) {
841
+ // 引用节点仍然有效且仍引用原来的 qName,添加到恢复集合中
842
+ validRefs.add(refInfo.ref);
843
+ }
844
+ }
845
+ // 如果有有效的引用,恢复它们
846
+ if (validRefs.size > 0) {
847
+ this.setSymbolRefs(defNode, validRefs);
848
+ }
849
+ // 使用后立即删除缓存,避免内存泄漏
850
+ this.pendingRefsForRecreation.delete(qName);
851
+ return validRefs.size > 0;
852
+ };
853
+ /**
854
+ * 获取待恢复引用缓存中的引用(用于查询场景,如 getOqlFiles)
855
+ * @param qName 节点的 qName
856
+ * @param app 可选的 App 实例(保留参数以保持向后兼容,但不再使用)
857
+ * @returns 缓存的引用集合,如果没有则返回 undefined
858
+ *
859
+ * 注意:只使用引用节点本身,检查引用节点是否仍在 app 树上且仍引用原来的 qName
860
+ */
861
+ this.getPendingRefsForRecreation = (qName, app) => {
862
+ const refInfos = this.pendingRefsForRecreation.get(qName);
863
+ if (!refInfos) {
864
+ return undefined;
865
+ }
866
+ const refs = new Set();
867
+ for (const refInfo of refInfos) {
868
+ // 检查引用节点是否仍在 app 树上
869
+ if (!this.isRefStillInAppTree(refInfo.ref)) {
870
+ continue;
871
+ }
872
+ // 检查引用节点是否仍引用原来的 qName
873
+ if (this.isRefStillReferencingQName(refInfo.ref, qName)) {
874
+ refs.add(refInfo.ref);
875
+ }
876
+ }
877
+ return refs;
878
+ };
879
+ /**
880
+ * 获取待恢复引用缓存的大小(用于测试和调试)
881
+ * @returns 缓存中 qName 的数量
882
+ */
883
+ this.getPendingRefsForRecreationSize = () => {
884
+ return this.pendingRefsForRecreation.size;
885
+ };
886
+ /**
887
+ * 清除所有待恢复引用缓存
888
+ * 用于清理操作,避免内存泄漏
889
+ */
890
+ this.clearPendingRefsCache = () => {
891
+ this.pendingRefsForRecreation.clear();
892
+ };
711
893
  /**
712
894
  * @warning Only handle global symbols
713
895
  */
@@ -719,16 +901,14 @@ class ReferenceManager {
719
901
  this.isLocalCacheValid = false;
720
902
  }
721
903
  else {
722
- // 可以链接回旧的引用,类似于 rename
723
- const oldRefs = this.gCachedQNameSymbolRefs.get(qName);
724
- oldRefs && this.setSymbolRefs(defNode, oldRefs);
725
904
  // qName 链接到新的 defNode 的 mem addr
726
905
  this.gQNameDefs.set(qName, defNode);
727
906
  if ((0, component_def_manager_1.isGeneralViewElementDefinition)(defNode)) {
728
907
  this.compDefMgr.add(defNode, 'handleDefOp');
729
908
  }
730
- // 删除缓存
731
- this.gCachedQNameSymbolRefs.delete(qName);
909
+ // 尝试从缓存恢复引用(来自删除操作)
910
+ // 如果恢复成功,缓存会被自动清除;如果失败,引用会在类型检查时自动重新建立
911
+ this.restoreRefsFromCache(qName, defNode);
732
912
  }
733
913
  break;
734
914
  }
@@ -737,17 +917,9 @@ class ReferenceManager {
737
917
  this.isLocalCacheValid = false;
738
918
  }
739
919
  else {
740
- const refs = this.getSymbolRefs(defNode);
741
- if (refs) {
742
- if (refs.size > 0) {
743
- // 过滤掉 BindAttribute 的引用,因为 BindAttribute 的引用很容易冗余
744
- // 使用类型断言因为 BindAttribute 是特殊的引用类型,未包含在 RefConcept 中
745
- this.gCachedQNameSymbolRefs.set(qName, new Set(Array.from(refs).filter(ref => ref.concept !== 'BindAttribute')));
746
- }
747
- else {
748
- this.gCachedQNameSymbolRefs.set(qName, refs);
749
- }
750
- }
920
+ // 缓存引用以备后续恢复(在删除引用之前调用)
921
+ this.cacheRefsForRecreation(qName, defNode);
922
+ // 删除 qName 和引用
751
923
  this.gQNameDefs.delete(qName);
752
924
  if ((0, component_def_manager_1.isGeneralViewElementDefinition)(defNode)) {
753
925
  this.compDefMgr.removeComponentGroup(defNode);
@@ -778,19 +950,8 @@ class ReferenceManager {
778
950
  }
779
951
  }
780
952
  }
781
- else {
782
- // cache 里的也要处理……
783
- switch (mode) {
784
- case "create" /* Operation.Create */: {
785
- (0, fp_macros_1.createOnAdd)(this.gCachedQNameSymbolRefs, qName, refNd);
786
- break;
787
- }
788
- case "delete" /* Operation.Remove */: {
789
- this.gCachedQNameSymbolRefs.get(qName)?.delete(refNd);
790
- break;
791
- }
792
- }
793
- }
953
+ // 注意:如果定义不存在,引用会被忽略
954
+ // 类型检查时会重新建立引用关系
794
955
  };
795
956
  this.handleSymbolImplicitRefs = (nd) => {
796
957
  if (!nd)
@@ -932,6 +1093,18 @@ class ReferenceManager {
932
1093
  }
933
1094
  });
934
1095
  };
1096
+ /**
1097
+ * 处理 ProcessElementV2 的 CallSubProcess 类型对 ProcessV2 的引用
1098
+ * 当 ProcessElementV2 的 type === 'CallSubProcess' 时,subProcessKey 字段引用另一个 ProcessV2 的 uniqueKey
1099
+ */
1100
+ this.handleProcessSubProcessRef = (env, nd) => {
1101
+ if (nd.type !== 'CallSubProcess' || !nd.subProcessKey) {
1102
+ return;
1103
+ }
1104
+ // subProcessKey 就是 ProcessV2 的 uniqueKey,直接作为 qName 使用
1105
+ const subProcessQName = nd.subProcessKey;
1106
+ this.handleRefOp(this.modeForCollect, nd, subProcessQName);
1107
+ };
935
1108
  /**
936
1109
  * 无论根节点是 ref 还是 def,都要递归收集下层所有的引用节点
937
1110
  * 会打散 a.b.c、A | B、x.a.b 等结构,并记录必要的信息
@@ -974,6 +1147,8 @@ class ReferenceManager {
974
1147
  n.concept === 'EntityProperty' && this.handleForeignKeyRef(env, n);
975
1148
  n.concept === 'AssigneeV2' && this.handleBindRoles(env, n);
976
1149
  n.concept === 'CallAuthInterface' && this.handleAuthLogicRef(env, n);
1150
+ // 处理流程子流程引用
1151
+ n.concept === 'ProcessElementV2' && this.handleProcessSubProcessRef(env, n);
977
1152
  if (!symbol_type_1.refConcept.includes(n.concept)) {
978
1153
  return;
979
1154
  }
@@ -1187,7 +1362,15 @@ class ReferenceManager {
1187
1362
  processVar = (0, typer_1.createProcessVariable)(env, proc);
1188
1363
  (0, helper_1.createOnPush)(env.allocatedVirtualNodes, this.curFileNode, processVar);
1189
1364
  });
1190
- if (symbol_type_1.refConcept.includes(id0.concept)) {
1365
+ // 处理 processVariable.variable1 的情况
1366
+ // processVariable 是虚拟变量,不需要添加引用,只需要设置类型以便后续处理
1367
+ if (processVar && id0.name === 'processVariable') {
1368
+ const procVarTy = env.getType(processVar);
1369
+ if (procVarTy) {
1370
+ env.setType(id0, procVarTy);
1371
+ }
1372
+ }
1373
+ else if (symbol_type_1.refConcept.includes(id0.concept)) {
1191
1374
  const qName = (0, get_q_name_1.getTokenQualifiedName)(id0);
1192
1375
  let isProcessRef = false;
1193
1376
  if (qName) {
@@ -1231,7 +1414,17 @@ class ReferenceManager {
1231
1414
  }
1232
1415
  // 是这样的,为了兼容 processVariable.variable1,前面的是匿名数据结构,只需要 variable1 的引用就行了
1233
1416
  let ndDef = this.getNodeDef(ty);
1234
- if (ndDef && (ndDef.concept === 'Entity' || ndDef.concept === 'Structure' || ndDef.concept === 'Enum')) {
1417
+ // 处理 processVariable.variable1 的情况:匿名结构类型,需要添加 processVariable.variable1 的引用
1418
+ if (ty.typeKind === 'anonymousStructure' && ids[0].name === 'processVariable' && processVar) {
1419
+ const procDef = processVar.parentNode;
1420
+ if (procDef && procDef.concept === 'ProcessDefinitionV2') {
1421
+ const procVar = procDef.variables?.find((v) => v.name === ids[i + 1].name);
1422
+ if (procVar) {
1423
+ res.push([ids[i + 1], `processVariable.${ids[i + 1].name}`]);
1424
+ }
1425
+ }
1426
+ }
1427
+ else if (ndDef && (ndDef.concept === 'Entity' || ndDef.concept === 'Structure' || ndDef.concept === 'Enum')) {
1235
1428
  const propQName = (0, string_2.getPropQName)(`${ty.typeNamespace}.${ty.typeName}`, ids[i + 1].name, 'Entity');
1236
1429
  res.push([ids[i + 1], propQName]); // type reference
1237
1430
  }
@@ -1358,7 +1551,7 @@ class ReferenceManager {
1358
1551
  const stats = {
1359
1552
  gQNameDefs: this.gQNameDefs,
1360
1553
  symbolRefs: this.gSymbolRefs, // Exporting private map for serialization
1361
- cachedQNameSymbolRefs: this.gCachedQNameSymbolRefs,
1554
+ pendingRefsForRecreation: this.pendingRefsForRecreation, // Exporting private map for serialization
1362
1555
  localQNameRefs: this.lQNameRefs,
1363
1556
  compDefMgr: this.compDefMgr,
1364
1557
  };
@@ -1531,11 +1724,11 @@ class ReferenceManager {
1531
1724
  clearAll() {
1532
1725
  this.clearSymbolRefs();
1533
1726
  this.gQNameDefs.clear();
1534
- this.gCachedQNameSymbolRefs.clear();
1535
1727
  this.lQNameRefs.clear();
1536
1728
  this.veQNameDefs.clear();
1537
1729
  this.veRefs.clear();
1538
1730
  this.compDefMgr.clearAll();
1731
+ this.clearPendingRefsCache(); // 清除待恢复引用缓存
1539
1732
  this.gSymbolImplicitRefs = new WeakMap();
1540
1733
  }
1541
1734
  }