@aiready/core 0.23.6 → 0.23.8
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/dist/chunk-5SHLHMH7.mjs +760 -0
- package/dist/chunk-TJXR2CHZ.mjs +799 -0
- package/dist/client-BrIMPk89.d.mts +1214 -0
- package/dist/client-BrIMPk89.d.ts +1214 -0
- package/dist/client-C5BuGX4F.d.mts +1205 -0
- package/dist/client-C5BuGX4F.d.ts +1205 -0
- package/dist/client-CLulBnie.d.mts +1182 -0
- package/dist/client-CLulBnie.d.ts +1182 -0
- package/dist/client-CQwvp8ep.d.mts +1182 -0
- package/dist/client-CQwvp8ep.d.ts +1182 -0
- package/dist/client-PFPdeo-z.d.mts +1186 -0
- package/dist/client-PFPdeo-z.d.ts +1186 -0
- package/dist/client-wk2fgk1q.d.mts +1184 -0
- package/dist/client-wk2fgk1q.d.ts +1184 -0
- package/dist/client.d.mts +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.js +42 -4
- package/dist/client.mjs +1 -1
- package/dist/index.d.mts +495 -149
- package/dist/index.d.ts +495 -149
- package/dist/index.js +507 -385
- package/dist/index.mjs +447 -364
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
AIReadyConfigSchema: () => AIReadyConfigSchema,
|
|
33
34
|
AnalysisResultSchema: () => AnalysisResultSchema,
|
|
34
35
|
AnalysisStatus: () => AnalysisStatus,
|
|
35
36
|
AnalysisStatusSchema: () => AnalysisStatusSchema,
|
|
@@ -111,8 +112,6 @@ __export(index_exports, {
|
|
|
111
112
|
estimateCostFromBudget: () => estimateCostFromBudget,
|
|
112
113
|
estimateTokens: () => estimateTokens,
|
|
113
114
|
exportHistory: () => exportHistory,
|
|
114
|
-
extractFunctions: () => extractFunctions,
|
|
115
|
-
extractImports: () => extractImports,
|
|
116
115
|
findLatestReport: () => findLatestReport,
|
|
117
116
|
findLatestScanReport: () => findLatestScanReport,
|
|
118
117
|
formatAcceptanceRate: () => formatAcceptanceRate,
|
|
@@ -157,8 +156,11 @@ __export(index_exports, {
|
|
|
157
156
|
loadMergedConfig: () => loadMergedConfig,
|
|
158
157
|
loadScoreHistory: () => loadScoreHistory,
|
|
159
158
|
mergeConfigWithDefaults: () => mergeConfigWithDefaults,
|
|
159
|
+
normalizeAnalysisResult: () => normalizeAnalysisResult,
|
|
160
|
+
normalizeIssue: () => normalizeIssue,
|
|
161
|
+
normalizeMetrics: () => normalizeMetrics,
|
|
162
|
+
normalizeSpokeOutput: () => normalizeSpokeOutput,
|
|
160
163
|
normalizeToolName: () => normalizeToolName,
|
|
161
|
-
parseCode: () => parseCode,
|
|
162
164
|
parseFileExports: () => parseFileExports,
|
|
163
165
|
parseWeightString: () => parseWeightString,
|
|
164
166
|
predictAcceptanceRate: () => predictAcceptanceRate,
|
|
@@ -184,21 +186,21 @@ var Severity = /* @__PURE__ */ ((Severity2) => {
|
|
|
184
186
|
return Severity2;
|
|
185
187
|
})(Severity || {});
|
|
186
188
|
var SeveritySchema = import_zod.z.nativeEnum(Severity);
|
|
187
|
-
var ToolName = /* @__PURE__ */ ((
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
return
|
|
189
|
+
var ToolName = /* @__PURE__ */ ((ToolName3) => {
|
|
190
|
+
ToolName3["PatternDetect"] = "pattern-detect";
|
|
191
|
+
ToolName3["ContextAnalyzer"] = "context-analyzer";
|
|
192
|
+
ToolName3["NamingConsistency"] = "naming-consistency";
|
|
193
|
+
ToolName3["AiSignalClarity"] = "ai-signal-clarity";
|
|
194
|
+
ToolName3["AgentGrounding"] = "agent-grounding";
|
|
195
|
+
ToolName3["TestabilityIndex"] = "testability-index";
|
|
196
|
+
ToolName3["DocDrift"] = "doc-drift";
|
|
197
|
+
ToolName3["DependencyHealth"] = "dependency-health";
|
|
198
|
+
ToolName3["ChangeAmplification"] = "change-amplification";
|
|
199
|
+
ToolName3["CognitiveLoad"] = "cognitive-load";
|
|
200
|
+
ToolName3["PatternEntropy"] = "pattern-entropy";
|
|
201
|
+
ToolName3["ConceptCohesion"] = "concept-cohesion";
|
|
202
|
+
ToolName3["SemanticDistance"] = "semantic-distance";
|
|
203
|
+
return ToolName3;
|
|
202
204
|
})(ToolName || {});
|
|
203
205
|
var ToolNameSchema = import_zod.z.nativeEnum(ToolName);
|
|
204
206
|
var FRIENDLY_TOOL_NAMES = {
|
|
@@ -334,6 +336,44 @@ var UnifiedReportSchema = import_zod.z.object({
|
|
|
334
336
|
)
|
|
335
337
|
}).optional()
|
|
336
338
|
}).catchall(import_zod.z.any());
|
|
339
|
+
var AIReadyConfigSchema = import_zod.z.object({
|
|
340
|
+
/** Target score threshold (0-100) */
|
|
341
|
+
threshold: import_zod.z.number().optional(),
|
|
342
|
+
/** Files or directories to include in scan */
|
|
343
|
+
include: import_zod.z.array(import_zod.z.string()).optional(),
|
|
344
|
+
/** Files or directories to exclude from scan */
|
|
345
|
+
exclude: import_zod.z.array(import_zod.z.string()).optional(),
|
|
346
|
+
/** Scan-specific configuration */
|
|
347
|
+
scan: import_zod.z.object({
|
|
348
|
+
include: import_zod.z.array(import_zod.z.string()).optional(),
|
|
349
|
+
exclude: import_zod.z.array(import_zod.z.string()).optional(),
|
|
350
|
+
parallel: import_zod.z.boolean().optional(),
|
|
351
|
+
deep: import_zod.z.boolean().optional(),
|
|
352
|
+
tools: import_zod.z.array(import_zod.z.string()).optional()
|
|
353
|
+
}).optional(),
|
|
354
|
+
/** Output-specific configuration */
|
|
355
|
+
output: import_zod.z.object({
|
|
356
|
+
/** Output format (json, console, html) */
|
|
357
|
+
format: import_zod.z.enum(["json", "console", "html"]).optional(),
|
|
358
|
+
/** Output file path */
|
|
359
|
+
path: import_zod.z.string().optional(),
|
|
360
|
+
/** Output directory */
|
|
361
|
+
saveTo: import_zod.z.string().optional(),
|
|
362
|
+
/** Whether to show score breakdown in console */
|
|
363
|
+
showBreakdown: import_zod.z.boolean().optional(),
|
|
364
|
+
/** Baseline report to compare against */
|
|
365
|
+
compareBaseline: import_zod.z.string().optional()
|
|
366
|
+
}).optional(),
|
|
367
|
+
/** Tool-specific configuration overrides (Strictly ToolName -> Config) */
|
|
368
|
+
tools: import_zod.z.record(import_zod.z.string(), import_zod.z.any()).optional(),
|
|
369
|
+
/** Scoring profile and weights */
|
|
370
|
+
scoring: import_zod.z.object({
|
|
371
|
+
/** Name of the scoring profile (e.g. "strict", "balanced") */
|
|
372
|
+
profile: import_zod.z.string().optional(),
|
|
373
|
+
/** Custom weights for tools and metrics */
|
|
374
|
+
weights: import_zod.z.record(import_zod.z.string(), import_zod.z.number()).optional()
|
|
375
|
+
}).optional()
|
|
376
|
+
});
|
|
337
377
|
|
|
338
378
|
// src/types/business.ts
|
|
339
379
|
var import_zod2 = require("zod");
|
|
@@ -450,51 +490,100 @@ var ParseError = class extends Error {
|
|
|
450
490
|
}
|
|
451
491
|
};
|
|
452
492
|
|
|
493
|
+
// src/utils/normalization.ts
|
|
494
|
+
function normalizeIssue(raw) {
|
|
495
|
+
return {
|
|
496
|
+
type: raw.type ?? "pattern-inconsistency" /* PatternInconsistency */,
|
|
497
|
+
severity: raw.severity ?? raw.severityLevel ?? "info" /* Info */,
|
|
498
|
+
message: raw.message ?? "Unknown issue",
|
|
499
|
+
location: raw.location ?? {
|
|
500
|
+
file: raw.fileName ?? raw.file ?? raw.filePath ?? "unknown",
|
|
501
|
+
line: raw.line ?? 1,
|
|
502
|
+
column: raw.column
|
|
503
|
+
},
|
|
504
|
+
suggestion: raw.suggestion
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
function normalizeMetrics(raw) {
|
|
508
|
+
return {
|
|
509
|
+
tokenCost: raw.tokenCost ?? 0,
|
|
510
|
+
complexityScore: raw.complexityScore ?? 0,
|
|
511
|
+
consistencyScore: raw.consistencyScore,
|
|
512
|
+
docFreshnessScore: raw.docFreshnessScore,
|
|
513
|
+
aiSignalClarityScore: raw.aiSignalClarityScore,
|
|
514
|
+
agentGroundingScore: raw.agentGroundingScore,
|
|
515
|
+
testabilityScore: raw.testabilityScore,
|
|
516
|
+
docDriftScore: raw.docDriftScore,
|
|
517
|
+
dependencyHealthScore: raw.dependencyHealthScore,
|
|
518
|
+
modelContextTier: raw.modelContextTier,
|
|
519
|
+
estimatedMonthlyCost: raw.estimatedMonthlyCost,
|
|
520
|
+
estimatedDeveloperHours: raw.estimatedDeveloperHours,
|
|
521
|
+
comprehensionDifficultyIndex: raw.comprehensionDifficultyIndex,
|
|
522
|
+
totalSymbols: raw.totalSymbols,
|
|
523
|
+
totalExports: raw.totalExports
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
function normalizeAnalysisResult(raw) {
|
|
527
|
+
const fileName = raw.fileName ?? raw.file ?? raw.filePath ?? "unknown";
|
|
528
|
+
const rawIssues = Array.isArray(raw.issues) ? raw.issues : [];
|
|
529
|
+
return {
|
|
530
|
+
fileName,
|
|
531
|
+
issues: rawIssues.map((issue) => {
|
|
532
|
+
if (typeof issue === "string") {
|
|
533
|
+
return {
|
|
534
|
+
type: "pattern-inconsistency" /* PatternInconsistency */,
|
|
535
|
+
// Default fallback
|
|
536
|
+
severity: raw.severity ?? "info" /* Info */,
|
|
537
|
+
message: issue,
|
|
538
|
+
location: { file: fileName, line: 1 }
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
return normalizeIssue({
|
|
542
|
+
...issue,
|
|
543
|
+
fileName: issue.fileName ?? fileName,
|
|
544
|
+
severity: issue.severity ?? raw.severity
|
|
545
|
+
});
|
|
546
|
+
}),
|
|
547
|
+
metrics: normalizeMetrics(raw.metrics ?? {})
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
function normalizeSpokeOutput(raw, toolName) {
|
|
551
|
+
const rawResults = Array.isArray(raw.results) ? raw.results : [];
|
|
552
|
+
return {
|
|
553
|
+
results: rawResults.map(normalizeAnalysisResult),
|
|
554
|
+
summary: raw.summary ?? {
|
|
555
|
+
totalFiles: rawResults.length,
|
|
556
|
+
totalIssues: 0,
|
|
557
|
+
criticalIssues: 0,
|
|
558
|
+
majorIssues: 0
|
|
559
|
+
},
|
|
560
|
+
metadata: {
|
|
561
|
+
toolName: raw.metadata?.toolName ?? toolName,
|
|
562
|
+
version: raw.metadata?.version,
|
|
563
|
+
timestamp: raw.metadata?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
564
|
+
config: raw.metadata?.config
|
|
565
|
+
}
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
|
|
453
569
|
// src/types/contract.ts
|
|
454
570
|
function validateSpokeOutput(toolName, output) {
|
|
455
|
-
const errors = [];
|
|
456
571
|
if (!output) {
|
|
457
572
|
return { valid: false, errors: ["Output is null or undefined"] };
|
|
458
573
|
}
|
|
459
|
-
if (!Array.isArray(output.results)) {
|
|
460
|
-
errors.push(`${toolName}: 'results' must be an array`);
|
|
461
|
-
} else {
|
|
462
|
-
output.results.forEach((res, idx) => {
|
|
463
|
-
const fileName = res.fileName || res.file || res.filePath;
|
|
464
|
-
if (!fileName)
|
|
465
|
-
errors.push(
|
|
466
|
-
`${toolName}: results[${idx}] missing 'fileName', 'file' or 'filePath'`
|
|
467
|
-
);
|
|
468
|
-
const issues = res.issues;
|
|
469
|
-
if (!Array.isArray(issues)) {
|
|
470
|
-
errors.push(`${toolName}: results[${idx}] 'issues' must be an array`);
|
|
471
|
-
} else if (issues.length > 0) {
|
|
472
|
-
issues.forEach((issue, iidx) => {
|
|
473
|
-
if (typeof issue === "string") return;
|
|
474
|
-
if (!issue.type && !res.file)
|
|
475
|
-
errors.push(
|
|
476
|
-
`${toolName}: results[${idx}].issues[${iidx}] missing 'type'`
|
|
477
|
-
);
|
|
478
|
-
if (!issue.severity && !res.severity)
|
|
479
|
-
errors.push(
|
|
480
|
-
`${toolName}: results[${idx}].issues[${iidx}] missing 'severity'`
|
|
481
|
-
);
|
|
482
|
-
const severity = issue.severity || res.severity;
|
|
483
|
-
if (severity && !["critical", "major", "minor", "info"].includes(severity)) {
|
|
484
|
-
errors.push(
|
|
485
|
-
`${toolName}: results[${idx}].issues[${iidx}] has invalid severity: ${severity}`
|
|
486
|
-
);
|
|
487
|
-
}
|
|
488
|
-
});
|
|
489
|
-
}
|
|
490
|
-
});
|
|
491
|
-
}
|
|
492
574
|
if (!output.summary) {
|
|
493
|
-
errors
|
|
575
|
+
return { valid: false, errors: [`${toolName}: missing 'summary'`] };
|
|
576
|
+
}
|
|
577
|
+
const normalized = normalizeSpokeOutput(output, toolName);
|
|
578
|
+
const result = SpokeOutputSchema.safeParse(normalized);
|
|
579
|
+
if (result.success) {
|
|
580
|
+
return { valid: true, errors: [] };
|
|
494
581
|
}
|
|
495
582
|
return {
|
|
496
|
-
valid:
|
|
497
|
-
errors
|
|
583
|
+
valid: false,
|
|
584
|
+
errors: result.error.issues.map(
|
|
585
|
+
(e) => `${toolName}: ${e.path.join(".")}: ${e.message}`
|
|
586
|
+
)
|
|
498
587
|
};
|
|
499
588
|
}
|
|
500
589
|
function validateWithSchema(schema, data) {
|
|
@@ -857,7 +946,7 @@ function resolveOutputPath(userPath, defaultFilename, workingDir = process.cwd()
|
|
|
857
946
|
if ((0, import_fs2.statSync)(workingDir).isFile()) {
|
|
858
947
|
baseDir = (0, import_path2.dirname)(workingDir);
|
|
859
948
|
}
|
|
860
|
-
} catch
|
|
949
|
+
} catch {
|
|
861
950
|
}
|
|
862
951
|
const aireadyDir = (0, import_path2.join)(baseDir, ".aiready");
|
|
863
952
|
outputPath = (0, import_path2.join)(aireadyDir, defaultFilename);
|
|
@@ -1029,8 +1118,8 @@ function findLatestScanReport(scanReportsDir, reportFilePrefix) {
|
|
|
1029
1118
|
return idB - idA;
|
|
1030
1119
|
});
|
|
1031
1120
|
return (0, import_path2.join)(scanReportsDir, reportFiles[0]);
|
|
1032
|
-
} catch
|
|
1033
|
-
console.error("Error while finding latest scan report
|
|
1121
|
+
} catch {
|
|
1122
|
+
console.error("Error while finding latest scan report");
|
|
1034
1123
|
return null;
|
|
1035
1124
|
}
|
|
1036
1125
|
}
|
|
@@ -1095,7 +1184,19 @@ function createProvider(config) {
|
|
|
1095
1184
|
};
|
|
1096
1185
|
}
|
|
1097
1186
|
|
|
1098
|
-
// src/utils/
|
|
1187
|
+
// src/utils/similarity-utils.ts
|
|
1188
|
+
function calculateImportSimilarity(export1, export2) {
|
|
1189
|
+
if (export1.imports.length === 0 && export2.imports.length === 0) {
|
|
1190
|
+
return 1;
|
|
1191
|
+
}
|
|
1192
|
+
const set1 = new Set(export1.imports);
|
|
1193
|
+
const set2 = new Set(export2.imports);
|
|
1194
|
+
const intersection = new Set([...set1].filter((x) => set2.has(x)));
|
|
1195
|
+
const union = /* @__PURE__ */ new Set([...set1, ...set2]);
|
|
1196
|
+
return intersection.size / union.size;
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
// src/utils/dependency-analyzer.ts
|
|
1099
1200
|
var import_typescript_estree2 = require("@typescript-eslint/typescript-estree");
|
|
1100
1201
|
|
|
1101
1202
|
// src/parsers/typescript-parser.ts
|
|
@@ -1106,148 +1207,67 @@ var TypeScriptParser = class {
|
|
|
1106
1207
|
this.extensions = [".ts", ".tsx", ".js", ".jsx"];
|
|
1107
1208
|
}
|
|
1108
1209
|
async initialize() {
|
|
1109
|
-
return Promise.resolve();
|
|
1110
1210
|
}
|
|
1111
|
-
|
|
1112
|
-
return (
|
|
1113
|
-
loc: true,
|
|
1114
|
-
range: true,
|
|
1115
|
-
jsx: filePath.match(/\.[jt]sx$/i) !== null,
|
|
1116
|
-
filePath,
|
|
1117
|
-
sourceType: "module",
|
|
1118
|
-
ecmaVersion: "latest",
|
|
1119
|
-
comment: true
|
|
1120
|
-
});
|
|
1211
|
+
canHandle(filePath) {
|
|
1212
|
+
return this.extensions.some((ext) => filePath.endsWith(ext));
|
|
1121
1213
|
}
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
const precedingStartOffset = Math.max(0, start - 1e3);
|
|
1138
|
-
const absoluteStartOffset = precedingStartOffset + (lastMatch.index || 0);
|
|
1139
|
-
const absoluteEndOffset = precedingStartOffset + matchEndIndex;
|
|
1140
|
-
const codeBeforeStart = code.slice(0, absoluteStartOffset);
|
|
1141
|
-
const startLines = codeBeforeStart.split("\n");
|
|
1142
|
-
const startLine = startLines.length;
|
|
1143
|
-
const startColumn = startLines[startLines.length - 1].length;
|
|
1144
|
-
const codeBeforeEnd = code.slice(0, absoluteEndOffset);
|
|
1145
|
-
const endLines = codeBeforeEnd.split("\n");
|
|
1146
|
-
const endLine = endLines.length;
|
|
1147
|
-
const endColumn = endLines[endLines.length - 1].length;
|
|
1148
|
-
metadata.documentation = {
|
|
1149
|
-
content: lastMatch[1].replace(/^\s*\*+/gm, "").trim(),
|
|
1150
|
-
type: "jsdoc",
|
|
1151
|
-
loc: {
|
|
1152
|
-
start: { line: startLine, column: startColumn },
|
|
1153
|
-
end: { line: endLine, column: endColumn }
|
|
1154
|
-
}
|
|
1155
|
-
};
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
const walk = (n) => {
|
|
1159
|
-
if (!n) return;
|
|
1160
|
-
if (n.type === "AssignmentExpression") {
|
|
1161
|
-
metadata.isPure = false;
|
|
1162
|
-
metadata.hasSideEffects = true;
|
|
1163
|
-
}
|
|
1164
|
-
if (n.type === "UpdateExpression") {
|
|
1165
|
-
metadata.isPure = false;
|
|
1166
|
-
metadata.hasSideEffects = true;
|
|
1167
|
-
}
|
|
1168
|
-
if (n.type === "CallExpression" && n.callee.type === "MemberExpression" && n.callee.object.type === "Identifier") {
|
|
1169
|
-
const objName = n.callee.object.name;
|
|
1170
|
-
if (["console", "process", "fs", "window", "document"].includes(objName)) {
|
|
1171
|
-
metadata.isPure = false;
|
|
1172
|
-
metadata.hasSideEffects = true;
|
|
1173
|
-
}
|
|
1174
|
-
}
|
|
1175
|
-
if (n.type === "ThrowStatement") {
|
|
1176
|
-
metadata.isPure = false;
|
|
1177
|
-
metadata.hasSideEffects = true;
|
|
1178
|
-
}
|
|
1179
|
-
for (const key of Object.keys(n)) {
|
|
1180
|
-
if (key === "parent") continue;
|
|
1181
|
-
const child = n[key];
|
|
1182
|
-
if (child && typeof child === "object") {
|
|
1183
|
-
if (Array.isArray(child)) {
|
|
1184
|
-
child.forEach((c) => c?.type && walk(c));
|
|
1185
|
-
} else if (child.type) {
|
|
1186
|
-
walk(child);
|
|
1187
|
-
}
|
|
1188
|
-
}
|
|
1189
|
-
}
|
|
1190
|
-
};
|
|
1191
|
-
let nodeToAnalyze = node;
|
|
1192
|
-
if (node.type === "ExportNamedDeclaration" && node.declaration) {
|
|
1193
|
-
nodeToAnalyze = node.declaration;
|
|
1194
|
-
} else if (node.type === "ExportDefaultDeclaration" && node.declaration) {
|
|
1195
|
-
if (node.declaration.type !== "TSInterfaceDeclaration" && node.declaration.type !== "TSTypeAliasDeclaration") {
|
|
1196
|
-
nodeToAnalyze = node.declaration;
|
|
1197
|
-
}
|
|
1198
|
-
}
|
|
1199
|
-
if (nodeToAnalyze.type === "FunctionDeclaration" || nodeToAnalyze.type === "FunctionExpression" || nodeToAnalyze.type === "ArrowFunctionExpression") {
|
|
1200
|
-
if (nodeToAnalyze.body) walk(nodeToAnalyze.body);
|
|
1201
|
-
} else if (nodeToAnalyze.type === "ClassDeclaration" || nodeToAnalyze.type === "ClassExpression") {
|
|
1202
|
-
walk(nodeToAnalyze.body);
|
|
1214
|
+
async getAST(code, filePath) {
|
|
1215
|
+
try {
|
|
1216
|
+
return (0, import_typescript_estree.parse)(code, {
|
|
1217
|
+
filePath,
|
|
1218
|
+
loc: true,
|
|
1219
|
+
range: true,
|
|
1220
|
+
tokens: true,
|
|
1221
|
+
comment: true,
|
|
1222
|
+
jsx: filePath.endsWith("x")
|
|
1223
|
+
});
|
|
1224
|
+
} catch (error) {
|
|
1225
|
+
throw new ParseError(error.message, filePath, {
|
|
1226
|
+
line: error.lineNumber || 1,
|
|
1227
|
+
column: error.column || 0
|
|
1228
|
+
});
|
|
1203
1229
|
}
|
|
1204
|
-
return metadata;
|
|
1205
1230
|
}
|
|
1206
1231
|
parse(code, filePath) {
|
|
1207
1232
|
try {
|
|
1208
|
-
const isJavaScript = filePath.match(/\.jsx?$/i);
|
|
1209
1233
|
const ast = (0, import_typescript_estree.parse)(code, {
|
|
1234
|
+
filePath,
|
|
1210
1235
|
loc: true,
|
|
1211
1236
|
range: true,
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
ecmaVersion: "latest",
|
|
1216
|
-
comment: true
|
|
1237
|
+
tokens: true,
|
|
1238
|
+
comment: true,
|
|
1239
|
+
jsx: filePath.endsWith("x")
|
|
1217
1240
|
});
|
|
1218
1241
|
const imports = this.extractImports(ast);
|
|
1219
|
-
const exports2 = this.extractExports(ast,
|
|
1242
|
+
const exports2 = this.extractExports(ast, code);
|
|
1220
1243
|
return {
|
|
1221
1244
|
exports: exports2,
|
|
1222
1245
|
imports,
|
|
1223
|
-
language:
|
|
1224
|
-
warnings: []
|
|
1246
|
+
language: this.language
|
|
1225
1247
|
};
|
|
1226
1248
|
} catch (error) {
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
);
|
|
1249
|
+
throw new ParseError(error.message, filePath, {
|
|
1250
|
+
line: error.lineNumber || 1,
|
|
1251
|
+
column: error.column || 0
|
|
1252
|
+
});
|
|
1232
1253
|
}
|
|
1233
1254
|
}
|
|
1234
1255
|
getNamingConventions() {
|
|
1235
1256
|
return {
|
|
1236
|
-
// camelCase for variables and functions
|
|
1237
1257
|
variablePattern: /^[a-z][a-zA-Z0-9]*$/,
|
|
1238
1258
|
functionPattern: /^[a-z][a-zA-Z0-9]*$/,
|
|
1239
|
-
// PascalCase for classes, types and interfaces
|
|
1240
1259
|
classPattern: /^[A-Z][a-zA-Z0-9]*$/,
|
|
1241
|
-
typePattern: /^[A-Z][a-zA-Z0-9]*$/,
|
|
1242
|
-
interfacePattern: /^[A-Z][a-zA-Z0-9]*$/,
|
|
1243
|
-
// UPPER_CASE for constants
|
|
1244
1260
|
constantPattern: /^[A-Z][A-Z0-9_]*$/,
|
|
1245
|
-
|
|
1246
|
-
|
|
1261
|
+
typePattern: /^[A-Z][a-zA-Z0-9]*$/,
|
|
1262
|
+
interfacePattern: /^I?[A-Z][a-zA-Z0-9]*$/
|
|
1247
1263
|
};
|
|
1248
1264
|
}
|
|
1249
|
-
|
|
1250
|
-
|
|
1265
|
+
analyzeMetadata(node, code) {
|
|
1266
|
+
if (!code) return {};
|
|
1267
|
+
return {
|
|
1268
|
+
isPure: this.isLikelyPure(node),
|
|
1269
|
+
hasSideEffects: !this.isLikelyPure(node)
|
|
1270
|
+
};
|
|
1251
1271
|
}
|
|
1252
1272
|
extractImports(ast) {
|
|
1253
1273
|
const imports = [];
|
|
@@ -1285,168 +1305,165 @@ var TypeScriptParser = class {
|
|
|
1285
1305
|
}
|
|
1286
1306
|
return imports;
|
|
1287
1307
|
}
|
|
1288
|
-
extractExports(ast,
|
|
1308
|
+
extractExports(ast, code) {
|
|
1289
1309
|
const exports2 = [];
|
|
1290
|
-
const importedNames = new Set(
|
|
1291
|
-
imports.flatMap(
|
|
1292
|
-
(imp) => imp.specifiers.filter((s) => s !== "*" && s !== "default")
|
|
1293
|
-
)
|
|
1294
|
-
);
|
|
1295
1310
|
for (const node of ast.body) {
|
|
1296
|
-
if (node.type === "ExportNamedDeclaration"
|
|
1297
|
-
|
|
1298
|
-
node.declaration
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1311
|
+
if (node.type === "ExportNamedDeclaration") {
|
|
1312
|
+
if (node.declaration) {
|
|
1313
|
+
const declaration = node.declaration;
|
|
1314
|
+
if ((declaration.type === "FunctionDeclaration" || declaration.type === "TSDeclareFunction") && declaration.id) {
|
|
1315
|
+
exports2.push(
|
|
1316
|
+
this.createExport(
|
|
1317
|
+
declaration.id.name,
|
|
1318
|
+
"function",
|
|
1319
|
+
node,
|
|
1320
|
+
// Pass the outer ExportNamedDeclaration
|
|
1321
|
+
code
|
|
1322
|
+
)
|
|
1323
|
+
);
|
|
1324
|
+
} else if (declaration.type === "ClassDeclaration" && declaration.id) {
|
|
1325
|
+
exports2.push(
|
|
1326
|
+
this.createExport(
|
|
1327
|
+
declaration.id.name,
|
|
1328
|
+
"class",
|
|
1329
|
+
node,
|
|
1330
|
+
// Pass the outer ExportNamedDeclaration
|
|
1331
|
+
code
|
|
1332
|
+
)
|
|
1333
|
+
);
|
|
1334
|
+
} else if (declaration.type === "TSTypeAliasDeclaration") {
|
|
1335
|
+
exports2.push(
|
|
1336
|
+
this.createExport(
|
|
1337
|
+
declaration.id.name,
|
|
1338
|
+
"type",
|
|
1339
|
+
node,
|
|
1340
|
+
// Pass the outer ExportNamedDeclaration
|
|
1341
|
+
code
|
|
1342
|
+
)
|
|
1343
|
+
);
|
|
1344
|
+
} else if (declaration.type === "TSInterfaceDeclaration") {
|
|
1345
|
+
exports2.push(
|
|
1346
|
+
this.createExport(
|
|
1347
|
+
declaration.id.name,
|
|
1348
|
+
"interface",
|
|
1349
|
+
node,
|
|
1350
|
+
// Pass the outer ExportNamedDeclaration
|
|
1351
|
+
code
|
|
1352
|
+
)
|
|
1353
|
+
);
|
|
1354
|
+
} else if (declaration.type === "VariableDeclaration") {
|
|
1355
|
+
for (const decl of declaration.declarations) {
|
|
1356
|
+
if (decl.id.type === "Identifier") {
|
|
1357
|
+
exports2.push(
|
|
1358
|
+
this.createExport(
|
|
1359
|
+
decl.id.name,
|
|
1360
|
+
"const",
|
|
1361
|
+
node,
|
|
1362
|
+
// Pass the outer ExportNamedDeclaration
|
|
1363
|
+
code,
|
|
1364
|
+
decl.init
|
|
1365
|
+
)
|
|
1366
|
+
);
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1315
1370
|
}
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
type,
|
|
1319
|
-
loc: node.loc ? {
|
|
1320
|
-
start: {
|
|
1321
|
-
line: node.loc.start.line,
|
|
1322
|
-
column: node.loc.start.column
|
|
1323
|
-
},
|
|
1324
|
-
end: { line: node.loc.end.line, column: node.loc.end.column }
|
|
1325
|
-
} : void 0,
|
|
1326
|
-
...metadata
|
|
1327
|
-
});
|
|
1371
|
+
} else if (node.type === "ExportDefaultDeclaration") {
|
|
1372
|
+
exports2.push(this.createExport("default", "default", node, code));
|
|
1328
1373
|
}
|
|
1329
1374
|
}
|
|
1330
1375
|
return exports2;
|
|
1331
1376
|
}
|
|
1332
|
-
|
|
1333
|
-
const
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1377
|
+
createExport(name, type, node, code, initializer) {
|
|
1378
|
+
const documentation = this.extractDocumentation(node, code);
|
|
1379
|
+
let methodCount;
|
|
1380
|
+
let propertyCount;
|
|
1381
|
+
let parameters;
|
|
1382
|
+
let isPrimitive = false;
|
|
1383
|
+
if (initializer) {
|
|
1384
|
+
if (initializer.type === "Literal" || initializer.type === "TemplateLiteral" && initializer.expressions.length === 0) {
|
|
1385
|
+
isPrimitive = true;
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
const structNode = node.type === "ExportNamedDeclaration" ? node.declaration : node.type === "ExportDefaultDeclaration" ? node.declaration : node;
|
|
1389
|
+
if (structNode.type === "ClassDeclaration" || structNode.type === "TSInterfaceDeclaration") {
|
|
1390
|
+
const body = structNode.type === "ClassDeclaration" ? structNode.body.body : structNode.body.body;
|
|
1391
|
+
methodCount = body.filter(
|
|
1392
|
+
(m) => m.type === "MethodDefinition" || m.type === "TSMethodSignature"
|
|
1393
|
+
).length;
|
|
1394
|
+
propertyCount = body.filter(
|
|
1395
|
+
(m) => m.type === "PropertyDefinition" || m.type === "TSPropertySignature"
|
|
1396
|
+
).length;
|
|
1397
|
+
if (structNode.type === "ClassDeclaration") {
|
|
1398
|
+
const constructor = body.find(
|
|
1399
|
+
(m) => m.type === "MethodDefinition" && m.kind === "constructor"
|
|
1400
|
+
);
|
|
1401
|
+
if (constructor && constructor.value && constructor.value.params) {
|
|
1402
|
+
parameters = constructor.value.params.map((p) => {
|
|
1403
|
+
if (p.type === "Identifier") return p.name;
|
|
1404
|
+
if (p.type === "TSParameterProperty" && p.parameter.type === "Identifier") {
|
|
1405
|
+
return p.parameter.name;
|
|
1406
|
+
}
|
|
1407
|
+
return void 0;
|
|
1408
|
+
}).filter(Boolean);
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
if (!parameters && (structNode.type === "FunctionDeclaration" || structNode.type === "TSDeclareFunction" || structNode.type === "MethodDefinition")) {
|
|
1413
|
+
const funcNode = structNode.type === "MethodDefinition" ? structNode.value : structNode;
|
|
1414
|
+
if (funcNode && funcNode.params) {
|
|
1415
|
+
parameters = funcNode.params.map((p) => {
|
|
1340
1416
|
if (p.type === "Identifier") return p.name;
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
}
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
const
|
|
1364
|
-
|
|
1365
|
-
);
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
}
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
column: declaration.loc.end.column
|
|
1386
|
-
}
|
|
1387
|
-
} : void 0,
|
|
1388
|
-
...metadata
|
|
1389
|
-
});
|
|
1390
|
-
} else if (declaration.type === "VariableDeclaration") {
|
|
1391
|
-
for (const declarator of declaration.declarations) {
|
|
1392
|
-
if (declarator.id.type === "Identifier") {
|
|
1393
|
-
exports2.push({
|
|
1394
|
-
name: declarator.id.name,
|
|
1395
|
-
type: "const",
|
|
1396
|
-
loc: declarator.loc ? {
|
|
1397
|
-
start: {
|
|
1398
|
-
line: declarator.loc.start.line,
|
|
1399
|
-
column: declarator.loc.start.column
|
|
1400
|
-
},
|
|
1401
|
-
end: {
|
|
1402
|
-
line: declarator.loc.end.line,
|
|
1403
|
-
column: declarator.loc.end.column
|
|
1404
|
-
}
|
|
1405
|
-
} : void 0,
|
|
1406
|
-
...metadata
|
|
1407
|
-
});
|
|
1417
|
+
return void 0;
|
|
1418
|
+
}).filter(Boolean);
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
return {
|
|
1422
|
+
name,
|
|
1423
|
+
type,
|
|
1424
|
+
isPrimitive,
|
|
1425
|
+
loc: node.loc ? {
|
|
1426
|
+
start: { line: node.loc.start.line, column: node.loc.start.column },
|
|
1427
|
+
end: { line: node.loc.end.line, column: node.loc.end.column }
|
|
1428
|
+
} : void 0,
|
|
1429
|
+
documentation,
|
|
1430
|
+
methodCount,
|
|
1431
|
+
propertyCount,
|
|
1432
|
+
parameters,
|
|
1433
|
+
isPure: this.isLikelyPure(node),
|
|
1434
|
+
hasSideEffects: !this.isLikelyPure(node)
|
|
1435
|
+
};
|
|
1436
|
+
}
|
|
1437
|
+
extractDocumentation(node, code) {
|
|
1438
|
+
if (node.range) {
|
|
1439
|
+
const start = node.range[0];
|
|
1440
|
+
const precedingCode = code.substring(0, start);
|
|
1441
|
+
const jsdocMatch = precedingCode.match(/\/\*\*([\s\S]*?)\*\/\s*$/);
|
|
1442
|
+
if (jsdocMatch) {
|
|
1443
|
+
return {
|
|
1444
|
+
content: jsdocMatch[1].trim(),
|
|
1445
|
+
type: "jsdoc"
|
|
1446
|
+
};
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
return void 0;
|
|
1450
|
+
}
|
|
1451
|
+
isLikelyPure(node) {
|
|
1452
|
+
const structNode = node.type === "ExportNamedDeclaration" ? node.declaration : node.type === "ExportDefaultDeclaration" ? node.declaration : node;
|
|
1453
|
+
if (structNode.type === "VariableDeclaration" && structNode.kind === "const")
|
|
1454
|
+
return true;
|
|
1455
|
+
if (structNode.type === "FunctionDeclaration" || structNode.type === "TSDeclareFunction" || structNode.type === "MethodDefinition" && structNode.value) {
|
|
1456
|
+
const body = structNode.type === "MethodDefinition" ? structNode.value.body : structNode.body;
|
|
1457
|
+
if (body && body.type === "BlockStatement") {
|
|
1458
|
+
const bodyContent = JSON.stringify(body);
|
|
1459
|
+
if (bodyContent.includes('"name":"console"') || bodyContent.includes('"name":"process"') || bodyContent.includes('"type":"AssignmentExpression"')) {
|
|
1460
|
+
return false;
|
|
1408
1461
|
}
|
|
1462
|
+
return true;
|
|
1409
1463
|
}
|
|
1410
|
-
|
|
1411
|
-
exports2.push({
|
|
1412
|
-
name: declaration.id.name,
|
|
1413
|
-
type: "type",
|
|
1414
|
-
loc: declaration.loc ? {
|
|
1415
|
-
start: {
|
|
1416
|
-
line: declaration.loc.start.line,
|
|
1417
|
-
column: declaration.loc.start.column
|
|
1418
|
-
},
|
|
1419
|
-
end: {
|
|
1420
|
-
line: declaration.loc.end.line,
|
|
1421
|
-
column: declaration.loc.end.column
|
|
1422
|
-
}
|
|
1423
|
-
} : void 0,
|
|
1424
|
-
...metadata
|
|
1425
|
-
});
|
|
1426
|
-
} else if (declaration.type === "TSInterfaceDeclaration") {
|
|
1427
|
-
const body = declaration.body.body;
|
|
1428
|
-
const methods = body.filter((m) => m.type === "TSMethodSignature");
|
|
1429
|
-
const properties = body.filter((m) => m.type === "TSPropertySignature");
|
|
1430
|
-
exports2.push({
|
|
1431
|
-
name: declaration.id.name,
|
|
1432
|
-
type: "interface",
|
|
1433
|
-
methodCount: methods.length,
|
|
1434
|
-
propertyCount: properties.length || body.length,
|
|
1435
|
-
// Fallback to body.length
|
|
1436
|
-
loc: declaration.loc ? {
|
|
1437
|
-
start: {
|
|
1438
|
-
line: declaration.loc.start.line,
|
|
1439
|
-
column: declaration.loc.start.column
|
|
1440
|
-
},
|
|
1441
|
-
end: {
|
|
1442
|
-
line: declaration.loc.end.line,
|
|
1443
|
-
column: declaration.loc.end.column
|
|
1444
|
-
}
|
|
1445
|
-
} : void 0,
|
|
1446
|
-
...metadata
|
|
1447
|
-
});
|
|
1464
|
+
return true;
|
|
1448
1465
|
}
|
|
1449
|
-
return
|
|
1466
|
+
return false;
|
|
1450
1467
|
}
|
|
1451
1468
|
};
|
|
1452
1469
|
|
|
@@ -1720,11 +1737,24 @@ var PythonParser = class extends BaseLanguageParser {
|
|
|
1720
1737
|
getParserName() {
|
|
1721
1738
|
return "python";
|
|
1722
1739
|
}
|
|
1740
|
+
/**
|
|
1741
|
+
* Analyze metadata for a Python node (purity, side effects).
|
|
1742
|
+
*
|
|
1743
|
+
* @param node - Tree-sitter node to analyze.
|
|
1744
|
+
* @param code - Source code for context.
|
|
1745
|
+
* @returns Partial ExportInfo containing discovered metadata.
|
|
1746
|
+
*/
|
|
1723
1747
|
analyzeMetadata(node, code) {
|
|
1724
1748
|
return analyzeNodeMetadata(node, code, {
|
|
1725
1749
|
sideEffectSignatures: ["print(", "input(", "open("]
|
|
1726
1750
|
});
|
|
1727
1751
|
}
|
|
1752
|
+
/**
|
|
1753
|
+
* Extract import information using AST walk.
|
|
1754
|
+
*
|
|
1755
|
+
* @param rootNode - Root node of the Python AST.
|
|
1756
|
+
* @returns Array of discovered FileImport objects.
|
|
1757
|
+
*/
|
|
1728
1758
|
extractImportsAST(rootNode) {
|
|
1729
1759
|
const imports = [];
|
|
1730
1760
|
const processImportNode = (node) => {
|
|
@@ -1806,6 +1836,13 @@ var PythonParser = class extends BaseLanguageParser {
|
|
|
1806
1836
|
}
|
|
1807
1837
|
return imports;
|
|
1808
1838
|
}
|
|
1839
|
+
/**
|
|
1840
|
+
* Extract export information using AST walk.
|
|
1841
|
+
*
|
|
1842
|
+
* @param rootNode - Root node of the Python AST.
|
|
1843
|
+
* @param code - Source code for documentation extraction.
|
|
1844
|
+
* @returns Array of discovered ExportInfo objects.
|
|
1845
|
+
*/
|
|
1809
1846
|
extractExportsAST(rootNode, code) {
|
|
1810
1847
|
const exports2 = [];
|
|
1811
1848
|
for (const node of rootNode.children) {
|
|
@@ -1884,6 +1921,12 @@ var PythonParser = class extends BaseLanguageParser {
|
|
|
1884
1921
|
}
|
|
1885
1922
|
return exports2;
|
|
1886
1923
|
}
|
|
1924
|
+
/**
|
|
1925
|
+
* Extract parameter names from a function definition node.
|
|
1926
|
+
*
|
|
1927
|
+
* @param node - Function definition node.
|
|
1928
|
+
* @returns Array of parameter name strings.
|
|
1929
|
+
*/
|
|
1887
1930
|
extractParameters(node) {
|
|
1888
1931
|
const paramsNode = node.childForFieldName("parameters");
|
|
1889
1932
|
if (!paramsNode) return [];
|
|
@@ -1897,6 +1940,13 @@ var PythonParser = class extends BaseLanguageParser {
|
|
|
1897
1940
|
return "unknown";
|
|
1898
1941
|
});
|
|
1899
1942
|
}
|
|
1943
|
+
/**
|
|
1944
|
+
* Fallback regex-based parsing when tree-sitter is unavailable.
|
|
1945
|
+
*
|
|
1946
|
+
* @param code - Source code content.
|
|
1947
|
+
* @param filePath - Path to the file being parsed.
|
|
1948
|
+
* @returns Consolidated ParseResult.
|
|
1949
|
+
*/
|
|
1900
1950
|
parseRegex(code, filePath) {
|
|
1901
1951
|
try {
|
|
1902
1952
|
const imports = this.extractImportsRegex(code, filePath);
|
|
@@ -2170,6 +2220,13 @@ var JavaParser = class extends BaseLanguageParser {
|
|
|
2170
2220
|
getParserName() {
|
|
2171
2221
|
return "java";
|
|
2172
2222
|
}
|
|
2223
|
+
/**
|
|
2224
|
+
* Analyze metadata for a Java node (purity, side effects).
|
|
2225
|
+
*
|
|
2226
|
+
* @param node - Tree-sitter node to analyze.
|
|
2227
|
+
* @param code - Source code for context.
|
|
2228
|
+
* @returns Partial ExportInfo containing discovered metadata.
|
|
2229
|
+
*/
|
|
2173
2230
|
analyzeMetadata(node, code) {
|
|
2174
2231
|
return analyzeGeneralMetadata(node, code, {
|
|
2175
2232
|
sideEffectSignatures: [
|
|
@@ -2249,6 +2306,12 @@ var JavaParser = class extends BaseLanguageParser {
|
|
|
2249
2306
|
warnings: ["Parser falling back to regex-based analysis"]
|
|
2250
2307
|
};
|
|
2251
2308
|
}
|
|
2309
|
+
/**
|
|
2310
|
+
* Extract import information using AST walk.
|
|
2311
|
+
*
|
|
2312
|
+
* @param rootNode - Root node of the Java AST.
|
|
2313
|
+
* @returns Array of discovered FileImport objects.
|
|
2314
|
+
*/
|
|
2252
2315
|
extractImportsAST(rootNode) {
|
|
2253
2316
|
const imports = [];
|
|
2254
2317
|
for (const node of rootNode.children) {
|
|
@@ -2282,6 +2345,13 @@ var JavaParser = class extends BaseLanguageParser {
|
|
|
2282
2345
|
}
|
|
2283
2346
|
return imports;
|
|
2284
2347
|
}
|
|
2348
|
+
/**
|
|
2349
|
+
* Extract export information (classes, interfaces, methods) using AST walk.
|
|
2350
|
+
*
|
|
2351
|
+
* @param rootNode - Root node of the Java AST.
|
|
2352
|
+
* @param code - Source code for documentation extraction.
|
|
2353
|
+
* @returns Array of discovered ExportInfo objects.
|
|
2354
|
+
*/
|
|
2285
2355
|
extractExportsAST(rootNode, code) {
|
|
2286
2356
|
const exports2 = [];
|
|
2287
2357
|
for (const node of rootNode.children) {
|
|
@@ -2312,11 +2382,25 @@ var JavaParser = class extends BaseLanguageParser {
|
|
|
2312
2382
|
}
|
|
2313
2383
|
return exports2;
|
|
2314
2384
|
}
|
|
2385
|
+
/**
|
|
2386
|
+
* Extract modifiers (visibility, static, etc.) from a node.
|
|
2387
|
+
*
|
|
2388
|
+
* @param node - AST node to extract modifiers from.
|
|
2389
|
+
* @returns Array of modifier strings.
|
|
2390
|
+
*/
|
|
2315
2391
|
getModifiers(node) {
|
|
2316
2392
|
const modifiersNode = node.children.find((c) => c.type === "modifiers");
|
|
2317
2393
|
if (!modifiersNode) return [];
|
|
2318
2394
|
return modifiersNode.children.map((c) => c.text);
|
|
2319
2395
|
}
|
|
2396
|
+
/**
|
|
2397
|
+
* Extract methods and nested exports from a class or interface body.
|
|
2398
|
+
*
|
|
2399
|
+
* @param parentNode - Class or interface declaration node.
|
|
2400
|
+
* @param parentName - Name of the parent class/interface.
|
|
2401
|
+
* @param exports - Array to collect discovered exports into.
|
|
2402
|
+
* @param code - Source code for context.
|
|
2403
|
+
*/
|
|
2320
2404
|
extractSubExports(parentNode, parentName, exports2, code) {
|
|
2321
2405
|
const bodyNode = parentNode.children.find((c) => c.type === "class_body");
|
|
2322
2406
|
if (!bodyNode) return;
|
|
@@ -2375,11 +2459,24 @@ var CSharpParser = class extends BaseLanguageParser {
|
|
|
2375
2459
|
getParserName() {
|
|
2376
2460
|
return "c_sharp";
|
|
2377
2461
|
}
|
|
2462
|
+
/**
|
|
2463
|
+
* Analyze metadata for a C# node (purity, side effects).
|
|
2464
|
+
*
|
|
2465
|
+
* @param node - Tree-sitter node to analyze.
|
|
2466
|
+
* @param code - Source code for context.
|
|
2467
|
+
* @returns Partial ExportInfo containing discovered metadata.
|
|
2468
|
+
*/
|
|
2378
2469
|
analyzeMetadata(node, code) {
|
|
2379
2470
|
return analyzeGeneralMetadata(node, code, {
|
|
2380
2471
|
sideEffectSignatures: ["Console.Write", "File.Write", "Logging."]
|
|
2381
2472
|
});
|
|
2382
2473
|
}
|
|
2474
|
+
/**
|
|
2475
|
+
* Fallback regex-based parsing when tree-sitter is unavailable.
|
|
2476
|
+
*
|
|
2477
|
+
* @param code - Source code content.
|
|
2478
|
+
* @returns Consolidated ParseResult.
|
|
2479
|
+
*/
|
|
2383
2480
|
parseRegex(code) {
|
|
2384
2481
|
const lines = code.split("\n");
|
|
2385
2482
|
const exports2 = [];
|
|
@@ -2441,6 +2538,12 @@ var CSharpParser = class extends BaseLanguageParser {
|
|
|
2441
2538
|
warnings: ["Parser falling back to regex-based analysis"]
|
|
2442
2539
|
};
|
|
2443
2540
|
}
|
|
2541
|
+
/**
|
|
2542
|
+
* Extract import information (usings) using AST walk.
|
|
2543
|
+
*
|
|
2544
|
+
* @param rootNode - Root node of the C# AST.
|
|
2545
|
+
* @returns Array of discovered FileImport objects.
|
|
2546
|
+
*/
|
|
2444
2547
|
extractImportsAST(rootNode) {
|
|
2445
2548
|
const imports = [];
|
|
2446
2549
|
const findUsings = (node) => {
|
|
@@ -2474,6 +2577,14 @@ var CSharpParser = class extends BaseLanguageParser {
|
|
|
2474
2577
|
findUsings(rootNode);
|
|
2475
2578
|
return imports;
|
|
2476
2579
|
}
|
|
2580
|
+
/**
|
|
2581
|
+
* Extract export information (classes, methods, properties) using AST walk.
|
|
2582
|
+
* Handles nested namespaces and classes.
|
|
2583
|
+
*
|
|
2584
|
+
* @param rootNode - Root node of the C# AST.
|
|
2585
|
+
* @param code - Source code for documentation extraction.
|
|
2586
|
+
* @returns Array of discovered ExportInfo objects.
|
|
2587
|
+
*/
|
|
2477
2588
|
extractExportsAST(rootNode, code) {
|
|
2478
2589
|
const exports2 = [];
|
|
2479
2590
|
const traverse = (node, currentNamespace, currentClass) => {
|
|
@@ -2585,11 +2696,24 @@ var GoParser = class extends BaseLanguageParser {
|
|
|
2585
2696
|
getParserName() {
|
|
2586
2697
|
return "go";
|
|
2587
2698
|
}
|
|
2699
|
+
/**
|
|
2700
|
+
* Analyze metadata for a Go node (purity, side effects).
|
|
2701
|
+
*
|
|
2702
|
+
* @param node - Tree-sitter node to analyze.
|
|
2703
|
+
* @param code - Source code for context.
|
|
2704
|
+
* @returns Partial ExportInfo containing discovered metadata.
|
|
2705
|
+
*/
|
|
2588
2706
|
analyzeMetadata(node, code) {
|
|
2589
2707
|
return analyzeGeneralMetadata(node, code, {
|
|
2590
2708
|
sideEffectSignatures: ["<-", "fmt.Print", "fmt.Fprintf", "os.Exit"]
|
|
2591
2709
|
});
|
|
2592
2710
|
}
|
|
2711
|
+
/**
|
|
2712
|
+
* Fallback regex-based parsing when tree-sitter is unavailable.
|
|
2713
|
+
*
|
|
2714
|
+
* @param code - Source code content.
|
|
2715
|
+
* @returns Consolidated ParseResult.
|
|
2716
|
+
*/
|
|
2593
2717
|
parseRegex(code) {
|
|
2594
2718
|
const lines = code.split("\n");
|
|
2595
2719
|
const exports2 = [];
|
|
@@ -2667,6 +2791,12 @@ var GoParser = class extends BaseLanguageParser {
|
|
|
2667
2791
|
warnings: ["Parser falling back to regex-based analysis"]
|
|
2668
2792
|
};
|
|
2669
2793
|
}
|
|
2794
|
+
/**
|
|
2795
|
+
* Extract import information using AST walk.
|
|
2796
|
+
*
|
|
2797
|
+
* @param rootNode - Root node of the Go AST.
|
|
2798
|
+
* @returns Array of discovered FileImport objects.
|
|
2799
|
+
*/
|
|
2670
2800
|
extractImportsAST(rootNode) {
|
|
2671
2801
|
const imports = [];
|
|
2672
2802
|
const findImports = (node) => {
|
|
@@ -2700,6 +2830,13 @@ var GoParser = class extends BaseLanguageParser {
|
|
|
2700
2830
|
findImports(rootNode);
|
|
2701
2831
|
return imports;
|
|
2702
2832
|
}
|
|
2833
|
+
/**
|
|
2834
|
+
* Extract export information (functions, types, vars) using AST walk.
|
|
2835
|
+
*
|
|
2836
|
+
* @param rootNode - Root node of the Go AST.
|
|
2837
|
+
* @param code - Source code for documentation extraction.
|
|
2838
|
+
* @returns Array of discovered ExportInfo objects.
|
|
2839
|
+
*/
|
|
2703
2840
|
extractExportsAST(rootNode, code) {
|
|
2704
2841
|
const exports2 = [];
|
|
2705
2842
|
const isExported = (name) => {
|
|
@@ -3056,7 +3193,7 @@ function extractTypeReferences(node) {
|
|
|
3056
3193
|
return Array.from(types);
|
|
3057
3194
|
}
|
|
3058
3195
|
|
|
3059
|
-
// src/utils/
|
|
3196
|
+
// src/utils/dependency-analyzer.ts
|
|
3060
3197
|
function parseFileExports(code, filePath) {
|
|
3061
3198
|
const parser = getParser(filePath);
|
|
3062
3199
|
if (parser && parser.language !== "typescript" /* TypeScript */ && parser.language !== "javascript" /* JavaScript */) {
|
|
@@ -3098,29 +3235,6 @@ function parseFileExports(code, filePath) {
|
|
|
3098
3235
|
return { exports: [], imports: [] };
|
|
3099
3236
|
}
|
|
3100
3237
|
}
|
|
3101
|
-
function calculateImportSimilarity(export1, export2) {
|
|
3102
|
-
if (export1.imports.length === 0 && export2.imports.length === 0) {
|
|
3103
|
-
return 1;
|
|
3104
|
-
}
|
|
3105
|
-
const set1 = new Set(export1.imports);
|
|
3106
|
-
const set2 = new Set(export2.imports);
|
|
3107
|
-
const intersection = new Set([...set1].filter((x) => set2.has(x)));
|
|
3108
|
-
const union = /* @__PURE__ */ new Set([...set1, ...set2]);
|
|
3109
|
-
return intersection.size / union.size;
|
|
3110
|
-
}
|
|
3111
|
-
function parseCode(_code, _language) {
|
|
3112
|
-
void _code;
|
|
3113
|
-
void _language;
|
|
3114
|
-
return null;
|
|
3115
|
-
}
|
|
3116
|
-
function extractFunctions(_ast) {
|
|
3117
|
-
void _ast;
|
|
3118
|
-
return [];
|
|
3119
|
-
}
|
|
3120
|
-
function extractImports(_ast) {
|
|
3121
|
-
void _ast;
|
|
3122
|
-
return [];
|
|
3123
|
-
}
|
|
3124
3238
|
|
|
3125
3239
|
// src/utils/metrics.ts
|
|
3126
3240
|
function estimateTokens(text) {
|
|
@@ -3169,10 +3283,25 @@ async function loadConfig(rootDir) {
|
|
|
3169
3283
|
const content = (0, import_fs3.readFileSync)(configPath, "utf-8");
|
|
3170
3284
|
config = JSON.parse(content);
|
|
3171
3285
|
}
|
|
3172
|
-
|
|
3173
|
-
|
|
3286
|
+
const legacyKeys = ["toolConfigs"];
|
|
3287
|
+
const rootLevelTools = [
|
|
3288
|
+
"pattern-detect",
|
|
3289
|
+
"context-analyzer",
|
|
3290
|
+
"naming-consistency",
|
|
3291
|
+
"ai-signal-clarity"
|
|
3292
|
+
];
|
|
3293
|
+
const allKeys = Object.keys(config);
|
|
3294
|
+
const foundLegacy = allKeys.filter(
|
|
3295
|
+
(k) => legacyKeys.includes(k) || rootLevelTools.includes(k)
|
|
3296
|
+
);
|
|
3297
|
+
if (foundLegacy.length > 0) {
|
|
3298
|
+
console.warn(
|
|
3299
|
+
`\u26A0\uFE0F Legacy configuration keys found: ${foundLegacy.join(
|
|
3300
|
+
", "
|
|
3301
|
+
)}. These are deprecated and should be moved under the "tools" key.`
|
|
3302
|
+
);
|
|
3174
3303
|
}
|
|
3175
|
-
return config;
|
|
3304
|
+
return AIReadyConfigSchema.parse(config);
|
|
3176
3305
|
} catch (error) {
|
|
3177
3306
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3178
3307
|
const configError = new Error(
|
|
@@ -3200,12 +3329,10 @@ function mergeConfigWithDefaults(userConfig, defaults) {
|
|
|
3200
3329
|
if (userConfig.scan.include) mergedConfig.include = userConfig.scan.include;
|
|
3201
3330
|
if (userConfig.scan.exclude) mergedConfig.exclude = userConfig.scan.exclude;
|
|
3202
3331
|
}
|
|
3203
|
-
|
|
3204
|
-
if (toolOverrides) {
|
|
3332
|
+
if (userConfig.tools) {
|
|
3205
3333
|
if (!mergedConfig.toolConfigs) mergedConfig.toolConfigs = {};
|
|
3206
|
-
for (const [toolName, toolConfig] of Object.entries(
|
|
3334
|
+
for (const [toolName, toolConfig] of Object.entries(userConfig.tools)) {
|
|
3207
3335
|
if (typeof toolConfig === "object" && toolConfig !== null) {
|
|
3208
|
-
mergedConfig[toolName] = { ...mergedConfig[toolName], ...toolConfig };
|
|
3209
3336
|
mergedConfig.toolConfigs[toolName] = {
|
|
3210
3337
|
...mergedConfig.toolConfigs[toolName],
|
|
3211
3338
|
...toolConfig
|
|
@@ -3507,12 +3634,12 @@ function getRecommendedThreshold(fileCount, modelTier = "standard") {
|
|
|
3507
3634
|
return base + modelBonus;
|
|
3508
3635
|
}
|
|
3509
3636
|
function normalizeToolName(shortName) {
|
|
3510
|
-
return TOOL_NAME_MAP[shortName.toLowerCase()]
|
|
3637
|
+
return TOOL_NAME_MAP[shortName.toLowerCase()] ?? shortName;
|
|
3511
3638
|
}
|
|
3512
3639
|
function getToolWeight(toolName, toolConfig, cliOverride, profile = "default" /* Default */) {
|
|
3513
3640
|
if (cliOverride !== void 0) return cliOverride;
|
|
3514
3641
|
if (toolConfig?.scoreWeight !== void 0) return toolConfig.scoreWeight;
|
|
3515
|
-
const profileWeights = SCORING_PROFILES[profile]
|
|
3642
|
+
const profileWeights = SCORING_PROFILES[profile] ?? DEFAULT_TOOL_WEIGHTS;
|
|
3516
3643
|
return profileWeights[toolName] ?? DEFAULT_TOOL_WEIGHTS[toolName] ?? 5;
|
|
3517
3644
|
}
|
|
3518
3645
|
function parseWeightString(weightStr) {
|
|
@@ -3549,7 +3676,7 @@ function calculateOverallScore(toolOutputs, config, cliWeights) {
|
|
|
3549
3676
|
const toolsUsed = [];
|
|
3550
3677
|
const calculationWeights = {};
|
|
3551
3678
|
for (const [toolName, output] of toolOutputs.entries()) {
|
|
3552
|
-
const weight = weights.get(toolName)
|
|
3679
|
+
const weight = weights.get(toolName) ?? 5;
|
|
3553
3680
|
weightedSum += output.score * weight;
|
|
3554
3681
|
totalWeight += weight;
|
|
3555
3682
|
toolsUsed.push(toolName);
|
|
@@ -3560,7 +3687,7 @@ function calculateOverallScore(toolOutputs, config, cliWeights) {
|
|
|
3560
3687
|
const rating = getRating(overall);
|
|
3561
3688
|
const formulaParts = Array.from(toolOutputs.entries()).map(
|
|
3562
3689
|
([name, output]) => {
|
|
3563
|
-
const w = weights.get(name)
|
|
3690
|
+
const w = weights.get(name) ?? 5;
|
|
3564
3691
|
return `(${output.score} \xD7 ${w})`;
|
|
3565
3692
|
}
|
|
3566
3693
|
);
|
|
@@ -3653,6 +3780,13 @@ function formatToolScore(output) {
|
|
|
3653
3780
|
|
|
3654
3781
|
// src/business/pricing-models.ts
|
|
3655
3782
|
var MODEL_PRICING_PRESETS = {
|
|
3783
|
+
"gpt-5.4-mini": {
|
|
3784
|
+
name: "GPT-5.4 Mini",
|
|
3785
|
+
pricePer1KInputTokens: 1e-4,
|
|
3786
|
+
pricePer1KOutputTokens: 4e-4,
|
|
3787
|
+
contextTier: "extended",
|
|
3788
|
+
typicalQueriesPerDevPerDay: 200
|
|
3789
|
+
},
|
|
3656
3790
|
"gpt-5.3": {
|
|
3657
3791
|
name: "GPT-5.3",
|
|
3658
3792
|
pricePer1KInputTokens: 2e-3,
|
|
@@ -3674,20 +3808,6 @@ var MODEL_PRICING_PRESETS = {
|
|
|
3674
3808
|
contextTier: "frontier",
|
|
3675
3809
|
typicalQueriesPerDevPerDay: 120
|
|
3676
3810
|
},
|
|
3677
|
-
"gpt-4o": {
|
|
3678
|
-
name: "GPT-4o (legacy)",
|
|
3679
|
-
pricePer1KInputTokens: 5e-3,
|
|
3680
|
-
pricePer1KOutputTokens: 0.015,
|
|
3681
|
-
contextTier: "extended",
|
|
3682
|
-
typicalQueriesPerDevPerDay: 60
|
|
3683
|
-
},
|
|
3684
|
-
"claude-3-5-sonnet": {
|
|
3685
|
-
name: "Claude 3.5 Sonnet (legacy)",
|
|
3686
|
-
pricePer1KInputTokens: 3e-3,
|
|
3687
|
-
pricePer1KOutputTokens: 0.015,
|
|
3688
|
-
contextTier: "extended",
|
|
3689
|
-
typicalQueriesPerDevPerDay: 80
|
|
3690
|
-
},
|
|
3691
3811
|
"gemini-1-5-pro": {
|
|
3692
3812
|
name: "Gemini 1.5 Pro (legacy)",
|
|
3693
3813
|
pricePer1KInputTokens: 125e-5,
|
|
@@ -3711,7 +3831,7 @@ var MODEL_PRICING_PRESETS = {
|
|
|
3711
3831
|
}
|
|
3712
3832
|
};
|
|
3713
3833
|
function getModelPreset(modelId) {
|
|
3714
|
-
return MODEL_PRICING_PRESETS[modelId] ?? MODEL_PRICING_PRESETS["
|
|
3834
|
+
return MODEL_PRICING_PRESETS[modelId] ?? MODEL_PRICING_PRESETS["gpt-5.4-mini"];
|
|
3715
3835
|
}
|
|
3716
3836
|
|
|
3717
3837
|
// src/business/cost-metrics.ts
|
|
@@ -3732,7 +3852,7 @@ function calculateMonthlyCost(tokenWaste, config = {}) {
|
|
|
3732
3852
|
// Added baseline chattiness
|
|
3733
3853
|
}
|
|
3734
3854
|
});
|
|
3735
|
-
const preset = getModelPreset("
|
|
3855
|
+
const preset = getModelPreset("gpt-5.4-mini");
|
|
3736
3856
|
return estimateCostFromBudget(budget, preset, config);
|
|
3737
3857
|
}
|
|
3738
3858
|
function calculateTokenBudget(params) {
|
|
@@ -4578,12 +4698,12 @@ function calculateTestabilityIndex(params) {
|
|
|
4578
4698
|
const rawCoverageRatio = sourceFiles > 0 ? testFiles / sourceFiles : 0;
|
|
4579
4699
|
const testCoverageRatio = Math.min(100, Math.round(rawCoverageRatio * 100));
|
|
4580
4700
|
const purityScore = Math.round(
|
|
4581
|
-
(totalFunctions > 0 ? pureFunctions / totalFunctions : 0.
|
|
4701
|
+
(totalFunctions > 0 ? pureFunctions / totalFunctions : 0.7) * 100
|
|
4582
4702
|
);
|
|
4583
4703
|
const dependencyInjectionScore = Math.round(
|
|
4584
4704
|
Math.min(
|
|
4585
4705
|
100,
|
|
4586
|
-
(totalClasses > 0 ? injectionPatterns / totalClasses : 0.
|
|
4706
|
+
(totalClasses > 0 ? injectionPatterns / totalClasses : 0.8) * 100
|
|
4587
4707
|
)
|
|
4588
4708
|
);
|
|
4589
4709
|
const interfaceFocusScore = Math.max(
|
|
@@ -4664,9 +4784,9 @@ function calculateDocDrift(params) {
|
|
|
4664
4784
|
const outdatedRatio = totalExports > 0 ? outdatedComments / totalExports : 0;
|
|
4665
4785
|
const complexityRatio = totalExports > 0 ? undocumentedComplexity / totalExports : 0;
|
|
4666
4786
|
const driftRatio = totalExports > 0 ? actualDrift / totalExports : 0;
|
|
4667
|
-
const DRIFT_THRESHOLD = 0.
|
|
4668
|
-
const OUTDATED_THRESHOLD = 0.
|
|
4669
|
-
const COMPLEXITY_THRESHOLD = 0.
|
|
4787
|
+
const DRIFT_THRESHOLD = 0.35;
|
|
4788
|
+
const OUTDATED_THRESHOLD = 0.5;
|
|
4789
|
+
const COMPLEXITY_THRESHOLD = 0.3;
|
|
4670
4790
|
const UNCOMMENTED_THRESHOLD = 0.8;
|
|
4671
4791
|
const driftRisk = Math.min(100, driftRatio / DRIFT_THRESHOLD * 100);
|
|
4672
4792
|
const outdatedRisk = Math.min(
|
|
@@ -5132,6 +5252,7 @@ function emitIssuesAsAnnotations(issues) {
|
|
|
5132
5252
|
}
|
|
5133
5253
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5134
5254
|
0 && (module.exports = {
|
|
5255
|
+
AIReadyConfigSchema,
|
|
5135
5256
|
AnalysisResultSchema,
|
|
5136
5257
|
AnalysisStatus,
|
|
5137
5258
|
AnalysisStatusSchema,
|
|
@@ -5213,8 +5334,6 @@ function emitIssuesAsAnnotations(issues) {
|
|
|
5213
5334
|
estimateCostFromBudget,
|
|
5214
5335
|
estimateTokens,
|
|
5215
5336
|
exportHistory,
|
|
5216
|
-
extractFunctions,
|
|
5217
|
-
extractImports,
|
|
5218
5337
|
findLatestReport,
|
|
5219
5338
|
findLatestScanReport,
|
|
5220
5339
|
formatAcceptanceRate,
|
|
@@ -5259,8 +5378,11 @@ function emitIssuesAsAnnotations(issues) {
|
|
|
5259
5378
|
loadMergedConfig,
|
|
5260
5379
|
loadScoreHistory,
|
|
5261
5380
|
mergeConfigWithDefaults,
|
|
5381
|
+
normalizeAnalysisResult,
|
|
5382
|
+
normalizeIssue,
|
|
5383
|
+
normalizeMetrics,
|
|
5384
|
+
normalizeSpokeOutput,
|
|
5262
5385
|
normalizeToolName,
|
|
5263
|
-
parseCode,
|
|
5264
5386
|
parseFileExports,
|
|
5265
5387
|
parseWeightString,
|
|
5266
5388
|
predictAcceptanceRate,
|