@aiready/consistency 0.20.2 → 0.20.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/.turbo/turbo-build.log +9 -9
- package/.turbo/turbo-lint.log +24 -17
- package/.turbo/turbo-test.log +13 -11
- package/dist/chunk-3ZB6FFRL.mjs +661 -0
- package/dist/chunk-6BM5MV3S.mjs +719 -0
- package/dist/chunk-BYY6MD5T.mjs +729 -0
- package/dist/chunk-DSI3TEO2.mjs +662 -0
- package/dist/chunk-H6S7WKSQ.mjs +729 -0
- package/dist/chunk-LMOXGPCM.mjs +722 -0
- package/dist/chunk-MAPVFXBP.mjs +708 -0
- package/dist/chunk-NPWCJZUG.mjs +708 -0
- package/dist/chunk-ZB6UK276.mjs +662 -0
- package/dist/cli.js +101 -159
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +101 -159
- package/dist/index.mjs +1 -1
- package/package.json +2 -2
- package/src/analyzer.ts +130 -184
- package/src/analyzers/naming-ast.ts +8 -3
- package/src/analyzers/naming-generalized.ts +3 -4
- package/src/analyzers/naming.ts +2 -0
- package/src/analyzers/patterns.ts +2 -5
- package/src/types.ts +6 -1
package/src/analyzer.ts
CHANGED
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
scanFiles,
|
|
3
3
|
Severity,
|
|
4
4
|
IssueType,
|
|
5
|
-
|
|
5
|
+
getSeverityLevel,
|
|
6
6
|
} from '@aiready/core';
|
|
7
7
|
import type { AnalysisResult, Issue } from '@aiready/core';
|
|
8
8
|
import type {
|
|
@@ -58,149 +58,70 @@ export async function analyzeConsistency(
|
|
|
58
58
|
|
|
59
59
|
// Process naming issues
|
|
60
60
|
for (const issue of namingIssues) {
|
|
61
|
-
if (!shouldIncludeSeverity(issue.severity, minSeverity))
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
category: 'naming',
|
|
71
|
-
severity: getSeverityEnum(issue.severity),
|
|
72
|
-
message: `${issue.type}: ${issue.identifier}`,
|
|
73
|
-
location: {
|
|
74
|
-
file: issue.file,
|
|
75
|
-
line: issue.line,
|
|
76
|
-
column: issue.column,
|
|
77
|
-
},
|
|
78
|
-
suggestion: issue.suggestion,
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
if (!fileIssuesMap.has(issue.file)) {
|
|
82
|
-
fileIssuesMap.set(issue.file, []);
|
|
83
|
-
}
|
|
84
|
-
fileIssuesMap.get(issue.file)!.push(consistencyIssue);
|
|
61
|
+
if (!shouldIncludeSeverity(issue.severity, minSeverity)) continue;
|
|
62
|
+
|
|
63
|
+
const fileName =
|
|
64
|
+
(issue as any).fileName ||
|
|
65
|
+
(issue as any).file ||
|
|
66
|
+
(issue as any).filePath ||
|
|
67
|
+
'unknown';
|
|
68
|
+
if (!fileIssuesMap.has(fileName)) fileIssuesMap.set(fileName, []);
|
|
69
|
+
fileIssuesMap.get(fileName)!.push(issue as unknown as ConsistencyIssue);
|
|
85
70
|
}
|
|
86
71
|
|
|
87
72
|
// Process pattern issues
|
|
88
73
|
for (const issue of patternIssues) {
|
|
89
|
-
if (!shouldIncludeSeverity(issue.severity, minSeverity))
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
line: 1,
|
|
101
|
-
},
|
|
102
|
-
examples: issue.examples,
|
|
103
|
-
suggestion: `Standardize ${issue.type} patterns across ${issue.files.length} files`,
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
// Add to first file in the pattern
|
|
107
|
-
const firstFile = issue.files[0];
|
|
108
|
-
if (firstFile && !fileIssuesMap.has(firstFile)) {
|
|
109
|
-
fileIssuesMap.set(firstFile, []);
|
|
110
|
-
}
|
|
111
|
-
if (firstFile) {
|
|
112
|
-
fileIssuesMap.get(firstFile)!.push(consistencyIssue);
|
|
113
|
-
}
|
|
74
|
+
if (!shouldIncludeSeverity(issue.severity, minSeverity)) continue;
|
|
75
|
+
|
|
76
|
+
const fileName =
|
|
77
|
+
(issue as any).fileName ||
|
|
78
|
+
(issue as any).file ||
|
|
79
|
+
(issue as any).filePath ||
|
|
80
|
+
(Array.isArray((issue as any).files)
|
|
81
|
+
? (issue as any).files[0]
|
|
82
|
+
: 'unknown');
|
|
83
|
+
if (!fileIssuesMap.has(fileName)) fileIssuesMap.set(fileName, []);
|
|
84
|
+
fileIssuesMap.get(fileName)!.push(issue as unknown as ConsistencyIssue);
|
|
114
85
|
}
|
|
115
86
|
|
|
116
|
-
//
|
|
117
|
-
for (const [fileName, issues] of fileIssuesMap) {
|
|
87
|
+
// Build final results
|
|
88
|
+
for (const [fileName, issues] of fileIssuesMap.entries()) {
|
|
118
89
|
results.push({
|
|
119
90
|
fileName,
|
|
120
|
-
issues: issues
|
|
91
|
+
issues: issues.map((i) => transformToIssue(i)),
|
|
121
92
|
metrics: {
|
|
122
93
|
consistencyScore: calculateConsistencyScore(issues),
|
|
123
94
|
},
|
|
124
95
|
});
|
|
125
96
|
}
|
|
126
97
|
|
|
127
|
-
//
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
...fileResultB.issues.map((i) => {
|
|
139
|
-
const val = getSeverityLevel((i as ConsistencyIssue).severity);
|
|
140
|
-
return val === 4 ? 0 : val === 3 ? 1 : val === 2 ? 2 : 3;
|
|
141
|
-
})
|
|
142
|
-
);
|
|
143
|
-
|
|
144
|
-
// Sort by severity first
|
|
145
|
-
if (maxSeverityA !== maxSeverityB) {
|
|
146
|
-
return maxSeverityA - maxSeverityB;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Then by issue count (descending)
|
|
150
|
-
return fileResultB.issues.length - fileResultA.issues.length;
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
// Generate recommendations
|
|
154
|
-
const recommendations = generateRecommendations(namingIssues, patternIssues);
|
|
155
|
-
|
|
156
|
-
// Compute filtered counts (respecting minSeverity) to report accurate summary
|
|
157
|
-
const namingCountFiltered = namingIssues.filter((i) =>
|
|
158
|
-
shouldIncludeSeverity(i.severity, minSeverity)
|
|
159
|
-
).length;
|
|
160
|
-
const patternCountFiltered = patternIssues.filter((i) =>
|
|
161
|
-
shouldIncludeSeverity(i.severity, minSeverity)
|
|
162
|
-
).length;
|
|
98
|
+
// Generate high-level recommendations
|
|
99
|
+
const recommendations: string[] = [];
|
|
100
|
+
if (namingIssues.length > 0) {
|
|
101
|
+
recommendations.push('Standardize naming conventions across the codebase');
|
|
102
|
+
}
|
|
103
|
+
if (patternIssues.length > 0) {
|
|
104
|
+
recommendations.push('Consolidate repetitive implementation patterns');
|
|
105
|
+
}
|
|
106
|
+
if (results.some((r) => (r.metrics?.consistencyScore ?? 1) < 0.8)) {
|
|
107
|
+
recommendations.push('Improve cross-module consistency to reduce AI confusion');
|
|
108
|
+
}
|
|
163
109
|
|
|
164
110
|
return {
|
|
111
|
+
results,
|
|
165
112
|
summary: {
|
|
166
|
-
totalIssues: namingCountFiltered + patternCountFiltered,
|
|
167
|
-
namingIssues: namingCountFiltered,
|
|
168
|
-
patternIssues: patternCountFiltered,
|
|
169
|
-
architectureIssues: 0,
|
|
170
113
|
filesAnalyzed: filePaths.length,
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
),
|
|
114
|
+
totalIssues: results.reduce((acc, r) => acc + r.issues.length, 0),
|
|
115
|
+
namingIssues: namingIssues.length,
|
|
116
|
+
patternIssues: patternIssues.length,
|
|
117
|
+
architectureIssues: 0,
|
|
176
118
|
},
|
|
177
|
-
results,
|
|
178
119
|
recommendations,
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
if (s === Severity.Major || s === 'major') return 3;
|
|
185
|
-
if (s === Severity.Minor || s === 'minor') return 2;
|
|
186
|
-
if (s === Severity.Info || s === 'info') return 1;
|
|
187
|
-
return 0;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
function getSeverityEnum(s: any): Severity {
|
|
191
|
-
const val = getSeverityLevel(s);
|
|
192
|
-
switch (val) {
|
|
193
|
-
case 4:
|
|
194
|
-
return Severity.Critical;
|
|
195
|
-
case 3:
|
|
196
|
-
return Severity.Major;
|
|
197
|
-
case 2:
|
|
198
|
-
return Severity.Minor;
|
|
199
|
-
case 1:
|
|
200
|
-
return Severity.Info;
|
|
201
|
-
default:
|
|
202
|
-
return Severity.Info;
|
|
203
|
-
}
|
|
120
|
+
metadata: {
|
|
121
|
+
toolName: 'naming-consistency',
|
|
122
|
+
timestamp: new Date().toISOString(),
|
|
123
|
+
},
|
|
124
|
+
} as unknown as ConsistencyReport;
|
|
204
125
|
}
|
|
205
126
|
|
|
206
127
|
function shouldIncludeSeverity(
|
|
@@ -210,6 +131,91 @@ function shouldIncludeSeverity(
|
|
|
210
131
|
return getSeverityLevel(severity) >= getSeverityLevel(minSeverity);
|
|
211
132
|
}
|
|
212
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Map string type to IssueType enum value
|
|
136
|
+
*/
|
|
137
|
+
function getIssueType(type: string | undefined): IssueType {
|
|
138
|
+
if (!type) return IssueType.NamingInconsistency;
|
|
139
|
+
|
|
140
|
+
// Map string values to enum
|
|
141
|
+
const typeMap: Record<string, IssueType> = {
|
|
142
|
+
'naming-inconsistency': IssueType.NamingInconsistency,
|
|
143
|
+
'naming-quality': IssueType.NamingQuality,
|
|
144
|
+
'pattern-inconsistency': IssueType.PatternInconsistency,
|
|
145
|
+
'architecture-inconsistency': IssueType.ArchitectureInconsistency,
|
|
146
|
+
'error-handling': IssueType.PatternInconsistency,
|
|
147
|
+
'async-style': IssueType.PatternInconsistency,
|
|
148
|
+
'import-style': IssueType.PatternInconsistency,
|
|
149
|
+
'api-design': IssueType.PatternInconsistency,
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
return typeMap[type] || IssueType.NamingInconsistency;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Transform NamingIssue or PatternIssue to the required Issue format
|
|
157
|
+
*/
|
|
158
|
+
function transformToIssue(i: any): Issue {
|
|
159
|
+
// If already has message and location, return as is
|
|
160
|
+
if (i.message && i.location) {
|
|
161
|
+
return {
|
|
162
|
+
type: getIssueType(i.type),
|
|
163
|
+
severity: i.severity as Severity,
|
|
164
|
+
message: i.message,
|
|
165
|
+
location: i.location,
|
|
166
|
+
suggestion: i.suggestion,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Handle NamingIssue format (has file, line, column, identifier, suggestion)
|
|
171
|
+
if (i.identifier || i.type) {
|
|
172
|
+
const line = i.line || 1;
|
|
173
|
+
const column = i.column || 1;
|
|
174
|
+
return {
|
|
175
|
+
type: getIssueType(i.type),
|
|
176
|
+
severity: i.severity as Severity,
|
|
177
|
+
message: i.suggestion
|
|
178
|
+
? `Naming issue: ${i.suggestion}`
|
|
179
|
+
: `Naming issue for '${i.identifier || 'unknown'}'`,
|
|
180
|
+
location: {
|
|
181
|
+
file: i.file || i.fileName || '',
|
|
182
|
+
line,
|
|
183
|
+
column,
|
|
184
|
+
endLine: line,
|
|
185
|
+
endColumn: column + (i.identifier?.length || 10),
|
|
186
|
+
},
|
|
187
|
+
suggestion: i.suggestion,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Handle PatternIssue format (has description, files)
|
|
192
|
+
if (i.description || i.files) {
|
|
193
|
+
const fileName = Array.isArray(i.files) ? i.files[0] : i.file || '';
|
|
194
|
+
return {
|
|
195
|
+
type: getIssueType(i.type),
|
|
196
|
+
severity: i.severity as Severity,
|
|
197
|
+
message: i.description || 'Pattern inconsistency found',
|
|
198
|
+
location: {
|
|
199
|
+
file: fileName,
|
|
200
|
+
line: 1,
|
|
201
|
+
column: 1,
|
|
202
|
+
endLine: 1,
|
|
203
|
+
endColumn: 10,
|
|
204
|
+
},
|
|
205
|
+
suggestion: i.examples?.[0],
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Fallback
|
|
210
|
+
return {
|
|
211
|
+
type: getIssueType(i.type),
|
|
212
|
+
severity: i.severity as Severity,
|
|
213
|
+
message: i.message || 'Unknown issue',
|
|
214
|
+
location: i.location || { file: '', line: 1, column: 1 },
|
|
215
|
+
suggestion: i.suggestion,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
213
219
|
function calculateConsistencyScore(issues: ConsistencyIssue[]): number {
|
|
214
220
|
let totalWeight = 0;
|
|
215
221
|
for (const issue of issues) {
|
|
@@ -234,63 +240,3 @@ function calculateConsistencyScore(issues: ConsistencyIssue[]): number {
|
|
|
234
240
|
// Score from 0-1, where 1 is perfect
|
|
235
241
|
return Math.max(0, 1 - totalWeight / 100);
|
|
236
242
|
}
|
|
237
|
-
|
|
238
|
-
function generateRecommendations(
|
|
239
|
-
namingIssues: any[],
|
|
240
|
-
patternIssues: any[]
|
|
241
|
-
): string[] {
|
|
242
|
-
const recommendations: string[] = [];
|
|
243
|
-
|
|
244
|
-
if (namingIssues.length > 0) {
|
|
245
|
-
const conventionMixCount = namingIssues.filter(
|
|
246
|
-
(i) => i.type === 'convention-mix'
|
|
247
|
-
).length;
|
|
248
|
-
if (conventionMixCount > 0) {
|
|
249
|
-
recommendations.push(
|
|
250
|
-
`Standardize naming conventions: Found ${conventionMixCount} snake_case variables in TypeScript/JavaScript (use camelCase)`
|
|
251
|
-
);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
const poorNamingCount = namingIssues.filter(
|
|
255
|
-
(i) => i.type === 'poor-naming'
|
|
256
|
-
).length;
|
|
257
|
-
if (poorNamingCount > 0) {
|
|
258
|
-
recommendations.push(
|
|
259
|
-
`Improve variable naming: Found ${poorNamingCount} single-letter or unclear variable names`
|
|
260
|
-
);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
if (patternIssues.length > 0) {
|
|
265
|
-
const errorHandlingIssues = patternIssues.filter(
|
|
266
|
-
(i) => i.type === 'error-handling'
|
|
267
|
-
);
|
|
268
|
-
if (errorHandlingIssues.length > 0) {
|
|
269
|
-
recommendations.push(
|
|
270
|
-
'Standardize error handling strategy across the codebase (prefer try-catch with typed errors)'
|
|
271
|
-
);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
const asyncIssues = patternIssues.filter((i) => i.type === 'async-style');
|
|
275
|
-
if (asyncIssues.length > 0) {
|
|
276
|
-
recommendations.push(
|
|
277
|
-
'Use async/await consistently instead of mixing with promise chains or callbacks'
|
|
278
|
-
);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
const importIssues = patternIssues.filter((i) => i.type === 'import-style');
|
|
282
|
-
if (importIssues.length > 0) {
|
|
283
|
-
recommendations.push(
|
|
284
|
-
'Use ES modules consistently across the project (avoid mixing with CommonJS)'
|
|
285
|
-
);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
if (recommendations.length === 0) {
|
|
290
|
-
recommendations.push(
|
|
291
|
-
'No major consistency issues found! Your codebase follows good practices.'
|
|
292
|
-
);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
return recommendations;
|
|
296
|
-
}
|
|
@@ -4,9 +4,7 @@ import type { NamingIssue } from '../types';
|
|
|
4
4
|
import {
|
|
5
5
|
parseFile,
|
|
6
6
|
traverseAST,
|
|
7
|
-
getFunctionName,
|
|
8
7
|
getLineNumber,
|
|
9
|
-
isCoverageContext,
|
|
10
8
|
isLoopStatement,
|
|
11
9
|
} from '../utils/ast-parser';
|
|
12
10
|
import {
|
|
@@ -154,7 +152,7 @@ function checkVariableNaming(
|
|
|
154
152
|
issues: NamingIssue[],
|
|
155
153
|
context: any
|
|
156
154
|
) {
|
|
157
|
-
const { name,
|
|
155
|
+
const { name, line, options } = varInfo;
|
|
158
156
|
|
|
159
157
|
// Skip very common small names if they are in acceptable context
|
|
160
158
|
if (isAcceptableInContext(name, context, options)) {
|
|
@@ -253,6 +251,13 @@ class ScopeTracker {
|
|
|
253
251
|
}
|
|
254
252
|
}
|
|
255
253
|
|
|
254
|
+
/**
|
|
255
|
+
* Extracts identifiers from destructured patterns (object or array destructuring)
|
|
256
|
+
* and registers them in the scope tracker.
|
|
257
|
+
* @param node - The AST node representing the destructured pattern
|
|
258
|
+
* @param isParameter - When true, indicates the destructured variable is a function parameter; when false, it's a local variable
|
|
259
|
+
* @param scopeTracker - The scope tracker to register variables with
|
|
260
|
+
*/
|
|
256
261
|
function extractDestructuredIdentifiers(
|
|
257
262
|
node: TSESTree.ObjectPattern | TSESTree.ArrayPattern,
|
|
258
263
|
isParameter: boolean,
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* naming conventions across all supported languages.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { getParser, Severity
|
|
8
|
+
import { getParser, Severity } from '@aiready/core';
|
|
9
9
|
import type { NamingIssue } from '../types';
|
|
10
10
|
import { readFileSync } from 'fs';
|
|
11
11
|
|
|
@@ -31,7 +31,6 @@ export async function analyzeNamingGeneralized(
|
|
|
31
31
|
// 1. Check Exports
|
|
32
32
|
for (const exp of result.exports) {
|
|
33
33
|
let pattern: RegExp | undefined;
|
|
34
|
-
const typeName = exp.type;
|
|
35
34
|
|
|
36
35
|
if (exp.type === 'class') {
|
|
37
36
|
pattern = conventions.classPattern;
|
|
@@ -49,7 +48,7 @@ export async function analyzeNamingGeneralized(
|
|
|
49
48
|
|
|
50
49
|
if (pattern && !pattern.test(exp.name)) {
|
|
51
50
|
issues.push({
|
|
52
|
-
type: '
|
|
51
|
+
type: 'naming-inconsistency',
|
|
53
52
|
identifier: exp.name,
|
|
54
53
|
file,
|
|
55
54
|
line: exp.loc?.start.line || 1,
|
|
@@ -72,7 +71,7 @@ export async function analyzeNamingGeneralized(
|
|
|
72
71
|
) {
|
|
73
72
|
// This is often a 'convention-mix' issue (e.g. importing snake_case into camelCase project)
|
|
74
73
|
issues.push({
|
|
75
|
-
type: '
|
|
74
|
+
type: 'naming-inconsistency',
|
|
76
75
|
identifier: spec,
|
|
77
76
|
file,
|
|
78
77
|
line: imp.loc?.start.line || 1,
|
package/src/analyzers/naming.ts
CHANGED
|
@@ -5,6 +5,8 @@ import type { NamingIssue } from '../types';
|
|
|
5
5
|
/**
|
|
6
6
|
* Legacy regex-based naming analyzer
|
|
7
7
|
* (Used as fallback or for languages without AST support)
|
|
8
|
+
* @param filePaths - Array of file paths to analyze
|
|
9
|
+
* @returns Array of naming issues found
|
|
8
10
|
*/
|
|
9
11
|
export async function analyzeNaming(
|
|
10
12
|
filePaths: string[]
|
|
@@ -13,7 +13,6 @@ export async function analyzePatterns(
|
|
|
13
13
|
|
|
14
14
|
// 1. Error handling style
|
|
15
15
|
const tryCatchPattern = /try\s*\{/g;
|
|
16
|
-
const catchPattern = /catch\s*\(\s*(\w+)\s*\)/g;
|
|
17
16
|
|
|
18
17
|
const styleStats = {
|
|
19
18
|
tryCatch: 0,
|
|
@@ -39,8 +38,6 @@ export async function analyzePatterns(
|
|
|
39
38
|
}
|
|
40
39
|
}
|
|
41
40
|
|
|
42
|
-
const totalFiles = filePaths.length;
|
|
43
|
-
|
|
44
41
|
// Report inconsistencies if there's a significant mix
|
|
45
42
|
if (styleStats.tryCatch > 0 && styleStats.thenCatch > 0) {
|
|
46
43
|
const dominant =
|
|
@@ -54,7 +51,7 @@ export async function analyzePatterns(
|
|
|
54
51
|
? c.match(tryCatchPattern)
|
|
55
52
|
: c.match(/\.catch\s*\(/);
|
|
56
53
|
}),
|
|
57
|
-
type: '
|
|
54
|
+
type: 'pattern-inconsistency',
|
|
58
55
|
description: `Mixed error handling styles: codebase primarily uses ${dominant}, but found ${minority} in some files.`,
|
|
59
56
|
examples: [dominant, minority],
|
|
60
57
|
severity: Severity.Minor,
|
|
@@ -73,7 +70,7 @@ export async function analyzePatterns(
|
|
|
73
70
|
? c.match(/\brequire\s*\(/)
|
|
74
71
|
: c.match(/\bimport\b/);
|
|
75
72
|
}),
|
|
76
|
-
type: '
|
|
73
|
+
type: 'pattern-inconsistency',
|
|
77
74
|
description: `Mixed module systems: found both ESM and CommonJS.`,
|
|
78
75
|
examples: ['import X from "y"', 'const X = require("y")'],
|
|
79
76
|
severity: Severity.Major,
|
package/src/types.ts
CHANGED
|
@@ -43,7 +43,12 @@ export interface NamingIssue {
|
|
|
43
43
|
|
|
44
44
|
export interface PatternIssue {
|
|
45
45
|
files: string[];
|
|
46
|
-
type:
|
|
46
|
+
type:
|
|
47
|
+
| 'error-handling'
|
|
48
|
+
| 'async-style'
|
|
49
|
+
| 'import-style'
|
|
50
|
+
| 'api-design'
|
|
51
|
+
| 'pattern-inconsistency';
|
|
47
52
|
description: string;
|
|
48
53
|
examples: string[];
|
|
49
54
|
severity: Severity;
|