@agile-team/wl-skills-kit 2.11.0 → 2.11.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/CHANGELOG.md +47 -9
  2. package/README.md +41 -23
  3. package/bin/wl-skills.js +133 -39
  4. package/docs/agent-pipeline-runbook.md +3 -3
  5. package/docs//345/205/250/347/233/230/345/210/206/346/236/220/344/270/216/346/231/272/350/203/275/344/275/223/346/220/255/345/273/272/346/214/207/345/215/227.md +4 -4
  6. package/files/.wl-skills/copilot-instructions-full.md +233 -233
  7. package/files/.wl-skills/docs/jh-pagination.md +505 -505
  8. package/files/.wl-skills/docs/page-spec-schema.md +109 -0
  9. package/files/.wl-skills/docs/request.md +940 -940
  10. package/files/.wl-skills/guides/architecture.md +1 -1
  11. package/files/.wl-skills/skills/core/convention-audit/SKILL.md +3 -3
  12. package/files/.wl-skills/skills/core/page-codegen/SKILL.md +10 -4
  13. package/files/.wl-skills/skills/core/spec-doc-parse/SKILL.md +332 -332
  14. package/files/.wl-skills/skills/core/spec-doc-parse/USAGE.md +97 -97
  15. package/files/.wl-skills/skills/sync/permission-sync/USAGE.md +107 -107
  16. package/files/.wl-skills/src/components/global/C_ParentView/index.vue +3 -3
  17. package/files/.wl-skills/src/components/global/C_RightToolbar/index.vue +157 -157
  18. package/files/.wl-skills/src/components/global/C_SvgIcon/index.vue +31 -31
  19. package/files/.wl-skills/src/components/global/C_SvgIcon/svgicon.js +10 -10
  20. package/files/.wl-skills/src/components/global/C_TagStatus/README.md +264 -264
  21. package/files/.wl-skills/src/components/global/C_TagStatus/config.ts +192 -192
  22. package/files/.wl-skills/src/components/global/C_TagStatus/index.vue +106 -106
  23. package/files/.wl-skills/src/components/global/C_TagStatus/types.ts +64 -64
  24. package/files/.wl-skills/src/components/global/C_Tree/README.md +153 -153
  25. package/files/.wl-skills/src/components/global/C_Tree/index.scss +42 -42
  26. package/files/.wl-skills/src/components/global/C_Tree/index.vue +78 -78
  27. package/files/.wl-skills/src/components/global/C_Tree/types.ts +59 -59
  28. package/files/.wl-skills/src/components/local/c_formModal/README.md +235 -235
  29. package/files/.wl-skills/src/components/local/c_formModal/data.ts +95 -95
  30. package/files/.wl-skills/src/components/local/c_formModal/index.scss +8 -8
  31. package/files/.wl-skills/src/components/local/c_formModal/index.vue +107 -107
  32. package/files/.wl-skills/src/components/local/c_formSections/data.ts +175 -175
  33. package/files/.wl-skills/src/components/local/c_formSections/index.scss +280 -280
  34. package/files/.wl-skills/src/components/local/c_formSections/index.vue +429 -429
  35. package/files/.wl-skills/src/components/local/c_listModal/data.ts +41 -41
  36. package/files/.wl-skills/src/components/local/c_listModal/index.vue +136 -136
  37. package/files/.wl-skills/src/components/local/c_spliterTitle/index.scss +25 -25
  38. package/files/.wl-skills/src/components/local/c_spliterTitle/index.vue +21 -21
  39. package/files/.wl-skills/src/components/remote/AGGrid/README.md +530 -530
  40. package/files/.wl-skills/src/components/remote/BaseForm/README.md +508 -508
  41. package/files/.wl-skills/src/components/remote/BaseQuery/README.md +865 -865
  42. package/files/.wl-skills/src/components/remote/BaseTable/README.md +941 -941
  43. package/files/.wl-skills/src/components/remote/BaseToolbar/README.md +496 -496
  44. package/files/.wl-skills/src/types/page.ts +24 -24
  45. package/files/.wl-skills/standards/04-coding-basics.md +39 -1
  46. package/files/.wl-skills/standards/09-typescript.md +26 -3
  47. package/files/.wl-skills/standards/14-layout-containers.md +6 -6
  48. package/files/.wl-skills/standards/index.md +2 -2
  49. package/files/.wl-skills/templates/README.md +44 -44
  50. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add/api.md +54 -54
  51. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add/data.ts +346 -346
  52. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add/index.scss +1 -1
  53. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add/index.vue +28 -28
  54. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add-form/data.ts +115 -115
  55. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add-form/index.scss +44 -44
  56. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add-form/index.vue +43 -43
  57. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change/data.ts +338 -338
  58. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change/index.scss +1 -1
  59. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change/index.vue +28 -28
  60. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change-form/data.ts +115 -115
  61. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change-form/index.scss +44 -44
  62. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change-form/index.vue +43 -43
  63. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-archive/api.md +88 -88
  64. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-archive/data.ts +601 -601
  65. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-archive/index.scss +1 -1
  66. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-archive/index.vue +64 -64
  67. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-detail/api.md +67 -67
  68. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-detail/data.ts +286 -286
  69. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-detail/index.scss +139 -139
  70. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-detail/index.vue +318 -318
  71. package/files/.wl-skills/templates/produce/aiflow/mmwr-temp-customer-archive/api.md +98 -98
  72. package/files/.wl-skills/templates/produce/aiflow/mmwr-temp-customer-archive/data.ts +543 -543
  73. package/files/.wl-skills/templates/produce/aiflow/mmwr-temp-customer-archive/index.scss +1 -1
  74. package/files/.wl-skills/templates/produce/aiflow/mmwr-temp-customer-archive/index.vue +52 -52
  75. package/files/.wl-skills/templates/sale/demo/add-demo/data.ts +518 -518
  76. package/files/.wl-skills/templates/sale/demo/billet-flame-cut-plan/data.ts +524 -524
  77. package/files/.wl-skills/templates/sale/demo/billet-flame-cut-plan/index.scss +154 -154
  78. package/files/.wl-skills/templates/sale/demo/billet-flame-cut-plan/index.vue +117 -117
  79. package/files/.wl-skills/templates/sale/demo/domestic-trade-order/data.ts +308 -308
  80. package/files/.wl-skills/templates/sale/demo/domestic-trade-order/index.scss +99 -99
  81. package/files/.wl-skills/templates/sale/demo/domestic-trade-order/index.vue +77 -77
  82. package/files/.wl-skills/templates/sale/demo/heat-batch-return/data.ts +367 -367
  83. package/files/.wl-skills/templates/sale/demo/heat-batch-return/index.scss +100 -100
  84. package/files/.wl-skills/templates/sale/demo/heat-batch-return/index.vue +170 -170
  85. package/files/.wl-skills/templates/sale/demo/heat-batch-return/meltDialog.vue +320 -320
  86. package/files/.wl-skills/templates/sale/demo/metallurgical-spec/data.ts +824 -824
  87. package/lib/ast-rules.js +304 -9
  88. package/lib/page-spec.js +588 -0
  89. package/lib/safe-fix.js +115 -0
  90. package/mcp/config.js +47 -47
  91. package/mcp/registry.js +6 -1
  92. package/mcp/tools/projectTools.js +19 -1
  93. package/package.json +16 -11
  94. package/files/.wl-skills/src/components/global/C_Splitter/index.scss +0 -61
  95. package/files/.wl-skills/src/components/global/C_Splitter/index.vue +0 -149
package/lib/ast-rules.js CHANGED
@@ -7,7 +7,7 @@
7
7
  * 依赖:@vue/compiler-sfc(解析 .vue)、@babel/parser(解析 <script> AST)
8
8
  * 这两个包在 Vue 3 + Vite 项目中天然存在,用 try-require 做优雅降级。
9
9
  *
10
- * 规则编号 R1~R12 对应 standards 02/06/07/10/12/13 中的语义约束:
10
+ * 规则编号 R1~R14 对应 standards 02/04/06/07/09/10/12/13 中的语义约束:
11
11
  * R1: index.vue <script setup> 业务逻辑行数超阈值 → warn(02)
12
12
  * R2: index.vue 含禁止 import(getAction/postAction/sessionStorage 等)→ error(02/06)
13
13
  * R3: 页面用 <el-table> 但未用 <BaseTable> → error(12/13)
@@ -20,17 +20,23 @@
20
20
  * R10: 平台组件替换检测 — el-form/el-select/el-date-picker 等应替换为平台封装 → error(13)
21
21
  * R11: data.ts 禁止 import Pinia Store → error(10)
22
22
  * R12: 硬编码 IP/URL 检测 → error/warn(07)
23
+ * R13: 单函数圈复杂度 > 10(Mcabe,与 ESLint complexity 定义一致)→ error(04)
24
+ * R14: 文件类型错误零容忍 — vue-tsc/tsc --noEmit 产物解析 → error(09)
25
+ * 注:R14 为项目级检查,体积较大,validate 默认不跑,
26
+ * 需显式 --typecheck(CLI)/ typecheck:true(MCP)触发,优雅降级为 warn
23
27
  *
24
28
  * 导出函数:
25
29
  * runAstRules(targetDir, scanRel, { stagedFiles }) → { issues, pages }
26
30
  * parseVueScript(absPath) → { content, template, source } | null
27
31
  * countEffectiveLines(scriptContent) → number
32
+ * computeFunctionComplexity(fnNode) → number
33
+ * runTypeCheck(root) → { issues, ran, errorCount }
28
34
  * hasAstAvailable() → boolean
29
35
  */
30
36
 
31
37
  const fs = require("fs");
32
38
  const path = require("path");
33
- const { execFileSync } = require("child_process");
39
+ const { execFileSync, spawnSync } = require("child_process");
34
40
 
35
41
  // ─── AST 依赖探测(优雅降级)──────────────────────────────────────────
36
42
  //
@@ -159,6 +165,10 @@ const CONFIG = {
159
165
  ],
160
166
  FORBIDDEN_GLOBALS: ["sessionStorage", "localStorage"],
161
167
  WARN_IMPORTS: ["useRoute"],
168
+ // R13: 单函数圈复杂度上限(Mcabe),与 ESLint complexity 规则阈值一致
169
+ MAX_CYCLOMATIC_COMPLEXITY: 10,
170
+ // R14: 单页类型错误采集上限(避免输出爆炸)
171
+ TYPECHECK_ERROR_CAP: 50,
162
172
  SKIP_DIRS: ["node_modules", "dist", ".git", "demo", "template"],
163
173
  };
164
174
 
@@ -238,22 +248,30 @@ function countEffectiveLines(scriptContent) {
238
248
  }
239
249
 
240
250
  /**
241
- * 用 babel/parser 解析 script,提取 import 标识符和来源
251
+ * 用 babel/parser 解析 script AST(复用给 extractScriptInfo / 圈复杂度计算)
242
252
  */
243
- function extractScriptInfo(scriptContent) {
244
- if (!ensureAst() || !scriptContent) {
245
- return { specifiers: [], sources: [] };
246
- }
247
- let ast;
253
+ function parseScriptAst(scriptContent) {
254
+ if (!ensureAst() || !scriptContent) return null;
248
255
  try {
249
- ast = _babelParser.parse(scriptContent, {
256
+ return _babelParser.parse(scriptContent, {
250
257
  sourceType: "module",
251
258
  plugins: ["typescript", "jsx"],
252
259
  errorRecovery: true,
253
260
  });
254
261
  } catch {
262
+ return null;
263
+ }
264
+ }
265
+
266
+ /**
267
+ * 用 babel/parser 解析 script,提取 import 标识符和来源
268
+ */
269
+ function extractScriptInfo(scriptContent) {
270
+ if (!ensureAst() || !scriptContent) {
255
271
  return { specifiers: [], sources: [] };
256
272
  }
273
+ const ast = parseScriptAst(scriptContent);
274
+ if (!ast) return { specifiers: [], sources: [] };
257
275
  const specifiers = [];
258
276
  const sources = [];
259
277
  for (const node of ast.program.body) {
@@ -272,6 +290,114 @@ function extractScriptInfo(scriptContent) {
272
290
  return { specifiers, sources };
273
291
  }
274
292
 
293
+ // ─── R13 圈复杂度(Mcabe)──────────────────────────────────────────────
294
+ //
295
+ // 定义与 ESLint `complexity` 规则一致:复杂度 = 1 + 决策点数。
296
+ // 不依赖 @babel/traverse,自写轻量遍历,避免新增运行时依赖。
297
+
298
+ const COMPLEXITY_NODE_TYPES = new Set([
299
+ "IfStatement", // if / else if(每个 IfStatement 计 1)
300
+ "SwitchCase", // 每个 case / default
301
+ "ForStatement",
302
+ "ForInStatement",
303
+ "ForOfStatement",
304
+ "WhileStatement",
305
+ "DoWhileStatement",
306
+ "CatchClause",
307
+ "ConditionalExpression", // 三元 ?:
308
+ "LogicalExpression", // && / || / ??
309
+ ]);
310
+
311
+ const FUNCTION_NODE_TYPES = new Set([
312
+ "FunctionDeclaration",
313
+ "FunctionExpression",
314
+ "ArrowFunctionExpression",
315
+ ]);
316
+
317
+ function isFunctionNode(node) {
318
+ return Boolean(node) && FUNCTION_NODE_TYPES.has(node.type);
319
+ }
320
+
321
+ // 取节点所有子 AST 节点(跳过位置/范围元信息)
322
+ function getChildNodes(node) {
323
+ const out = [];
324
+ for (const key of Object.keys(node)) {
325
+ if (key === "loc" || key === "range" || key === "start" || key === "end") {
326
+ continue;
327
+ }
328
+ const child = node[key];
329
+ if (Array.isArray(child)) {
330
+ for (const c of child) {
331
+ if (c && typeof c.type === "string") out.push(c);
332
+ }
333
+ } else if (child && typeof child.type === "string") {
334
+ out.push(child);
335
+ }
336
+ }
337
+ return out;
338
+ }
339
+
340
+ // 尽力推断函数名(变量赋值 / 类方法 / 对象方法 / 命名函数表达式)
341
+ function resolveFnName(node, parent) {
342
+ if (node.id && node.id.name) return node.id.name;
343
+ if (!parent) return "(anonymous)";
344
+ if (parent.type === "VariableDeclarator" && parent.id && parent.id.name) {
345
+ return parent.id.name;
346
+ }
347
+ if (
348
+ (parent.type === "MethodDefinition" || parent.type === "Property") &&
349
+ parent.key
350
+ ) {
351
+ return parent.key.name || parent.key.value || "(anonymous)";
352
+ }
353
+ if (parent.type === "AssignmentExpression" && parent.left) {
354
+ const left = parent.left;
355
+ if (left.property) return left.property.name || left.property.value;
356
+ if (left.name) return left.name;
357
+ }
358
+ return "(anonymous)";
359
+ }
360
+
361
+ // 收集整棵 AST 中的所有函数节点 + 名字(含嵌套函数,各独立计 R13)
362
+ function collectFunctions(ast) {
363
+ const fns = [];
364
+ const stack = [];
365
+ function walk(node) {
366
+ if (!node || typeof node.type !== "string") return;
367
+ let pushed = false;
368
+ if (isFunctionNode(node)) {
369
+ const parent = stack.length ? stack[stack.length - 1] : null;
370
+ fns.push({ node, name: resolveFnName(node, parent) });
371
+ // 不再下钻到该函数体内部去发现"孙函数"——
372
+ // 嵌套函数会在遍历其父函数体时自然被收集
373
+ }
374
+ stack.push(node);
375
+ pushed = true;
376
+ for (const child of getChildNodes(node)) walk(child);
377
+ if (pushed) stack.pop();
378
+ }
379
+ walk(ast);
380
+ return fns;
381
+ }
382
+
383
+ /**
384
+ * 计算单个函数的圈复杂度(不下钻进嵌套函数体,嵌套函数独立计)
385
+ * @param {object} fnNode FunctionDeclaration / FunctionExpression / ArrowFunctionExpression
386
+ * @returns {number}
387
+ */
388
+ function computeFunctionComplexity(fnNode) {
389
+ if (!fnNode) return 0;
390
+ let complexity = 1;
391
+ function walk(node) {
392
+ if (!node || typeof node.type !== "string") return;
393
+ if (node !== fnNode && isFunctionNode(node)) return; // 嵌套函数边界
394
+ if (COMPLEXITY_NODE_TYPES.has(node.type)) complexity++;
395
+ for (const child of getChildNodes(node)) walk(child);
396
+ }
397
+ walk(fnNode);
398
+ return complexity;
399
+ }
400
+
275
401
  /**
276
402
  * 检测模板中是否有 el-table(非 BaseTable)
277
403
  */
@@ -419,6 +545,34 @@ function runAstRules(targetDir, scanRel, options) {
419
545
  });
420
546
  }
421
547
 
548
+ // R13: 单函数圈复杂度 ≤ MAX_CYCLOMATIC_COMPLEXITY(standard 04,Mcabe)
549
+ // 覆盖 index.vue <script> 与 data.ts 的所有函数/方法/箭头函数
550
+ if (!hasIgnoreMarker(fullSource, "R13")) {
551
+ const maxC = CONFIG.MAX_CYCLOMATIC_COMPLEXITY;
552
+ const scanComplexity = (code, label) => {
553
+ const ast = parseScriptAst(code);
554
+ if (!ast) return;
555
+ for (const fn of collectFunctions(ast)) {
556
+ const cc = computeFunctionComplexity(fn.node);
557
+ if (cc > maxC) {
558
+ issues.push({
559
+ level: "error",
560
+ dir: page.dir,
561
+ text:
562
+ label + " 函数 " + fn.name +
563
+ "() 圈复杂度 " + cc + "(阈值 " + maxC +
564
+ "),需拆分为更小函数(standard 04)",
565
+ rule: "R13",
566
+ });
567
+ }
568
+ }
569
+ };
570
+ scanComplexity(scriptContent, "index.vue");
571
+ if (fs.existsSync(dataPath)) {
572
+ scanComplexity(fs.readFileSync(dataPath, "utf8"), "data.ts");
573
+ }
574
+ }
575
+
422
576
  // R2: 禁止的 import / 全局 API
423
577
  if (scriptContent) {
424
578
  const { specifiers, sources } = extractScriptInfo(scriptContent);
@@ -754,11 +908,152 @@ function getStagedFiles(targetDir) {
754
908
  }
755
909
  }
756
910
 
911
+ // ─── R14 类型错误零容忍(项目级,vue-tsc / tsc 委托)──────────────────
912
+ //
913
+ // 体积较大,validate 默认不触发,由 CLI --typecheck / MCP typecheck:true 显式开启。
914
+ // 无 tsconfig / 无 checker → 优雅降级为 warn(与 AST 依赖降级策略一致)。
915
+ // 该函数不进入 page 粒度,整项目执行一次,结果按文件归并到 issues。
916
+
917
+ function runTypeCheck(root) {
918
+ const safeRoot = root || process.cwd();
919
+ const label = path.basename(safeRoot) || ".";
920
+ const tsconfigPath = path.join(safeRoot, "tsconfig.json");
921
+
922
+ if (!fs.existsSync(tsconfigPath)) {
923
+ return {
924
+ issues: [
925
+ {
926
+ level: "warn",
927
+ dir: label,
928
+ text: "未发现 tsconfig.json,跳过类型检查 R14",
929
+ rule: "R14",
930
+ },
931
+ ],
932
+ ran: false,
933
+ errorCount: 0,
934
+ };
935
+ }
936
+
937
+ const nmBin = path.join(safeRoot, "node_modules", ".bin");
938
+ const envPath =
939
+ nmBin + path.delimiter + (process.env.PATH || process.env.Path || "");
940
+ const env = Object.assign({}, process.env, { PATH: envPath });
941
+
942
+ // 优先 vue-tsc(.vue 项目),回退 tsc;shell:true 让 Windows 找到 .cmd
943
+ let checker = null;
944
+ for (const bin of ["vue-tsc", "tsc"]) {
945
+ try {
946
+ const probe = spawnSync(bin, ["--version"], {
947
+ shell: true,
948
+ env,
949
+ encoding: "utf8",
950
+ timeout: 20000,
951
+ });
952
+ if (probe.status === 0) {
953
+ checker = bin;
954
+ break;
955
+ }
956
+ } catch {
957
+ // ignore, try next
958
+ }
959
+ }
960
+ if (!checker) {
961
+ return {
962
+ issues: [
963
+ {
964
+ level: "warn",
965
+ dir: label,
966
+ text: "未发现 vue-tsc / tsc,跳过类型检查 R14(建议安装后纳入 CI)",
967
+ rule: "R14",
968
+ },
969
+ ],
970
+ ran: false,
971
+ errorCount: 0,
972
+ };
973
+ }
974
+
975
+ let result;
976
+ try {
977
+ result = spawnSync(checker, ["--noEmit"], {
978
+ cwd: safeRoot,
979
+ shell: true,
980
+ env,
981
+ encoding: "utf8",
982
+ timeout: 180000,
983
+ });
984
+ } catch (e) {
985
+ return {
986
+ issues: [
987
+ {
988
+ level: "warn",
989
+ dir: label,
990
+ text:
991
+ "类型检查执行异常:" + ((e && e.message) || String(e)),
992
+ rule: "R14",
993
+ },
994
+ ],
995
+ ran: false,
996
+ errorCount: 0,
997
+ };
998
+ }
999
+
1000
+ const out =
1001
+ String(result.stdout || "") + String(result.stderr || "");
1002
+ // 标准格式:path(line,col): error TS1234: message
1003
+ // 捕获组:1=file 2=line 3=col 4=code 5=msg
1004
+ const errRe = /^(.+?)\((\d+),(\d+)\):\s+error\s+(TS\d+):\s*(.+)$/gm;
1005
+ const errors = [];
1006
+ let m;
1007
+ while ((m = errRe.exec(out)) !== null) {
1008
+ errors.push({ file: m[1], line: m[2], code: m[4], msg: m[5] });
1009
+ if (errors.length >= CONFIG.TYPECHECK_ERROR_CAP) break;
1010
+ }
1011
+
1012
+ if (errors.length === 0) {
1013
+ if (result.status === 0) {
1014
+ return { issues: [], ran: true, errorCount: 0 };
1015
+ }
1016
+ // 退出码非 0 但未解析出标准 error 行:疑似 tsconfig / 配置级错误
1017
+ return {
1018
+ issues: [
1019
+ {
1020
+ level: "error",
1021
+ dir: label,
1022
+ text:
1023
+ checker +
1024
+ " --noEmit 退出码 " +
1025
+ result.status +
1026
+ "(请检查 tsconfig / 类型配置,无标准 TS 错误输出)",
1027
+ rule: "R14",
1028
+ },
1029
+ ],
1030
+ ran: true,
1031
+ errorCount: 1,
1032
+ };
1033
+ }
1034
+
1035
+ const issues = errors.map((e) => {
1036
+ const rel = path.relative(safeRoot, e.file).replace(/\\/g, "/") || e.file;
1037
+ return {
1038
+ level: "error",
1039
+ dir: path.dirname(rel) || ".",
1040
+ text:
1041
+ e.code + " " + e.msg + " (" + path.basename(rel) + ":" + e.line + ")",
1042
+ rule: "R14",
1043
+ };
1044
+ });
1045
+ return { issues, ran: true, errorCount: errors.length };
1046
+ }
1047
+
757
1048
  module.exports = {
758
1049
  runAstRules,
759
1050
  parseVueScript,
760
1051
  countEffectiveLines,
761
1052
  extractScriptInfo,
1053
+ parseScriptAst,
1054
+ computeFunctionComplexity,
1055
+ collectFunctions,
1056
+ runTypeCheck,
762
1057
  hasAstAvailable,
763
1058
  isAstFunctionallyUsable,
764
1059
  getStagedFiles,