@lcap/nasl-language-server-core 4.4.0-rc.1 → 4.4.1-rc.1

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 (121) hide show
  1. package/out/checker.d.ts.map +1 -1
  2. package/out/checker.js +250 -17
  3. package/out/checker.js.map +1 -1
  4. package/out/index.d.ts +1 -1
  5. package/out/index.d.ts.map +1 -1
  6. package/out/index.js +5 -3
  7. package/out/index.js.map +1 -1
  8. package/out/reference-manager/build-q-name-def.d.ts.map +1 -1
  9. package/out/reference-manager/build-q-name-def.js +11 -0
  10. package/out/reference-manager/build-q-name-def.js.map +1 -1
  11. package/out/reference-manager/builtin-q-name.js +2 -2
  12. package/out/reference-manager/builtin-q-name.js.map +1 -1
  13. package/out/reference-manager/collect-q-name.d.ts +1 -1
  14. package/out/reference-manager/collect-q-name.d.ts.map +1 -1
  15. package/out/reference-manager/collect-q-name.js +58 -24
  16. package/out/reference-manager/collect-q-name.js.map +1 -1
  17. package/out/reference-manager/def-key-helpers.d.ts +38 -0
  18. package/out/reference-manager/def-key-helpers.d.ts.map +1 -0
  19. package/out/reference-manager/{get-q-name.js → def-key-helpers.js} +183 -19
  20. package/out/reference-manager/def-key-helpers.js.map +1 -0
  21. package/out/reference-manager/helper.js +2 -2
  22. package/out/reference-manager/helper.js.map +1 -1
  23. package/out/reference-manager/reference-manager.d.ts +60 -43
  24. package/out/reference-manager/reference-manager.d.ts.map +1 -1
  25. package/out/reference-manager/reference-manager.js +381 -146
  26. package/out/reference-manager/reference-manager.js.map +1 -1
  27. package/out/reference-manager/remove-q-name.d.ts +1 -1
  28. package/out/reference-manager/remove-q-name.d.ts.map +1 -1
  29. package/out/reference-manager/remove-q-name.js +7 -10
  30. package/out/reference-manager/remove-q-name.js.map +1 -1
  31. package/out/reference-manager/rename-q-name.d.ts +26 -26
  32. package/out/reference-manager/rename-q-name.d.ts.map +1 -1
  33. package/out/reference-manager/rename-q-name.js +48 -167
  34. package/out/reference-manager/rename-q-name.js.map +1 -1
  35. package/out/reference-manager/symbol-type.d.ts +8 -3
  36. package/out/reference-manager/symbol-type.d.ts.map +1 -1
  37. package/out/reference-manager/symbol-type.js +8 -2
  38. package/out/reference-manager/symbol-type.js.map +1 -1
  39. package/out/reference-manager/update-nasl-fragment.js +4 -4
  40. package/out/reference-manager/update-nasl-fragment.js.map +1 -1
  41. package/out/services/bindable-logic-service.js.map +1 -1
  42. package/out/symbol/traverse/concepts/logic/expression/member-expression.js.map +1 -1
  43. package/out/typer/collectGlobalDefs.d.ts +8 -0
  44. package/out/typer/collectGlobalDefs.d.ts.map +1 -1
  45. package/out/typer/collectGlobalDefs.js +77 -52
  46. package/out/typer/collectGlobalDefs.js.map +1 -1
  47. package/out/typer/component-def-manager/component-def-manager.d.ts +16 -0
  48. package/out/typer/component-def-manager/component-def-manager.d.ts.map +1 -1
  49. package/out/typer/component-def-manager/component-def-manager.js +63 -2
  50. package/out/typer/component-def-manager/component-def-manager.js.map +1 -1
  51. package/out/typer/component-def-manager/utils.d.ts.map +1 -1
  52. package/out/typer/component-def-manager/utils.js +26 -0
  53. package/out/typer/component-def-manager/utils.js.map +1 -1
  54. package/out/typer/dispatch-all.d.ts +3 -1
  55. package/out/typer/dispatch-all.d.ts.map +1 -1
  56. package/out/typer/dispatch-all.js +48 -5
  57. package/out/typer/dispatch-all.js.map +1 -1
  58. package/out/typer/dispatch-call.d.ts +27 -1
  59. package/out/typer/dispatch-call.d.ts.map +1 -1
  60. package/out/typer/dispatch-call.js +141 -107
  61. package/out/typer/dispatch-call.js.map +1 -1
  62. package/out/typer/dispatch-def.d.ts.map +1 -1
  63. package/out/typer/dispatch-def.js +3 -3
  64. package/out/typer/dispatch-def.js.map +1 -1
  65. package/out/typer/dispatch-expr.d.ts.map +1 -1
  66. package/out/typer/dispatch-expr.js +32 -73
  67. package/out/typer/dispatch-expr.js.map +1 -1
  68. package/out/typer/dispatch-process.js +3 -3
  69. package/out/typer/dispatch-process.js.map +1 -1
  70. package/out/typer/dispatch-stmt.d.ts.map +1 -1
  71. package/out/typer/dispatch-stmt.js +9 -11
  72. package/out/typer/dispatch-stmt.js.map +1 -1
  73. package/out/typer/dispatch-view.d.ts +1 -1
  74. package/out/typer/dispatch-view.d.ts.map +1 -1
  75. package/out/typer/dispatch-view.js +37 -28
  76. package/out/typer/dispatch-view.js.map +1 -1
  77. package/out/typer/fix-use-before-assign.js.map +1 -1
  78. package/out/typer/get-oql-files.js +1 -1
  79. package/out/typer/get-oql-files.js.map +1 -1
  80. package/out/typer/incremental-update.d.ts +2 -2
  81. package/out/typer/incremental-update.d.ts.map +1 -1
  82. package/out/typer/incremental-update.js +142 -30
  83. package/out/typer/incremental-update.js.map +1 -1
  84. package/out/typer/overload-helper.d.ts.map +1 -1
  85. package/out/typer/overload-helper.js +52 -16
  86. package/out/typer/overload-helper.js.map +1 -1
  87. package/out/typer/solver.d.ts +8 -9
  88. package/out/typer/solver.d.ts.map +1 -1
  89. package/out/typer/solver.js +43 -32
  90. package/out/typer/solver.js.map +1 -1
  91. package/out/typer/subster.d.ts.map +1 -1
  92. package/out/typer/subster.js +101 -20
  93. package/out/typer/subster.js.map +1 -1
  94. package/out/typer/topo-sort.d.ts +37 -0
  95. package/out/typer/topo-sort.d.ts.map +1 -1
  96. package/out/typer/topo-sort.js +264 -5
  97. package/out/typer/topo-sort.js.map +1 -1
  98. package/out/typer/type-manager.d.ts +1 -0
  99. package/out/typer/type-manager.d.ts.map +1 -1
  100. package/out/typer/type-manager.js +14 -11
  101. package/out/typer/type-manager.js.map +1 -1
  102. package/out/typer/type-predicate.d.ts.map +1 -1
  103. package/out/typer/type-predicate.js +11 -5
  104. package/out/typer/type-predicate.js.map +1 -1
  105. package/out/typer/typer.d.ts +18 -3
  106. package/out/typer/typer.d.ts.map +1 -1
  107. package/out/typer/typer.js +70 -29
  108. package/out/typer/typer.js.map +1 -1
  109. package/out/typer/unifier.d.ts +2 -0
  110. package/out/typer/unifier.d.ts.map +1 -1
  111. package/out/typer/unifier.js +40 -32
  112. package/out/typer/unifier.js.map +1 -1
  113. package/out/utils/debug.js.map +1 -1
  114. package/package.json +5 -5
  115. package/out/reference-manager/get-q-name.d.ts +0 -9
  116. package/out/reference-manager/get-q-name.d.ts.map +0 -1
  117. package/out/reference-manager/get-q-name.js.map +0 -1
  118. package/out/reference-manager/view-elem-logic.d.ts +0 -44
  119. package/out/reference-manager/view-elem-logic.d.ts.map +0 -1
  120. package/out/reference-manager/view-elem-logic.js +0 -181
  121. package/out/reference-manager/view-elem-logic.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"checker.d.ts","sourceRoot":"","sources":["../src/checker.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,UAAU,EAC4C,QAAQ,EAC5B,IAAI,EAQ+E,GAAG,EAMxH,QAAQ,EAGT,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACgE,cAAc,EAGpF,MAAM,qBAAqB,CAAC;AAS7B,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAK5C,OAAO,EAAE,UAAU,IAAI,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAWpE,oBAAY,QAAQ;IAClB,IAAI,YAAY;IAChB,KAAK,UAAU;CAChB;AAED,MAAM,MAAM,UAAU,GAAG,kBAAkB,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;AAEnE,KAAK,YAAY,GAAG;IAClB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB,CAAC;AAMF,MAAM,MAAM,kBAAkB,GAAG,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;AAEpE,MAAM,MAAM,kBAAkB,GAAG,GAAG,CAAC,UAAU,EAAE,kBAAkB,CAAC,CAAC;AAMrE,KAAK,gBAAgB,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAqBF,KAAK,eAAe,GAAG;IACrB,GAAG,EAAE,GAAG,CAAC;IACT,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,OAAO,CAAC;IACf,yBAAyB,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC/C,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB,CAAC;AAkPF;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,eAAe;oCAykKpB,OAAO;sDAPW,gBAAgB,EAAE;;;;sBAhBjD,UAAU,GAAG,SAAS;;;8BA4Df,UAAU;2BAyBb,UAAU;;iDAlwFY,GAAG,KAAG,IAAI;;iBA6wFjD,MAAM;kBACL,MAAM;kBACN,MAAM;qBACH,MAAM;;kBA1lKF,UAAU,WAAW,MAAM,YAAY,YAAY;sCAk1D/B,IAAI,GAAG,QAAQ;2CA2yGxC,UAAU,gBACV,CAAC,YAAY,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,gBAC/C,CAAC,GAAG,EAAE,UAAU,KAAK,OAAO,qBACvB,MAAM,EAAE,oBACT,CAAC,YAAY,EAAE,UAAU,KAAK,UAAU,EAAE,KAC3D,kBAAkB,GAAG,IAAI;EAwF7B;AAGD,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IAEX,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IACrC,mBAAmB,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IACvC,qBAAqB,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;CAC1C;AAMD,eAAO,MAAM,6BAA6B,aAC9B,UAAU,+DAGnB,MAAM,gBAAgB,CAyCxB,CAAC;AAMF,MAAM,MAAM,cAAc,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC"}
1
+ {"version":3,"file":"checker.d.ts","sourceRoot":"","sources":["../src/checker.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,UAAU,EAC4C,QAAQ,EAC5B,IAAI,EAQ+E,GAAG,EAMxH,QAAQ,EAGT,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACgE,cAAc,EAGpF,MAAM,qBAAqB,CAAC;AAS7B,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAK5C,OAAO,EAAE,UAAU,IAAI,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAYpE,oBAAY,QAAQ;IAClB,IAAI,YAAY;IAChB,KAAK,UAAU;CAChB;AAED,MAAM,MAAM,UAAU,GAAG,kBAAkB,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;AAEnE,KAAK,YAAY,GAAG;IAClB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB,CAAC;AAOF,MAAM,MAAM,kBAAkB,GAAG,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;AAEpE,MAAM,MAAM,kBAAkB,GAAG,GAAG,CAAC,UAAU,EAAE,kBAAkB,CAAC,CAAC;AAMrE,KAAK,gBAAgB,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAqBF,KAAK,eAAe,GAAG;IACrB,GAAG,EAAE,GAAG,CAAC;IACT,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,OAAO,CAAC;IACf,yBAAyB,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC/C,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB,CAAC;AAmPF;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,eAAe;oCAowKpB,OAAO;sDAPW,gBAAgB,EAAE;;;;sBAhBjD,UAAU,GAAG,SAAS;;;8BA4Df,UAAU;2BAyBb,UAAU;;iDAl2FY,GAAG,KAAG,IAAI;;iBA62FjD,MAAM;kBACL,MAAM;kBACN,MAAM;qBACH,MAAM;;kBAjxKF,UAAU,WAAW,MAAM,YAAY,YAAY;sCA04D/B,IAAI,GAAG,QAAQ;2CA06GxC,UAAU,gBACV,CAAC,YAAY,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,gBAC/C,CAAC,GAAG,EAAE,UAAU,KAAK,OAAO,qBACvB,MAAM,EAAE,oBACT,CAAC,YAAY,EAAE,UAAU,KAAK,UAAU,EAAE,KAC3D,kBAAkB,GAAG,IAAI;EAwF7B;AAqED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IAEX,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IACrC,mBAAmB,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IACvC,qBAAqB,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;CAC1C;AAMD,eAAO,MAAM,6BAA6B,aAC9B,UAAU,+DAGnB,MAAM,gBAAgB,CAyCxB,CAAC;AAMF,MAAM,MAAM,cAAc,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC"}
package/out/checker.js CHANGED
@@ -14,6 +14,7 @@ const lodash_1 = require("lodash");
14
14
  const asserts_1 = require("@lcap/nasl-concepts/asserts");
15
15
  const helper_1 = require("./typer/helper");
16
16
  const semantic_rules_1 = require("./semantic-rules");
17
+ const view_element_field_attrs_1 = require("@lcap/nasl-concepts/view-element-field-attrs");
17
18
  const regeExp = new nasl_utils_1.ExpressionLexer();
18
19
  regeExp.profile = nasl_utils_1.profiles.js;
19
20
  var Severity;
@@ -73,6 +74,7 @@ function getExpressionNodeName(concept) {
73
74
  CallMicroserviceInterface: '微服务接口',
74
75
  CallGatewayInterface: '网关接口',
75
76
  CallEvent: '事件',
77
+ Destination: '页面',
76
78
  };
77
79
  return expressionNodeName[concept];
78
80
  }
@@ -254,6 +256,8 @@ function createErrorDiagnoser(context) {
254
256
  let app = context.app;
255
257
  let env = context.env;
256
258
  let isDebug = context.debug;
259
+ // 严格模式
260
+ let isStrictMode = context.isStrictMode;
257
261
  // 引用管理器
258
262
  let referenceManager = env.refMgr;
259
263
  // 检查共享数据是否有更新
@@ -266,6 +270,8 @@ function createErrorDiagnoser(context) {
266
270
  let inModule = false;
267
271
  let inPlayground = 0;
268
272
  let inAuthLogic = false;
273
+ let inFrontendType = false;
274
+ let currentFrontendKind = '';
269
275
  let dbType = '';
270
276
  let curVarCounter = 0;
271
277
  const listComponentStack = [];
@@ -313,6 +319,16 @@ function createErrorDiagnoser(context) {
313
319
  diagnosticMap.set(curFileNode, diagnostics);
314
320
  }
315
321
  if (diagnostics) {
322
+ const parentKey = node?.parentKey;
323
+ const parentConcept = node.parentNode?.concept;
324
+ if (message.startsWith('类型不匹配:') &&
325
+ ((parentKey === 'test' && parentConcept === 'IfStatement') || (parentKey === 'condition' && parentConcept === 'IfExpression'))) {
326
+ const map = {
327
+ 'IfExpression': 'If表达式',
328
+ 'IfStatement': 'If语句',
329
+ };
330
+ message = `${map[parentConcept]}条件槽位${message}`;
331
+ }
316
332
  const diagnostic = {
317
333
  message,
318
334
  severity: inPlayground > 0 ? Severity.WARN : (severity ?? Severity.ERROR),
@@ -775,6 +791,31 @@ function createErrorDiagnoser(context) {
775
791
  }
776
792
  return false;
777
793
  }
794
+ /**
795
+ * 获取 ViewElement 的数据源类型(T 或 T1)
796
+ * 参考 util.js 中的 getDataTypeOfViewElement 实现
797
+ */
798
+ function getDataSourceTypeAnnotation(viewElement) {
799
+ // 向上查找定义了数据源类型的祖先组件
800
+ let currentNode = viewElement;
801
+ let depth = 0;
802
+ const maxSearchDepth = 5;
803
+ while (currentNode?.concept === 'ViewElement' && depth <= maxSearchDepth) {
804
+ // 使用 __ViewElementTV 获取类型,与 IDE 前端 getDataTypeOfViewElement 保持一致
805
+ if (currentNode.__TypeAnnotation && currentNode.__ViewElementTV?.length) {
806
+ // 先查找 T1(动态列),若无再查找 T(普通数据源组件)
807
+ const t1 = currentNode.__ViewElementTV.find((x) => x.rawName === 'T1');
808
+ if (t1?.renamed)
809
+ return t1.renamed;
810
+ const t = currentNode.__ViewElementTV.find((x) => x.rawName === 'T');
811
+ if (t?.renamed)
812
+ return t.renamed;
813
+ }
814
+ currentNode = currentNode.parentNode;
815
+ depth++;
816
+ }
817
+ return undefined;
818
+ }
778
819
  /**
779
820
  * 是否在赋值左侧
780
821
  * @param node
@@ -857,7 +898,8 @@ function createErrorDiagnoser(context) {
857
898
  if (param?.spread) {
858
899
  continue;
859
900
  }
860
- if (!isNonRequiredParam(param)) {
901
+ // 严格模式非必填也需要有Argument占位
902
+ if (isStrictMode || !isNonRequiredParam(param)) {
861
903
  minArgsCount++; // 如果参数有默认值,则跳过
862
904
  }
863
905
  }
@@ -975,7 +1017,11 @@ function createErrorDiagnoser(context) {
975
1017
  error(node, `预期 ${paramsLen} 个参数,但传入了 ${argsLen} 个。`);
976
1018
  }
977
1019
  else if (argsLen < minArgsCount) {
978
- error(node, `预期 ${minArgsCount} 个参数,但传入了 ${argsLen} 个。`);
1020
+ let msg = `传入参数的个数 ${argsLen} ${getExpressionNodeName(node.concept)} 定义的参数个数 ${paramsLen} 不符。`;
1021
+ if (isStrictMode) {
1022
+ msg += `可选参数和默认值参数必须用 undefined 占位`;
1023
+ }
1024
+ error(node, msg);
979
1025
  }
980
1026
  yield* (0, nasl_utils_1.wrapForEachToGenerator)(args, function* (arg, index) {
981
1027
  const param = params?.[index];
@@ -1252,6 +1298,11 @@ function createErrorDiagnoser(context) {
1252
1298
  });
1253
1299
  }
1254
1300
  }
1301
+ if (node.interfaces?.length) {
1302
+ yield* (0, nasl_utils_1.wrapForEachToGenerator)(node.interfaces, function* (node) {
1303
+ yield* checkNode(node);
1304
+ });
1305
+ }
1255
1306
  yield* checkNode(node.configuration);
1256
1307
  if (node.type === 'sharedApp') {
1257
1308
  const status = getStatusOfSharedApp(node);
@@ -1267,12 +1318,13 @@ function createErrorDiagnoser(context) {
1267
1318
  }
1268
1319
  // 检查 JDK 版本兼容性
1269
1320
  function jdkDisabled(item) {
1270
- if (item?.frontends?.length) {
1271
- return false;
1321
+ const isBackendComp = !!item?.externalDependencyMap?.maven;
1322
+ if (isBackendComp) {
1323
+ const jdk = app?.jdkVersion || 'JDK8';
1324
+ const dependencyJdk = item?.externalDependencyMap?.jdk?.version || 'JDK8';
1325
+ return jdk.toLowerCase() !== dependencyJdk.toLowerCase();
1272
1326
  }
1273
- const jdk = app?.jdkVersion || 'JDK8';
1274
- const dependencyJdk = item?.externalDependencyMap?.jdk?.version || 'JDK8';
1275
- return jdk.toLowerCase() !== dependencyJdk.toLowerCase();
1327
+ return false;
1276
1328
  }
1277
1329
  if (jdkDisabled(node)) {
1278
1330
  error(node, `与当前应用的JDK版本不匹配`);
@@ -1453,7 +1505,7 @@ function createErrorDiagnoser(context) {
1453
1505
  yield* checkNode(node);
1454
1506
  });
1455
1507
  }
1456
- const dataSourceGroup = app.configuration?.getGroup('dataSource');
1508
+ const dataSourceGroup = app.configuration?.getGroup?.('dataSource');
1457
1509
  if (dataSourceGroup) {
1458
1510
  const property = dataSourceGroup.getProperty(node.name);
1459
1511
  if (property.values?.length) {
@@ -1725,7 +1777,7 @@ function createErrorDiagnoser(context) {
1725
1777
  const decimalPlaces = value?.split('.')[1]?.length || 0;
1726
1778
  if (decimalPlaces > +scale) {
1727
1779
  error(node, `实体字段${node.name}默认值的小数位数不能大于设置的小数位数${scale},否则将会按照小数位数自动截断`, {
1728
- severity: Severity.WARN,
1780
+ severity: isStrictMode ? Severity.ERROR : Severity.WARN,
1729
1781
  });
1730
1782
  }
1731
1783
  }
@@ -1837,6 +1889,9 @@ function createErrorDiagnoser(context) {
1837
1889
  * @param node
1838
1890
  */
1839
1891
  function* checkEnum(node) {
1892
+ if (!node.valueType) {
1893
+ error(node, `枚举 ${node.name} 缺少值类型定义`);
1894
+ }
1840
1895
  if (node.enumItems?.length) {
1841
1896
  yield* (0, nasl_utils_1.wrapForEachToGenerator)(node.enumItems, function* (node) {
1842
1897
  yield* checkNode(node);
@@ -1972,8 +2027,10 @@ function createErrorDiagnoser(context) {
1972
2027
  yield* checkNode(node);
1973
2028
  });
1974
2029
  }
1975
- if (ensureNodeKeyExists(node, 'originLogicName')) {
1976
- if (nasl_concepts_1.asserts.isApp(node.parentNode)) {
2030
+ // 仅对内部接口(app.interfaces,由 Logic 导出)校验 originLogicName;外部接口(interfaceDependencies 等)无此字段
2031
+ const isInternalInterface = nasl_concepts_1.asserts.isApp(node.parentNode);
2032
+ if (isInternalInterface) {
2033
+ if (ensureNodeKeyExists(node, 'originLogicName')) {
1977
2034
  const originLogicName = node.originLogicName;
1978
2035
  const ref = app.logics.find((item) => item.name === originLogicName);
1979
2036
  if (!ref) {
@@ -2345,6 +2402,31 @@ function createErrorDiagnoser(context) {
2345
2402
  }
2346
2403
  yield* checkPlayground(node.playground);
2347
2404
  yield* checkBindExpressions(node);
2405
+ // 检查数据源上的字段属性是否在类型上存在
2406
+ // 判断条件:
2407
+ // 1. 属性的 setter 是 PropertySelectSetter(从组件定义的 ViewComponentDeclaration 中获取)
2408
+ // 2. 或者属性在 FIELD_ATTRS_BY_COMPONENT 配置中(兼容老版本组件配置)
2409
+ if (node.type === 'string' && typeof node.value === 'string' && node.value) {
2410
+ const viewElement = node.parentNode;
2411
+ if (viewElement?.concept === 'ViewElement') {
2412
+ // 优先检查组件定义中的 PropertySelectSetter
2413
+ const isPropertySelect = env.refMgr.compDefMgr.isPropertySelectSetter(viewElement.tag, node.name);
2414
+ // 同时兼容 FIELD_ATTRS_BY_COMPONENT 配置
2415
+ const needsFieldCheck = isPropertySelect || (0, view_element_field_attrs_1.shouldCheckFieldExists)(viewElement.tag, node.name);
2416
+ if (needsFieldCheck) {
2417
+ const dataSourceType = getDataSourceTypeAnnotation(viewElement);
2418
+ if (dataSourceType) {
2419
+ const { exists, missingField } = checkFieldExistsInType(env, dataSourceType, node.value);
2420
+ if (!exists && missingField) {
2421
+ // 优先从组件定义中获取属性标题,兜底使用硬编码配置
2422
+ const attrTitle = env.refMgr.compDefMgr.getPropTitle(viewElement.tag, node.name)
2423
+ || (0, view_element_field_attrs_1.getFieldAttrTitle)(node.name);
2424
+ error(node, `${attrTitle} "${missingField}" 在数据类型上不存在`);
2425
+ }
2426
+ }
2427
+ }
2428
+ }
2429
+ }
2348
2430
  // 检查不可复制属性开启双向绑定
2349
2431
  if ((node.model || node.sync) && node.expression) {
2350
2432
  const bindExpression = node.expression;
@@ -2440,6 +2522,11 @@ function createErrorDiagnoser(context) {
2440
2522
  // 任务完成人为空会有一个提示信息
2441
2523
  error(node, `${title}为空`);
2442
2524
  }
2525
+ if (Array.isArray(node.fromLogics)) {
2526
+ yield* (0, nasl_utils_1.wrapForEachToGenerator)(node.fromLogics, function* (node) {
2527
+ yield* checkNode(node);
2528
+ });
2529
+ }
2443
2530
  }
2444
2531
  /**
2445
2532
  * 检查 元素指令
@@ -3013,8 +3100,8 @@ function createErrorDiagnoser(context) {
3013
3100
  }
3014
3101
  }
3015
3102
  if (!isSame) {
3016
- const macthed = exportInterface.concept === 'McpInterface';
3017
- const key = macthed ? 'exportMcpInterface' : 'exportInterface';
3103
+ const matched = exportInterface.concept === 'McpInterface';
3104
+ const key = matched ? 'exportMcpInterface' : 'exportInterface';
3018
3105
  error(node, `逻辑已变更,请确认请求类型无误后重新导出${'${event}'}`, {
3019
3106
  severity: Severity.ERROR,
3020
3107
  events: [
@@ -3274,7 +3361,7 @@ function createErrorDiagnoser(context) {
3274
3361
  return;
3275
3362
  }
3276
3363
  yield* checkVoidCallUsedAsStatement(node);
3277
- const ref = env.resolveRef(node); // 前端
3364
+ const ref = env.resolveRef(node) ?? env.quickGetLibDef(node, node.calleeName, undefined); // 前端
3278
3365
  // TODO: sql 函数的 namespace 带有数据库名 nasl.sqlFunction.mysql nasl.sqlFunction.oracle ...
3279
3366
  // 暂时不在 gQNameDefs 里,用 isBuiltInCall 简单判断了
3280
3367
  if (!ref && !isBuiltInCall(node)) {
@@ -3375,17 +3462,30 @@ function createErrorDiagnoser(context) {
3375
3462
  for (let i = 1; i < nd.arguments.length; i++) {
3376
3463
  const expr = nd.arguments[i].expression;
3377
3464
  let resTy;
3465
+ const reportArgError = (targetExpr) => {
3466
+ const actualTy = targetExpr ? env.getType(targetExpr) || type_manager_1.naslAnyTy : type_manager_1.naslAnyTy;
3467
+ error(nd.arguments[i], (0, sem_diag_1.mkIncompatibleTyErr)(env, actualTy, expectTy));
3468
+ };
3378
3469
  if (expr?.concept === 'AnonymousFunction') {
3379
3470
  resTy = env.getType(expr.body);
3380
3471
  if (!nasl_concepts_1.asserts.isNewComposite(expr.body)) {
3381
- error(nd.arguments[i], (0, sem_diag_1.mkIncompatibleTyErr)(env, env.getType(expr) || type_manager_1.naslAnyTy, expectTy));
3472
+ reportArgError(expr);
3382
3473
  }
3383
3474
  }
3384
3475
  else if (expr?.concept === 'SubLogic') {
3385
3476
  resTy = env.getType(expr.returns?.[0]);
3386
3477
  }
3478
+ else if (expr?.concept === 'Identifier') {
3479
+ const ty = env.getType(expr);
3480
+ if ((0, type_predicate_1.isFuncTy)(ty)) {
3481
+ resTy = ty;
3482
+ }
3483
+ else {
3484
+ reportArgError(expr);
3485
+ }
3486
+ }
3387
3487
  else {
3388
- error(nd.arguments[i], (0, sem_diag_1.mkIncompatibleTyErr)(env, env.getType(expr) || type_manager_1.naslAnyTy, expectTy));
3488
+ reportArgError(expr);
3389
3489
  }
3390
3490
  const byTy = resTy?.properties?.find((prop) => prop.name === 'by')?.typeAnnotation;
3391
3491
  if (byTy?.typeKind === 'union') {
@@ -3422,6 +3522,29 @@ function createErrorDiagnoser(context) {
3422
3522
  error(node, '下载组件必须为page和size指定入参,且不能重复');
3423
3523
  }
3424
3524
  }
3525
+ const map = {
3526
+ frontend: {
3527
+ scope: '前端',
3528
+ forbiddenScope: '服务端',
3529
+ forbiddenCalleeNamesMap: {
3530
+ 'nasl.auth': ['getCurrentUser', 'generateUserId', 'validatePassword', 'encryptPassword'],
3531
+ },
3532
+ },
3533
+ backend: {
3534
+ scope: '服务端',
3535
+ forbiddenScope: '前端',
3536
+ forbiddenCalleeNamespaces: ['nasl.browser', 'nasl.io'],
3537
+ forbiddenCalleeNamesMap: {
3538
+ 'nasl.auth': ['decryptByAES', 'encryptByAES', 'logout', 'hasAuth'],
3539
+ 'nasl.configuration': ['getCurrentIp', 'getUserLanguage', 'getI18nList', 'setI18nLocale'],
3540
+ },
3541
+ },
3542
+ };
3543
+ const config = inFrontendType ? map.frontend : map.backend;
3544
+ const { scope, forbiddenScope, forbiddenCalleeNamespaces, forbiddenCalleeNamesMap } = config;
3545
+ if (forbiddenCalleeNamespaces?.includes(node.calleeNamespace) || forbiddenCalleeNamesMap?.[node.calleeNamespace]?.includes(node.calleeName)) {
3546
+ error(node, `不能在${scope}作用域下使用${forbiddenScope}系统逻辑`);
3547
+ }
3425
3548
  return env.getType(node);
3426
3549
  }
3427
3550
  /**
@@ -3780,12 +3903,18 @@ function createErrorDiagnoser(context) {
3780
3903
  */
3781
3904
  function* checkForEachStatement(node) {
3782
3905
  env.enterScope(node);
3906
+ if (ensureNodeKeyExists(node, 'item')) {
3907
+ yield* checkNode(node.item);
3908
+ }
3783
3909
  if (ensureNodeKeyExists(node, 'each')) {
3784
3910
  yield* checkNode(node.each);
3785
3911
  }
3786
3912
  if (ensureNodeKeyExists(node, 'start')) {
3787
3913
  yield* checkNode(node.start);
3788
3914
  }
3915
+ if (node.end) {
3916
+ yield* checkNode(node.end);
3917
+ }
3789
3918
  if (node.body?.length) {
3790
3919
  yield* (0, nasl_utils_1.wrapForEachToGenerator)(node.body, function* (node) {
3791
3920
  yield* checkNode(node);
@@ -3875,6 +4004,36 @@ function createErrorDiagnoser(context) {
3875
4004
  scopedError(node, `${node.toNaturalTS()} 枚举类不能直接使用,请取它的枚举项`);
3876
4005
  return errorType;
3877
4006
  }
4007
+ const map = {
4008
+ frontend: {
4009
+ scope: '前端',
4010
+ forbiddenScope: '服务端',
4011
+ prefix: 'app.frontendTypes',
4012
+ forbiddenPrefix: 'app.backend',
4013
+ },
4014
+ backend: {
4015
+ scope: '服务端',
4016
+ forbiddenScope: '前端',
4017
+ prefix: 'app.backend',
4018
+ forbiddenPrefix: 'app.frontendTypes',
4019
+ forbiddenCalleeNamesMap: {
4020
+ 'nasl.auth': ['userInfo']
4021
+ }
4022
+ },
4023
+ };
4024
+ const config = inFrontendType ? map.frontend : map.backend;
4025
+ const { scope, forbiddenScope, prefix, forbiddenPrefix, forbiddenCalleeNamesMap } = config;
4026
+ // 互斥的端类型 (pc <-> h5)
4027
+ const forbiddenKind = currentFrontendKind === 'pc' ? 'h5' : 'pc';
4028
+ if (node.namespace?.startsWith(forbiddenPrefix)) {
4029
+ error(node, `不能在${scope}作用域下使用${forbiddenScope}全局变量`);
4030
+ }
4031
+ else if (inFrontendType && node.namespace?.startsWith(`${prefix}.${forbiddenKind}`)) {
4032
+ error(node, `不能在${currentFrontendKind}作用域下使用${forbiddenKind}作用域下的前端变量`);
4033
+ }
4034
+ if (forbiddenCalleeNamesMap?.[node.namespace]?.includes(node.name)) {
4035
+ error(node, '不能在服务端作用域下使用前端公共变量');
4036
+ }
3878
4037
  // 检查使用范围
3879
4038
  yield* checkScopeOfUse(node, ref);
3880
4039
  return env.getType(node);
@@ -4329,6 +4488,9 @@ function createErrorDiagnoser(context) {
4329
4488
  error(args[i], '当前参数无效,不可用。');
4330
4489
  }
4331
4490
  }
4491
+ if (isStrictMode) {
4492
+ yield* checkCallExpressionParameters(node, ref);
4493
+ }
4332
4494
  }
4333
4495
  else {
4334
4496
  error(node, `找不到页面${node.viewName}`);
@@ -4536,6 +4698,9 @@ function createErrorDiagnoser(context) {
4536
4698
  yield* checkNode(node);
4537
4699
  });
4538
4700
  }
4701
+ else {
4702
+ error(node, 'Join 子句的关联关系不能为空');
4703
+ }
4539
4704
  if (node.joinParts?.length) {
4540
4705
  yield* (0, nasl_utils_1.wrapForEachToGenerator)(node.joinParts, function* (node) {
4541
4706
  yield* checkNode(node);
@@ -4570,6 +4735,9 @@ function createErrorDiagnoser(context) {
4570
4735
  else if (!node.asName) {
4571
4736
  error(node, '数据查询:聚合函数别名不能为空。');
4572
4737
  }
4738
+ if (node.aggregateParam) {
4739
+ yield* checkNode(node.aggregateParam);
4740
+ }
4573
4741
  }
4574
4742
  /**
4575
4743
  * 检查 SQL 查询
@@ -5156,6 +5324,13 @@ function createErrorDiagnoser(context) {
5156
5324
  // TODO: checkNodeIsFileModuleInIdeWithCache 也慢,后续可以优化
5157
5325
  const isFileModule = fileNodes.length ? (0, file_node_cache_1.checkNodeIsFileModuleInIdeWithCache)(node) : true;
5158
5326
  if (isFileModule) {
5327
+ // 增量更新时按文件逐个 checkNode,需重置闭包状态;若本文件在 Module 内,inModule 需为 true(否则不会经过 checkModule,inModule 会失效)
5328
+ inModule = !!node.getAncestor?.('Module');
5329
+ inPlayground = 0;
5330
+ inAuthLogic = false;
5331
+ const frontendType = node.getAncestor?.('FrontendType');
5332
+ inFrontendType = !!frontendType;
5333
+ currentFrontendKind = frontendType?.kind || '';
5159
5334
  fileNodes.push(node);
5160
5335
  let diagnostics = diagnosticMap.get(node);
5161
5336
  if (!diagnostics) {
@@ -5372,6 +5547,64 @@ function createErrorDiagnoser(context) {
5372
5547
  };
5373
5548
  }
5374
5549
  exports.createErrorDiagnoser = createErrorDiagnoser;
5550
+ /**
5551
+ * 检查字段路径是否在类型上存在
5552
+ * 类似于 s-component-attr-form.vue 中的 findPropertyNode 功能
5553
+ * @param env 语义环境
5554
+ * @param dataType 数据源类型
5555
+ * @param fieldPath 字段路径,如 "name" 或 "user.name"
5556
+ * @returns { exists: boolean, missingField?: string } 如果字段不存在,返回第一个不存在的字段名
5557
+ */
5558
+ function checkFieldExistsInType(env, dataType, fieldPath) {
5559
+ if (!dataType || !fieldPath) {
5560
+ return { exists: true }; // 没有类型信息或字段路径时,跳过检查
5561
+ }
5562
+ const fieldParts = fieldPath.split('.');
5563
+ let currentType = dataType;
5564
+ for (const fieldName of fieldParts) {
5565
+ if (!currentType) {
5566
+ return { exists: false, missingField: fieldName };
5567
+ }
5568
+ // 获取类型的 properties
5569
+ let properties;
5570
+ if (currentType.typeKind === 'anonymousStructure') {
5571
+ properties = currentType.properties;
5572
+ }
5573
+ else if (currentType.typeKind === 'reference') {
5574
+ // 对于引用类型,需要解析引用
5575
+ const resolved = env.resolveRef(currentType);
5576
+ // @ts-expect-error
5577
+ properties = resolved?.properties;
5578
+ }
5579
+ else if (currentType.typeKind === 'generic' && currentType.typeName === 'List') {
5580
+ // 对于 List<T>,检查 T 的属性
5581
+ currentType = currentType.typeArguments?.[0];
5582
+ if (currentType?.typeKind === 'anonymousStructure') {
5583
+ properties = currentType.properties;
5584
+ }
5585
+ else if (currentType?.typeKind === 'reference') {
5586
+ const resolved = env.resolveRef(currentType);
5587
+ // @ts-expect-error
5588
+ properties = resolved?.properties;
5589
+ }
5590
+ }
5591
+ if (!properties) {
5592
+ // 类型没有 properties,可能是基本类型或未解析的类型
5593
+ // 对于未解析的类型,跳过检查
5594
+ if ((0, type_predicate_1.isTyAnnTyParam)(currentType) || (0, type_predicate_1.isAnyTy)(currentType)) {
5595
+ return { exists: true };
5596
+ }
5597
+ return { exists: false, missingField: fieldName };
5598
+ }
5599
+ const prop = properties.find((p) => p.name === fieldName);
5600
+ if (!prop) {
5601
+ return { exists: false, missingField: fieldName };
5602
+ }
5603
+ // 继续检查下一级
5604
+ currentType = prop.typeAnnotation;
5605
+ }
5606
+ return { exists: true };
5607
+ }
5375
5608
  function deduplicateDiagnostics(diagnostics) {
5376
5609
  return (0, lodash_1.uniqWith)(diagnostics, (a, b) => a.node === b.node && a.message === b.message);
5377
5610
  }
@@ -5421,7 +5654,7 @@ exports.transformDiagnosticsToRecords = transformDiagnosticsToRecords;
5421
5654
  // @ts-expect-error
5422
5655
  const toRaw = (nd) => nd.__v_raw ?? nd;
5423
5656
  // 是否来自系统内置
5424
- const isBuiltInCall = (nd) => !!nd.calleeNamespace?.startsWith('nasl.');
5657
+ const isBuiltInCall = (nd) => !!nd.calleeNamespace?.startsWith('nasl.') && !['nasl.auth'].includes(nd.calleeNamespace);
5425
5658
  // 获取依赖库名
5426
5659
  const getExtensionLibName = (nd) => nd.calleeNamespace?.startsWith('extensions.') ? nd.calleeNamespace.split('.')[1] : undefined;
5427
5660
  //# sourceMappingURL=checker.js.map