@aiready/consistency 0.6.16 → 0.7.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 +9 -9
- package/.turbo/turbo-test.log +12 -12
- package/README.md +31 -2
- package/dist/chunk-YEHXYHGY.mjs +1497 -0
- package/dist/cli.js +131 -12
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +1 -2
- package/dist/index.d.ts +1 -2
- package/dist/index.js +138 -9
- package/dist/index.mjs +1 -1
- package/package.json +2 -2
- package/src/analyzer.ts +14 -4
- package/src/analyzers/naming-python.ts +183 -0
package/dist/cli.js
CHANGED
|
@@ -27,7 +27,7 @@ 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
|
|
30
|
+
var import_core4 = require("@aiready/core");
|
|
31
31
|
|
|
32
32
|
// src/utils/ast-parser.ts
|
|
33
33
|
var import_typescript_estree = require("@typescript-eslint/typescript-estree");
|
|
@@ -1083,8 +1083,120 @@ function extractIdentifiersFromPattern(pattern, scopeTracker, isParameter, ances
|
|
|
1083
1083
|
}
|
|
1084
1084
|
}
|
|
1085
1085
|
|
|
1086
|
-
// src/analyzers/
|
|
1086
|
+
// src/analyzers/naming-python.ts
|
|
1087
1087
|
var import_core2 = require("@aiready/core");
|
|
1088
|
+
async function analyzePythonNaming(files) {
|
|
1089
|
+
const issues = [];
|
|
1090
|
+
const parser = (0, import_core2.getParser)("dummy.py");
|
|
1091
|
+
if (!parser) {
|
|
1092
|
+
console.warn("Python parser not available");
|
|
1093
|
+
return issues;
|
|
1094
|
+
}
|
|
1095
|
+
const pythonFiles = files.filter((f) => f.toLowerCase().endsWith(".py"));
|
|
1096
|
+
for (const file of pythonFiles) {
|
|
1097
|
+
try {
|
|
1098
|
+
const fs = await import("fs");
|
|
1099
|
+
const code = await fs.promises.readFile(file, "utf-8");
|
|
1100
|
+
const result = parser.parse(code, file);
|
|
1101
|
+
for (const exp of result.exports) {
|
|
1102
|
+
const nameIssue = checkPythonNaming(exp.name, exp.type, file, exp.loc?.start.line || 0);
|
|
1103
|
+
if (nameIssue) {
|
|
1104
|
+
issues.push(nameIssue);
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
for (const imp of result.imports) {
|
|
1108
|
+
for (const spec of imp.specifiers) {
|
|
1109
|
+
if (spec !== "*" && spec !== "default") {
|
|
1110
|
+
const nameIssue = checkPythonNaming(spec, "variable", file, imp.loc?.start.line || 0);
|
|
1111
|
+
if (nameIssue) {
|
|
1112
|
+
issues.push(nameIssue);
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
} catch (error) {
|
|
1118
|
+
console.warn(`Skipping ${file} due to error:`, error);
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
return issues;
|
|
1122
|
+
}
|
|
1123
|
+
function checkPythonNaming(identifier, type, file, line) {
|
|
1124
|
+
const parser = (0, import_core2.getParser)("dummy.py");
|
|
1125
|
+
const conventions = parser?.getNamingConventions();
|
|
1126
|
+
if (!conventions) return null;
|
|
1127
|
+
if (conventions.exceptions?.includes(identifier)) {
|
|
1128
|
+
return null;
|
|
1129
|
+
}
|
|
1130
|
+
if (type === "class") {
|
|
1131
|
+
if (!conventions.classPattern.test(identifier)) {
|
|
1132
|
+
return {
|
|
1133
|
+
type: "poor-naming",
|
|
1134
|
+
identifier,
|
|
1135
|
+
file,
|
|
1136
|
+
line,
|
|
1137
|
+
column: 0,
|
|
1138
|
+
severity: "major",
|
|
1139
|
+
category: "naming",
|
|
1140
|
+
suggestion: `Class names should use PascalCase (e.g., ${toPascalCase(identifier)})`
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
1143
|
+
} else if (type === "function") {
|
|
1144
|
+
if (!conventions.functionPattern.test(identifier)) {
|
|
1145
|
+
if (/^[a-z][a-zA-Z0-9]*$/.test(identifier) && /[A-Z]/.test(identifier)) {
|
|
1146
|
+
return {
|
|
1147
|
+
type: "convention-mix",
|
|
1148
|
+
identifier,
|
|
1149
|
+
file,
|
|
1150
|
+
line,
|
|
1151
|
+
column: 0,
|
|
1152
|
+
severity: "major",
|
|
1153
|
+
category: "naming",
|
|
1154
|
+
suggestion: `Function names should use snake_case, not camelCase (e.g., ${toSnakeCase(identifier)})`
|
|
1155
|
+
};
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
} else if (type === "const" || type === "variable") {
|
|
1159
|
+
if (identifier === identifier.toUpperCase() && identifier.length > 1) {
|
|
1160
|
+
if (!conventions.constantPattern.test(identifier)) {
|
|
1161
|
+
return {
|
|
1162
|
+
type: "poor-naming",
|
|
1163
|
+
identifier,
|
|
1164
|
+
file,
|
|
1165
|
+
line,
|
|
1166
|
+
column: 0,
|
|
1167
|
+
severity: "minor",
|
|
1168
|
+
category: "naming",
|
|
1169
|
+
suggestion: "Constants should use UPPER_CASE_WITH_UNDERSCORES"
|
|
1170
|
+
};
|
|
1171
|
+
}
|
|
1172
|
+
} else {
|
|
1173
|
+
if (!conventions.variablePattern.test(identifier)) {
|
|
1174
|
+
if (/^[a-z][a-zA-Z0-9]*$/.test(identifier) && /[A-Z]/.test(identifier)) {
|
|
1175
|
+
return {
|
|
1176
|
+
type: "convention-mix",
|
|
1177
|
+
identifier,
|
|
1178
|
+
file,
|
|
1179
|
+
line,
|
|
1180
|
+
column: 0,
|
|
1181
|
+
severity: "major",
|
|
1182
|
+
category: "naming",
|
|
1183
|
+
suggestion: `Variable names should use snake_case, not camelCase (e.g., ${toSnakeCase(identifier)})`
|
|
1184
|
+
};
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
return null;
|
|
1190
|
+
}
|
|
1191
|
+
function toSnakeCase(str) {
|
|
1192
|
+
return str.replace(/([A-Z])/g, "_$1").toLowerCase().replace(/^_/, "");
|
|
1193
|
+
}
|
|
1194
|
+
function toPascalCase(str) {
|
|
1195
|
+
return str.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
// src/analyzers/patterns.ts
|
|
1199
|
+
var import_core3 = require("@aiready/core");
|
|
1088
1200
|
async function analyzePatterns(files) {
|
|
1089
1201
|
const issues = [];
|
|
1090
1202
|
const errorHandlingIssues = await analyzeErrorHandling(files);
|
|
@@ -1103,7 +1215,7 @@ async function analyzeErrorHandling(files) {
|
|
|
1103
1215
|
returnsError: []
|
|
1104
1216
|
};
|
|
1105
1217
|
for (const file of files) {
|
|
1106
|
-
const content = await (0,
|
|
1218
|
+
const content = await (0, import_core3.readFileContent)(file);
|
|
1107
1219
|
if (content.includes("try {") || content.includes("} catch")) {
|
|
1108
1220
|
patterns.tryCatch.push(file);
|
|
1109
1221
|
}
|
|
@@ -1147,7 +1259,7 @@ async function analyzeAsyncPatterns(files) {
|
|
|
1147
1259
|
callbacks: []
|
|
1148
1260
|
};
|
|
1149
1261
|
for (const file of files) {
|
|
1150
|
-
const content = await (0,
|
|
1262
|
+
const content = await (0, import_core3.readFileContent)(file);
|
|
1151
1263
|
if (content.match(/async\s+(function|\(|[a-zA-Z])/)) {
|
|
1152
1264
|
patterns.asyncAwait.push(file);
|
|
1153
1265
|
}
|
|
@@ -1189,7 +1301,7 @@ async function analyzeImportStyles(files) {
|
|
|
1189
1301
|
mixed: []
|
|
1190
1302
|
};
|
|
1191
1303
|
for (const file of files) {
|
|
1192
|
-
const content = await (0,
|
|
1304
|
+
const content = await (0, import_core3.readFileContent)(file);
|
|
1193
1305
|
const hasESM = content.match(/^import\s+/m);
|
|
1194
1306
|
const hasCJS = hasActualRequireCalls(content);
|
|
1195
1307
|
if (hasESM && hasCJS) {
|
|
@@ -1247,8 +1359,15 @@ async function analyzeConsistency(options) {
|
|
|
1247
1359
|
minSeverity = "info",
|
|
1248
1360
|
...scanOptions
|
|
1249
1361
|
} = options;
|
|
1250
|
-
const filePaths = await (0,
|
|
1251
|
-
const
|
|
1362
|
+
const filePaths = await (0, import_core4.scanFiles)(scanOptions);
|
|
1363
|
+
const tsJsFiles = filePaths.filter((f) => /\.(ts|tsx|js|jsx)$/i.test(f));
|
|
1364
|
+
const pythonFiles = filePaths.filter((f) => /\.py$/i.test(f));
|
|
1365
|
+
let namingIssues = [];
|
|
1366
|
+
if (checkNaming) {
|
|
1367
|
+
const tsJsNamingIssues = tsJsFiles.length > 0 ? await analyzeNamingAST(tsJsFiles) : [];
|
|
1368
|
+
const pythonNamingIssues = pythonFiles.length > 0 ? await analyzePythonNaming(pythonFiles) : [];
|
|
1369
|
+
namingIssues = [...tsJsNamingIssues, ...pythonNamingIssues];
|
|
1370
|
+
}
|
|
1252
1371
|
const patternIssues = checkPatterns ? await analyzePatterns(filePaths) : [];
|
|
1253
1372
|
const results = [];
|
|
1254
1373
|
const fileIssuesMap = /* @__PURE__ */ new Map();
|
|
@@ -1389,7 +1508,7 @@ function generateRecommendations(namingIssues, patternIssues) {
|
|
|
1389
1508
|
var import_chalk = __toESM(require("chalk"));
|
|
1390
1509
|
var import_fs2 = require("fs");
|
|
1391
1510
|
var import_path2 = require("path");
|
|
1392
|
-
var
|
|
1511
|
+
var import_core5 = require("@aiready/core");
|
|
1393
1512
|
var program = new import_commander.Command();
|
|
1394
1513
|
program.name("aiready-consistency").description("Detect consistency patterns in naming, code structure, and architecture").version("0.1.0").addHelpText("after", `
|
|
1395
1514
|
LANGUAGE SUPPORT:
|
|
@@ -1413,7 +1532,7 @@ EXAMPLES:
|
|
|
1413
1532
|
`).argument("<directory>", "Directory to analyze").option("--naming", "Check naming conventions and quality (default: true)").option("--no-naming", "Skip naming analysis").option("--patterns", "Check code pattern consistency (default: true)").option("--no-patterns", "Skip pattern analysis").option("--architecture", "Check architectural consistency (not yet implemented)").option("--min-severity <level>", "Minimum severity: info|minor|major|critical. Default: info").option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console|json|markdown", "console").option("--output-file <path>", "Output file path (for json/markdown)").action(async (directory, options) => {
|
|
1414
1533
|
console.log(import_chalk.default.blue("\u{1F50D} Analyzing consistency...\n"));
|
|
1415
1534
|
const startTime = Date.now();
|
|
1416
|
-
const config = await (0,
|
|
1535
|
+
const config = await (0, import_core5.loadConfig)(directory);
|
|
1417
1536
|
const defaults = {
|
|
1418
1537
|
checkNaming: true,
|
|
1419
1538
|
checkPatterns: true,
|
|
@@ -1422,7 +1541,7 @@ EXAMPLES:
|
|
|
1422
1541
|
include: void 0,
|
|
1423
1542
|
exclude: void 0
|
|
1424
1543
|
};
|
|
1425
|
-
const mergedConfig = (0,
|
|
1544
|
+
const mergedConfig = (0, import_core5.mergeConfigWithDefaults)(config, defaults);
|
|
1426
1545
|
const finalOptions = {
|
|
1427
1546
|
rootDir: directory,
|
|
1428
1547
|
checkNaming: options.naming !== false && mergedConfig.checkNaming,
|
|
@@ -1436,7 +1555,7 @@ EXAMPLES:
|
|
|
1436
1555
|
const elapsedTime = ((Date.now() - startTime) / 1e3).toFixed(2);
|
|
1437
1556
|
if (options.output === "json") {
|
|
1438
1557
|
const output = JSON.stringify(report, null, 2);
|
|
1439
|
-
const outputPath = (0,
|
|
1558
|
+
const outputPath = (0, import_core5.resolveOutputPath)(
|
|
1440
1559
|
options.outputFile,
|
|
1441
1560
|
`consistency-report-${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}.json`,
|
|
1442
1561
|
directory
|
|
@@ -1449,7 +1568,7 @@ EXAMPLES:
|
|
|
1449
1568
|
console.log(import_chalk.default.green(`\u2713 Report saved to ${outputPath}`));
|
|
1450
1569
|
} else if (options.output === "markdown") {
|
|
1451
1570
|
const markdown = generateMarkdownReport(report, elapsedTime);
|
|
1452
|
-
const outputPath = (0,
|
|
1571
|
+
const outputPath = (0, import_core5.resolveOutputPath)(
|
|
1453
1572
|
options.outputFile,
|
|
1454
1573
|
`consistency-report-${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}.md`,
|
|
1455
1574
|
directory
|
package/dist/cli.mjs
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -54,8 +54,7 @@ interface ConsistencyReport {
|
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
56
|
* Main consistency analyzer that orchestrates all analysis types
|
|
57
|
-
*
|
|
58
|
-
* Python and other language files will be ignored during naming analysis.
|
|
57
|
+
* Supports: TypeScript, JavaScript, Python
|
|
59
58
|
*/
|
|
60
59
|
declare function analyzeConsistency(options: ConsistencyOptions): Promise<ConsistencyReport>;
|
|
61
60
|
|
package/dist/index.d.ts
CHANGED
|
@@ -54,8 +54,7 @@ interface ConsistencyReport {
|
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
56
|
* Main consistency analyzer that orchestrates all analysis types
|
|
57
|
-
*
|
|
58
|
-
* Python and other language files will be ignored during naming analysis.
|
|
57
|
+
* Supports: TypeScript, JavaScript, Python
|
|
59
58
|
*/
|
|
60
59
|
declare function analyzeConsistency(options: ConsistencyOptions): Promise<ConsistencyReport>;
|
|
61
60
|
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
@@ -30,7 +40,7 @@ __export(index_exports, {
|
|
|
30
40
|
module.exports = __toCommonJS(index_exports);
|
|
31
41
|
|
|
32
42
|
// src/analyzer.ts
|
|
33
|
-
var
|
|
43
|
+
var import_core4 = require("@aiready/core");
|
|
34
44
|
|
|
35
45
|
// src/utils/ast-parser.ts
|
|
36
46
|
var import_typescript_estree = require("@typescript-eslint/typescript-estree");
|
|
@@ -1097,8 +1107,120 @@ function extractIdentifiersFromPattern(pattern, scopeTracker, isParameter, ances
|
|
|
1097
1107
|
}
|
|
1098
1108
|
}
|
|
1099
1109
|
|
|
1100
|
-
// src/analyzers/
|
|
1110
|
+
// src/analyzers/naming-python.ts
|
|
1101
1111
|
var import_core2 = require("@aiready/core");
|
|
1112
|
+
async function analyzePythonNaming(files) {
|
|
1113
|
+
const issues = [];
|
|
1114
|
+
const parser = (0, import_core2.getParser)("dummy.py");
|
|
1115
|
+
if (!parser) {
|
|
1116
|
+
console.warn("Python parser not available");
|
|
1117
|
+
return issues;
|
|
1118
|
+
}
|
|
1119
|
+
const pythonFiles = files.filter((f) => f.toLowerCase().endsWith(".py"));
|
|
1120
|
+
for (const file of pythonFiles) {
|
|
1121
|
+
try {
|
|
1122
|
+
const fs = await import("fs");
|
|
1123
|
+
const code = await fs.promises.readFile(file, "utf-8");
|
|
1124
|
+
const result = parser.parse(code, file);
|
|
1125
|
+
for (const exp of result.exports) {
|
|
1126
|
+
const nameIssue = checkPythonNaming(exp.name, exp.type, file, exp.loc?.start.line || 0);
|
|
1127
|
+
if (nameIssue) {
|
|
1128
|
+
issues.push(nameIssue);
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
for (const imp of result.imports) {
|
|
1132
|
+
for (const spec of imp.specifiers) {
|
|
1133
|
+
if (spec !== "*" && spec !== "default") {
|
|
1134
|
+
const nameIssue = checkPythonNaming(spec, "variable", file, imp.loc?.start.line || 0);
|
|
1135
|
+
if (nameIssue) {
|
|
1136
|
+
issues.push(nameIssue);
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
} catch (error) {
|
|
1142
|
+
console.warn(`Skipping ${file} due to error:`, error);
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
return issues;
|
|
1146
|
+
}
|
|
1147
|
+
function checkPythonNaming(identifier, type, file, line) {
|
|
1148
|
+
const parser = (0, import_core2.getParser)("dummy.py");
|
|
1149
|
+
const conventions = parser?.getNamingConventions();
|
|
1150
|
+
if (!conventions) return null;
|
|
1151
|
+
if (conventions.exceptions?.includes(identifier)) {
|
|
1152
|
+
return null;
|
|
1153
|
+
}
|
|
1154
|
+
if (type === "class") {
|
|
1155
|
+
if (!conventions.classPattern.test(identifier)) {
|
|
1156
|
+
return {
|
|
1157
|
+
type: "poor-naming",
|
|
1158
|
+
identifier,
|
|
1159
|
+
file,
|
|
1160
|
+
line,
|
|
1161
|
+
column: 0,
|
|
1162
|
+
severity: "major",
|
|
1163
|
+
category: "naming",
|
|
1164
|
+
suggestion: `Class names should use PascalCase (e.g., ${toPascalCase(identifier)})`
|
|
1165
|
+
};
|
|
1166
|
+
}
|
|
1167
|
+
} else if (type === "function") {
|
|
1168
|
+
if (!conventions.functionPattern.test(identifier)) {
|
|
1169
|
+
if (/^[a-z][a-zA-Z0-9]*$/.test(identifier) && /[A-Z]/.test(identifier)) {
|
|
1170
|
+
return {
|
|
1171
|
+
type: "convention-mix",
|
|
1172
|
+
identifier,
|
|
1173
|
+
file,
|
|
1174
|
+
line,
|
|
1175
|
+
column: 0,
|
|
1176
|
+
severity: "major",
|
|
1177
|
+
category: "naming",
|
|
1178
|
+
suggestion: `Function names should use snake_case, not camelCase (e.g., ${toSnakeCase(identifier)})`
|
|
1179
|
+
};
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
} else if (type === "const" || type === "variable") {
|
|
1183
|
+
if (identifier === identifier.toUpperCase() && identifier.length > 1) {
|
|
1184
|
+
if (!conventions.constantPattern.test(identifier)) {
|
|
1185
|
+
return {
|
|
1186
|
+
type: "poor-naming",
|
|
1187
|
+
identifier,
|
|
1188
|
+
file,
|
|
1189
|
+
line,
|
|
1190
|
+
column: 0,
|
|
1191
|
+
severity: "minor",
|
|
1192
|
+
category: "naming",
|
|
1193
|
+
suggestion: "Constants should use UPPER_CASE_WITH_UNDERSCORES"
|
|
1194
|
+
};
|
|
1195
|
+
}
|
|
1196
|
+
} else {
|
|
1197
|
+
if (!conventions.variablePattern.test(identifier)) {
|
|
1198
|
+
if (/^[a-z][a-zA-Z0-9]*$/.test(identifier) && /[A-Z]/.test(identifier)) {
|
|
1199
|
+
return {
|
|
1200
|
+
type: "convention-mix",
|
|
1201
|
+
identifier,
|
|
1202
|
+
file,
|
|
1203
|
+
line,
|
|
1204
|
+
column: 0,
|
|
1205
|
+
severity: "major",
|
|
1206
|
+
category: "naming",
|
|
1207
|
+
suggestion: `Variable names should use snake_case, not camelCase (e.g., ${toSnakeCase(identifier)})`
|
|
1208
|
+
};
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
return null;
|
|
1214
|
+
}
|
|
1215
|
+
function toSnakeCase(str) {
|
|
1216
|
+
return str.replace(/([A-Z])/g, "_$1").toLowerCase().replace(/^_/, "");
|
|
1217
|
+
}
|
|
1218
|
+
function toPascalCase(str) {
|
|
1219
|
+
return str.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
// src/analyzers/patterns.ts
|
|
1223
|
+
var import_core3 = require("@aiready/core");
|
|
1102
1224
|
async function analyzePatterns(files) {
|
|
1103
1225
|
const issues = [];
|
|
1104
1226
|
const errorHandlingIssues = await analyzeErrorHandling(files);
|
|
@@ -1117,7 +1239,7 @@ async function analyzeErrorHandling(files) {
|
|
|
1117
1239
|
returnsError: []
|
|
1118
1240
|
};
|
|
1119
1241
|
for (const file of files) {
|
|
1120
|
-
const content = await (0,
|
|
1242
|
+
const content = await (0, import_core3.readFileContent)(file);
|
|
1121
1243
|
if (content.includes("try {") || content.includes("} catch")) {
|
|
1122
1244
|
patterns.tryCatch.push(file);
|
|
1123
1245
|
}
|
|
@@ -1161,7 +1283,7 @@ async function analyzeAsyncPatterns(files) {
|
|
|
1161
1283
|
callbacks: []
|
|
1162
1284
|
};
|
|
1163
1285
|
for (const file of files) {
|
|
1164
|
-
const content = await (0,
|
|
1286
|
+
const content = await (0, import_core3.readFileContent)(file);
|
|
1165
1287
|
if (content.match(/async\s+(function|\(|[a-zA-Z])/)) {
|
|
1166
1288
|
patterns.asyncAwait.push(file);
|
|
1167
1289
|
}
|
|
@@ -1203,7 +1325,7 @@ async function analyzeImportStyles(files) {
|
|
|
1203
1325
|
mixed: []
|
|
1204
1326
|
};
|
|
1205
1327
|
for (const file of files) {
|
|
1206
|
-
const content = await (0,
|
|
1328
|
+
const content = await (0, import_core3.readFileContent)(file);
|
|
1207
1329
|
const hasESM = content.match(/^import\s+/m);
|
|
1208
1330
|
const hasCJS = hasActualRequireCalls(content);
|
|
1209
1331
|
if (hasESM && hasCJS) {
|
|
@@ -1261,8 +1383,15 @@ async function analyzeConsistency(options) {
|
|
|
1261
1383
|
minSeverity = "info",
|
|
1262
1384
|
...scanOptions
|
|
1263
1385
|
} = options;
|
|
1264
|
-
const filePaths = await (0,
|
|
1265
|
-
const
|
|
1386
|
+
const filePaths = await (0, import_core4.scanFiles)(scanOptions);
|
|
1387
|
+
const tsJsFiles = filePaths.filter((f) => /\.(ts|tsx|js|jsx)$/i.test(f));
|
|
1388
|
+
const pythonFiles = filePaths.filter((f) => /\.py$/i.test(f));
|
|
1389
|
+
let namingIssues = [];
|
|
1390
|
+
if (checkNaming) {
|
|
1391
|
+
const tsJsNamingIssues = tsJsFiles.length > 0 ? await analyzeNamingAST(tsJsFiles) : [];
|
|
1392
|
+
const pythonNamingIssues = pythonFiles.length > 0 ? await analyzePythonNaming(pythonFiles) : [];
|
|
1393
|
+
namingIssues = [...tsJsNamingIssues, ...pythonNamingIssues];
|
|
1394
|
+
}
|
|
1266
1395
|
const patternIssues = checkPatterns ? await analyzePatterns(filePaths) : [];
|
|
1267
1396
|
const results = [];
|
|
1268
1397
|
const fileIssuesMap = /* @__PURE__ */ new Map();
|
|
@@ -1400,12 +1529,12 @@ function generateRecommendations(namingIssues, patternIssues) {
|
|
|
1400
1529
|
}
|
|
1401
1530
|
|
|
1402
1531
|
// src/analyzers/naming.ts
|
|
1403
|
-
var
|
|
1532
|
+
var import_core5 = require("@aiready/core");
|
|
1404
1533
|
async function analyzeNaming(files) {
|
|
1405
1534
|
const issues = [];
|
|
1406
1535
|
const { customAbbreviations, customShortWords, disabledChecks } = await loadNamingConfig(files);
|
|
1407
1536
|
for (const file of files) {
|
|
1408
|
-
const content = await (0,
|
|
1537
|
+
const content = await (0, import_core5.readFileContent)(file);
|
|
1409
1538
|
const fileIssues = analyzeFileNaming(file, content, customAbbreviations, customShortWords, disabledChecks);
|
|
1410
1539
|
issues.push(...fileIssues);
|
|
1411
1540
|
}
|
package/dist/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiready/consistency",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
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.
|
|
46
|
+
"@aiready/core": "0.8.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@types/node": "^24.0.0",
|
package/src/analyzer.ts
CHANGED
|
@@ -2,12 +2,12 @@ import { scanFiles } from '@aiready/core';
|
|
|
2
2
|
import type { AnalysisResult, Issue } from '@aiready/core';
|
|
3
3
|
import type { ConsistencyOptions, ConsistencyReport, ConsistencyIssue } from './types';
|
|
4
4
|
import { analyzeNamingAST } from './analyzers/naming-ast';
|
|
5
|
+
import { analyzePythonNaming } from './analyzers/naming-python';
|
|
5
6
|
import { analyzePatterns } from './analyzers/patterns';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Main consistency analyzer that orchestrates all analysis types
|
|
9
|
-
*
|
|
10
|
-
* Python and other language files will be ignored during naming analysis.
|
|
10
|
+
* Supports: TypeScript, JavaScript, Python
|
|
11
11
|
*/
|
|
12
12
|
export async function analyzeConsistency(
|
|
13
13
|
options: ConsistencyOptions
|
|
@@ -23,8 +23,18 @@ export async function analyzeConsistency(
|
|
|
23
23
|
// Scan files
|
|
24
24
|
const filePaths = await scanFiles(scanOptions);
|
|
25
25
|
|
|
26
|
-
//
|
|
27
|
-
const
|
|
26
|
+
// Separate files by language
|
|
27
|
+
const tsJsFiles = filePaths.filter(f => /\.(ts|tsx|js|jsx)$/i.test(f));
|
|
28
|
+
const pythonFiles = filePaths.filter(f => /\.py$/i.test(f));
|
|
29
|
+
|
|
30
|
+
// Collect issues by category - now handles multiple languages
|
|
31
|
+
let namingIssues: any[] = [];
|
|
32
|
+
if (checkNaming) {
|
|
33
|
+
const tsJsNamingIssues = tsJsFiles.length > 0 ? await analyzeNamingAST(tsJsFiles) : [];
|
|
34
|
+
const pythonNamingIssues = pythonFiles.length > 0 ? await analyzePythonNaming(pythonFiles) : [];
|
|
35
|
+
namingIssues = [...tsJsNamingIssues, ...pythonNamingIssues];
|
|
36
|
+
}
|
|
37
|
+
|
|
28
38
|
const patternIssues = checkPatterns ? await analyzePatterns(filePaths) : [];
|
|
29
39
|
|
|
30
40
|
// Convert to AnalysisResult format
|