@aiready/consistency 0.16.3 → 0.18.0
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 +10 -10
- package/.turbo/turbo-lint.log +13 -1
- package/.turbo/turbo-test.log +14 -12
- package/dist/chunk-IXBC6GVT.mjs +832 -0
- package/dist/cli.js +12 -1
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +7 -2
- package/dist/index.d.ts +7 -2
- package/dist/index.js +128 -73
- package/dist/index.mjs +118 -70
- package/package.json +2 -2
- package/src/__tests__/scoring.test.ts +1 -1
- package/src/analyzer.ts +29 -15
- package/src/analyzers/naming-ast.ts +18 -2
- package/src/analyzers/naming.ts +15 -6
- package/src/analyzers/patterns.ts +20 -10
- package/src/index.ts +7 -0
- package/src/provider.ts +48 -0
- package/src/scoring.ts +2 -2
- package/src/types.ts +7 -1
package/src/analyzers/naming.ts
CHANGED
|
@@ -6,7 +6,9 @@ import type { NamingIssue } from '../types';
|
|
|
6
6
|
* Legacy regex-based naming analyzer
|
|
7
7
|
* (Used as fallback or for languages without AST support)
|
|
8
8
|
*/
|
|
9
|
-
export async function analyzeNaming(
|
|
9
|
+
export async function analyzeNaming(
|
|
10
|
+
filePaths: string[]
|
|
11
|
+
): Promise<NamingIssue[]> {
|
|
10
12
|
const issues: NamingIssue[] = [];
|
|
11
13
|
|
|
12
14
|
for (const filePath of filePaths) {
|
|
@@ -16,9 +18,11 @@ export async function analyzeNaming(filePaths: string[]): Promise<NamingIssue[]>
|
|
|
16
18
|
|
|
17
19
|
lines.forEach((line, index) => {
|
|
18
20
|
// Simple regex patterns for naming issues
|
|
19
|
-
|
|
21
|
+
|
|
20
22
|
// 1. Single letter variables (except common ones)
|
|
21
|
-
const singleLetterMatch = line.match(
|
|
23
|
+
const singleLetterMatch = line.match(
|
|
24
|
+
/\b(const|let|var)\s+([a-hj-km-np-zA-Z])\s*=/
|
|
25
|
+
);
|
|
22
26
|
if (singleLetterMatch) {
|
|
23
27
|
issues.push({
|
|
24
28
|
file: filePath,
|
|
@@ -32,7 +36,9 @@ export async function analyzeNaming(filePaths: string[]): Promise<NamingIssue[]>
|
|
|
32
36
|
|
|
33
37
|
// 2. Snake case in TS/JS files
|
|
34
38
|
if (filePath.match(/\.(ts|tsx|js|jsx)$/)) {
|
|
35
|
-
const snakeCaseMatch = line.match(
|
|
39
|
+
const snakeCaseMatch = line.match(
|
|
40
|
+
/\b(const|let|var|function)\s+([a-z]+_[a-z0-9_]+)\b/
|
|
41
|
+
);
|
|
36
42
|
if (snakeCaseMatch) {
|
|
37
43
|
issues.push({
|
|
38
44
|
file: filePath,
|
|
@@ -40,13 +46,16 @@ export async function analyzeNaming(filePaths: string[]): Promise<NamingIssue[]>
|
|
|
40
46
|
type: 'convention-mix',
|
|
41
47
|
identifier: snakeCaseMatch[2],
|
|
42
48
|
severity: Severity.Info,
|
|
43
|
-
suggestion:
|
|
49
|
+
suggestion:
|
|
50
|
+
'Use camelCase instead of snake_case in TypeScript/JavaScript',
|
|
44
51
|
});
|
|
45
52
|
}
|
|
46
53
|
}
|
|
47
54
|
|
|
48
55
|
// 3. Very short names
|
|
49
|
-
const shortNameMatch = line.match(
|
|
56
|
+
const shortNameMatch = line.match(
|
|
57
|
+
/\b(const|let|var)\s+([a-zA-Z0-9]{2,3})\s*=/
|
|
58
|
+
);
|
|
50
59
|
if (shortNameMatch) {
|
|
51
60
|
const name = shortNameMatch[2].toLowerCase();
|
|
52
61
|
const vagueNames = ['obj', 'val', 'tmp', 'res', 'ret', 'data'];
|
|
@@ -5,14 +5,16 @@ import type { PatternIssue } from '../types';
|
|
|
5
5
|
/**
|
|
6
6
|
* Detect inconsistent code patterns across files
|
|
7
7
|
*/
|
|
8
|
-
export async function analyzePatterns(
|
|
8
|
+
export async function analyzePatterns(
|
|
9
|
+
filePaths: string[]
|
|
10
|
+
): Promise<PatternIssue[]> {
|
|
9
11
|
const issues: PatternIssue[] = [];
|
|
10
12
|
const contents = new Map<string, string>();
|
|
11
13
|
|
|
12
14
|
// 1. Error handling style
|
|
13
15
|
const tryCatchPattern = /try\s*\{/g;
|
|
14
16
|
const catchPattern = /catch\s*\(\s*(\w+)\s*\)/g;
|
|
15
|
-
|
|
17
|
+
|
|
16
18
|
const styleStats = {
|
|
17
19
|
tryCatch: 0,
|
|
18
20
|
thenCatch: 0,
|
|
@@ -29,7 +31,7 @@ export async function analyzePatterns(filePaths: string[]): Promise<PatternIssue
|
|
|
29
31
|
if (content.match(tryCatchPattern)) styleStats.tryCatch++;
|
|
30
32
|
if (content.match(/\.catch\s*\(/)) styleStats.thenCatch++;
|
|
31
33
|
if (content.match(/\bawait\b/)) styleStats.asyncAwait++;
|
|
32
|
-
|
|
34
|
+
|
|
33
35
|
if (content.match(/\brequire\s*\(/)) styleStats.commonJs++;
|
|
34
36
|
if (content.match(/\bimport\b.*\bfrom\b/)) styleStats.esm++;
|
|
35
37
|
} catch (err) {
|
|
@@ -41,13 +43,16 @@ export async function analyzePatterns(filePaths: string[]): Promise<PatternIssue
|
|
|
41
43
|
|
|
42
44
|
// Report inconsistencies if there's a significant mix
|
|
43
45
|
if (styleStats.tryCatch > 0 && styleStats.thenCatch > 0) {
|
|
44
|
-
const dominant =
|
|
46
|
+
const dominant =
|
|
47
|
+
styleStats.tryCatch >= styleStats.thenCatch ? 'try-catch' : '.catch()';
|
|
45
48
|
const minority = dominant === 'try-catch' ? '.catch()' : 'try-catch';
|
|
46
|
-
|
|
49
|
+
|
|
47
50
|
issues.push({
|
|
48
|
-
files: filePaths.filter(f => {
|
|
51
|
+
files: filePaths.filter((f) => {
|
|
49
52
|
const c = contents.get(f) || '';
|
|
50
|
-
return minority === 'try-catch'
|
|
53
|
+
return minority === 'try-catch'
|
|
54
|
+
? c.match(tryCatchPattern)
|
|
55
|
+
: c.match(/\.catch\s*\(/);
|
|
51
56
|
}),
|
|
52
57
|
type: 'error-handling',
|
|
53
58
|
description: `Mixed error handling styles: codebase primarily uses ${dominant}, but found ${minority} in some files.`,
|
|
@@ -57,11 +62,16 @@ export async function analyzePatterns(filePaths: string[]): Promise<PatternIssue
|
|
|
57
62
|
}
|
|
58
63
|
|
|
59
64
|
if (styleStats.commonJs > 0 && styleStats.esm > 0) {
|
|
60
|
-
const minority =
|
|
65
|
+
const minority =
|
|
66
|
+
styleStats.esm >= styleStats.commonJs
|
|
67
|
+
? 'CommonJS (require)'
|
|
68
|
+
: 'ESM (import)';
|
|
61
69
|
issues.push({
|
|
62
|
-
files: filePaths.filter(f => {
|
|
70
|
+
files: filePaths.filter((f) => {
|
|
63
71
|
const c = contents.get(f) || '';
|
|
64
|
-
return minority === 'CommonJS (require)'
|
|
72
|
+
return minority === 'CommonJS (require)'
|
|
73
|
+
? c.match(/\brequire\s*\(/)
|
|
74
|
+
: c.match(/\bimport\b/);
|
|
65
75
|
}),
|
|
66
76
|
type: 'import-style',
|
|
67
77
|
description: `Mixed module systems: found both ESM and CommonJS.`,
|
package/src/index.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
+
import { ToolRegistry } from '@aiready/core';
|
|
2
|
+
import { ConsistencyProvider } from './provider';
|
|
3
|
+
|
|
4
|
+
// Register with global registry
|
|
5
|
+
ToolRegistry.register(ConsistencyProvider);
|
|
6
|
+
|
|
1
7
|
export { analyzeConsistency } from './analyzer';
|
|
2
8
|
export { analyzeNamingAST } from './analyzers/naming-ast';
|
|
3
9
|
export { analyzeNaming } from './analyzers/naming'; // Legacy regex version
|
|
4
10
|
export { detectNamingConventions } from './analyzers/naming-constants';
|
|
5
11
|
export { analyzePatterns } from './analyzers/patterns';
|
|
6
12
|
export { calculateConsistencyScore } from './scoring';
|
|
13
|
+
export { ConsistencyProvider };
|
|
7
14
|
export type {
|
|
8
15
|
ConsistencyOptions,
|
|
9
16
|
ConsistencyReport,
|
package/src/provider.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ToolProvider,
|
|
3
|
+
ToolName,
|
|
4
|
+
SpokeOutput,
|
|
5
|
+
ScanOptions,
|
|
6
|
+
ToolScoringOutput,
|
|
7
|
+
AnalysisResult,
|
|
8
|
+
SpokeOutputSchema,
|
|
9
|
+
} from '@aiready/core';
|
|
10
|
+
import { analyzeConsistency } from './analyzer';
|
|
11
|
+
import { calculateConsistencyScore } from './scoring';
|
|
12
|
+
import { ConsistencyOptions, ConsistencyIssue } from './types';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Consistency Tool Provider
|
|
16
|
+
*/
|
|
17
|
+
export const ConsistencyProvider: ToolProvider = {
|
|
18
|
+
id: ToolName.NamingConsistency,
|
|
19
|
+
alias: ['consistency', 'naming', 'standards'],
|
|
20
|
+
|
|
21
|
+
async analyze(options: ScanOptions): Promise<SpokeOutput> {
|
|
22
|
+
const report = await analyzeConsistency(options as ConsistencyOptions);
|
|
23
|
+
|
|
24
|
+
return SpokeOutputSchema.parse({
|
|
25
|
+
results: report.results as AnalysisResult[],
|
|
26
|
+
summary: report.summary,
|
|
27
|
+
metadata: {
|
|
28
|
+
toolName: ToolName.NamingConsistency,
|
|
29
|
+
version: '0.16.5',
|
|
30
|
+
timestamp: new Date().toISOString(),
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
score(output: SpokeOutput, options: ScanOptions): ToolScoringOutput {
|
|
36
|
+
const results = output.results as AnalysisResult[];
|
|
37
|
+
const allIssues = results.flatMap((r) => r.issues as ConsistencyIssue[]);
|
|
38
|
+
const totalFiles = (output.summary as any).filesAnalyzed || results.length;
|
|
39
|
+
|
|
40
|
+
return calculateConsistencyScore(
|
|
41
|
+
allIssues,
|
|
42
|
+
totalFiles,
|
|
43
|
+
(options as any).costConfig
|
|
44
|
+
);
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
defaultWeight: 14,
|
|
48
|
+
};
|
package/src/scoring.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { calculateProductivityImpact } from '@aiready/core';
|
|
1
|
+
import { calculateProductivityImpact, ToolName } from '@aiready/core';
|
|
2
2
|
import type { ToolScoringOutput, CostConfig } from '@aiready/core';
|
|
3
3
|
import type { ConsistencyIssue } from './types';
|
|
4
4
|
|
|
@@ -127,7 +127,7 @@ export function calculateConsistencyScore(
|
|
|
127
127
|
const productivityImpact = calculateProductivityImpact(issues);
|
|
128
128
|
|
|
129
129
|
return {
|
|
130
|
-
toolName:
|
|
130
|
+
toolName: ToolName.NamingConsistency,
|
|
131
131
|
score,
|
|
132
132
|
rawMetrics: {
|
|
133
133
|
totalIssues,
|
package/src/types.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
ScanOptions,
|
|
3
|
+
AnalysisResult,
|
|
4
|
+
Issue,
|
|
5
|
+
Severity,
|
|
6
|
+
IssueType,
|
|
7
|
+
} from '@aiready/core';
|
|
2
8
|
|
|
3
9
|
export interface ConsistencyOptions extends ScanOptions {
|
|
4
10
|
/** Check naming conventions and quality */
|