@lcap/nasl-language-server-core 4.4.0-beta.4 → 4.4.0-beta.6

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 (59) hide show
  1. package/out/checker.d.ts +3 -1
  2. package/out/checker.d.ts.map +1 -1
  3. package/out/checker.js +156 -3
  4. package/out/checker.js.map +1 -1
  5. package/out/reference-manager/reference-manager.d.ts +2 -2
  6. package/out/reference-manager/reference-manager.d.ts.map +1 -1
  7. package/out/reference-manager/reference-manager.js +2 -2
  8. package/out/reference-manager/reference-manager.js.map +1 -1
  9. package/out/reference-manager/view-elem-logic.d.ts +3 -3
  10. package/out/reference-manager/view-elem-logic.d.ts.map +1 -1
  11. package/out/reference-manager/view-elem-logic.js +17 -0
  12. package/out/reference-manager/view-elem-logic.js.map +1 -1
  13. package/out/symbol/traverse/concepts/index.d.ts +1 -1
  14. package/out/symbol/traverse/concepts/index.d.ts.map +1 -1
  15. package/out/typer/dispatch-call.d.ts.map +1 -1
  16. package/out/typer/dispatch-call.js +6 -0
  17. package/out/typer/dispatch-call.js.map +1 -1
  18. package/out/typer/dispatch-def.d.ts.map +1 -1
  19. package/out/typer/dispatch-def.js +3 -1
  20. package/out/typer/dispatch-def.js.map +1 -1
  21. package/out/typer/dispatch-expr.d.ts +2 -1
  22. package/out/typer/dispatch-expr.d.ts.map +1 -1
  23. package/out/typer/dispatch-expr.js +95 -21
  24. package/out/typer/dispatch-expr.js.map +1 -1
  25. package/out/typer/dispatch-stmt.d.ts.map +1 -1
  26. package/out/typer/dispatch-stmt.js +29 -15
  27. package/out/typer/dispatch-stmt.js.map +1 -1
  28. package/out/typer/dispatch-view.d.ts.map +1 -1
  29. package/out/typer/dispatch-view.js +0 -4
  30. package/out/typer/dispatch-view.js.map +1 -1
  31. package/out/typer/incremental-update.d.ts +10 -0
  32. package/out/typer/incremental-update.d.ts.map +1 -1
  33. package/out/typer/incremental-update.js +167 -2
  34. package/out/typer/incremental-update.js.map +1 -1
  35. package/out/typer/oql-checker/chain-call-transformer.d.ts.map +1 -1
  36. package/out/typer/oql-checker/chain-call-transformer.js +17 -4
  37. package/out/typer/oql-checker/chain-call-transformer.js.map +1 -1
  38. package/out/typer/oql-checker/ts-parser.d.ts.map +1 -1
  39. package/out/typer/oql-checker/ts-parser.js +157 -21
  40. package/out/typer/oql-checker/ts-parser.js.map +1 -1
  41. package/out/typer/overload-helper.d.ts.map +1 -1
  42. package/out/typer/overload-helper.js +5 -0
  43. package/out/typer/overload-helper.js.map +1 -1
  44. package/out/typer/subster.d.ts +1 -1
  45. package/out/typer/subster.d.ts.map +1 -1
  46. package/out/typer/subster.js +7 -3
  47. package/out/typer/subster.js.map +1 -1
  48. package/out/typer/type-predicate.d.ts.map +1 -1
  49. package/out/typer/type-predicate.js +38 -2
  50. package/out/typer/type-predicate.js.map +1 -1
  51. package/out/typer/typer.d.ts +22 -2
  52. package/out/typer/typer.d.ts.map +1 -1
  53. package/out/typer/typer.js +117 -16
  54. package/out/typer/typer.js.map +1 -1
  55. package/out/typer/unifier.d.ts +1 -1
  56. package/out/typer/unifier.d.ts.map +1 -1
  57. package/out/typer/unifier.js +8 -4
  58. package/out/typer/unifier.js.map +1 -1
  59. package/package.json +6 -6
package/out/checker.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { SyntaxNode, App, BaseNode } from '@lcap/nasl-concepts';
1
+ import type { SyntaxNode, Frontend, View, App, BaseNode } from '@lcap/nasl-concepts';
2
2
  import { TypeAnnotation } from '@lcap/nasl-concepts';
3
3
  import { type SemEnv } from './typer/typer';
4
4
  import { Diagnostic as NaslTypeDiagnostic } from '@lcap/nasl-types';
@@ -49,6 +49,8 @@ export declare function createErrorDiagnoser(context: DiagnoseContext): {
49
49
  nodeConcept: string;
50
50
  }[];
51
51
  error: (node: SyntaxNode, message: string, context?: ErrorContext) => void;
52
+ checkViewIndexPageSetting: (node: View | Frontend) => void;
53
+ revalidateAncestorNode: (ancestorNode: SyntaxNode, validationFn: (ancestorNode: SyntaxNode, env: SemEnv) => void, errorFilter?: (err: Diagnostic) => boolean) => NodeDiagnosticsMap | null;
52
54
  };
53
55
  export interface DiagnosticRecord {
54
56
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"checker.d.ts","sourceRoot":"","sources":["../src/checker.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,UAAU,EAU2G,GAAG,EAMxH,QAAQ,EAET,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;AAOpE,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;AA4OF;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,eAAe;oCAy2IpB,OAAO;sDAPW,gBAAgB,EAAE;;;;sBAhBjD,UAAU,GAAG,SAAS;;;8BA4Df,UAAU;2BAyBb,UAAU;;;iBAW3B,MAAM;kBACL,MAAM;kBACN,MAAM;qBACH,MAAM;;kBA53IF,UAAU,WAAW,MAAM,YAAY,YAAY;EA+5IzE;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,EAET,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;AAOpE,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;AA4OF;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,eAAe;oCA49IpB,OAAO;sDAPW,gBAAgB,EAAE;;;;sBAhBjD,UAAU,GAAG,SAAS;;;8BA4Df,UAAU;2BAyBb,UAAU;;;iBAW3B,MAAM;kBACL,MAAM;kBACN,MAAM;qBACH,MAAM;;kBA/+IF,UAAU,WAAW,MAAM,YAAY,YAAY;sCA+qD/B,IAAI,GAAG,QAAQ;2CAi2FxC,UAAU,gBACV,CAAC,YAAY,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,gBAC/C,CAAC,GAAG,EAAE,UAAU,KAAK,OAAO,KACzC,kBAAkB,GAAG,IAAI;EAgD7B;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"}
package/out/checker.js CHANGED
@@ -10,8 +10,8 @@ const sem_diag_1 = require("./typer/sem-diag");
10
10
  const type_predicate_1 = require("./typer/type-predicate");
11
11
  const type_manager_1 = require("./typer/type-manager");
12
12
  const service_2 = require("@lcap/nasl-concepts/service");
13
- const asserts_1 = require("@lcap/nasl-concepts/asserts");
14
13
  const lodash_1 = require("lodash");
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
17
  var Severity;
@@ -321,7 +321,30 @@ function createErrorDiagnoser(context) {
321
321
  }
322
322
  const finalNode = memberExpression ?? node;
323
323
  (0, helper_1.createOnPush)(diagnostics, finalNode, diagnostic);
324
- finalNode.tsErrorDetail = diagnostic;
324
+ const aggregationFields = {
325
+ assignmentLine: 'assignmentLines',
326
+ };
327
+ const nodeDiagnostics = diagnostics.get(finalNode);
328
+ if (nodeDiagnostics && nodeDiagnostics.length > 0) {
329
+ // 构建最终的 tsErrorDetail,合并所有上下文信息
330
+ const aggregatedContext = {};
331
+ // 对每个需要聚合的字段进行收集
332
+ for (const [singleField, arrayField] of Object.entries(aggregationFields)) {
333
+ const values = nodeDiagnostics
334
+ .map(d => d[singleField])
335
+ .filter((val) => val !== undefined);
336
+ if (values.length > 0) {
337
+ aggregatedContext[arrayField] = values;
338
+ }
339
+ }
340
+ finalNode.tsErrorDetail = {
341
+ ...diagnostic,
342
+ ...aggregatedContext,
343
+ };
344
+ }
345
+ else {
346
+ finalNode.tsErrorDetail = diagnostic;
347
+ }
325
348
  }
326
349
  else { }
327
350
  }
@@ -343,7 +366,7 @@ function createErrorDiagnoser(context) {
343
366
  * @returns
344
367
  */
345
368
  function getError(node) {
346
- const curFileNode = getCurFileNode();
369
+ const curFileNode = getCurFileNode() ?? node;
347
370
  const diagnostics = diagnosticMap.get(curFileNode);
348
371
  if (diagnostics) {
349
372
  return diagnostics.get(node);
@@ -1912,9 +1935,39 @@ function createErrorDiagnoser(context) {
1912
1935
  yield* (0, nasl_utils_1.wrapForEachToGenerator)(node.views, function* (node) {
1913
1936
  yield* checkNode(node);
1914
1937
  });
1938
+ checkViewIndexPageSetting(node);
1915
1939
  }
1916
1940
  env.exitScope();
1917
1941
  }
1942
+ /**
1943
+ * 检查页面的首页/默认跳转页设置
1944
+ * 根据父级类型(Frontend 或 View)自动判断检查场景
1945
+ * @param node 当前页面节点
1946
+ */
1947
+ function checkViewIndexPageSetting(node) {
1948
+ const isNodeFrontend = (0, asserts_1.isFrontend)(node);
1949
+ const children = isNodeFrontend ? node.views : node.children;
1950
+ // 防御性检查:确保 children 存在且是数组
1951
+ if (!children || !Array.isArray(children)) {
1952
+ return;
1953
+ }
1954
+ // 检查默认跳转页数量,只允许有一个默认跳转页
1955
+ const defaultViews = children.filter((view) => view.isIndex);
1956
+ if (defaultViews.length > 1) {
1957
+ // 收集所有默认跳转页的名称
1958
+ const defaultViewNames = defaultViews.map((view) => view.name).join('、');
1959
+ const typeMap = {
1960
+ Frontend: '首页',
1961
+ View: '默认跳转页',
1962
+ };
1963
+ const pageType = typeMap[node.concept] || '默认跳转页';
1964
+ const errorMessage = `页面 ${node.name} 只能有一个 ${pageType},目前存在 ${defaultViewNames}`;
1965
+ error(node, errorMessage, {
1966
+ fileNode: node,
1967
+ isIndex: true,
1968
+ });
1969
+ }
1970
+ }
1918
1971
  /**
1919
1972
  * 检查 页面
1920
1973
  * @param node
@@ -1962,6 +2015,7 @@ function createErrorDiagnoser(context) {
1962
2015
  yield* (0, nasl_utils_1.wrapForEachToGenerator)(node.children, function* (node) {
1963
2016
  yield* checkNode(node);
1964
2017
  });
2018
+ checkViewIndexPageSetting(node);
1965
2019
  }
1966
2020
  env.exitScope();
1967
2021
  }
@@ -2941,15 +2995,27 @@ function createErrorDiagnoser(context) {
2941
2995
  }
2942
2996
  return type;
2943
2997
  function checkListSort(nd) {
2998
+ const parTy = env.getType(nd.arguments?.[0]);
2999
+ let paramType = '未知类型';
3000
+ if (parTy?.typeName === 'List') {
3001
+ paramType = (0, type_manager_1.showUserLevelType)(parTy.typeArguments?.[0] || type_manager_1.naslAnyTy);
3002
+ }
3003
+ const expectTy = `{ by: (item: ${paramType}) => 未知类型, asc: 布尔值 }`;
2944
3004
  for (let i = 1; i < nd.arguments.length; i++) {
2945
3005
  const expr = nd.arguments[i].expression;
2946
3006
  let resTy;
2947
3007
  if (expr?.concept === 'AnonymousFunction') {
2948
3008
  resTy = env.getType(expr.body);
3009
+ if (!nasl_concepts_1.asserts.isNewComposite(expr.body)) {
3010
+ error(nd.arguments[i], (0, sem_diag_1.mkIncompatibleTyErr)(env, env.getType(expr) || type_manager_1.naslAnyTy, expectTy));
3011
+ }
2949
3012
  }
2950
3013
  else if (expr?.concept === 'SubLogic') {
2951
3014
  resTy = env.getType(expr.returns?.[0]);
2952
3015
  }
3016
+ else {
3017
+ error(nd.arguments[i], (0, sem_diag_1.mkIncompatibleTyErr)(env, env.getType(expr) || type_manager_1.naslAnyTy, expectTy));
3018
+ }
2953
3019
  const byTy = resTy?.properties?.find((prop) => prop.name === 'by')?.typeAnnotation;
2954
3020
  if (byTy?.typeKind === 'union') {
2955
3021
  // 这里使用 node.arguments[i] 则无红框,猜测是 ListSort 的特殊交互导致的问题
@@ -3031,6 +3097,7 @@ function createErrorDiagnoser(context) {
3031
3097
  */
3032
3098
  function* checkIfStatement(node) {
3033
3099
  if (ensureNodeKeyExists(node, 'test')) {
3100
+ yield* rejectNullLiteral(node.test);
3034
3101
  yield* checkNode(node.test);
3035
3102
  }
3036
3103
  // then
@@ -3046,12 +3113,32 @@ function createErrorDiagnoser(context) {
3046
3113
  });
3047
3114
  }
3048
3115
  }
3116
+ /**
3117
+ * 检查 条件表达式
3118
+ * @param node
3119
+ */
3120
+ function* checkIfExpression(node) {
3121
+ if (ensureNodeKeyExists(node, 'condition')) {
3122
+ yield* rejectNullLiteral(node.condition);
3123
+ yield* checkNode(node.condition);
3124
+ }
3125
+ // then
3126
+ if (ensureNodeKeyExists(node, 'consequent')) {
3127
+ yield* checkNode(node.consequent);
3128
+ }
3129
+ // else
3130
+ if (ensureNodeKeyExists(node, 'alternate')) {
3131
+ yield* checkNode(node.alternate);
3132
+ }
3133
+ return env.getType(node);
3134
+ }
3049
3135
  /**
3050
3136
  * 检查 匹配
3051
3137
  * @param node
3052
3138
  */
3053
3139
  function* checkMatch(node) {
3054
3140
  if (ensureNodeKeyExists(node, 'expression')) {
3141
+ yield* rejectNullLiteral(node.expression);
3055
3142
  yield* checkNode(node.expression);
3056
3143
  }
3057
3144
  if (node.cases?.length) {
@@ -3350,6 +3437,7 @@ function createErrorDiagnoser(context) {
3350
3437
  */
3351
3438
  function* checkWhileStatement(node) {
3352
3439
  if (ensureNodeKeyExists(node, 'test')) {
3440
+ yield* rejectNullLiteral(node.test);
3353
3441
  yield* checkNode(node.test);
3354
3442
  }
3355
3443
  if (node.body?.length) {
@@ -3469,6 +3557,11 @@ function createErrorDiagnoser(context) {
3469
3557
  if (typeof node.value !== 'string') {
3470
3558
  error(node, '字符串');
3471
3559
  }
3560
+ const MAX_LENGTH = 2 ** 16;
3561
+ if (node.value.length >= MAX_LENGTH) {
3562
+ // 插值内部的字符串过长时要报错在插值节点上有红框
3563
+ error(node.parentNode?.concept === 'StringInterpolation' ? node.parentNode : node, `存在过长文本,当前长度:${node.value.length},最大长度:${MAX_LENGTH}。建议使用变量拆分文本后再拼接。`);
3564
+ }
3472
3565
  return env.getType(node);
3473
3566
  }
3474
3567
  /**
@@ -4003,10 +4096,17 @@ function createErrorDiagnoser(context) {
4003
4096
  */
4004
4097
  function* checkBinaryExpression(node) {
4005
4098
  yield* semantic_rules_1.ExtraSemanticRules.rejectFileTypes(node, env, error);
4099
+ const isCandidate = ['+', '-', '*', '/', '%', '>', '<', '>=', '<='].includes(node.operator);
4006
4100
  if (ensureNodeKeyExists(node, 'left')) {
4101
+ if (isCandidate) {
4102
+ yield* rejectNullLiteral(node.left);
4103
+ }
4007
4104
  yield* checkNode(node.left);
4008
4105
  }
4009
4106
  if (ensureNodeKeyExists(node, 'right')) {
4107
+ if (isCandidate) {
4108
+ yield* rejectNullLiteral(node.right);
4109
+ }
4010
4110
  yield* checkNode(node.right);
4011
4111
  }
4012
4112
  return env.getType(node);
@@ -4019,6 +4119,7 @@ function createErrorDiagnoser(context) {
4019
4119
  error(node, '表达式不能为空!');
4020
4120
  }
4021
4121
  yield* (0, nasl_utils_1.wrapForEachToGenerator)(node.expressions, function* (node) {
4122
+ yield* rejectNullLiteral(node);
4022
4123
  yield* checkNode(node);
4023
4124
  });
4024
4125
  return env.getType(node);
@@ -4208,6 +4309,15 @@ function createErrorDiagnoser(context) {
4208
4309
  error(node, `无返回值的${node?.constructor?.nodeTitle}${node.calleeName} 不能在${parentNode?.constructor?.nodeTitle}中作为表达式使用。`);
4209
4310
  }
4210
4311
  }
4312
+ /**
4313
+ * 检查 不允许使用 null 字面量
4314
+ * @param node
4315
+ */
4316
+ function* rejectNullLiteral(node) {
4317
+ if (node.concept === 'NullLiteral') {
4318
+ error(node, `此处不允许使用 null`);
4319
+ }
4320
+ }
4211
4321
  function* dispatchNode(node) {
4212
4322
  try {
4213
4323
  // 调用表达式
@@ -4354,6 +4464,8 @@ function createErrorDiagnoser(context) {
4354
4464
  return yield* checkBlock(node);
4355
4465
  case 'IfStatement':
4356
4466
  return yield* checkIfStatement(node);
4467
+ case 'IfExpression':
4468
+ return yield* checkIfExpression(node);
4357
4469
  case 'Match':
4358
4470
  return yield* checkMatch(node);
4359
4471
  case 'MatchCase':
@@ -4593,6 +4705,45 @@ function createErrorDiagnoser(context) {
4593
4705
  });
4594
4706
  return flattenedDiags;
4595
4707
  }
4708
+ /**
4709
+ * 重新验证祖先节点
4710
+ * 用于增量更新时,当子节点变更需要重新验证祖先节点的场景
4711
+ * @param ancestorNode 需要重新验证的祖先节点
4712
+ * @param validationFn 验证函数
4713
+ * @param errorFilter 错误过滤函数(可选),用于保留特定的错误
4714
+ * @returns 新的诊断信息 Map,如果没有则返回 null
4715
+ */
4716
+ function revalidateAncestorNode(ancestorNode, validationFn, errorFilter) {
4717
+ // 保存并过滤相关的错误诊断
4718
+ const errs = getError(ancestorNode) || [];
4719
+ const filteredErrs = errorFilter
4720
+ ? errs.filter(errorFilter)
4721
+ : [];
4722
+ // 清除祖先节点的诊断信息
4723
+ clearDiagnostics(ancestorNode);
4724
+ // 恢复过滤后的错误诊断
4725
+ if (filteredErrs.length > 0) {
4726
+ filteredErrs.forEach((err) => {
4727
+ const { message, severity, ...context } = err;
4728
+ if (message) {
4729
+ error(ancestorNode, message, {
4730
+ severity: severity,
4731
+ ...context,
4732
+ });
4733
+ }
4734
+ });
4735
+ }
4736
+ // 设置文件节点上下文并执行验证
4737
+ const cleanup = handleFileNode(ancestorNode);
4738
+ try {
4739
+ validationFn(ancestorNode, env);
4740
+ }
4741
+ finally {
4742
+ cleanup?.();
4743
+ }
4744
+ // 返回新的诊断信息
4745
+ return getDiagnostics(ancestorNode) || null;
4746
+ }
4596
4747
  return {
4597
4748
  setMetadataTypeEnable,
4598
4749
  setLatestVersionsOfSharedApp,
@@ -4603,6 +4754,8 @@ function createErrorDiagnoser(context) {
4603
4754
  getAllDiagnostics,
4604
4755
  getDebugDiagnostics,
4605
4756
  error,
4757
+ checkViewIndexPageSetting,
4758
+ revalidateAncestorNode,
4606
4759
  };
4607
4760
  }
4608
4761
  exports.createErrorDiagnoser = createErrorDiagnoser;