@aiready/consistency 0.20.19 → 0.20.21
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/.turbo/turbo-build.log +23 -24
- package/.turbo/turbo-lint.log +4 -5
- package/.turbo/turbo-test.log +28 -31
- package/dist/chunk-CLWNLHDB.mjs +909 -0
- package/dist/chunk-KWQVBF7K.mjs +831 -0
- package/dist/chunk-P6NVKUBB.mjs +831 -0
- package/dist/cli.js +126 -50
- package/dist/cli.mjs +1 -1
- package/dist/index.js +123 -143
- package/dist/index.mjs +5 -102
- package/package.json +2 -2
- package/src/__tests__/scoring.test.ts +9 -9
- package/src/analyzer.ts +6 -26
- package/src/analyzers/naming-ast.ts +10 -8
- package/src/analyzers/naming-generalized.ts +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
analyzeConsistency,
|
|
3
3
|
analyzeNamingAST,
|
|
4
|
-
analyzePatterns
|
|
5
|
-
|
|
4
|
+
analyzePatterns,
|
|
5
|
+
calculateConsistencyScore
|
|
6
|
+
} from "./chunk-CLWNLHDB.mjs";
|
|
6
7
|
|
|
7
8
|
// src/index.ts
|
|
8
9
|
import { ToolRegistry } from "@aiready/core";
|
|
@@ -10,108 +11,10 @@ import { ToolRegistry } from "@aiready/core";
|
|
|
10
11
|
// src/provider.ts
|
|
11
12
|
import {
|
|
12
13
|
createProvider,
|
|
13
|
-
ToolName
|
|
14
|
+
ToolName
|
|
14
15
|
} from "@aiready/core";
|
|
15
|
-
|
|
16
|
-
// src/scoring.ts
|
|
17
|
-
import { calculateProductivityImpact, ToolName } from "@aiready/core";
|
|
18
|
-
function calculateConsistencyScore(issues, totalFilesAnalyzed, costConfig) {
|
|
19
|
-
void costConfig;
|
|
20
|
-
const criticalIssues = issues.filter((i) => i.severity === "critical").length;
|
|
21
|
-
const majorIssues = issues.filter((i) => i.severity === "major").length;
|
|
22
|
-
const minorIssues = issues.filter((i) => i.severity === "minor").length;
|
|
23
|
-
const totalIssues = issues.length;
|
|
24
|
-
const issuesPerFile = totalFilesAnalyzed > 0 ? totalIssues / totalFilesAnalyzed : 0;
|
|
25
|
-
const densityPenalty = Math.min(50, issuesPerFile * 15);
|
|
26
|
-
const weightedCount = criticalIssues * 10 + majorIssues * 3 + minorIssues * 0.5;
|
|
27
|
-
const avgWeightedIssuesPerFile = totalFilesAnalyzed > 0 ? weightedCount / totalFilesAnalyzed : 0;
|
|
28
|
-
const severityPenalty = Math.min(50, avgWeightedIssuesPerFile * 2);
|
|
29
|
-
const rawScore = 100 - densityPenalty - severityPenalty;
|
|
30
|
-
const score = Math.max(0, Math.min(100, Math.round(rawScore)));
|
|
31
|
-
const factors = [
|
|
32
|
-
{
|
|
33
|
-
name: "Issue Density",
|
|
34
|
-
impact: -Math.round(densityPenalty),
|
|
35
|
-
description: `${issuesPerFile.toFixed(2)} issues per file ${issuesPerFile < 1 ? "(excellent)" : issuesPerFile < 3 ? "(acceptable)" : "(high)"}`
|
|
36
|
-
}
|
|
37
|
-
];
|
|
38
|
-
if (criticalIssues > 0) {
|
|
39
|
-
const criticalImpact = Math.min(30, criticalIssues * 10);
|
|
40
|
-
factors.push({
|
|
41
|
-
name: "Critical Issues",
|
|
42
|
-
impact: -criticalImpact,
|
|
43
|
-
description: `${criticalIssues} critical consistency issue${criticalIssues > 1 ? "s" : ""} (high AI confusion risk)`
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
if (majorIssues > 0) {
|
|
47
|
-
const majorImpact = Math.min(20, Math.round(majorIssues * 3));
|
|
48
|
-
factors.push({
|
|
49
|
-
name: "Major Issues",
|
|
50
|
-
impact: -majorImpact,
|
|
51
|
-
description: `${majorIssues} major issue${majorIssues > 1 ? "s" : ""} (moderate AI confusion risk)`
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
if (minorIssues > 0 && minorIssues >= totalFilesAnalyzed) {
|
|
55
|
-
const minorImpact = -Math.round(minorIssues * 0.5);
|
|
56
|
-
factors.push({
|
|
57
|
-
name: "Minor Issues",
|
|
58
|
-
impact: minorImpact,
|
|
59
|
-
description: `${minorIssues} minor issue${minorIssues > 1 ? "s" : ""} (slight AI confusion risk)`
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
const recommendations = [];
|
|
63
|
-
if (criticalIssues > 0) {
|
|
64
|
-
const estimatedImpact = Math.min(30, criticalIssues * 10);
|
|
65
|
-
recommendations.push({
|
|
66
|
-
action: "Fix critical naming/pattern inconsistencies (highest AI confusion risk)",
|
|
67
|
-
estimatedImpact,
|
|
68
|
-
priority: "high"
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
if (majorIssues > 5) {
|
|
72
|
-
const estimatedImpact = Math.min(15, Math.round(majorIssues / 2));
|
|
73
|
-
recommendations.push({
|
|
74
|
-
action: "Standardize naming conventions across codebase",
|
|
75
|
-
estimatedImpact,
|
|
76
|
-
priority: "medium"
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
if (issuesPerFile > 3) {
|
|
80
|
-
recommendations.push({
|
|
81
|
-
action: "Establish and enforce coding style guide to reduce inconsistencies",
|
|
82
|
-
estimatedImpact: 12,
|
|
83
|
-
priority: "medium"
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
if (totalIssues > 20 && minorIssues / totalIssues > 0.7) {
|
|
87
|
-
recommendations.push({
|
|
88
|
-
action: "Enable linter/formatter to automatically fix minor style issues",
|
|
89
|
-
estimatedImpact: 8,
|
|
90
|
-
priority: "low"
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
const productivityImpact = calculateProductivityImpact(issues);
|
|
94
|
-
return {
|
|
95
|
-
toolName: ToolName.NamingConsistency,
|
|
96
|
-
score,
|
|
97
|
-
rawMetrics: {
|
|
98
|
-
totalIssues,
|
|
99
|
-
criticalIssues,
|
|
100
|
-
majorIssues,
|
|
101
|
-
minorIssues,
|
|
102
|
-
issuesPerFile: Math.round(issuesPerFile * 100) / 100,
|
|
103
|
-
avgWeightedIssuesPerFile: Math.round(avgWeightedIssuesPerFile * 100) / 100,
|
|
104
|
-
// Business value metrics
|
|
105
|
-
estimatedDeveloperHours: productivityImpact.totalHours
|
|
106
|
-
},
|
|
107
|
-
factors,
|
|
108
|
-
recommendations
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// src/provider.ts
|
|
113
16
|
var ConsistencyProvider = createProvider({
|
|
114
|
-
id:
|
|
17
|
+
id: ToolName.NamingConsistency,
|
|
115
18
|
alias: ["consistency", "naming", "standards"],
|
|
116
19
|
version: "0.16.5",
|
|
117
20
|
defaultWeight: 14,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiready/consistency",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.21",
|
|
4
4
|
"description": "Detects consistency issues in naming, patterns, and architecture that confuse AI models",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"@typescript-eslint/typescript-estree": "^8.53.0",
|
|
44
44
|
"chalk": "^5.3.0",
|
|
45
45
|
"commander": "^14.0.0",
|
|
46
|
-
"@aiready/core": "0.23.
|
|
46
|
+
"@aiready/core": "0.23.22"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@types/node": "^24.0.0",
|
|
@@ -52,12 +52,12 @@ describe('Consistency Scoring', () => {
|
|
|
52
52
|
// score = 100 - 3 - 4 = 93
|
|
53
53
|
expect(result.score).toBe(93);
|
|
54
54
|
expect(result.rawMetrics.criticalIssues).toBe(2);
|
|
55
|
-
expect(
|
|
56
|
-
|
|
57
|
-
);
|
|
58
|
-
expect(
|
|
59
|
-
|
|
60
|
-
);
|
|
55
|
+
expect(
|
|
56
|
+
result.factors.some((f: any) => f.name === 'Critical Issues')
|
|
57
|
+
).toBe(true);
|
|
58
|
+
expect(
|
|
59
|
+
result.recommendations.some((r: any) => r.priority === 'high')
|
|
60
|
+
).toBe(true);
|
|
61
61
|
});
|
|
62
62
|
|
|
63
63
|
it('should apply weighted severity penalties', () => {
|
|
@@ -109,10 +109,10 @@ describe('Consistency Scoring', () => {
|
|
|
109
109
|
|
|
110
110
|
expect(result.recommendations.length).toBeGreaterThan(0);
|
|
111
111
|
expect(
|
|
112
|
-
result.recommendations.some((r) => r.action.includes('critical'))
|
|
112
|
+
result.recommendations.some((r: any) => r.action.includes('critical'))
|
|
113
113
|
).toBe(true);
|
|
114
114
|
expect(
|
|
115
|
-
result.recommendations.some((r) => r.action.includes('naming'))
|
|
115
|
+
result.recommendations.some((r: any) => r.action.includes('naming'))
|
|
116
116
|
).toBe(true);
|
|
117
117
|
});
|
|
118
118
|
|
|
@@ -136,7 +136,7 @@ describe('Consistency Scoring', () => {
|
|
|
136
136
|
const result = calculateConsistencyScore(issues, 10);
|
|
137
137
|
|
|
138
138
|
expect(
|
|
139
|
-
result.recommendations.some((r) => r.action.includes('linter'))
|
|
139
|
+
result.recommendations.some((r: any) => r.action.includes('linter'))
|
|
140
140
|
).toBe(true);
|
|
141
141
|
});
|
|
142
142
|
|
package/src/analyzer.ts
CHANGED
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
13
|
import { analyzeNamingAST } from './analyzers/naming-ast';
|
|
14
14
|
import { analyzeNamingGeneralized } from './analyzers/naming-generalized';
|
|
15
15
|
import { analyzePatterns } from './analyzers/patterns';
|
|
16
|
+
import { calculateConsistencyScore as calculateConsistencyScoreFromScoring } from './scoring';
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
19
|
* Main consistency analyzer that orchestrates all analysis types.
|
|
@@ -90,11 +91,15 @@ export async function analyzeConsistency(
|
|
|
90
91
|
|
|
91
92
|
// Build final results
|
|
92
93
|
for (const [fileName, issues] of fileIssuesMap.entries()) {
|
|
94
|
+
const scoreResult = calculateConsistencyScoreFromScoring(
|
|
95
|
+
issues,
|
|
96
|
+
filePaths.length
|
|
97
|
+
);
|
|
93
98
|
results.push({
|
|
94
99
|
fileName,
|
|
95
100
|
issues: issues.map((i) => transformToIssue(i)),
|
|
96
101
|
metrics: {
|
|
97
|
-
consistencyScore:
|
|
102
|
+
consistencyScore: scoreResult.score / 100,
|
|
98
103
|
},
|
|
99
104
|
});
|
|
100
105
|
}
|
|
@@ -234,28 +239,3 @@ function transformToIssue(i: any): Issue {
|
|
|
234
239
|
suggestion: i.suggestion,
|
|
235
240
|
};
|
|
236
241
|
}
|
|
237
|
-
|
|
238
|
-
function calculateConsistencyScore(issues: ConsistencyIssue[]): number {
|
|
239
|
-
let totalWeight = 0;
|
|
240
|
-
for (const issue of issues) {
|
|
241
|
-
const val = getSeverityLevel(issue.severity);
|
|
242
|
-
switch (val) {
|
|
243
|
-
case 4:
|
|
244
|
-
totalWeight += 10;
|
|
245
|
-
break;
|
|
246
|
-
case 3:
|
|
247
|
-
totalWeight += 5;
|
|
248
|
-
break;
|
|
249
|
-
case 2:
|
|
250
|
-
totalWeight += 2;
|
|
251
|
-
break;
|
|
252
|
-
case 1:
|
|
253
|
-
totalWeight += 1;
|
|
254
|
-
break;
|
|
255
|
-
default:
|
|
256
|
-
totalWeight += 1;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
// Score from 0-1, where 1 is perfect
|
|
260
|
-
return Math.max(0, 1 - totalWeight / 100);
|
|
261
|
-
}
|
|
@@ -79,12 +79,10 @@ function analyzeIdentifiers(
|
|
|
79
79
|
);
|
|
80
80
|
} else if (param.type === 'ObjectPattern') {
|
|
81
81
|
// Handle destructured parameters: { id, name }
|
|
82
|
-
extractDestructuredIdentifiers(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
isArrowParameter
|
|
87
|
-
);
|
|
82
|
+
extractDestructuredIdentifiers(param, scopeTracker, {
|
|
83
|
+
isParameter: true,
|
|
84
|
+
isArrowParameter,
|
|
85
|
+
});
|
|
88
86
|
}
|
|
89
87
|
});
|
|
90
88
|
}
|
|
@@ -299,10 +297,14 @@ class ScopeTracker {
|
|
|
299
297
|
*/
|
|
300
298
|
function extractDestructuredIdentifiers(
|
|
301
299
|
node: TSESTree.ObjectPattern | TSESTree.ArrayPattern,
|
|
302
|
-
isParameter: boolean,
|
|
303
300
|
scopeTracker: ScopeTracker,
|
|
304
|
-
|
|
301
|
+
options: {
|
|
302
|
+
isParameter?: boolean;
|
|
303
|
+
isArrowParameter?: boolean;
|
|
304
|
+
} = {}
|
|
305
305
|
) {
|
|
306
|
+
const { isParameter = false, isArrowParameter = false } = options;
|
|
307
|
+
|
|
306
308
|
if (node.type === 'ObjectPattern') {
|
|
307
309
|
node.properties.forEach((prop) => {
|
|
308
310
|
if (prop.type === 'Property' && prop.value.type === 'Identifier') {
|