@aiready/consistency 0.21.8 → 0.21.11

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 (136) hide show
  1. package/.turbo/turbo-build.log +23 -24
  2. package/.turbo/turbo-format-check.log +1 -1
  3. package/.turbo/turbo-lint.log +1 -1
  4. package/.turbo/turbo-test.log +18 -19
  5. package/.turbo/turbo-type-check.log +1 -1
  6. package/dist/index.d.mts +3 -3
  7. package/dist/index.d.ts +3 -3
  8. package/dist/index.js +4 -4
  9. package/dist/index.mjs +3 -3
  10. package/package.json +2 -2
  11. package/src/__tests__/provider.test.ts +6 -34
  12. package/src/index.ts +3 -3
  13. package/src/provider.ts +2 -2
  14. package/dist/__tests__/analyzer.test.d.ts +0 -2
  15. package/dist/__tests__/analyzer.test.d.ts.map +0 -1
  16. package/dist/__tests__/analyzer.test.js +0 -157
  17. package/dist/__tests__/analyzer.test.js.map +0 -1
  18. package/dist/__tests__/language-filter.test.d.ts +0 -2
  19. package/dist/__tests__/language-filter.test.d.ts.map +0 -1
  20. package/dist/__tests__/language-filter.test.js +0 -46
  21. package/dist/__tests__/language-filter.test.js.map +0 -1
  22. package/dist/__tests__/scoring.test.d.ts +0 -2
  23. package/dist/__tests__/scoring.test.d.ts.map +0 -1
  24. package/dist/__tests__/scoring.test.js +0 -118
  25. package/dist/__tests__/scoring.test.js.map +0 -1
  26. package/dist/analyzer.d.ts +0 -7
  27. package/dist/analyzer.d.ts.map +0 -1
  28. package/dist/analyzer.js +0 -160
  29. package/dist/analyzer.js.map +0 -1
  30. package/dist/analyzers/naming-ast.d.ts +0 -7
  31. package/dist/analyzers/naming-ast.d.ts.map +0 -1
  32. package/dist/analyzers/naming-ast.js +0 -253
  33. package/dist/analyzers/naming-ast.js.map +0 -1
  34. package/dist/analyzers/naming-constants.d.ts +0 -21
  35. package/dist/analyzers/naming-constants.d.ts.map +0 -1
  36. package/dist/analyzers/naming-constants.js +0 -96
  37. package/dist/analyzers/naming-constants.js.map +0 -1
  38. package/dist/analyzers/naming-python.d.ts +0 -16
  39. package/dist/analyzers/naming-python.d.ts.map +0 -1
  40. package/dist/analyzers/naming-python.js +0 -165
  41. package/dist/analyzers/naming-python.js.map +0 -1
  42. package/dist/analyzers/naming.d.ts +0 -6
  43. package/dist/analyzers/naming.d.ts.map +0 -1
  44. package/dist/analyzers/naming.js +0 -234
  45. package/dist/analyzers/naming.js.map +0 -1
  46. package/dist/analyzers/patterns.d.ts +0 -10
  47. package/dist/analyzers/patterns.d.ts.map +0 -1
  48. package/dist/analyzers/patterns.js +0 -197
  49. package/dist/analyzers/patterns.js.map +0 -1
  50. package/dist/chunk-2BTBNG6X.mjs +0 -814
  51. package/dist/chunk-3ZB6FFRL.mjs +0 -661
  52. package/dist/chunk-5UFRGXSB.mjs +0 -783
  53. package/dist/chunk-66M3TIO7.mjs +0 -837
  54. package/dist/chunk-6BM5MV3S.mjs +0 -719
  55. package/dist/chunk-6H3JHDP7.mjs +0 -832
  56. package/dist/chunk-7PHHJOGC.mjs +0 -1374
  57. package/dist/chunk-AASFXGUR.mjs +0 -1622
  58. package/dist/chunk-AR7DIZLP.mjs +0 -827
  59. package/dist/chunk-BDDMOIU2.mjs +0 -385
  60. package/dist/chunk-BMILMNKJ.mjs +0 -1633
  61. package/dist/chunk-BYY6MD5T.mjs +0 -729
  62. package/dist/chunk-CA4Q5JBK.mjs +0 -1143
  63. package/dist/chunk-CF4LU7KE.mjs +0 -384
  64. package/dist/chunk-CJINEUIH.mjs +0 -1369
  65. package/dist/chunk-CLWNLHDB.mjs +0 -909
  66. package/dist/chunk-CZUJTDNH.mjs +0 -848
  67. package/dist/chunk-DNGW3WQK.mjs +0 -810
  68. package/dist/chunk-DSI3TEO2.mjs +0 -662
  69. package/dist/chunk-EIQ5K6OO.mjs +0 -1579
  70. package/dist/chunk-FEJODRK5.mjs +0 -783
  71. package/dist/chunk-FK56AZ43.mjs +0 -817
  72. package/dist/chunk-H6S7WKSQ.mjs +0 -729
  73. package/dist/chunk-HAOJLJNB.mjs +0 -1290
  74. package/dist/chunk-HJCP36VW.mjs +0 -821
  75. package/dist/chunk-HPG7P6PD.mjs +0 -1372
  76. package/dist/chunk-IVRBV7SE.mjs +0 -1295
  77. package/dist/chunk-IXBC6GVT.mjs +0 -832
  78. package/dist/chunk-J5IFYDVU.mjs +0 -1579
  79. package/dist/chunk-KWQVBF7K.mjs +0 -831
  80. package/dist/chunk-LD3CHHU2.mjs +0 -1297
  81. package/dist/chunk-LMOXGPCM.mjs +0 -722
  82. package/dist/chunk-LSXZH6X6.mjs +0 -810
  83. package/dist/chunk-LUAREV6A.mjs +0 -508
  84. package/dist/chunk-MAPVFXBP.mjs +0 -708
  85. package/dist/chunk-MM2PLUCH.mjs +0 -1376
  86. package/dist/chunk-NPWCJZUG.mjs +0 -708
  87. package/dist/chunk-ON73WHHU.mjs +0 -1310
  88. package/dist/chunk-P6NVKUBB.mjs +0 -831
  89. package/dist/chunk-Q3KTWDSL.mjs +0 -808
  90. package/dist/chunk-Q5XMWG33.mjs +0 -661
  91. package/dist/chunk-QOIPVP6P.mjs +0 -1607
  92. package/dist/chunk-RMEQWG52.mjs +0 -1633
  93. package/dist/chunk-S6BZVTWN.mjs +0 -731
  94. package/dist/chunk-TE6JYZD3.mjs +0 -810
  95. package/dist/chunk-TLVLM3M5.mjs +0 -771
  96. package/dist/chunk-TXHPUU7A.mjs +0 -863
  97. package/dist/chunk-UMBBTNQN.mjs +0 -787
  98. package/dist/chunk-V2UPXL7L.mjs +0 -842
  99. package/dist/chunk-VODCPPET.mjs +0 -1292
  100. package/dist/chunk-W6UGMKRV.mjs +0 -1310
  101. package/dist/chunk-WGH4TGZ3.mjs +0 -1288
  102. package/dist/chunk-WTBDNCEN.mjs +0 -1352
  103. package/dist/chunk-XVW5DKJQ.mjs +0 -1619
  104. package/dist/chunk-YCDCIOJN.mjs +0 -842
  105. package/dist/chunk-YEHXYHGY.mjs +0 -1497
  106. package/dist/chunk-YHHXE2JX.mjs +0 -912
  107. package/dist/chunk-ZB6UK276.mjs +0 -662
  108. package/dist/chunk-ZG3KFSD3.mjs +0 -1142
  109. package/dist/cli.d.ts.map +0 -1
  110. package/dist/cli.js.map +0 -1
  111. package/dist/index.d.ts.map +0 -1
  112. package/dist/index.js.map +0 -1
  113. package/dist/scoring.d.ts +0 -12
  114. package/dist/scoring.d.ts.map +0 -1
  115. package/dist/scoring.js +0 -110
  116. package/dist/scoring.js.map +0 -1
  117. package/dist/types.d.ts +0 -53
  118. package/dist/types.d.ts.map +0 -1
  119. package/dist/types.js +0 -2
  120. package/dist/types.js.map +0 -1
  121. package/dist/utils/ast-parser.d.ts +0 -46
  122. package/dist/utils/ast-parser.d.ts.map +0 -1
  123. package/dist/utils/ast-parser.js +0 -157
  124. package/dist/utils/ast-parser.js.map +0 -1
  125. package/dist/utils/config-loader.d.ts +0 -19
  126. package/dist/utils/config-loader.d.ts.map +0 -1
  127. package/dist/utils/config-loader.js +0 -31
  128. package/dist/utils/config-loader.js.map +0 -1
  129. package/dist/utils/context-detector.d.ts +0 -40
  130. package/dist/utils/context-detector.d.ts.map +0 -1
  131. package/dist/utils/context-detector.js +0 -225
  132. package/dist/utils/context-detector.js.map +0 -1
  133. package/dist/utils/scope-tracker.d.ts +0 -87
  134. package/dist/utils/scope-tracker.d.ts.map +0 -1
  135. package/dist/utils/scope-tracker.js +0 -161
  136. package/dist/utils/scope-tracker.js.map +0 -1
@@ -1,708 +0,0 @@
1
- // src/analyzers/naming-ast.ts
2
- import { Severity as Severity2 } from "@aiready/core";
3
-
4
- // src/utils/ast-parser.ts
5
- import { parse } from "@typescript-eslint/typescript-estree";
6
- import { readFileSync } from "fs";
7
- function parseFile(filePath, content) {
8
- try {
9
- const code = content ?? readFileSync(filePath, "utf-8");
10
- const isTypeScript = filePath.match(/\.tsx?$/);
11
- return parse(code, {
12
- jsx: filePath.match(/\.[jt]sx$/i) !== null,
13
- loc: true,
14
- range: true,
15
- comment: false,
16
- tokens: false,
17
- // Relaxed parsing for JavaScript files
18
- sourceType: "module",
19
- ecmaVersion: "latest",
20
- // Only use TypeScript parser features for .ts/.tsx files
21
- filePath: isTypeScript ? filePath : void 0
22
- });
23
- } catch (error) {
24
- void error;
25
- return null;
26
- }
27
- }
28
- function traverseAST(node, visitor, parent = null) {
29
- if (!node) return;
30
- visitor.enter?.(node, parent);
31
- for (const key of Object.keys(node)) {
32
- const value = node[key];
33
- if (Array.isArray(value)) {
34
- for (const child of value) {
35
- if (child && typeof child === "object" && "type" in child) {
36
- traverseAST(child, visitor, node);
37
- }
38
- }
39
- } else if (value && typeof value === "object" && "type" in value) {
40
- traverseAST(value, visitor, node);
41
- }
42
- }
43
- visitor.leave?.(node, parent);
44
- }
45
- function isLoopStatement(node) {
46
- return [
47
- "ForStatement",
48
- "ForInStatement",
49
- "ForOfStatement",
50
- "WhileStatement",
51
- "DoWhileStatement"
52
- ].includes(node.type);
53
- }
54
- function getLineNumber(node) {
55
- return node.loc?.start.line ?? 0;
56
- }
57
-
58
- // src/utils/context-detector.ts
59
- import { Severity } from "@aiready/core";
60
- function detectFileType(filePath, ast) {
61
- void ast;
62
- const path = filePath.toLowerCase();
63
- if (path.match(/\.(test|spec)\.(ts|tsx|js|jsx)$/) || path.includes("__tests__")) {
64
- return "test";
65
- }
66
- if (path.endsWith(".d.ts") || path.includes("types")) {
67
- return "types";
68
- }
69
- if (path.match(/config|\.config\.|rc\.|setup/) || path.includes("configuration")) {
70
- return "config";
71
- }
72
- return "production";
73
- }
74
- function detectCodeLayer(ast) {
75
- let hasAPIIndicators = 0;
76
- let hasBusinessIndicators = 0;
77
- let hasDataIndicators = 0;
78
- let hasUtilityIndicators = 0;
79
- traverseAST(ast, {
80
- enter: (node) => {
81
- if (node.type === "ImportDeclaration") {
82
- const source = node.source.value;
83
- if (source.match(/express|fastify|koa|@nestjs|axios|fetch|http/i)) {
84
- hasAPIIndicators++;
85
- }
86
- if (source.match(/database|prisma|typeorm|sequelize|mongoose|pg|mysql/i)) {
87
- hasDataIndicators++;
88
- }
89
- }
90
- if (node.type === "FunctionDeclaration" && node.id) {
91
- const name = node.id.name;
92
- if (name.match(
93
- /^(get|post|put|delete|patch|handle|api|route|controller)/i
94
- )) {
95
- hasAPIIndicators++;
96
- }
97
- if (name.match(/^(calculate|process|validate|transform|compute|analyze)/i)) {
98
- hasBusinessIndicators++;
99
- }
100
- if (name.match(/^(find|create|update|delete|save|fetch|query|insert)/i)) {
101
- hasDataIndicators++;
102
- }
103
- if (name.match(
104
- /^(format|parse|convert|normalize|sanitize|encode|decode)/i
105
- )) {
106
- hasUtilityIndicators++;
107
- }
108
- }
109
- if (node.type === "ExportNamedDeclaration" || node.type === "ExportDefaultDeclaration") {
110
- if (node.type === "ExportNamedDeclaration" && node.declaration) {
111
- if (node.declaration.type === "FunctionDeclaration" && node.declaration.id) {
112
- const name = node.declaration.id.name;
113
- if (name.match(/handler|route|api|controller/i)) {
114
- hasAPIIndicators += 2;
115
- }
116
- }
117
- }
118
- }
119
- }
120
- });
121
- const scores = {
122
- api: hasAPIIndicators,
123
- business: hasBusinessIndicators,
124
- data: hasDataIndicators,
125
- utility: hasUtilityIndicators
126
- };
127
- const maxScore = Math.max(...Object.values(scores));
128
- if (maxScore === 0) {
129
- return "unknown";
130
- }
131
- if (scores.api === maxScore) return "api";
132
- if (scores.data === maxScore) return "data";
133
- if (scores.business === maxScore) return "business";
134
- if (scores.utility === maxScore) return "utility";
135
- return "unknown";
136
- }
137
- function calculateComplexity(node) {
138
- let complexity = 1;
139
- traverseAST(node, {
140
- enter: (childNode) => {
141
- switch (childNode.type) {
142
- case "IfStatement":
143
- case "ConditionalExpression":
144
- // ternary
145
- case "SwitchCase":
146
- case "ForStatement":
147
- case "ForInStatement":
148
- case "ForOfStatement":
149
- case "WhileStatement":
150
- case "DoWhileStatement":
151
- case "CatchClause":
152
- complexity++;
153
- break;
154
- case "LogicalExpression":
155
- if (childNode.operator === "&&" || childNode.operator === "||") {
156
- complexity++;
157
- }
158
- break;
159
- }
160
- }
161
- });
162
- return complexity;
163
- }
164
- function buildCodeContext(filePath, ast) {
165
- const fileType = detectFileType(filePath, ast);
166
- const codeLayer = detectCodeLayer(ast);
167
- let totalComplexity = 0;
168
- let functionCount = 0;
169
- traverseAST(ast, {
170
- enter: (node) => {
171
- if (node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression") {
172
- totalComplexity += calculateComplexity(node);
173
- functionCount++;
174
- }
175
- }
176
- });
177
- const avgComplexity = functionCount > 0 ? totalComplexity / functionCount : 1;
178
- return {
179
- fileType,
180
- codeLayer,
181
- complexity: Math.round(avgComplexity),
182
- isTestFile: fileType === "test",
183
- isTypeDefinition: fileType === "types"
184
- };
185
- }
186
- function adjustSeverity(baseSeverity, context, issueType) {
187
- const getEnum = (s) => {
188
- if (s === Severity.Critical || s === "critical") return Severity.Critical;
189
- if (s === Severity.Major || s === "major") return Severity.Major;
190
- if (s === Severity.Minor || s === "minor") return Severity.Minor;
191
- return Severity.Info;
192
- };
193
- let currentSev = getEnum(baseSeverity);
194
- if (context.isTestFile) {
195
- if (currentSev === Severity.Minor) currentSev = Severity.Info;
196
- if (currentSev === Severity.Major) currentSev = Severity.Minor;
197
- }
198
- if (context.isTypeDefinition) {
199
- if (currentSev === Severity.Minor) currentSev = Severity.Info;
200
- }
201
- if (context.codeLayer === "api") {
202
- if (currentSev === Severity.Info && issueType === "unclear")
203
- currentSev = Severity.Minor;
204
- if (currentSev === Severity.Minor && issueType === "unclear")
205
- currentSev = Severity.Major;
206
- }
207
- if (context.complexity > 10) {
208
- if (currentSev === Severity.Info) currentSev = Severity.Minor;
209
- }
210
- if (context.codeLayer === "utility") {
211
- if (currentSev === Severity.Minor && issueType === "abbreviation")
212
- currentSev = Severity.Info;
213
- }
214
- return currentSev;
215
- }
216
- function isAcceptableInContext(name, context, options) {
217
- if (options.isLoopVariable && ["i", "j", "k", "l", "n", "m"].includes(name)) {
218
- return true;
219
- }
220
- if (context.isTestFile) {
221
- if (["a", "b", "c", "x", "y", "z"].includes(name) && options.isParameter) {
222
- return true;
223
- }
224
- }
225
- if (context.codeLayer === "utility" && ["x", "y", "z"].includes(name)) {
226
- return true;
227
- }
228
- if (options.isDestructured) {
229
- if (["s", "b", "f", "l"].includes(name)) {
230
- return true;
231
- }
232
- }
233
- if (options.isParameter && (options.complexity ?? context.complexity) < 3) {
234
- if (name.length >= 2) {
235
- return true;
236
- }
237
- }
238
- return false;
239
- }
240
-
241
- // src/analyzers/naming-ast.ts
242
- async function analyzeNamingAST(filePaths) {
243
- const allIssues = [];
244
- for (const filePath of filePaths) {
245
- try {
246
- const ast = parseFile(filePath);
247
- if (!ast) continue;
248
- const context = buildCodeContext(filePath, ast);
249
- const issues = analyzeIdentifiers(ast, filePath, context);
250
- allIssues.push(...issues);
251
- } catch (err) {
252
- void err;
253
- }
254
- }
255
- return allIssues;
256
- }
257
- function analyzeIdentifiers(ast, filePath, context) {
258
- const issues = [];
259
- const scopeTracker = new ScopeTracker();
260
- traverseAST(ast, {
261
- enter: (node) => {
262
- if (node.type === "VariableDeclarator" && node.id.type === "Identifier") {
263
- const isParameter = false;
264
- const isLoopVariable = isLoopStatement(node.parent?.parent);
265
- scopeTracker.declareVariable(
266
- node.id.name,
267
- node.id,
268
- getLineNumber(node.id),
269
- { isParameter, isLoopVariable }
270
- );
271
- }
272
- if (node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression") {
273
- node.params.forEach((param) => {
274
- if (param.type === "Identifier") {
275
- scopeTracker.declareVariable(
276
- param.name,
277
- param,
278
- getLineNumber(param),
279
- { isParameter: true }
280
- );
281
- } else if (param.type === "ObjectPattern") {
282
- extractDestructuredIdentifiers(param, true, scopeTracker);
283
- }
284
- });
285
- }
286
- if ((node.type === "ClassDeclaration" || node.type === "TSInterfaceDeclaration" || node.type === "TSTypeAliasDeclaration") && node.id) {
287
- checkNamingConvention(
288
- node.id.name,
289
- "PascalCase",
290
- node.id,
291
- filePath,
292
- issues,
293
- context
294
- );
295
- }
296
- }
297
- });
298
- for (const varInfo of scopeTracker.getVariables()) {
299
- checkVariableNaming(varInfo, filePath, issues, context);
300
- }
301
- return issues;
302
- }
303
- function checkNamingConvention(name, convention, node, file, issues, context) {
304
- let isValid = true;
305
- if (convention === "PascalCase") {
306
- isValid = /^[A-Z][a-zA-Z0-9]*$/.test(name);
307
- } else if (convention === "camelCase") {
308
- isValid = /^[a-z][a-zA-Z0-9]*$/.test(name);
309
- } else if (convention === "UPPER_CASE") {
310
- isValid = /^[A-Z][A-Z0-9_]*$/.test(name);
311
- }
312
- if (!isValid) {
313
- const severity = adjustSeverity(Severity2.Info, context, "convention-mix");
314
- issues.push({
315
- file,
316
- line: getLineNumber(node),
317
- type: "convention-mix",
318
- identifier: name,
319
- severity,
320
- suggestion: `Follow ${convention} for this identifier`
321
- });
322
- }
323
- }
324
- function checkVariableNaming(varInfo, file, issues, context) {
325
- const { name, node, line, options } = varInfo;
326
- if (isAcceptableInContext(name, context, options)) {
327
- return;
328
- }
329
- if (name.length === 1 && !options.isLoopVariable) {
330
- const severity = adjustSeverity(Severity2.Minor, context, "poor-naming");
331
- issues.push({
332
- file,
333
- line,
334
- type: "poor-naming",
335
- identifier: name,
336
- severity,
337
- suggestion: "Use a more descriptive name than a single letter"
338
- });
339
- }
340
- const vagueNames = [
341
- "data",
342
- "info",
343
- "item",
344
- "obj",
345
- "val",
346
- "tmp",
347
- "temp",
348
- "thing",
349
- "stuff"
350
- ];
351
- if (vagueNames.includes(name.toLowerCase())) {
352
- const severity = adjustSeverity(Severity2.Minor, context, "poor-naming");
353
- issues.push({
354
- file,
355
- line,
356
- type: "poor-naming",
357
- identifier: name,
358
- severity,
359
- suggestion: `Avoid vague names like '${name}'. What does this data represent?`
360
- });
361
- }
362
- if (name.length > 1 && name.length <= 3 && !options.isLoopVariable && !isCommonAbbreviation(name)) {
363
- const severity = adjustSeverity(Severity2.Info, context, "abbreviation");
364
- issues.push({
365
- file,
366
- line,
367
- type: "abbreviation",
368
- identifier: name,
369
- severity,
370
- suggestion: "Avoid non-standard abbreviations"
371
- });
372
- }
373
- }
374
- function isCommonAbbreviation(name) {
375
- const common = [
376
- "id",
377
- "db",
378
- "fs",
379
- "os",
380
- "ip",
381
- "ui",
382
- "ux",
383
- "api",
384
- "env",
385
- "url"
386
- ];
387
- return common.includes(name.toLowerCase());
388
- }
389
- var ScopeTracker = class {
390
- constructor() {
391
- this.variables = [];
392
- }
393
- declareVariable(name, node, line, options = {}) {
394
- this.variables.push({ name, node, line, options });
395
- }
396
- getVariables() {
397
- return this.variables;
398
- }
399
- };
400
- function extractDestructuredIdentifiers(node, isParameter, scopeTracker) {
401
- if (node.type === "ObjectPattern") {
402
- node.properties.forEach((prop) => {
403
- if (prop.type === "Property" && prop.value.type === "Identifier") {
404
- scopeTracker.declareVariable(
405
- prop.value.name,
406
- prop.value,
407
- getLineNumber(prop.value),
408
- {
409
- isParameter,
410
- isDestructured: true
411
- }
412
- );
413
- }
414
- });
415
- } else if (node.type === "ArrayPattern") {
416
- for (const element of node.elements) {
417
- if (element?.type === "Identifier") {
418
- scopeTracker.declareVariable(
419
- element.name,
420
- element,
421
- getLineNumber(element),
422
- {
423
- isParameter,
424
- isDestructured: true
425
- }
426
- );
427
- }
428
- }
429
- }
430
- }
431
-
432
- // src/analyzers/patterns.ts
433
- import { readFileSync as readFileSync2 } from "fs";
434
- import { Severity as Severity3 } from "@aiready/core";
435
- async function analyzePatterns(filePaths) {
436
- const issues = [];
437
- const contents = /* @__PURE__ */ new Map();
438
- const tryCatchPattern = /try\s*\{/g;
439
- const catchPattern = /catch\s*\(\s*(\w+)\s*\)/g;
440
- const styleStats = {
441
- tryCatch: 0,
442
- thenCatch: 0,
443
- asyncAwait: 0,
444
- commonJs: 0,
445
- esm: 0
446
- };
447
- for (const filePath of filePaths) {
448
- try {
449
- const content = readFileSync2(filePath, "utf-8");
450
- contents.set(filePath, content);
451
- if (content.match(tryCatchPattern)) styleStats.tryCatch++;
452
- if (content.match(/\.catch\s*\(/)) styleStats.thenCatch++;
453
- if (content.match(/\bawait\b/)) styleStats.asyncAwait++;
454
- if (content.match(/\brequire\s*\(/)) styleStats.commonJs++;
455
- if (content.match(/\bimport\b.*\bfrom\b/)) styleStats.esm++;
456
- } catch (err) {
457
- void err;
458
- }
459
- }
460
- const totalFiles = filePaths.length;
461
- if (styleStats.tryCatch > 0 && styleStats.thenCatch > 0) {
462
- const dominant = styleStats.tryCatch >= styleStats.thenCatch ? "try-catch" : ".catch()";
463
- const minority = dominant === "try-catch" ? ".catch()" : "try-catch";
464
- issues.push({
465
- files: filePaths.filter((f) => {
466
- const c = contents.get(f) || "";
467
- return minority === "try-catch" ? c.match(tryCatchPattern) : c.match(/\.catch\s*\(/);
468
- }),
469
- type: "pattern-inconsistency",
470
- description: `Mixed error handling styles: codebase primarily uses ${dominant}, but found ${minority} in some files.`,
471
- examples: [dominant, minority],
472
- severity: Severity3.Minor
473
- });
474
- }
475
- if (styleStats.commonJs > 0 && styleStats.esm > 0) {
476
- const minority = styleStats.esm >= styleStats.commonJs ? "CommonJS (require)" : "ESM (import)";
477
- issues.push({
478
- files: filePaths.filter((f) => {
479
- const c = contents.get(f) || "";
480
- return minority === "CommonJS (require)" ? c.match(/\brequire\s*\(/) : c.match(/\bimport\b/);
481
- }),
482
- type: "pattern-inconsistency",
483
- description: `Mixed module systems: found both ESM and CommonJS.`,
484
- examples: ['import X from "y"', 'const X = require("y")'],
485
- severity: Severity3.Major
486
- });
487
- }
488
- return issues;
489
- }
490
-
491
- // src/analyzer.ts
492
- import {
493
- scanFiles,
494
- Severity as Severity5,
495
- IssueType as IssueType2,
496
- getSeverityLevel
497
- } from "@aiready/core";
498
-
499
- // src/analyzers/naming-generalized.ts
500
- import { getParser, Severity as Severity4 } from "@aiready/core";
501
- import { readFileSync as readFileSync3 } from "fs";
502
- async function analyzeNamingGeneralized(files) {
503
- const issues = [];
504
- for (const file of files) {
505
- const parser = getParser(file);
506
- if (!parser) continue;
507
- try {
508
- const code = readFileSync3(file, "utf-8");
509
- await parser.initialize();
510
- const result = parser.parse(code, file);
511
- const conventions = parser.getNamingConventions();
512
- for (const exp of result.exports) {
513
- let pattern;
514
- const typeName = exp.type;
515
- if (exp.type === "class") {
516
- pattern = conventions.classPattern;
517
- } else if (exp.type === "interface" && conventions.interfacePattern) {
518
- pattern = conventions.interfacePattern;
519
- } else if (exp.type === "type" && conventions.typePattern) {
520
- pattern = conventions.typePattern;
521
- } else if (exp.type === "function") {
522
- pattern = conventions.functionPattern;
523
- } else if (exp.type === "const") {
524
- pattern = conventions.constantPattern;
525
- } else {
526
- pattern = conventions.variablePattern;
527
- }
528
- if (pattern && !pattern.test(exp.name)) {
529
- issues.push({
530
- type: "naming-inconsistency",
531
- identifier: exp.name,
532
- file,
533
- line: exp.loc?.start.line || 1,
534
- column: exp.loc?.start.column || 0,
535
- severity: Severity4.Major,
536
- category: "naming",
537
- suggestion: `Follow ${parser.language} ${exp.type} naming convention: ${pattern.toString()}`
538
- });
539
- }
540
- }
541
- for (const imp of result.imports) {
542
- for (const spec of imp.specifiers) {
543
- if (spec === "*" || spec === "default") continue;
544
- if (!conventions.variablePattern.test(spec) && !conventions.classPattern.test(spec)) {
545
- issues.push({
546
- type: "naming-inconsistency",
547
- identifier: spec,
548
- file,
549
- line: imp.loc?.start.line || 1,
550
- column: imp.loc?.start.column || 0,
551
- severity: Severity4.Minor,
552
- category: "naming",
553
- suggestion: `Imported identifier '${spec}' may not follow standard conventions for this language.`
554
- });
555
- }
556
- }
557
- }
558
- } catch (error) {
559
- console.warn(`Consistency: Failed to analyze ${file}: ${error}`);
560
- }
561
- }
562
- return issues;
563
- }
564
-
565
- // src/analyzer.ts
566
- async function analyzeConsistency(options) {
567
- const {
568
- checkNaming = true,
569
- checkPatterns = true,
570
- checkArchitecture = false,
571
- // Not implemented yet
572
- minSeverity = Severity5.Info,
573
- ...scanOptions
574
- } = options;
575
- void checkArchitecture;
576
- const filePaths = await scanFiles(scanOptions);
577
- let namingIssues = [];
578
- if (checkNaming) {
579
- namingIssues = await analyzeNamingGeneralized(filePaths);
580
- const tsJsFiles = filePaths.filter((f) => /\.(ts|tsx|js|jsx)$/i.test(f));
581
- if (tsJsFiles.length > 0) {
582
- const deepTsIssues = await analyzeNamingAST(tsJsFiles);
583
- namingIssues = [...namingIssues, ...deepTsIssues];
584
- }
585
- }
586
- const patternIssues = checkPatterns ? await analyzePatterns(filePaths) : [];
587
- const results = [];
588
- const fileIssuesMap = /* @__PURE__ */ new Map();
589
- for (const issue of namingIssues) {
590
- if (!shouldIncludeSeverity(issue.severity, minSeverity)) continue;
591
- const fileName = issue.fileName || issue.file || issue.filePath;
592
- if (!fileIssuesMap.has(fileName)) fileIssuesMap.set(fileName, []);
593
- fileIssuesMap.get(fileName).push(issue);
594
- }
595
- for (const issue of patternIssues) {
596
- if (!shouldIncludeSeverity(issue.severity, minSeverity)) continue;
597
- const fileName = issue.fileName || issue.file || issue.filePath;
598
- if (!fileIssuesMap.has(fileName)) fileIssuesMap.set(fileName, []);
599
- fileIssuesMap.get(fileName).push(issue);
600
- }
601
- for (const [fileName, issues] of fileIssuesMap.entries()) {
602
- results.push({
603
- fileName,
604
- issues: issues.map((i) => transformToIssue(i)),
605
- metrics: {
606
- consistencyScore: calculateConsistencyScore(issues)
607
- }
608
- });
609
- }
610
- return {
611
- results,
612
- summary: {
613
- filesAnalyzed: filePaths.length,
614
- totalIssues: results.reduce((acc, r) => acc + r.issues.length, 0),
615
- namingIssues: namingIssues.length,
616
- patternIssues: patternIssues.length,
617
- architectureIssues: 0
618
- },
619
- recommendations: [],
620
- metadata: {
621
- toolName: "naming-consistency",
622
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
623
- }
624
- };
625
- }
626
- function shouldIncludeSeverity(severity, minSeverity) {
627
- return getSeverityLevel(severity) >= getSeverityLevel(minSeverity);
628
- }
629
- function transformToIssue(i) {
630
- if (i.message && i.location) {
631
- return {
632
- type: i.type,
633
- severity: i.severity,
634
- message: i.message,
635
- location: i.location,
636
- suggestion: i.suggestion
637
- };
638
- }
639
- if (i.identifier || i.type) {
640
- const line = i.line || 1;
641
- const column = i.column || 1;
642
- return {
643
- type: i.type || IssueType2.NamingInconsistency,
644
- severity: i.severity,
645
- message: i.suggestion ? `Naming issue: ${i.suggestion}` : `Naming issue for '${i.identifier || "unknown"}'`,
646
- location: {
647
- file: i.file || i.fileName || "",
648
- line,
649
- column,
650
- endLine: line,
651
- endColumn: column + (i.identifier?.length || 10)
652
- },
653
- suggestion: i.suggestion
654
- };
655
- }
656
- if (i.description || i.files) {
657
- const fileName = Array.isArray(i.files) ? i.files[0] : i.file || "";
658
- return {
659
- type: i.type || IssueType2.PatternInconsistency,
660
- severity: i.severity,
661
- message: i.description || "Pattern inconsistency found",
662
- location: {
663
- file: fileName,
664
- line: 1,
665
- column: 1,
666
- endLine: 1,
667
- endColumn: 10
668
- },
669
- suggestion: i.examples?.[0]
670
- };
671
- }
672
- return {
673
- type: i.type,
674
- severity: i.severity,
675
- message: i.message || "Unknown issue",
676
- location: i.location || { file: "", line: 1, column: 1 },
677
- suggestion: i.suggestion
678
- };
679
- }
680
- function calculateConsistencyScore(issues) {
681
- let totalWeight = 0;
682
- for (const issue of issues) {
683
- const val = getSeverityLevel(issue.severity);
684
- switch (val) {
685
- case 4:
686
- totalWeight += 10;
687
- break;
688
- case 3:
689
- totalWeight += 5;
690
- break;
691
- case 2:
692
- totalWeight += 2;
693
- break;
694
- case 1:
695
- totalWeight += 1;
696
- break;
697
- default:
698
- totalWeight += 1;
699
- }
700
- }
701
- return Math.max(0, 1 - totalWeight / 100);
702
- }
703
-
704
- export {
705
- analyzeNamingAST,
706
- analyzePatterns,
707
- analyzeConsistency
708
- };