@aiready/consistency 0.16.2 → 0.16.3

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/dist/cli.js CHANGED
@@ -27,7 +27,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
27
  var import_commander = require("commander");
28
28
 
29
29
  // src/analyzer.ts
30
- var import_core4 = require("@aiready/core");
30
+ var import_core5 = require("@aiready/core");
31
+
32
+ // src/analyzers/naming-ast.ts
33
+ var import_core2 = require("@aiready/core");
31
34
 
32
35
  // src/utils/ast-parser.ts
33
36
  var import_typescript_estree = require("@typescript-eslint/typescript-estree");
@@ -79,214 +82,12 @@ function isLoopStatement(node) {
79
82
  "DoWhileStatement"
80
83
  ].includes(node.type);
81
84
  }
82
- function getFunctionName(node) {
83
- switch (node.type) {
84
- case "FunctionDeclaration":
85
- return node.id?.name ?? null;
86
- case "FunctionExpression":
87
- return node.id?.name ?? null;
88
- case "ArrowFunctionExpression":
89
- return null;
90
- // Arrow functions don't have names directly
91
- case "MethodDefinition":
92
- if (node.key.type === "Identifier") {
93
- return node.key.name;
94
- }
95
- return null;
96
- default:
97
- return null;
98
- }
99
- }
100
85
  function getLineNumber(node) {
101
86
  return node.loc?.start.line ?? 0;
102
87
  }
103
- function isCoverageContext(node, ancestors) {
104
- const coveragePatterns = /coverage|summary|metrics|pct|percent|statements|branches|functions|lines/i;
105
- if (node.type === "Identifier" && coveragePatterns.test(node.name)) {
106
- return true;
107
- }
108
- for (const ancestor of ancestors.slice(-3)) {
109
- if (ancestor.type === "MemberExpression") {
110
- const memberExpr = ancestor;
111
- if (memberExpr.object.type === "Identifier" && coveragePatterns.test(memberExpr.object.name)) {
112
- return true;
113
- }
114
- }
115
- if (ancestor.type === "ObjectPattern" || ancestor.type === "ObjectExpression") {
116
- const parent = ancestors[ancestors.indexOf(ancestor) - 1];
117
- if (parent?.type === "VariableDeclarator") {
118
- const varDecl = parent;
119
- if (varDecl.id.type === "Identifier" && coveragePatterns.test(varDecl.id.name)) {
120
- return true;
121
- }
122
- }
123
- }
124
- }
125
- return false;
126
- }
127
-
128
- // src/utils/scope-tracker.ts
129
- var ScopeTracker = class {
130
- constructor(rootNode) {
131
- this.allScopes = [];
132
- this.rootScope = {
133
- type: "global",
134
- node: rootNode,
135
- parent: null,
136
- children: [],
137
- variables: /* @__PURE__ */ new Map()
138
- };
139
- this.currentScope = this.rootScope;
140
- this.allScopes.push(this.rootScope);
141
- }
142
- /**
143
- * Enter a new scope
144
- */
145
- enterScope(type, node) {
146
- const newScope = {
147
- type,
148
- node,
149
- parent: this.currentScope,
150
- children: [],
151
- variables: /* @__PURE__ */ new Map()
152
- };
153
- this.currentScope.children.push(newScope);
154
- this.currentScope = newScope;
155
- this.allScopes.push(newScope);
156
- }
157
- /**
158
- * Exit current scope and return to parent
159
- */
160
- exitScope() {
161
- if (this.currentScope.parent) {
162
- this.currentScope = this.currentScope.parent;
163
- }
164
- }
165
- /**
166
- * Declare a variable in the current scope
167
- */
168
- declareVariable(name, node, line, options = {}) {
169
- const varInfo = {
170
- name,
171
- node,
172
- declarationLine: line,
173
- references: [],
174
- type: options.type,
175
- isParameter: options.isParameter ?? false,
176
- isDestructured: options.isDestructured ?? false,
177
- isLoopVariable: options.isLoopVariable ?? false
178
- };
179
- this.currentScope.variables.set(name, varInfo);
180
- }
181
- /**
182
- * Add a reference to a variable
183
- */
184
- addReference(name, node) {
185
- const varInfo = this.findVariable(name);
186
- if (varInfo) {
187
- varInfo.references.push(node);
188
- }
189
- }
190
- /**
191
- * Find a variable in current or parent scopes
192
- */
193
- findVariable(name) {
194
- let scope = this.currentScope;
195
- while (scope) {
196
- const varInfo = scope.variables.get(name);
197
- if (varInfo) {
198
- return varInfo;
199
- }
200
- scope = scope.parent;
201
- }
202
- return null;
203
- }
204
- /**
205
- * Get all variables in current scope (not including parent scopes)
206
- */
207
- getCurrentScopeVariables() {
208
- return Array.from(this.currentScope.variables.values());
209
- }
210
- /**
211
- * Get all variables across all scopes
212
- */
213
- getAllVariables() {
214
- const allVars = [];
215
- for (const scope of this.allScopes) {
216
- allVars.push(...Array.from(scope.variables.values()));
217
- }
218
- return allVars;
219
- }
220
- /**
221
- * Calculate actual usage count (references minus declaration)
222
- */
223
- getUsageCount(varInfo) {
224
- return varInfo.references.length;
225
- }
226
- /**
227
- * Check if a variable is short-lived (used within N lines)
228
- */
229
- isShortLived(varInfo, maxLines = 5) {
230
- if (varInfo.references.length === 0) {
231
- return false;
232
- }
233
- const declarationLine = varInfo.declarationLine;
234
- const maxUsageLine = Math.max(
235
- ...varInfo.references.map((ref) => ref.loc?.start.line ?? declarationLine)
236
- );
237
- return maxUsageLine - declarationLine <= maxLines;
238
- }
239
- /**
240
- * Check if a variable is used in a limited scope (e.g., only in one callback)
241
- */
242
- isLocallyScoped(varInfo) {
243
- if (varInfo.references.length === 0) return false;
244
- const lines = varInfo.references.map((ref) => ref.loc?.start.line ?? 0);
245
- const minLine = Math.min(...lines);
246
- const maxLine = Math.max(...lines);
247
- return maxLine - minLine <= 3;
248
- }
249
- /**
250
- * Get current scope type
251
- */
252
- getCurrentScopeType() {
253
- return this.currentScope.type;
254
- }
255
- /**
256
- * Check if currently in a loop scope
257
- */
258
- isInLoop() {
259
- let scope = this.currentScope;
260
- while (scope) {
261
- if (scope.type === "loop") {
262
- return true;
263
- }
264
- scope = scope.parent;
265
- }
266
- return false;
267
- }
268
- /**
269
- * Check if currently in a function scope
270
- */
271
- isInFunction() {
272
- let scope = this.currentScope;
273
- while (scope) {
274
- if (scope.type === "function") {
275
- return true;
276
- }
277
- scope = scope.parent;
278
- }
279
- return false;
280
- }
281
- /**
282
- * Get the root scope
283
- */
284
- getRootScope() {
285
- return this.rootScope;
286
- }
287
- };
288
88
 
289
89
  // src/utils/context-detector.ts
90
+ var import_core = require("@aiready/core");
290
91
  function detectFileType(filePath, ast) {
291
92
  void ast;
292
93
  const path = filePath.toLowerCase();
@@ -414,24 +215,34 @@ function buildCodeContext(filePath, ast) {
414
215
  };
415
216
  }
416
217
  function adjustSeverity(baseSeverity, context, issueType) {
218
+ const getEnum = (s) => {
219
+ if (s === import_core.Severity.Critical || s === "critical") return import_core.Severity.Critical;
220
+ if (s === import_core.Severity.Major || s === "major") return import_core.Severity.Major;
221
+ if (s === import_core.Severity.Minor || s === "minor") return import_core.Severity.Minor;
222
+ return import_core.Severity.Info;
223
+ };
224
+ let currentSev = getEnum(baseSeverity);
417
225
  if (context.isTestFile) {
418
- if (baseSeverity === "minor") return "info";
419
- if (baseSeverity === "major") return "minor";
226
+ if (currentSev === import_core.Severity.Minor) currentSev = import_core.Severity.Info;
227
+ if (currentSev === import_core.Severity.Major) currentSev = import_core.Severity.Minor;
420
228
  }
421
229
  if (context.isTypeDefinition) {
422
- if (baseSeverity === "minor") return "info";
230
+ if (currentSev === import_core.Severity.Minor) currentSev = import_core.Severity.Info;
423
231
  }
424
232
  if (context.codeLayer === "api") {
425
- if (baseSeverity === "info" && issueType === "unclear") return "minor";
426
- if (baseSeverity === "minor" && issueType === "unclear") return "major";
233
+ if (currentSev === import_core.Severity.Info && issueType === "unclear")
234
+ currentSev = import_core.Severity.Minor;
235
+ if (currentSev === import_core.Severity.Minor && issueType === "unclear")
236
+ currentSev = import_core.Severity.Major;
427
237
  }
428
238
  if (context.complexity > 10) {
429
- if (baseSeverity === "info") return "minor";
239
+ if (currentSev === import_core.Severity.Info) currentSev = import_core.Severity.Minor;
430
240
  }
431
241
  if (context.codeLayer === "utility") {
432
- if (baseSeverity === "minor" && issueType === "abbreviation") return "info";
242
+ if (currentSev === import_core.Severity.Minor && issueType === "abbreviation")
243
+ currentSev = import_core.Severity.Info;
433
244
  }
434
- return baseSeverity;
245
+ return currentSev;
435
246
  }
436
247
  function isAcceptableInContext(name, context, options) {
437
248
  if (options.isLoopVariable && ["i", "j", "k", "l", "n", "m"].includes(name)) {
@@ -458,638 +269,157 @@ function isAcceptableInContext(name, context, options) {
458
269
  return false;
459
270
  }
460
271
 
461
- // src/utils/config-loader.ts
462
- var import_core = require("@aiready/core");
463
- var import_path = require("path");
464
-
465
- // src/analyzers/naming-constants.ts
466
- var COMMON_SHORT_WORDS = /* @__PURE__ */ new Set([
467
- // Full English words (1-3 letters)
468
- "day",
469
- "key",
470
- "net",
471
- "to",
472
- "go",
473
- "for",
474
- "not",
475
- "new",
476
- "old",
477
- "top",
478
- "end",
479
- "run",
480
- "try",
481
- "use",
482
- "get",
483
- "set",
484
- "add",
485
- "put",
486
- "map",
487
- "log",
488
- "row",
489
- "col",
490
- "tab",
491
- "box",
492
- "div",
493
- "nav",
494
- "tag",
495
- "any",
496
- "all",
497
- "one",
498
- "two",
499
- "out",
500
- "off",
501
- "on",
502
- "yes",
503
- "no",
504
- "now",
505
- "max",
506
- "min",
507
- "sum",
508
- "avg",
509
- "ref",
510
- "src",
511
- "dst",
512
- "raw",
513
- "def",
514
- "sub",
515
- "pub",
516
- "pre",
517
- "mid",
518
- "alt",
519
- "opt",
520
- "tmp",
521
- "ext",
522
- "sep",
523
- // Prepositions and conjunctions
524
- "and",
525
- "from",
526
- "how",
527
- "pad",
528
- "bar",
529
- "non",
530
- // Additional full words commonly flagged
531
- "tax",
532
- "cat",
533
- "dog",
534
- "car",
535
- "bus",
536
- "web",
537
- "app",
538
- "war",
539
- "law",
540
- "pay",
541
- "buy",
542
- "win",
543
- "cut",
544
- "hit",
545
- "hot",
546
- "pop",
547
- "job",
548
- "age",
549
- "act",
550
- "let",
551
- "lot",
552
- "bad",
553
- "big",
554
- "far",
555
- "few",
556
- "own",
557
- "per",
558
- "red",
559
- "low",
560
- "see",
561
- "six",
562
- "ten",
563
- "way",
564
- "who",
565
- "why",
566
- "yet",
567
- "via",
568
- "due",
569
- "fee",
570
- "fun",
571
- "gas",
572
- "gay",
573
- "god",
574
- "gun",
575
- "guy",
576
- "ice",
577
- "ill",
578
- "kid",
579
- "mad",
580
- "man",
581
- "mix",
582
- "mom",
583
- "mrs",
584
- "nor",
585
- "odd",
586
- "oil",
587
- "pan",
588
- "pet",
589
- "pit",
590
- "pot",
591
- "pow",
592
- "pro",
593
- "raw",
594
- "rep",
595
- "rid",
596
- "sad",
597
- "sea",
598
- "sit",
599
- "sky",
600
- "son",
601
- "tea",
602
- "tie",
603
- "tip",
604
- "van",
605
- "war",
606
- "win",
607
- "won"
608
- ]);
609
- var ACCEPTABLE_ABBREVIATIONS = /* @__PURE__ */ new Set([
610
- // Standard identifiers
611
- "id",
612
- "uid",
613
- "gid",
614
- "pid",
615
- // Loop counters and iterators
616
- "i",
617
- "j",
618
- "k",
619
- "n",
620
- "m",
621
- // Web/Network
622
- "url",
623
- "uri",
624
- "api",
625
- "cdn",
626
- "dns",
627
- "ip",
628
- "tcp",
629
- "udp",
630
- "http",
631
- "ssl",
632
- "tls",
633
- "utm",
634
- "seo",
635
- "rss",
636
- "xhr",
637
- "ajax",
638
- "cors",
639
- "ws",
640
- "wss",
641
- // Data formats
642
- "json",
643
- "xml",
644
- "yaml",
645
- "csv",
646
- "html",
647
- "css",
648
- "svg",
649
- "pdf",
650
- // File types & extensions
651
- "img",
652
- "txt",
653
- "doc",
654
- "docx",
655
- "xlsx",
656
- "ppt",
657
- "md",
658
- "rst",
659
- "jpg",
660
- "png",
661
- "gif",
662
- // Databases
663
- "db",
664
- "sql",
665
- "orm",
666
- "dao",
667
- "dto",
668
- "ddb",
669
- "rds",
670
- "nosql",
671
- // File system
672
- "fs",
673
- "dir",
674
- "tmp",
675
- "src",
676
- "dst",
677
- "bin",
678
- "lib",
679
- "pkg",
680
- // Operating system
681
- "os",
682
- "env",
683
- "arg",
684
- "cli",
685
- "cmd",
686
- "exe",
687
- "cwd",
688
- "pwd",
689
- // UI/UX
690
- "ui",
691
- "ux",
692
- "gui",
693
- "dom",
694
- "ref",
695
- // Request/Response
696
- "req",
697
- "res",
698
- "ctx",
699
- "err",
700
- "msg",
701
- "auth",
702
- // Mathematics/Computing
703
- "max",
704
- "min",
705
- "avg",
706
- "sum",
707
- "abs",
708
- "cos",
709
- "sin",
710
- "tan",
711
- "log",
712
- "exp",
713
- "pow",
714
- "sqrt",
715
- "std",
716
- "var",
717
- "int",
718
- "num",
719
- "idx",
720
- // Time
721
- "now",
722
- "utc",
723
- "tz",
724
- "ms",
725
- "sec",
726
- "hr",
727
- "min",
728
- "yr",
729
- "mo",
730
- // Common patterns
731
- "app",
732
- "cfg",
733
- "config",
734
- "init",
735
- "len",
736
- "val",
737
- "str",
738
- "obj",
739
- "arr",
740
- "gen",
741
- "def",
742
- "raw",
743
- "new",
744
- "old",
745
- "pre",
746
- "post",
747
- "sub",
748
- "pub",
749
- // Programming/Framework specific
750
- "ts",
751
- "js",
752
- "jsx",
753
- "tsx",
754
- "py",
755
- "rb",
756
- "vue",
757
- "re",
758
- "fn",
759
- "fns",
760
- "mod",
761
- "opts",
762
- "dev",
763
- // Cloud/Infrastructure
764
- "s3",
765
- "ec2",
766
- "sqs",
767
- "sns",
768
- "vpc",
769
- "ami",
770
- "iam",
771
- "acl",
772
- "elb",
773
- "alb",
774
- "nlb",
775
- "aws",
776
- "ses",
777
- "gst",
778
- "cdk",
779
- "btn",
780
- "buf",
781
- "agg",
782
- "ocr",
783
- "ai",
784
- "cf",
785
- "cfn",
786
- "ga",
787
- // Metrics/Performance
788
- "fcp",
789
- "lcp",
790
- "cls",
791
- "ttfb",
792
- "tti",
793
- "fid",
794
- "fps",
795
- "qps",
796
- "rps",
797
- "tps",
798
- "wpm",
799
- // Testing & i18n
800
- "po",
801
- "e2e",
802
- "a11y",
803
- "i18n",
804
- "l10n",
805
- "spy",
806
- // Domain-specific abbreviations (context-aware)
807
- "sk",
808
- "fy",
809
- "faq",
810
- "og",
811
- "seo",
812
- "cta",
813
- "roi",
814
- "kpi",
815
- "ttl",
816
- "pct",
817
- // Technical abbreviations
818
- "mac",
819
- "hex",
820
- "esm",
821
- "git",
822
- "rec",
823
- "loc",
824
- "dup",
825
- // Boolean helpers (these are intentional short names)
826
- "is",
827
- "has",
828
- "can",
829
- "did",
830
- "was",
831
- "are",
832
- // Date/Time context (when in date contexts)
833
- "d",
834
- "t",
835
- "dt",
836
- // Coverage metrics (industry standard: statements/branches/functions/lines)
837
- "s",
838
- "b",
839
- "f",
840
- "l",
841
- // Common media/content abbreviations
842
- "vid",
843
- "pic",
844
- "img",
845
- "doc",
846
- "msg"
847
- ]);
848
-
849
- // src/utils/config-loader.ts
850
- async function loadNamingConfig(files) {
851
- const rootDir = files.length > 0 ? (0, import_path.dirname)(files[0]) : process.cwd();
852
- const config = await (0, import_core.loadConfig)(rootDir);
853
- const consistencyConfig = config?.tools?.["consistency"];
854
- const customAbbreviations = new Set(
855
- consistencyConfig?.acceptedAbbreviations || []
856
- );
857
- const customShortWords = new Set(consistencyConfig?.shortWords || []);
858
- const disabledChecks = new Set(consistencyConfig?.disableChecks || []);
859
- const allAbbreviations = /* @__PURE__ */ new Set([
860
- ...ACCEPTABLE_ABBREVIATIONS,
861
- ...customAbbreviations
862
- ]);
863
- const allShortWords = /* @__PURE__ */ new Set([...COMMON_SHORT_WORDS, ...customShortWords]);
864
- return {
865
- customAbbreviations,
866
- customShortWords,
867
- disabledChecks,
868
- allAbbreviations,
869
- allShortWords
870
- };
871
- }
872
-
873
272
  // src/analyzers/naming-ast.ts
874
- async function analyzeNamingAST(files) {
875
- const issues = [];
876
- const { allAbbreviations, allShortWords, disabledChecks } = await loadNamingConfig(files);
877
- const supportedFiles = files.filter(
878
- (file) => /\.(js|jsx|ts|tsx)$/i.test(file)
879
- );
880
- for (const file of supportedFiles) {
273
+ async function analyzeNamingAST(filePaths) {
274
+ const allIssues = [];
275
+ for (const filePath of filePaths) {
881
276
  try {
882
- const ast = parseFile(file);
277
+ const ast = parseFile(filePath);
883
278
  if (!ast) continue;
884
- const fileIssues = analyzeFileNamingAST(
885
- file,
886
- ast,
887
- allAbbreviations,
888
- allShortWords,
889
- disabledChecks
890
- );
891
- issues.push(...fileIssues);
892
- } catch (error) {
893
- console.warn(`Skipping ${file} due to parse error:`, error);
279
+ const context = buildCodeContext(filePath, ast);
280
+ const issues = analyzeIdentifiers(ast, filePath, context);
281
+ allIssues.push(...issues);
282
+ } catch (err) {
283
+ void err;
894
284
  }
895
285
  }
896
- return issues;
286
+ return allIssues;
897
287
  }
898
- function analyzeFileNamingAST(file, ast, allAbbreviations, allShortWords, disabledChecks) {
288
+ function analyzeIdentifiers(ast, filePath, context) {
899
289
  const issues = [];
900
- const scopeTracker = new ScopeTracker(ast);
901
- const context = buildCodeContext(file, ast);
902
- const ancestors = [];
290
+ const scopeTracker = new ScopeTracker();
903
291
  traverseAST(ast, {
904
- enter: (node, parent) => {
905
- ancestors.push(node);
906
- if (node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression") {
907
- scopeTracker.enterScope("function", node);
908
- if ("params" in node) {
909
- for (const param of node.params) {
910
- if (param.type === "Identifier") {
911
- scopeTracker.declareVariable(
912
- param.name,
913
- param,
914
- getLineNumber(param),
915
- {
916
- isParameter: true
917
- }
918
- );
919
- } else if (param.type === "ObjectPattern" || param.type === "ArrayPattern") {
920
- extractIdentifiersFromPattern(param, scopeTracker, true);
921
- }
922
- }
923
- }
924
- } else if (node.type === "BlockStatement") {
925
- scopeTracker.enterScope("block", node);
926
- } else if (isLoopStatement(node)) {
927
- scopeTracker.enterScope("loop", node);
928
- } else if (node.type === "ClassDeclaration") {
929
- scopeTracker.enterScope("class", node);
930
- }
931
- if (node.type === "VariableDeclarator") {
932
- if (node.id.type === "Identifier") {
933
- void isCoverageContext(node, ancestors);
934
- scopeTracker.declareVariable(
935
- node.id.name,
936
- node.id,
937
- getLineNumber(node.id),
938
- {
939
- type: "typeAnnotation" in node.id ? node.id.typeAnnotation : null,
940
- isDestructured: false,
941
- isLoopVariable: scopeTracker.getCurrentScopeType() === "loop"
942
- }
943
- );
944
- } else if (node.id.type === "ObjectPattern" || node.id.type === "ArrayPattern") {
945
- extractIdentifiersFromPattern(
946
- node.id,
947
- scopeTracker,
948
- false,
949
- ancestors
950
- );
951
- }
292
+ enter: (node) => {
293
+ if (node.type === "VariableDeclarator" && node.id.type === "Identifier") {
294
+ const isParameter = false;
295
+ const isLoopVariable = isLoopStatement(node.parent?.parent);
296
+ scopeTracker.declareVariable(
297
+ node.id.name,
298
+ node.id,
299
+ getLineNumber(node.id),
300
+ { isParameter, isLoopVariable }
301
+ );
952
302
  }
953
- if (node.type === "Identifier" && parent) {
954
- if (parent.type !== "VariableDeclarator" || parent.id !== node) {
955
- if (parent.type !== "FunctionDeclaration" || parent.id !== node) {
956
- scopeTracker.addReference(node.name, node);
303
+ if (node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression") {
304
+ node.params.forEach((param) => {
305
+ if (param.type === "Identifier") {
306
+ scopeTracker.declareVariable(
307
+ param.name,
308
+ param,
309
+ getLineNumber(param),
310
+ { isParameter: true }
311
+ );
312
+ } else if (param.type === "ObjectPattern") {
313
+ extractDestructuredIdentifiers(param, true, scopeTracker);
957
314
  }
958
- }
959
- }
960
- },
961
- leave: (node) => {
962
- ancestors.pop();
963
- if (node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression" || node.type === "BlockStatement" || isLoopStatement(node) || node.type === "ClassDeclaration") {
964
- scopeTracker.exitScope();
965
- }
966
- }
967
- });
968
- const allVariables = scopeTracker.getAllVariables();
969
- for (const varInfo of allVariables) {
970
- const name = varInfo.name;
971
- const line = varInfo.declarationLine;
972
- if (disabledChecks.has("single-letter") && name.length === 1) continue;
973
- if (disabledChecks.has("abbreviation") && name.length <= 3) continue;
974
- const isInCoverage = ["s", "b", "f", "l"].includes(name) && varInfo.isDestructured;
975
- if (isInCoverage) continue;
976
- const functionComplexity = varInfo.node.type === "Identifier" && "parent" in varInfo.node ? calculateComplexity(varInfo.node) : context.complexity;
977
- if (isAcceptableInContext(name, context, {
978
- isLoopVariable: varInfo.isLoopVariable || allAbbreviations.has(name),
979
- isParameter: varInfo.isParameter,
980
- isDestructured: varInfo.isDestructured,
981
- complexity: functionComplexity
982
- })) {
983
- continue;
984
- }
985
- if (name.length === 1 && !allAbbreviations.has(name) && !allShortWords.has(name)) {
986
- const isShortLived = scopeTracker.isShortLived(varInfo, 5);
987
- if (!isShortLived) {
988
- issues.push({
989
- file,
990
- line,
991
- type: "poor-naming",
992
- identifier: name,
993
- severity: adjustSeverity("minor", context, "poor-naming"),
994
- suggestion: `Use descriptive variable name instead of single letter '${name}'`
995
315
  });
996
316
  }
997
- continue;
998
- }
999
- if (name.length >= 2 && name.length <= 3) {
1000
- if (!allShortWords.has(name.toLowerCase()) && !allAbbreviations.has(name.toLowerCase())) {
1001
- const isShortLived = scopeTracker.isShortLived(varInfo, 5);
1002
- if (!isShortLived) {
1003
- issues.push({
1004
- file,
1005
- line,
1006
- type: "abbreviation",
1007
- identifier: name,
1008
- severity: adjustSeverity("info", context, "abbreviation"),
1009
- suggestion: `Consider using full word instead of abbreviation '${name}'`
1010
- });
1011
- }
1012
- }
1013
- continue;
1014
- }
1015
- if (!disabledChecks.has("convention-mix") && file.match(/\.(ts|tsx|js|jsx)$/)) {
1016
- if (name.includes("_") && !name.startsWith("_") && name.toLowerCase() === name) {
1017
- const camelCase = name.replace(
1018
- /_([a-z])/g,
1019
- (_, letter) => letter.toUpperCase()
317
+ if ((node.type === "ClassDeclaration" || node.type === "TSInterfaceDeclaration" || node.type === "TSTypeAliasDeclaration") && node.id) {
318
+ checkNamingConvention(
319
+ node.id.name,
320
+ "PascalCase",
321
+ node.id,
322
+ filePath,
323
+ issues,
324
+ context
1020
325
  );
1021
- issues.push({
1022
- file,
1023
- line,
1024
- type: "convention-mix",
1025
- identifier: name,
1026
- severity: adjustSeverity("minor", context, "convention-mix"),
1027
- suggestion: `Use camelCase '${camelCase}' instead of snake_case in TypeScript/JavaScript`
1028
- });
1029
326
  }
1030
327
  }
328
+ });
329
+ for (const varInfo of scopeTracker.getVariables()) {
330
+ checkVariableNaming(varInfo, filePath, issues, context);
1031
331
  }
1032
- if (!disabledChecks.has("unclear")) {
1033
- traverseAST(ast, {
1034
- enter: (node) => {
1035
- if (node.type === "FunctionDeclaration" || node.type === "MethodDefinition") {
1036
- const name = getFunctionName(node);
1037
- if (!name) return;
1038
- const line = getLineNumber(node);
1039
- if (["main", "init", "setup", "bootstrap"].includes(name)) return;
1040
- const hasActionVerb = name.match(
1041
- /^(get|set|is|has|can|should|create|update|delete|fetch|load|save|process|handle|validate|check|find|search|filter|map|reduce|make|do|run|start|stop|build|parse|format|render|calculate|compute|generate|transform|convert|normalize|sanitize|encode|decode|compress|extract|merge|split|join|sort|compare|test|verify|ensure|apply|execute|invoke|call|emit|dispatch|trigger|listen|subscribe|unsubscribe|add|remove|clear|reset|toggle|enable|disable|open|close|connect|disconnect|send|receive|read|write|import|export|register|unregister|mount|unmount|track|store|persist|upsert|derive|classify|combine|discover|activate|require|assert|expect|mask|escape|sign|put|list|complete|page|safe|mock|pick|pluralize|text|count|detect|select)/
1042
- );
1043
- const isFactoryPattern = name.match(
1044
- /(Factory|Builder|Creator|Generator|Provider|Adapter|Mock)$/
1045
- );
1046
- const isEventHandler = name.match(/^on[A-Z]/);
1047
- const isDescriptiveLong = name.length > 15;
1048
- const isReactHook = name.match(/^use[A-Z]/);
1049
- const isHelperPattern = name.match(/^(to|from|with|without|for|as|into)\w+/) || name.match(/^\w+(To|From|With|Without|For|As|Into)\w*$/);
1050
- const isUtilityName = [
1051
- "cn",
1052
- "proxy",
1053
- "sitemap",
1054
- "robots",
1055
- "gtag"
1056
- ].includes(name);
1057
- const isLanguageKeyword = [
1058
- "constructor",
1059
- "toString",
1060
- "valueOf",
1061
- "toJSON"
1062
- ].includes(name);
1063
- const isFrameworkPattern = name.match(
1064
- /^(goto|fill|click|select|submit|wait|expect)\w*/
1065
- );
1066
- const isDescriptivePattern = name.match(
1067
- /^(default|total|count|sum|avg|max|min|initial|current|previous|next)\w+/
1068
- ) || name.match(
1069
- /\w+(Count|Total|Sum|Average|List|Map|Set|Config|Settings|Options|Props|Data|Info|Details|State|Status|Response|Result)$/
1070
- );
1071
- const capitalCount = (name.match(/[A-Z]/g) || []).length;
1072
- const isCompoundWord = capitalCount >= 3;
1073
- if (!hasActionVerb && !isFactoryPattern && !isEventHandler && !isDescriptiveLong && !isReactHook && !isHelperPattern && !isUtilityName && !isDescriptivePattern && !isCompoundWord && !isLanguageKeyword && !isFrameworkPattern) {
1074
- issues.push({
1075
- file,
1076
- line,
1077
- type: "unclear",
1078
- identifier: name,
1079
- severity: adjustSeverity("info", context, "unclear"),
1080
- suggestion: `Function '${name}' should start with an action verb (get, set, create, etc.)`
1081
- });
1082
- }
1083
- }
1084
- }
332
+ return issues;
333
+ }
334
+ function checkNamingConvention(name, convention, node, file, issues, context) {
335
+ let isValid = true;
336
+ if (convention === "PascalCase") {
337
+ isValid = /^[A-Z][a-zA-Z0-9]*$/.test(name);
338
+ } else if (convention === "camelCase") {
339
+ isValid = /^[a-z][a-zA-Z0-9]*$/.test(name);
340
+ } else if (convention === "UPPER_CASE") {
341
+ isValid = /^[A-Z][A-Z0-9_]*$/.test(name);
342
+ }
343
+ if (!isValid) {
344
+ const severity = adjustSeverity(import_core2.Severity.Info, context, "convention-mix");
345
+ issues.push({
346
+ file,
347
+ line: getLineNumber(node),
348
+ type: "convention-mix",
349
+ identifier: name,
350
+ severity,
351
+ suggestion: `Follow ${convention} for this identifier`
1085
352
  });
1086
353
  }
1087
- return issues;
1088
354
  }
1089
- function extractIdentifiersFromPattern(pattern, scopeTracker, isParameter, ancestors) {
1090
- void ancestors;
1091
- if (pattern.type === "ObjectPattern") {
1092
- for (const prop of pattern.properties) {
355
+ function checkVariableNaming(varInfo, file, issues, context) {
356
+ const { name, node, line, options } = varInfo;
357
+ if (isAcceptableInContext(name, context, options)) {
358
+ return;
359
+ }
360
+ if (name.length === 1 && !options.isLoopVariable) {
361
+ const severity = adjustSeverity(import_core2.Severity.Minor, context, "poor-naming");
362
+ issues.push({
363
+ file,
364
+ line,
365
+ type: "poor-naming",
366
+ identifier: name,
367
+ severity,
368
+ suggestion: "Use a more descriptive name than a single letter"
369
+ });
370
+ }
371
+ const vagueNames = [
372
+ "data",
373
+ "info",
374
+ "item",
375
+ "obj",
376
+ "val",
377
+ "tmp",
378
+ "temp",
379
+ "thing",
380
+ "stuff"
381
+ ];
382
+ if (vagueNames.includes(name.toLowerCase())) {
383
+ const severity = adjustSeverity(import_core2.Severity.Minor, context, "poor-naming");
384
+ issues.push({
385
+ file,
386
+ line,
387
+ type: "poor-naming",
388
+ identifier: name,
389
+ severity,
390
+ suggestion: `Avoid vague names like '${name}'. What does this data represent?`
391
+ });
392
+ }
393
+ if (name.length > 1 && name.length <= 3 && !options.isLoopVariable && !isCommonAbbreviation(name)) {
394
+ const severity = adjustSeverity(import_core2.Severity.Info, context, "abbreviation");
395
+ issues.push({
396
+ file,
397
+ line,
398
+ type: "abbreviation",
399
+ identifier: name,
400
+ severity,
401
+ suggestion: "Avoid non-standard abbreviations"
402
+ });
403
+ }
404
+ }
405
+ function isCommonAbbreviation(name) {
406
+ const common = ["id", "db", "fs", "os", "ip", "ui", "ux", "api", "env", "url"];
407
+ return common.includes(name.toLowerCase());
408
+ }
409
+ var ScopeTracker = class {
410
+ constructor() {
411
+ this.variables = [];
412
+ }
413
+ declareVariable(name, node, line, options = {}) {
414
+ this.variables.push({ name, node, line, options });
415
+ }
416
+ getVariables() {
417
+ return this.variables;
418
+ }
419
+ };
420
+ function extractDestructuredIdentifiers(node, isParameter, scopeTracker) {
421
+ if (node.type === "ObjectPattern") {
422
+ node.properties.forEach((prop) => {
1093
423
  if (prop.type === "Property" && prop.value.type === "Identifier") {
1094
424
  scopeTracker.declareVariable(
1095
425
  prop.value.name,
@@ -1100,21 +430,11 @@ function extractIdentifiersFromPattern(pattern, scopeTracker, isParameter, ances
1100
430
  isDestructured: true
1101
431
  }
1102
432
  );
1103
- } else if (prop.type === "RestElement" && prop.argument.type === "Identifier") {
1104
- scopeTracker.declareVariable(
1105
- prop.argument.name,
1106
- prop.argument,
1107
- getLineNumber(prop.argument),
1108
- {
1109
- isParameter,
1110
- isDestructured: true
1111
- }
1112
- );
1113
433
  }
1114
- }
1115
- } else if (pattern.type === "ArrayPattern") {
1116
- for (const element of pattern.elements) {
1117
- if (element && element.type === "Identifier") {
434
+ });
435
+ } else if (node.type === "ArrayPattern") {
436
+ for (const element of node.elements) {
437
+ if (element?.type === "Identifier") {
1118
438
  scopeTracker.declareVariable(
1119
439
  element.name,
1120
440
  element,
@@ -1130,10 +450,10 @@ function extractIdentifiersFromPattern(pattern, scopeTracker, isParameter, ances
1130
450
  }
1131
451
 
1132
452
  // src/analyzers/naming-python.ts
1133
- var import_core2 = require("@aiready/core");
453
+ var import_core3 = require("@aiready/core");
1134
454
  async function analyzePythonNaming(files) {
1135
455
  const issues = [];
1136
- const parser = (0, import_core2.getParser)("dummy.py");
456
+ const parser = (0, import_core3.getParser)("dummy.py");
1137
457
  if (!parser) {
1138
458
  console.warn("Python parser not available");
1139
459
  return issues;
@@ -1177,7 +497,7 @@ async function analyzePythonNaming(files) {
1177
497
  return issues;
1178
498
  }
1179
499
  function checkPythonNaming(identifier, type, file, line) {
1180
- const parser = (0, import_core2.getParser)("dummy.py");
500
+ const parser = (0, import_core3.getParser)("dummy.py");
1181
501
  const conventions = parser?.getNamingConventions();
1182
502
  if (!conventions) return null;
1183
503
  if (conventions.exceptions?.includes(identifier)) {
@@ -1252,162 +572,63 @@ function toPascalCase(str) {
1252
572
  }
1253
573
 
1254
574
  // src/analyzers/patterns.ts
1255
- var import_core3 = require("@aiready/core");
1256
- async function analyzePatterns(files) {
575
+ var import_fs2 = require("fs");
576
+ var import_core4 = require("@aiready/core");
577
+ async function analyzePatterns(filePaths) {
1257
578
  const issues = [];
1258
- const errorHandlingIssues = await analyzeErrorHandling(files);
1259
- issues.push(...errorHandlingIssues);
1260
- const asyncIssues = await analyzeAsyncPatterns(files);
1261
- issues.push(...asyncIssues);
1262
- const importIssues = await analyzeImportStyles(files);
1263
- issues.push(...importIssues);
1264
- return issues;
1265
- }
1266
- async function analyzeErrorHandling(files) {
1267
- const patterns = {
1268
- tryCatch: [],
1269
- throwsError: [],
1270
- returnsNull: [],
1271
- returnsError: []
579
+ const contents = /* @__PURE__ */ new Map();
580
+ const tryCatchPattern = /try\s*\{/g;
581
+ const catchPattern = /catch\s*\(\s*(\w+)\s*\)/g;
582
+ const styleStats = {
583
+ tryCatch: 0,
584
+ thenCatch: 0,
585
+ asyncAwait: 0,
586
+ commonJs: 0,
587
+ esm: 0
1272
588
  };
1273
- for (const file of files) {
1274
- const content = await (0, import_core3.readFileContent)(file);
1275
- if (content.includes("try {") || content.includes("} catch")) {
1276
- patterns.tryCatch.push(file);
1277
- }
1278
- if (content.match(/throw new \w*Error/)) {
1279
- patterns.throwsError.push(file);
1280
- }
1281
- if (content.match(/return null/)) {
1282
- patterns.returnsNull.push(file);
1283
- }
1284
- if (content.match(/return \{ error:/)) {
1285
- patterns.returnsError.push(file);
589
+ for (const filePath of filePaths) {
590
+ try {
591
+ const content = (0, import_fs2.readFileSync)(filePath, "utf-8");
592
+ contents.set(filePath, content);
593
+ if (content.match(tryCatchPattern)) styleStats.tryCatch++;
594
+ if (content.match(/\.catch\s*\(/)) styleStats.thenCatch++;
595
+ if (content.match(/\bawait\b/)) styleStats.asyncAwait++;
596
+ if (content.match(/\brequire\s*\(/)) styleStats.commonJs++;
597
+ if (content.match(/\bimport\b.*\bfrom\b/)) styleStats.esm++;
598
+ } catch (err) {
599
+ void err;
1286
600
  }
1287
601
  }
1288
- const issues = [];
1289
- const strategiesUsed = Object.values(patterns).filter(
1290
- (p) => p.length > 0
1291
- ).length;
1292
- if (strategiesUsed > 2) {
602
+ const totalFiles = filePaths.length;
603
+ if (styleStats.tryCatch > 0 && styleStats.thenCatch > 0) {
604
+ const dominant = styleStats.tryCatch >= styleStats.thenCatch ? "try-catch" : ".catch()";
605
+ const minority = dominant === "try-catch" ? ".catch()" : "try-catch";
1293
606
  issues.push({
1294
- files: [
1295
- .../* @__PURE__ */ new Set([
1296
- ...patterns.tryCatch,
1297
- ...patterns.throwsError,
1298
- ...patterns.returnsNull,
1299
- ...patterns.returnsError
1300
- ])
1301
- ],
607
+ files: filePaths.filter((f) => {
608
+ const c = contents.get(f) || "";
609
+ return minority === "try-catch" ? c.match(tryCatchPattern) : c.match(/\.catch\s*\(/);
610
+ }),
1302
611
  type: "error-handling",
1303
- description: "Inconsistent error handling strategies across codebase",
1304
- examples: [
1305
- patterns.tryCatch.length > 0 ? `Try-catch used in ${patterns.tryCatch.length} files` : "",
1306
- patterns.throwsError.length > 0 ? `Throws errors in ${patterns.throwsError.length} files` : "",
1307
- patterns.returnsNull.length > 0 ? `Returns null in ${patterns.returnsNull.length} files` : "",
1308
- patterns.returnsError.length > 0 ? `Returns error objects in ${patterns.returnsError.length} files` : ""
1309
- ].filter((e) => e),
1310
- severity: "major"
612
+ description: `Mixed error handling styles: codebase primarily uses ${dominant}, but found ${minority} in some files.`,
613
+ examples: [dominant, minority],
614
+ severity: import_core4.Severity.Minor
1311
615
  });
1312
616
  }
1313
- return issues;
1314
- }
1315
- async function analyzeAsyncPatterns(files) {
1316
- const patterns = {
1317
- asyncAwait: [],
1318
- promises: [],
1319
- callbacks: []
1320
- };
1321
- for (const file of files) {
1322
- const content = await (0, import_core3.readFileContent)(file);
1323
- if (content.match(/async\s+(function|\(|[a-zA-Z])/)) {
1324
- patterns.asyncAwait.push(file);
1325
- }
1326
- if (content.match(/\.then\(/) || content.match(/\.catch\(/)) {
1327
- patterns.promises.push(file);
1328
- }
1329
- if (content.match(/callback\s*\(/) || content.match(/\(\s*err\s*,/)) {
1330
- patterns.callbacks.push(file);
1331
- }
1332
- }
1333
- const issues = [];
1334
- if (patterns.callbacks.length > 0 && patterns.asyncAwait.length > 0) {
1335
- issues.push({
1336
- files: [...patterns.callbacks, ...patterns.asyncAwait],
1337
- type: "async-style",
1338
- description: "Mixed async patterns: callbacks and async/await",
1339
- examples: [
1340
- `Callbacks found in: ${patterns.callbacks.slice(0, 3).join(", ")}`,
1341
- `Async/await used in: ${patterns.asyncAwait.slice(0, 3).join(", ")}`
1342
- ],
1343
- severity: "minor"
1344
- });
1345
- }
1346
- if (patterns.promises.length > patterns.asyncAwait.length * 0.3 && patterns.asyncAwait.length > 0) {
617
+ if (styleStats.commonJs > 0 && styleStats.esm > 0) {
618
+ const minority = styleStats.esm >= styleStats.commonJs ? "CommonJS (require)" : "ESM (import)";
1347
619
  issues.push({
1348
- files: patterns.promises,
1349
- type: "async-style",
1350
- description: "Consider using async/await instead of promise chains for consistency",
1351
- examples: patterns.promises.slice(0, 5),
1352
- severity: "info"
1353
- });
1354
- }
1355
- return issues;
1356
- }
1357
- async function analyzeImportStyles(files) {
1358
- const patterns = {
1359
- esModules: [],
1360
- commonJS: [],
1361
- mixed: []
1362
- };
1363
- for (const file of files) {
1364
- const content = await (0, import_core3.readFileContent)(file);
1365
- const hasESM = content.match(/^import\s+/m);
1366
- const hasCJS = hasActualRequireCalls(content);
1367
- if (hasESM && hasCJS) {
1368
- patterns.mixed.push(file);
1369
- } else if (hasESM) {
1370
- patterns.esModules.push(file);
1371
- } else if (hasCJS) {
1372
- patterns.commonJS.push(file);
1373
- }
1374
- }
1375
- const issues = [];
1376
- if (patterns.mixed.length > 0) {
1377
- issues.push({
1378
- files: patterns.mixed,
620
+ files: filePaths.filter((f) => {
621
+ const c = contents.get(f) || "";
622
+ return minority === "CommonJS (require)" ? c.match(/\brequire\s*\(/) : c.match(/\bimport\b/);
623
+ }),
1379
624
  type: "import-style",
1380
- description: "Mixed ES modules and CommonJS imports in same files",
1381
- examples: patterns.mixed.slice(0, 5),
1382
- severity: "major"
625
+ description: `Mixed module systems: found both ESM and CommonJS.`,
626
+ examples: ['import X from "y"', 'const X = require("y")'],
627
+ severity: import_core4.Severity.Major
1383
628
  });
1384
629
  }
1385
- if (patterns.esModules.length > 0 && patterns.commonJS.length > 0) {
1386
- const ratio = patterns.commonJS.length / (patterns.esModules.length + patterns.commonJS.length);
1387
- if (ratio > 0.2 && ratio < 0.8) {
1388
- issues.push({
1389
- files: [...patterns.esModules, ...patterns.commonJS],
1390
- type: "import-style",
1391
- description: "Inconsistent import styles across project",
1392
- examples: [
1393
- `ES modules: ${patterns.esModules.length} files`,
1394
- `CommonJS: ${patterns.commonJS.length} files`
1395
- ],
1396
- severity: "minor"
1397
- });
1398
- }
1399
- }
1400
630
  return issues;
1401
631
  }
1402
- function hasActualRequireCalls(content) {
1403
- let cleaned = content.replace(/\/\/.*$/gm, "");
1404
- cleaned = cleaned.replace(/\/\*[\s\S]*?\*\//g, "");
1405
- cleaned = cleaned.replace(/"[^"\n]*"/g, '""');
1406
- cleaned = cleaned.replace(/'[^'\n]*'/g, "''");
1407
- cleaned = cleaned.replace(/`[^`]*`/g, "``");
1408
- cleaned = cleaned.replace(/\/[^/\n]*require[^/\n]*\/[gimsuvy]*/g, "");
1409
- return /require\s*\(/.test(cleaned);
1410
- }
1411
632
 
1412
633
  // src/analyzer.ts
1413
634
  async function analyzeConsistency(options) {
@@ -1416,11 +637,11 @@ async function analyzeConsistency(options) {
1416
637
  checkPatterns = true,
1417
638
  checkArchitecture = false,
1418
639
  // Not implemented yet
1419
- minSeverity = "info",
640
+ minSeverity = import_core5.Severity.Info,
1420
641
  ...scanOptions
1421
642
  } = options;
1422
643
  void checkArchitecture;
1423
- const filePaths = await (0, import_core4.scanFiles)(scanOptions);
644
+ const filePaths = await (0, import_core5.scanFiles)(scanOptions);
1424
645
  const tsJsFiles = filePaths.filter((f) => /\.(ts|tsx|js|jsx)$/i.test(f));
1425
646
  const pythonFiles = filePaths.filter((f) => /\.py$/i.test(f));
1426
647
  let namingIssues = [];
@@ -1437,9 +658,9 @@ async function analyzeConsistency(options) {
1437
658
  continue;
1438
659
  }
1439
660
  const consistencyIssue = {
1440
- type: issue.type === "convention-mix" ? "naming-inconsistency" : "naming-quality",
661
+ type: issue.type === "convention-mix" ? import_core5.IssueType.NamingInconsistency : import_core5.IssueType.NamingQuality,
1441
662
  category: "naming",
1442
- severity: issue.severity,
663
+ severity: getSeverityEnum(issue.severity),
1443
664
  message: `${issue.type}: ${issue.identifier}`,
1444
665
  location: {
1445
666
  file: issue.file,
@@ -1458,9 +679,9 @@ async function analyzeConsistency(options) {
1458
679
  continue;
1459
680
  }
1460
681
  const consistencyIssue = {
1461
- type: "pattern-inconsistency",
682
+ type: import_core5.IssueType.PatternInconsistency,
1462
683
  category: "patterns",
1463
- severity: issue.severity,
684
+ severity: getSeverityEnum(issue.severity),
1464
685
  message: issue.description,
1465
686
  location: {
1466
687
  file: issue.files[0] || "multiple files",
@@ -1487,16 +708,17 @@ async function analyzeConsistency(options) {
1487
708
  });
1488
709
  }
1489
710
  results.sort((fileResultA, fileResultB) => {
1490
- const severityOrder = { critical: 0, major: 1, minor: 2, info: 3 };
1491
711
  const maxSeverityA = Math.min(
1492
- ...fileResultA.issues.map(
1493
- (i) => severityOrder[i.severity]
1494
- )
712
+ ...fileResultA.issues.map((i) => {
713
+ const val = getSeverityLevel(i.severity);
714
+ return val === 4 ? 0 : val === 3 ? 1 : val === 2 ? 2 : 3;
715
+ })
1495
716
  );
1496
717
  const maxSeverityB = Math.min(
1497
- ...fileResultB.issues.map(
1498
- (i) => severityOrder[i.severity]
1499
- )
718
+ ...fileResultB.issues.map((i) => {
719
+ const val = getSeverityLevel(i.severity);
720
+ return val === 4 ? 0 : val === 3 ? 1 : val === 2 ? 2 : 3;
721
+ })
1500
722
  );
1501
723
  if (maxSeverityA !== maxSeverityB) {
1502
724
  return maxSeverityA - maxSeverityB;
@@ -1522,16 +744,52 @@ async function analyzeConsistency(options) {
1522
744
  recommendations
1523
745
  };
1524
746
  }
747
+ function getSeverityLevel(s) {
748
+ if (s === import_core5.Severity.Critical || s === "critical") return 4;
749
+ if (s === import_core5.Severity.Major || s === "major") return 3;
750
+ if (s === import_core5.Severity.Minor || s === "minor") return 2;
751
+ if (s === import_core5.Severity.Info || s === "info") return 1;
752
+ return 0;
753
+ }
754
+ function getSeverityEnum(s) {
755
+ const val = getSeverityLevel(s);
756
+ switch (val) {
757
+ case 4:
758
+ return import_core5.Severity.Critical;
759
+ case 3:
760
+ return import_core5.Severity.Major;
761
+ case 2:
762
+ return import_core5.Severity.Minor;
763
+ case 1:
764
+ return import_core5.Severity.Info;
765
+ default:
766
+ return import_core5.Severity.Info;
767
+ }
768
+ }
1525
769
  function shouldIncludeSeverity(severity, minSeverity) {
1526
- const severityLevels = { info: 0, minor: 1, major: 2, critical: 3 };
1527
- return severityLevels[severity] >= severityLevels[minSeverity];
770
+ return getSeverityLevel(severity) >= getSeverityLevel(minSeverity);
1528
771
  }
1529
772
  function calculateConsistencyScore(issues) {
1530
- const weights = { critical: 10, major: 5, minor: 2, info: 1 };
1531
- const totalWeight = issues.reduce(
1532
- (sum, issue) => sum + weights[issue.severity],
1533
- 0
1534
- );
773
+ let totalWeight = 0;
774
+ for (const issue of issues) {
775
+ const val = getSeverityLevel(issue.severity);
776
+ switch (val) {
777
+ case 4:
778
+ totalWeight += 10;
779
+ break;
780
+ case 3:
781
+ totalWeight += 5;
782
+ break;
783
+ case 2:
784
+ totalWeight += 2;
785
+ break;
786
+ case 1:
787
+ totalWeight += 1;
788
+ break;
789
+ default:
790
+ totalWeight += 1;
791
+ }
792
+ }
1535
793
  return Math.max(0, 1 - totalWeight / 100);
1536
794
  }
1537
795
  function generateRecommendations(namingIssues, patternIssues) {
@@ -1586,9 +844,9 @@ function generateRecommendations(namingIssues, patternIssues) {
1586
844
 
1587
845
  // src/cli.ts
1588
846
  var import_chalk = __toESM(require("chalk"));
1589
- var import_fs2 = require("fs");
1590
- var import_path2 = require("path");
1591
- var import_core5 = require("@aiready/core");
847
+ var import_fs3 = require("fs");
848
+ var import_path = require("path");
849
+ var import_core6 = require("@aiready/core");
1592
850
  var program = new import_commander.Command();
1593
851
  program.name("aiready-consistency").description(
1594
852
  "Detect consistency patterns in naming, code structure, and architecture"
@@ -1627,7 +885,7 @@ EXAMPLES:
1627
885
  ).option("--output-file <path>", "Output file path (for json/markdown)").action(async (directory, options) => {
1628
886
  console.log(import_chalk.default.blue("\u{1F50D} Analyzing consistency...\n"));
1629
887
  const startTime = Date.now();
1630
- const config = await (0, import_core5.loadConfig)(directory);
888
+ const config = await (0, import_core6.loadConfig)(directory);
1631
889
  const defaults = {
1632
890
  checkNaming: true,
1633
891
  checkPatterns: true,
@@ -1636,7 +894,7 @@ EXAMPLES:
1636
894
  include: void 0,
1637
895
  exclude: void 0
1638
896
  };
1639
- const mergedConfig = (0, import_core5.mergeConfigWithDefaults)(config, defaults);
897
+ const mergedConfig = (0, import_core6.mergeConfigWithDefaults)(config, defaults);
1640
898
  const finalOptions = {
1641
899
  rootDir: directory,
1642
900
  checkNaming: options.naming !== false && mergedConfig.checkNaming,
@@ -1650,29 +908,29 @@ EXAMPLES:
1650
908
  const elapsedTime = ((Date.now() - startTime) / 1e3).toFixed(2);
1651
909
  if (options.output === "json") {
1652
910
  const output = JSON.stringify(report, null, 2);
1653
- const outputPath = (0, import_core5.resolveOutputPath)(
911
+ const outputPath = (0, import_core6.resolveOutputPath)(
1654
912
  options.outputFile,
1655
913
  `consistency-report-${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}.json`,
1656
914
  directory
1657
915
  );
1658
- const dir = (0, import_path2.dirname)(outputPath);
1659
- if (!(0, import_fs2.existsSync)(dir)) {
1660
- (0, import_fs2.mkdirSync)(dir, { recursive: true });
916
+ const dir = (0, import_path.dirname)(outputPath);
917
+ if (!(0, import_fs3.existsSync)(dir)) {
918
+ (0, import_fs3.mkdirSync)(dir, { recursive: true });
1661
919
  }
1662
- (0, import_fs2.writeFileSync)(outputPath, output);
920
+ (0, import_fs3.writeFileSync)(outputPath, output);
1663
921
  console.log(import_chalk.default.green(`\u2713 Report saved to ${outputPath}`));
1664
922
  } else if (options.output === "markdown") {
1665
923
  const markdown = generateMarkdownReport(report, elapsedTime);
1666
- const outputPath = (0, import_core5.resolveOutputPath)(
924
+ const outputPath = (0, import_core6.resolveOutputPath)(
1667
925
  options.outputFile,
1668
926
  `consistency-report-${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}.md`,
1669
927
  directory
1670
928
  );
1671
- const dir = (0, import_path2.dirname)(outputPath);
1672
- if (!(0, import_fs2.existsSync)(dir)) {
1673
- (0, import_fs2.mkdirSync)(dir, { recursive: true });
929
+ const dir = (0, import_path.dirname)(outputPath);
930
+ if (!(0, import_fs3.existsSync)(dir)) {
931
+ (0, import_fs3.mkdirSync)(dir, { recursive: true });
1674
932
  }
1675
- (0, import_fs2.writeFileSync)(outputPath, markdown);
933
+ (0, import_fs3.writeFileSync)(outputPath, markdown);
1676
934
  console.log(import_chalk.default.green(`\u2713 Report saved to ${outputPath}`));
1677
935
  } else {
1678
936
  displayConsoleReport(report, elapsedTime);