@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.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
AIReadyConfigSchema,
|
|
2
3
|
AnalysisResultSchema,
|
|
3
4
|
AnalysisStatus,
|
|
4
5
|
AnalysisStatusSchema,
|
|
@@ -49,53 +50,102 @@ import {
|
|
|
49
50
|
getToolWeight,
|
|
50
51
|
normalizeToolName,
|
|
51
52
|
parseWeightString
|
|
52
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-TJXR2CHZ.mjs";
|
|
54
|
+
|
|
55
|
+
// src/utils/normalization.ts
|
|
56
|
+
function normalizeIssue(raw) {
|
|
57
|
+
return {
|
|
58
|
+
type: raw.type ?? "pattern-inconsistency" /* PatternInconsistency */,
|
|
59
|
+
severity: raw.severity ?? raw.severityLevel ?? "info" /* Info */,
|
|
60
|
+
message: raw.message ?? "Unknown issue",
|
|
61
|
+
location: raw.location ?? {
|
|
62
|
+
file: raw.fileName ?? raw.file ?? raw.filePath ?? "unknown",
|
|
63
|
+
line: raw.line ?? 1,
|
|
64
|
+
column: raw.column
|
|
65
|
+
},
|
|
66
|
+
suggestion: raw.suggestion
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function normalizeMetrics(raw) {
|
|
70
|
+
return {
|
|
71
|
+
tokenCost: raw.tokenCost ?? 0,
|
|
72
|
+
complexityScore: raw.complexityScore ?? 0,
|
|
73
|
+
consistencyScore: raw.consistencyScore,
|
|
74
|
+
docFreshnessScore: raw.docFreshnessScore,
|
|
75
|
+
aiSignalClarityScore: raw.aiSignalClarityScore,
|
|
76
|
+
agentGroundingScore: raw.agentGroundingScore,
|
|
77
|
+
testabilityScore: raw.testabilityScore,
|
|
78
|
+
docDriftScore: raw.docDriftScore,
|
|
79
|
+
dependencyHealthScore: raw.dependencyHealthScore,
|
|
80
|
+
modelContextTier: raw.modelContextTier,
|
|
81
|
+
estimatedMonthlyCost: raw.estimatedMonthlyCost,
|
|
82
|
+
estimatedDeveloperHours: raw.estimatedDeveloperHours,
|
|
83
|
+
comprehensionDifficultyIndex: raw.comprehensionDifficultyIndex,
|
|
84
|
+
totalSymbols: raw.totalSymbols,
|
|
85
|
+
totalExports: raw.totalExports
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function normalizeAnalysisResult(raw) {
|
|
89
|
+
const fileName = raw.fileName ?? raw.file ?? raw.filePath ?? "unknown";
|
|
90
|
+
const rawIssues = Array.isArray(raw.issues) ? raw.issues : [];
|
|
91
|
+
return {
|
|
92
|
+
fileName,
|
|
93
|
+
issues: rawIssues.map((issue) => {
|
|
94
|
+
if (typeof issue === "string") {
|
|
95
|
+
return {
|
|
96
|
+
type: "pattern-inconsistency" /* PatternInconsistency */,
|
|
97
|
+
// Default fallback
|
|
98
|
+
severity: raw.severity ?? "info" /* Info */,
|
|
99
|
+
message: issue,
|
|
100
|
+
location: { file: fileName, line: 1 }
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return normalizeIssue({
|
|
104
|
+
...issue,
|
|
105
|
+
fileName: issue.fileName ?? fileName,
|
|
106
|
+
severity: issue.severity ?? raw.severity
|
|
107
|
+
});
|
|
108
|
+
}),
|
|
109
|
+
metrics: normalizeMetrics(raw.metrics ?? {})
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function normalizeSpokeOutput(raw, toolName) {
|
|
113
|
+
const rawResults = Array.isArray(raw.results) ? raw.results : [];
|
|
114
|
+
return {
|
|
115
|
+
results: rawResults.map(normalizeAnalysisResult),
|
|
116
|
+
summary: raw.summary ?? {
|
|
117
|
+
totalFiles: rawResults.length,
|
|
118
|
+
totalIssues: 0,
|
|
119
|
+
criticalIssues: 0,
|
|
120
|
+
majorIssues: 0
|
|
121
|
+
},
|
|
122
|
+
metadata: {
|
|
123
|
+
toolName: raw.metadata?.toolName ?? toolName,
|
|
124
|
+
version: raw.metadata?.version,
|
|
125
|
+
timestamp: raw.metadata?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
126
|
+
config: raw.metadata?.config
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
53
130
|
|
|
54
131
|
// src/types/contract.ts
|
|
55
132
|
function validateSpokeOutput(toolName, output) {
|
|
56
|
-
const errors = [];
|
|
57
133
|
if (!output) {
|
|
58
134
|
return { valid: false, errors: ["Output is null or undefined"] };
|
|
59
135
|
}
|
|
60
|
-
if (!Array.isArray(output.results)) {
|
|
61
|
-
errors.push(`${toolName}: 'results' must be an array`);
|
|
62
|
-
} else {
|
|
63
|
-
output.results.forEach((res, idx) => {
|
|
64
|
-
const fileName = res.fileName || res.file || res.filePath;
|
|
65
|
-
if (!fileName)
|
|
66
|
-
errors.push(
|
|
67
|
-
`${toolName}: results[${idx}] missing 'fileName', 'file' or 'filePath'`
|
|
68
|
-
);
|
|
69
|
-
const issues = res.issues;
|
|
70
|
-
if (!Array.isArray(issues)) {
|
|
71
|
-
errors.push(`${toolName}: results[${idx}] 'issues' must be an array`);
|
|
72
|
-
} else if (issues.length > 0) {
|
|
73
|
-
issues.forEach((issue, iidx) => {
|
|
74
|
-
if (typeof issue === "string") return;
|
|
75
|
-
if (!issue.type && !res.file)
|
|
76
|
-
errors.push(
|
|
77
|
-
`${toolName}: results[${idx}].issues[${iidx}] missing 'type'`
|
|
78
|
-
);
|
|
79
|
-
if (!issue.severity && !res.severity)
|
|
80
|
-
errors.push(
|
|
81
|
-
`${toolName}: results[${idx}].issues[${iidx}] missing 'severity'`
|
|
82
|
-
);
|
|
83
|
-
const severity = issue.severity || res.severity;
|
|
84
|
-
if (severity && !["critical", "major", "minor", "info"].includes(severity)) {
|
|
85
|
-
errors.push(
|
|
86
|
-
`${toolName}: results[${idx}].issues[${iidx}] has invalid severity: ${severity}`
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
136
|
if (!output.summary) {
|
|
94
|
-
errors
|
|
137
|
+
return { valid: false, errors: [`${toolName}: missing 'summary'`] };
|
|
138
|
+
}
|
|
139
|
+
const normalized = normalizeSpokeOutput(output, toolName);
|
|
140
|
+
const result = SpokeOutputSchema.safeParse(normalized);
|
|
141
|
+
if (result.success) {
|
|
142
|
+
return { valid: true, errors: [] };
|
|
95
143
|
}
|
|
96
144
|
return {
|
|
97
|
-
valid:
|
|
98
|
-
errors
|
|
145
|
+
valid: false,
|
|
146
|
+
errors: result.error.issues.map(
|
|
147
|
+
(e) => `${toolName}: ${e.path.join(".")}: ${e.message}`
|
|
148
|
+
)
|
|
99
149
|
};
|
|
100
150
|
}
|
|
101
151
|
function validateWithSchema(schema, data) {
|
|
@@ -464,7 +514,7 @@ function resolveOutputPath(userPath, defaultFilename, workingDir = process.cwd()
|
|
|
464
514
|
if (statSync(workingDir).isFile()) {
|
|
465
515
|
baseDir = dirname2(workingDir);
|
|
466
516
|
}
|
|
467
|
-
} catch
|
|
517
|
+
} catch {
|
|
468
518
|
}
|
|
469
519
|
const aireadyDir = join2(baseDir, ".aiready");
|
|
470
520
|
outputPath = join2(aireadyDir, defaultFilename);
|
|
@@ -636,8 +686,8 @@ function findLatestScanReport(scanReportsDir, reportFilePrefix) {
|
|
|
636
686
|
return idB - idA;
|
|
637
687
|
});
|
|
638
688
|
return join2(scanReportsDir, reportFiles[0]);
|
|
639
|
-
} catch
|
|
640
|
-
console.error("Error while finding latest scan report
|
|
689
|
+
} catch {
|
|
690
|
+
console.error("Error while finding latest scan report");
|
|
641
691
|
return null;
|
|
642
692
|
}
|
|
643
693
|
}
|
|
@@ -702,7 +752,19 @@ function createProvider(config) {
|
|
|
702
752
|
};
|
|
703
753
|
}
|
|
704
754
|
|
|
705
|
-
// src/utils/
|
|
755
|
+
// src/utils/similarity-utils.ts
|
|
756
|
+
function calculateImportSimilarity(export1, export2) {
|
|
757
|
+
if (export1.imports.length === 0 && export2.imports.length === 0) {
|
|
758
|
+
return 1;
|
|
759
|
+
}
|
|
760
|
+
const set1 = new Set(export1.imports);
|
|
761
|
+
const set2 = new Set(export2.imports);
|
|
762
|
+
const intersection = new Set([...set1].filter((x) => set2.has(x)));
|
|
763
|
+
const union = /* @__PURE__ */ new Set([...set1, ...set2]);
|
|
764
|
+
return intersection.size / union.size;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
// src/utils/dependency-analyzer.ts
|
|
706
768
|
import { parse as parse2 } from "@typescript-eslint/typescript-estree";
|
|
707
769
|
|
|
708
770
|
// src/parsers/typescript-parser.ts
|
|
@@ -713,148 +775,67 @@ var TypeScriptParser = class {
|
|
|
713
775
|
this.extensions = [".ts", ".tsx", ".js", ".jsx"];
|
|
714
776
|
}
|
|
715
777
|
async initialize() {
|
|
716
|
-
return Promise.resolve();
|
|
717
778
|
}
|
|
718
|
-
|
|
719
|
-
return
|
|
720
|
-
loc: true,
|
|
721
|
-
range: true,
|
|
722
|
-
jsx: filePath.match(/\.[jt]sx$/i) !== null,
|
|
723
|
-
filePath,
|
|
724
|
-
sourceType: "module",
|
|
725
|
-
ecmaVersion: "latest",
|
|
726
|
-
comment: true
|
|
727
|
-
});
|
|
779
|
+
canHandle(filePath) {
|
|
780
|
+
return this.extensions.some((ext) => filePath.endsWith(ext));
|
|
728
781
|
}
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
const precedingStartOffset = Math.max(0, start - 1e3);
|
|
745
|
-
const absoluteStartOffset = precedingStartOffset + (lastMatch.index || 0);
|
|
746
|
-
const absoluteEndOffset = precedingStartOffset + matchEndIndex;
|
|
747
|
-
const codeBeforeStart = code.slice(0, absoluteStartOffset);
|
|
748
|
-
const startLines = codeBeforeStart.split("\n");
|
|
749
|
-
const startLine = startLines.length;
|
|
750
|
-
const startColumn = startLines[startLines.length - 1].length;
|
|
751
|
-
const codeBeforeEnd = code.slice(0, absoluteEndOffset);
|
|
752
|
-
const endLines = codeBeforeEnd.split("\n");
|
|
753
|
-
const endLine = endLines.length;
|
|
754
|
-
const endColumn = endLines[endLines.length - 1].length;
|
|
755
|
-
metadata.documentation = {
|
|
756
|
-
content: lastMatch[1].replace(/^\s*\*+/gm, "").trim(),
|
|
757
|
-
type: "jsdoc",
|
|
758
|
-
loc: {
|
|
759
|
-
start: { line: startLine, column: startColumn },
|
|
760
|
-
end: { line: endLine, column: endColumn }
|
|
761
|
-
}
|
|
762
|
-
};
|
|
763
|
-
}
|
|
764
|
-
}
|
|
765
|
-
const walk = (n) => {
|
|
766
|
-
if (!n) return;
|
|
767
|
-
if (n.type === "AssignmentExpression") {
|
|
768
|
-
metadata.isPure = false;
|
|
769
|
-
metadata.hasSideEffects = true;
|
|
770
|
-
}
|
|
771
|
-
if (n.type === "UpdateExpression") {
|
|
772
|
-
metadata.isPure = false;
|
|
773
|
-
metadata.hasSideEffects = true;
|
|
774
|
-
}
|
|
775
|
-
if (n.type === "CallExpression" && n.callee.type === "MemberExpression" && n.callee.object.type === "Identifier") {
|
|
776
|
-
const objName = n.callee.object.name;
|
|
777
|
-
if (["console", "process", "fs", "window", "document"].includes(objName)) {
|
|
778
|
-
metadata.isPure = false;
|
|
779
|
-
metadata.hasSideEffects = true;
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
if (n.type === "ThrowStatement") {
|
|
783
|
-
metadata.isPure = false;
|
|
784
|
-
metadata.hasSideEffects = true;
|
|
785
|
-
}
|
|
786
|
-
for (const key of Object.keys(n)) {
|
|
787
|
-
if (key === "parent") continue;
|
|
788
|
-
const child = n[key];
|
|
789
|
-
if (child && typeof child === "object") {
|
|
790
|
-
if (Array.isArray(child)) {
|
|
791
|
-
child.forEach((c) => c?.type && walk(c));
|
|
792
|
-
} else if (child.type) {
|
|
793
|
-
walk(child);
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
};
|
|
798
|
-
let nodeToAnalyze = node;
|
|
799
|
-
if (node.type === "ExportNamedDeclaration" && node.declaration) {
|
|
800
|
-
nodeToAnalyze = node.declaration;
|
|
801
|
-
} else if (node.type === "ExportDefaultDeclaration" && node.declaration) {
|
|
802
|
-
if (node.declaration.type !== "TSInterfaceDeclaration" && node.declaration.type !== "TSTypeAliasDeclaration") {
|
|
803
|
-
nodeToAnalyze = node.declaration;
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
if (nodeToAnalyze.type === "FunctionDeclaration" || nodeToAnalyze.type === "FunctionExpression" || nodeToAnalyze.type === "ArrowFunctionExpression") {
|
|
807
|
-
if (nodeToAnalyze.body) walk(nodeToAnalyze.body);
|
|
808
|
-
} else if (nodeToAnalyze.type === "ClassDeclaration" || nodeToAnalyze.type === "ClassExpression") {
|
|
809
|
-
walk(nodeToAnalyze.body);
|
|
782
|
+
async getAST(code, filePath) {
|
|
783
|
+
try {
|
|
784
|
+
return parse(code, {
|
|
785
|
+
filePath,
|
|
786
|
+
loc: true,
|
|
787
|
+
range: true,
|
|
788
|
+
tokens: true,
|
|
789
|
+
comment: true,
|
|
790
|
+
jsx: filePath.endsWith("x")
|
|
791
|
+
});
|
|
792
|
+
} catch (error) {
|
|
793
|
+
throw new ParseError(error.message, filePath, {
|
|
794
|
+
line: error.lineNumber || 1,
|
|
795
|
+
column: error.column || 0
|
|
796
|
+
});
|
|
810
797
|
}
|
|
811
|
-
return metadata;
|
|
812
798
|
}
|
|
813
799
|
parse(code, filePath) {
|
|
814
800
|
try {
|
|
815
|
-
const isJavaScript = filePath.match(/\.jsx?$/i);
|
|
816
801
|
const ast = parse(code, {
|
|
802
|
+
filePath,
|
|
817
803
|
loc: true,
|
|
818
804
|
range: true,
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
ecmaVersion: "latest",
|
|
823
|
-
comment: true
|
|
805
|
+
tokens: true,
|
|
806
|
+
comment: true,
|
|
807
|
+
jsx: filePath.endsWith("x")
|
|
824
808
|
});
|
|
825
809
|
const imports = this.extractImports(ast);
|
|
826
|
-
const exports = this.extractExports(ast,
|
|
810
|
+
const exports = this.extractExports(ast, code);
|
|
827
811
|
return {
|
|
828
812
|
exports,
|
|
829
813
|
imports,
|
|
830
|
-
language:
|
|
831
|
-
warnings: []
|
|
814
|
+
language: this.language
|
|
832
815
|
};
|
|
833
816
|
} catch (error) {
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
);
|
|
817
|
+
throw new ParseError(error.message, filePath, {
|
|
818
|
+
line: error.lineNumber || 1,
|
|
819
|
+
column: error.column || 0
|
|
820
|
+
});
|
|
839
821
|
}
|
|
840
822
|
}
|
|
841
823
|
getNamingConventions() {
|
|
842
824
|
return {
|
|
843
|
-
// camelCase for variables and functions
|
|
844
825
|
variablePattern: /^[a-z][a-zA-Z0-9]*$/,
|
|
845
826
|
functionPattern: /^[a-z][a-zA-Z0-9]*$/,
|
|
846
|
-
// PascalCase for classes, types and interfaces
|
|
847
827
|
classPattern: /^[A-Z][a-zA-Z0-9]*$/,
|
|
848
|
-
typePattern: /^[A-Z][a-zA-Z0-9]*$/,
|
|
849
|
-
interfacePattern: /^[A-Z][a-zA-Z0-9]*$/,
|
|
850
|
-
// UPPER_CASE for constants
|
|
851
828
|
constantPattern: /^[A-Z][A-Z0-9_]*$/,
|
|
852
|
-
|
|
853
|
-
|
|
829
|
+
typePattern: /^[A-Z][a-zA-Z0-9]*$/,
|
|
830
|
+
interfacePattern: /^I?[A-Z][a-zA-Z0-9]*$/
|
|
854
831
|
};
|
|
855
832
|
}
|
|
856
|
-
|
|
857
|
-
|
|
833
|
+
analyzeMetadata(node, code) {
|
|
834
|
+
if (!code) return {};
|
|
835
|
+
return {
|
|
836
|
+
isPure: this.isLikelyPure(node),
|
|
837
|
+
hasSideEffects: !this.isLikelyPure(node)
|
|
838
|
+
};
|
|
858
839
|
}
|
|
859
840
|
extractImports(ast) {
|
|
860
841
|
const imports = [];
|
|
@@ -892,168 +873,165 @@ var TypeScriptParser = class {
|
|
|
892
873
|
}
|
|
893
874
|
return imports;
|
|
894
875
|
}
|
|
895
|
-
extractExports(ast,
|
|
876
|
+
extractExports(ast, code) {
|
|
896
877
|
const exports = [];
|
|
897
|
-
const importedNames = new Set(
|
|
898
|
-
imports.flatMap(
|
|
899
|
-
(imp) => imp.specifiers.filter((s) => s !== "*" && s !== "default")
|
|
900
|
-
)
|
|
901
|
-
);
|
|
902
878
|
for (const node of ast.body) {
|
|
903
|
-
if (node.type === "ExportNamedDeclaration"
|
|
904
|
-
|
|
905
|
-
node.declaration
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
879
|
+
if (node.type === "ExportNamedDeclaration") {
|
|
880
|
+
if (node.declaration) {
|
|
881
|
+
const declaration = node.declaration;
|
|
882
|
+
if ((declaration.type === "FunctionDeclaration" || declaration.type === "TSDeclareFunction") && declaration.id) {
|
|
883
|
+
exports.push(
|
|
884
|
+
this.createExport(
|
|
885
|
+
declaration.id.name,
|
|
886
|
+
"function",
|
|
887
|
+
node,
|
|
888
|
+
// Pass the outer ExportNamedDeclaration
|
|
889
|
+
code
|
|
890
|
+
)
|
|
891
|
+
);
|
|
892
|
+
} else if (declaration.type === "ClassDeclaration" && declaration.id) {
|
|
893
|
+
exports.push(
|
|
894
|
+
this.createExport(
|
|
895
|
+
declaration.id.name,
|
|
896
|
+
"class",
|
|
897
|
+
node,
|
|
898
|
+
// Pass the outer ExportNamedDeclaration
|
|
899
|
+
code
|
|
900
|
+
)
|
|
901
|
+
);
|
|
902
|
+
} else if (declaration.type === "TSTypeAliasDeclaration") {
|
|
903
|
+
exports.push(
|
|
904
|
+
this.createExport(
|
|
905
|
+
declaration.id.name,
|
|
906
|
+
"type",
|
|
907
|
+
node,
|
|
908
|
+
// Pass the outer ExportNamedDeclaration
|
|
909
|
+
code
|
|
910
|
+
)
|
|
911
|
+
);
|
|
912
|
+
} else if (declaration.type === "TSInterfaceDeclaration") {
|
|
913
|
+
exports.push(
|
|
914
|
+
this.createExport(
|
|
915
|
+
declaration.id.name,
|
|
916
|
+
"interface",
|
|
917
|
+
node,
|
|
918
|
+
// Pass the outer ExportNamedDeclaration
|
|
919
|
+
code
|
|
920
|
+
)
|
|
921
|
+
);
|
|
922
|
+
} else if (declaration.type === "VariableDeclaration") {
|
|
923
|
+
for (const decl of declaration.declarations) {
|
|
924
|
+
if (decl.id.type === "Identifier") {
|
|
925
|
+
exports.push(
|
|
926
|
+
this.createExport(
|
|
927
|
+
decl.id.name,
|
|
928
|
+
"const",
|
|
929
|
+
node,
|
|
930
|
+
// Pass the outer ExportNamedDeclaration
|
|
931
|
+
code,
|
|
932
|
+
decl.init
|
|
933
|
+
)
|
|
934
|
+
);
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
}
|
|
922
938
|
}
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
type,
|
|
926
|
-
loc: node.loc ? {
|
|
927
|
-
start: {
|
|
928
|
-
line: node.loc.start.line,
|
|
929
|
-
column: node.loc.start.column
|
|
930
|
-
},
|
|
931
|
-
end: { line: node.loc.end.line, column: node.loc.end.column }
|
|
932
|
-
} : void 0,
|
|
933
|
-
...metadata
|
|
934
|
-
});
|
|
939
|
+
} else if (node.type === "ExportDefaultDeclaration") {
|
|
940
|
+
exports.push(this.createExport("default", "default", node, code));
|
|
935
941
|
}
|
|
936
942
|
}
|
|
937
943
|
return exports;
|
|
938
944
|
}
|
|
939
|
-
|
|
940
|
-
const
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
945
|
+
createExport(name, type, node, code, initializer) {
|
|
946
|
+
const documentation = this.extractDocumentation(node, code);
|
|
947
|
+
let methodCount;
|
|
948
|
+
let propertyCount;
|
|
949
|
+
let parameters;
|
|
950
|
+
let isPrimitive = false;
|
|
951
|
+
if (initializer) {
|
|
952
|
+
if (initializer.type === "Literal" || initializer.type === "TemplateLiteral" && initializer.expressions.length === 0) {
|
|
953
|
+
isPrimitive = true;
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
const structNode = node.type === "ExportNamedDeclaration" ? node.declaration : node.type === "ExportDefaultDeclaration" ? node.declaration : node;
|
|
957
|
+
if (structNode.type === "ClassDeclaration" || structNode.type === "TSInterfaceDeclaration") {
|
|
958
|
+
const body = structNode.type === "ClassDeclaration" ? structNode.body.body : structNode.body.body;
|
|
959
|
+
methodCount = body.filter(
|
|
960
|
+
(m) => m.type === "MethodDefinition" || m.type === "TSMethodSignature"
|
|
961
|
+
).length;
|
|
962
|
+
propertyCount = body.filter(
|
|
963
|
+
(m) => m.type === "PropertyDefinition" || m.type === "TSPropertySignature"
|
|
964
|
+
).length;
|
|
965
|
+
if (structNode.type === "ClassDeclaration") {
|
|
966
|
+
const constructor = body.find(
|
|
967
|
+
(m) => m.type === "MethodDefinition" && m.kind === "constructor"
|
|
968
|
+
);
|
|
969
|
+
if (constructor && constructor.value && constructor.value.params) {
|
|
970
|
+
parameters = constructor.value.params.map((p) => {
|
|
971
|
+
if (p.type === "Identifier") return p.name;
|
|
972
|
+
if (p.type === "TSParameterProperty" && p.parameter.type === "Identifier") {
|
|
973
|
+
return p.parameter.name;
|
|
974
|
+
}
|
|
975
|
+
return void 0;
|
|
976
|
+
}).filter(Boolean);
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
if (!parameters && (structNode.type === "FunctionDeclaration" || structNode.type === "TSDeclareFunction" || structNode.type === "MethodDefinition")) {
|
|
981
|
+
const funcNode = structNode.type === "MethodDefinition" ? structNode.value : structNode;
|
|
982
|
+
if (funcNode && funcNode.params) {
|
|
983
|
+
parameters = funcNode.params.map((p) => {
|
|
947
984
|
if (p.type === "Identifier") return p.name;
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
const
|
|
971
|
-
|
|
972
|
-
);
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
}
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
column: declaration.loc.end.column
|
|
993
|
-
}
|
|
994
|
-
} : void 0,
|
|
995
|
-
...metadata
|
|
996
|
-
});
|
|
997
|
-
} else if (declaration.type === "VariableDeclaration") {
|
|
998
|
-
for (const declarator of declaration.declarations) {
|
|
999
|
-
if (declarator.id.type === "Identifier") {
|
|
1000
|
-
exports.push({
|
|
1001
|
-
name: declarator.id.name,
|
|
1002
|
-
type: "const",
|
|
1003
|
-
loc: declarator.loc ? {
|
|
1004
|
-
start: {
|
|
1005
|
-
line: declarator.loc.start.line,
|
|
1006
|
-
column: declarator.loc.start.column
|
|
1007
|
-
},
|
|
1008
|
-
end: {
|
|
1009
|
-
line: declarator.loc.end.line,
|
|
1010
|
-
column: declarator.loc.end.column
|
|
1011
|
-
}
|
|
1012
|
-
} : void 0,
|
|
1013
|
-
...metadata
|
|
1014
|
-
});
|
|
985
|
+
return void 0;
|
|
986
|
+
}).filter(Boolean);
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
return {
|
|
990
|
+
name,
|
|
991
|
+
type,
|
|
992
|
+
isPrimitive,
|
|
993
|
+
loc: node.loc ? {
|
|
994
|
+
start: { line: node.loc.start.line, column: node.loc.start.column },
|
|
995
|
+
end: { line: node.loc.end.line, column: node.loc.end.column }
|
|
996
|
+
} : void 0,
|
|
997
|
+
documentation,
|
|
998
|
+
methodCount,
|
|
999
|
+
propertyCount,
|
|
1000
|
+
parameters,
|
|
1001
|
+
isPure: this.isLikelyPure(node),
|
|
1002
|
+
hasSideEffects: !this.isLikelyPure(node)
|
|
1003
|
+
};
|
|
1004
|
+
}
|
|
1005
|
+
extractDocumentation(node, code) {
|
|
1006
|
+
if (node.range) {
|
|
1007
|
+
const start = node.range[0];
|
|
1008
|
+
const precedingCode = code.substring(0, start);
|
|
1009
|
+
const jsdocMatch = precedingCode.match(/\/\*\*([\s\S]*?)\*\/\s*$/);
|
|
1010
|
+
if (jsdocMatch) {
|
|
1011
|
+
return {
|
|
1012
|
+
content: jsdocMatch[1].trim(),
|
|
1013
|
+
type: "jsdoc"
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
return void 0;
|
|
1018
|
+
}
|
|
1019
|
+
isLikelyPure(node) {
|
|
1020
|
+
const structNode = node.type === "ExportNamedDeclaration" ? node.declaration : node.type === "ExportDefaultDeclaration" ? node.declaration : node;
|
|
1021
|
+
if (structNode.type === "VariableDeclaration" && structNode.kind === "const")
|
|
1022
|
+
return true;
|
|
1023
|
+
if (structNode.type === "FunctionDeclaration" || structNode.type === "TSDeclareFunction" || structNode.type === "MethodDefinition" && structNode.value) {
|
|
1024
|
+
const body = structNode.type === "MethodDefinition" ? structNode.value.body : structNode.body;
|
|
1025
|
+
if (body && body.type === "BlockStatement") {
|
|
1026
|
+
const bodyContent = JSON.stringify(body);
|
|
1027
|
+
if (bodyContent.includes('"name":"console"') || bodyContent.includes('"name":"process"') || bodyContent.includes('"type":"AssignmentExpression"')) {
|
|
1028
|
+
return false;
|
|
1015
1029
|
}
|
|
1030
|
+
return true;
|
|
1016
1031
|
}
|
|
1017
|
-
|
|
1018
|
-
exports.push({
|
|
1019
|
-
name: declaration.id.name,
|
|
1020
|
-
type: "type",
|
|
1021
|
-
loc: declaration.loc ? {
|
|
1022
|
-
start: {
|
|
1023
|
-
line: declaration.loc.start.line,
|
|
1024
|
-
column: declaration.loc.start.column
|
|
1025
|
-
},
|
|
1026
|
-
end: {
|
|
1027
|
-
line: declaration.loc.end.line,
|
|
1028
|
-
column: declaration.loc.end.column
|
|
1029
|
-
}
|
|
1030
|
-
} : void 0,
|
|
1031
|
-
...metadata
|
|
1032
|
-
});
|
|
1033
|
-
} else if (declaration.type === "TSInterfaceDeclaration") {
|
|
1034
|
-
const body = declaration.body.body;
|
|
1035
|
-
const methods = body.filter((m) => m.type === "TSMethodSignature");
|
|
1036
|
-
const properties = body.filter((m) => m.type === "TSPropertySignature");
|
|
1037
|
-
exports.push({
|
|
1038
|
-
name: declaration.id.name,
|
|
1039
|
-
type: "interface",
|
|
1040
|
-
methodCount: methods.length,
|
|
1041
|
-
propertyCount: properties.length || body.length,
|
|
1042
|
-
// Fallback to body.length
|
|
1043
|
-
loc: declaration.loc ? {
|
|
1044
|
-
start: {
|
|
1045
|
-
line: declaration.loc.start.line,
|
|
1046
|
-
column: declaration.loc.start.column
|
|
1047
|
-
},
|
|
1048
|
-
end: {
|
|
1049
|
-
line: declaration.loc.end.line,
|
|
1050
|
-
column: declaration.loc.end.column
|
|
1051
|
-
}
|
|
1052
|
-
} : void 0,
|
|
1053
|
-
...metadata
|
|
1054
|
-
});
|
|
1032
|
+
return true;
|
|
1055
1033
|
}
|
|
1056
|
-
return
|
|
1034
|
+
return false;
|
|
1057
1035
|
}
|
|
1058
1036
|
};
|
|
1059
1037
|
|
|
@@ -1327,11 +1305,24 @@ var PythonParser = class extends BaseLanguageParser {
|
|
|
1327
1305
|
getParserName() {
|
|
1328
1306
|
return "python";
|
|
1329
1307
|
}
|
|
1308
|
+
/**
|
|
1309
|
+
* Analyze metadata for a Python node (purity, side effects).
|
|
1310
|
+
*
|
|
1311
|
+
* @param node - Tree-sitter node to analyze.
|
|
1312
|
+
* @param code - Source code for context.
|
|
1313
|
+
* @returns Partial ExportInfo containing discovered metadata.
|
|
1314
|
+
*/
|
|
1330
1315
|
analyzeMetadata(node, code) {
|
|
1331
1316
|
return analyzeNodeMetadata(node, code, {
|
|
1332
1317
|
sideEffectSignatures: ["print(", "input(", "open("]
|
|
1333
1318
|
});
|
|
1334
1319
|
}
|
|
1320
|
+
/**
|
|
1321
|
+
* Extract import information using AST walk.
|
|
1322
|
+
*
|
|
1323
|
+
* @param rootNode - Root node of the Python AST.
|
|
1324
|
+
* @returns Array of discovered FileImport objects.
|
|
1325
|
+
*/
|
|
1335
1326
|
extractImportsAST(rootNode) {
|
|
1336
1327
|
const imports = [];
|
|
1337
1328
|
const processImportNode = (node) => {
|
|
@@ -1413,6 +1404,13 @@ var PythonParser = class extends BaseLanguageParser {
|
|
|
1413
1404
|
}
|
|
1414
1405
|
return imports;
|
|
1415
1406
|
}
|
|
1407
|
+
/**
|
|
1408
|
+
* Extract export information using AST walk.
|
|
1409
|
+
*
|
|
1410
|
+
* @param rootNode - Root node of the Python AST.
|
|
1411
|
+
* @param code - Source code for documentation extraction.
|
|
1412
|
+
* @returns Array of discovered ExportInfo objects.
|
|
1413
|
+
*/
|
|
1416
1414
|
extractExportsAST(rootNode, code) {
|
|
1417
1415
|
const exports = [];
|
|
1418
1416
|
for (const node of rootNode.children) {
|
|
@@ -1491,6 +1489,12 @@ var PythonParser = class extends BaseLanguageParser {
|
|
|
1491
1489
|
}
|
|
1492
1490
|
return exports;
|
|
1493
1491
|
}
|
|
1492
|
+
/**
|
|
1493
|
+
* Extract parameter names from a function definition node.
|
|
1494
|
+
*
|
|
1495
|
+
* @param node - Function definition node.
|
|
1496
|
+
* @returns Array of parameter name strings.
|
|
1497
|
+
*/
|
|
1494
1498
|
extractParameters(node) {
|
|
1495
1499
|
const paramsNode = node.childForFieldName("parameters");
|
|
1496
1500
|
if (!paramsNode) return [];
|
|
@@ -1504,6 +1508,13 @@ var PythonParser = class extends BaseLanguageParser {
|
|
|
1504
1508
|
return "unknown";
|
|
1505
1509
|
});
|
|
1506
1510
|
}
|
|
1511
|
+
/**
|
|
1512
|
+
* Fallback regex-based parsing when tree-sitter is unavailable.
|
|
1513
|
+
*
|
|
1514
|
+
* @param code - Source code content.
|
|
1515
|
+
* @param filePath - Path to the file being parsed.
|
|
1516
|
+
* @returns Consolidated ParseResult.
|
|
1517
|
+
*/
|
|
1507
1518
|
parseRegex(code, filePath) {
|
|
1508
1519
|
try {
|
|
1509
1520
|
const imports = this.extractImportsRegex(code, filePath);
|
|
@@ -1777,6 +1788,13 @@ var JavaParser = class extends BaseLanguageParser {
|
|
|
1777
1788
|
getParserName() {
|
|
1778
1789
|
return "java";
|
|
1779
1790
|
}
|
|
1791
|
+
/**
|
|
1792
|
+
* Analyze metadata for a Java node (purity, side effects).
|
|
1793
|
+
*
|
|
1794
|
+
* @param node - Tree-sitter node to analyze.
|
|
1795
|
+
* @param code - Source code for context.
|
|
1796
|
+
* @returns Partial ExportInfo containing discovered metadata.
|
|
1797
|
+
*/
|
|
1780
1798
|
analyzeMetadata(node, code) {
|
|
1781
1799
|
return analyzeGeneralMetadata(node, code, {
|
|
1782
1800
|
sideEffectSignatures: [
|
|
@@ -1856,6 +1874,12 @@ var JavaParser = class extends BaseLanguageParser {
|
|
|
1856
1874
|
warnings: ["Parser falling back to regex-based analysis"]
|
|
1857
1875
|
};
|
|
1858
1876
|
}
|
|
1877
|
+
/**
|
|
1878
|
+
* Extract import information using AST walk.
|
|
1879
|
+
*
|
|
1880
|
+
* @param rootNode - Root node of the Java AST.
|
|
1881
|
+
* @returns Array of discovered FileImport objects.
|
|
1882
|
+
*/
|
|
1859
1883
|
extractImportsAST(rootNode) {
|
|
1860
1884
|
const imports = [];
|
|
1861
1885
|
for (const node of rootNode.children) {
|
|
@@ -1889,6 +1913,13 @@ var JavaParser = class extends BaseLanguageParser {
|
|
|
1889
1913
|
}
|
|
1890
1914
|
return imports;
|
|
1891
1915
|
}
|
|
1916
|
+
/**
|
|
1917
|
+
* Extract export information (classes, interfaces, methods) using AST walk.
|
|
1918
|
+
*
|
|
1919
|
+
* @param rootNode - Root node of the Java AST.
|
|
1920
|
+
* @param code - Source code for documentation extraction.
|
|
1921
|
+
* @returns Array of discovered ExportInfo objects.
|
|
1922
|
+
*/
|
|
1892
1923
|
extractExportsAST(rootNode, code) {
|
|
1893
1924
|
const exports = [];
|
|
1894
1925
|
for (const node of rootNode.children) {
|
|
@@ -1919,11 +1950,25 @@ var JavaParser = class extends BaseLanguageParser {
|
|
|
1919
1950
|
}
|
|
1920
1951
|
return exports;
|
|
1921
1952
|
}
|
|
1953
|
+
/**
|
|
1954
|
+
* Extract modifiers (visibility, static, etc.) from a node.
|
|
1955
|
+
*
|
|
1956
|
+
* @param node - AST node to extract modifiers from.
|
|
1957
|
+
* @returns Array of modifier strings.
|
|
1958
|
+
*/
|
|
1922
1959
|
getModifiers(node) {
|
|
1923
1960
|
const modifiersNode = node.children.find((c) => c.type === "modifiers");
|
|
1924
1961
|
if (!modifiersNode) return [];
|
|
1925
1962
|
return modifiersNode.children.map((c) => c.text);
|
|
1926
1963
|
}
|
|
1964
|
+
/**
|
|
1965
|
+
* Extract methods and nested exports from a class or interface body.
|
|
1966
|
+
*
|
|
1967
|
+
* @param parentNode - Class or interface declaration node.
|
|
1968
|
+
* @param parentName - Name of the parent class/interface.
|
|
1969
|
+
* @param exports - Array to collect discovered exports into.
|
|
1970
|
+
* @param code - Source code for context.
|
|
1971
|
+
*/
|
|
1927
1972
|
extractSubExports(parentNode, parentName, exports, code) {
|
|
1928
1973
|
const bodyNode = parentNode.children.find((c) => c.type === "class_body");
|
|
1929
1974
|
if (!bodyNode) return;
|
|
@@ -1982,11 +2027,24 @@ var CSharpParser = class extends BaseLanguageParser {
|
|
|
1982
2027
|
getParserName() {
|
|
1983
2028
|
return "c_sharp";
|
|
1984
2029
|
}
|
|
2030
|
+
/**
|
|
2031
|
+
* Analyze metadata for a C# node (purity, side effects).
|
|
2032
|
+
*
|
|
2033
|
+
* @param node - Tree-sitter node to analyze.
|
|
2034
|
+
* @param code - Source code for context.
|
|
2035
|
+
* @returns Partial ExportInfo containing discovered metadata.
|
|
2036
|
+
*/
|
|
1985
2037
|
analyzeMetadata(node, code) {
|
|
1986
2038
|
return analyzeGeneralMetadata(node, code, {
|
|
1987
2039
|
sideEffectSignatures: ["Console.Write", "File.Write", "Logging."]
|
|
1988
2040
|
});
|
|
1989
2041
|
}
|
|
2042
|
+
/**
|
|
2043
|
+
* Fallback regex-based parsing when tree-sitter is unavailable.
|
|
2044
|
+
*
|
|
2045
|
+
* @param code - Source code content.
|
|
2046
|
+
* @returns Consolidated ParseResult.
|
|
2047
|
+
*/
|
|
1990
2048
|
parseRegex(code) {
|
|
1991
2049
|
const lines = code.split("\n");
|
|
1992
2050
|
const exports = [];
|
|
@@ -2048,6 +2106,12 @@ var CSharpParser = class extends BaseLanguageParser {
|
|
|
2048
2106
|
warnings: ["Parser falling back to regex-based analysis"]
|
|
2049
2107
|
};
|
|
2050
2108
|
}
|
|
2109
|
+
/**
|
|
2110
|
+
* Extract import information (usings) using AST walk.
|
|
2111
|
+
*
|
|
2112
|
+
* @param rootNode - Root node of the C# AST.
|
|
2113
|
+
* @returns Array of discovered FileImport objects.
|
|
2114
|
+
*/
|
|
2051
2115
|
extractImportsAST(rootNode) {
|
|
2052
2116
|
const imports = [];
|
|
2053
2117
|
const findUsings = (node) => {
|
|
@@ -2081,6 +2145,14 @@ var CSharpParser = class extends BaseLanguageParser {
|
|
|
2081
2145
|
findUsings(rootNode);
|
|
2082
2146
|
return imports;
|
|
2083
2147
|
}
|
|
2148
|
+
/**
|
|
2149
|
+
* Extract export information (classes, methods, properties) using AST walk.
|
|
2150
|
+
* Handles nested namespaces and classes.
|
|
2151
|
+
*
|
|
2152
|
+
* @param rootNode - Root node of the C# AST.
|
|
2153
|
+
* @param code - Source code for documentation extraction.
|
|
2154
|
+
* @returns Array of discovered ExportInfo objects.
|
|
2155
|
+
*/
|
|
2084
2156
|
extractExportsAST(rootNode, code) {
|
|
2085
2157
|
const exports = [];
|
|
2086
2158
|
const traverse = (node, currentNamespace, currentClass) => {
|
|
@@ -2192,11 +2264,24 @@ var GoParser = class extends BaseLanguageParser {
|
|
|
2192
2264
|
getParserName() {
|
|
2193
2265
|
return "go";
|
|
2194
2266
|
}
|
|
2267
|
+
/**
|
|
2268
|
+
* Analyze metadata for a Go node (purity, side effects).
|
|
2269
|
+
*
|
|
2270
|
+
* @param node - Tree-sitter node to analyze.
|
|
2271
|
+
* @param code - Source code for context.
|
|
2272
|
+
* @returns Partial ExportInfo containing discovered metadata.
|
|
2273
|
+
*/
|
|
2195
2274
|
analyzeMetadata(node, code) {
|
|
2196
2275
|
return analyzeGeneralMetadata(node, code, {
|
|
2197
2276
|
sideEffectSignatures: ["<-", "fmt.Print", "fmt.Fprintf", "os.Exit"]
|
|
2198
2277
|
});
|
|
2199
2278
|
}
|
|
2279
|
+
/**
|
|
2280
|
+
* Fallback regex-based parsing when tree-sitter is unavailable.
|
|
2281
|
+
*
|
|
2282
|
+
* @param code - Source code content.
|
|
2283
|
+
* @returns Consolidated ParseResult.
|
|
2284
|
+
*/
|
|
2200
2285
|
parseRegex(code) {
|
|
2201
2286
|
const lines = code.split("\n");
|
|
2202
2287
|
const exports = [];
|
|
@@ -2274,6 +2359,12 @@ var GoParser = class extends BaseLanguageParser {
|
|
|
2274
2359
|
warnings: ["Parser falling back to regex-based analysis"]
|
|
2275
2360
|
};
|
|
2276
2361
|
}
|
|
2362
|
+
/**
|
|
2363
|
+
* Extract import information using AST walk.
|
|
2364
|
+
*
|
|
2365
|
+
* @param rootNode - Root node of the Go AST.
|
|
2366
|
+
* @returns Array of discovered FileImport objects.
|
|
2367
|
+
*/
|
|
2277
2368
|
extractImportsAST(rootNode) {
|
|
2278
2369
|
const imports = [];
|
|
2279
2370
|
const findImports = (node) => {
|
|
@@ -2307,6 +2398,13 @@ var GoParser = class extends BaseLanguageParser {
|
|
|
2307
2398
|
findImports(rootNode);
|
|
2308
2399
|
return imports;
|
|
2309
2400
|
}
|
|
2401
|
+
/**
|
|
2402
|
+
* Extract export information (functions, types, vars) using AST walk.
|
|
2403
|
+
*
|
|
2404
|
+
* @param rootNode - Root node of the Go AST.
|
|
2405
|
+
* @param code - Source code for documentation extraction.
|
|
2406
|
+
* @returns Array of discovered ExportInfo objects.
|
|
2407
|
+
*/
|
|
2310
2408
|
extractExportsAST(rootNode, code) {
|
|
2311
2409
|
const exports = [];
|
|
2312
2410
|
const isExported = (name) => {
|
|
@@ -2663,7 +2761,7 @@ function extractTypeReferences(node) {
|
|
|
2663
2761
|
return Array.from(types);
|
|
2664
2762
|
}
|
|
2665
2763
|
|
|
2666
|
-
// src/utils/
|
|
2764
|
+
// src/utils/dependency-analyzer.ts
|
|
2667
2765
|
function parseFileExports(code, filePath) {
|
|
2668
2766
|
const parser = getParser(filePath);
|
|
2669
2767
|
if (parser && parser.language !== "typescript" /* TypeScript */ && parser.language !== "javascript" /* JavaScript */) {
|
|
@@ -2705,29 +2803,6 @@ function parseFileExports(code, filePath) {
|
|
|
2705
2803
|
return { exports: [], imports: [] };
|
|
2706
2804
|
}
|
|
2707
2805
|
}
|
|
2708
|
-
function calculateImportSimilarity(export1, export2) {
|
|
2709
|
-
if (export1.imports.length === 0 && export2.imports.length === 0) {
|
|
2710
|
-
return 1;
|
|
2711
|
-
}
|
|
2712
|
-
const set1 = new Set(export1.imports);
|
|
2713
|
-
const set2 = new Set(export2.imports);
|
|
2714
|
-
const intersection = new Set([...set1].filter((x) => set2.has(x)));
|
|
2715
|
-
const union = /* @__PURE__ */ new Set([...set1, ...set2]);
|
|
2716
|
-
return intersection.size / union.size;
|
|
2717
|
-
}
|
|
2718
|
-
function parseCode(_code, _language) {
|
|
2719
|
-
void _code;
|
|
2720
|
-
void _language;
|
|
2721
|
-
return null;
|
|
2722
|
-
}
|
|
2723
|
-
function extractFunctions(_ast) {
|
|
2724
|
-
void _ast;
|
|
2725
|
-
return [];
|
|
2726
|
-
}
|
|
2727
|
-
function extractImports(_ast) {
|
|
2728
|
-
void _ast;
|
|
2729
|
-
return [];
|
|
2730
|
-
}
|
|
2731
2806
|
|
|
2732
2807
|
// src/utils/metrics.ts
|
|
2733
2808
|
function estimateTokens(text) {
|
|
@@ -2776,10 +2851,25 @@ async function loadConfig(rootDir) {
|
|
|
2776
2851
|
const content = readFileSync(configPath, "utf-8");
|
|
2777
2852
|
config = JSON.parse(content);
|
|
2778
2853
|
}
|
|
2779
|
-
|
|
2780
|
-
|
|
2854
|
+
const legacyKeys = ["toolConfigs"];
|
|
2855
|
+
const rootLevelTools = [
|
|
2856
|
+
"pattern-detect",
|
|
2857
|
+
"context-analyzer",
|
|
2858
|
+
"naming-consistency",
|
|
2859
|
+
"ai-signal-clarity"
|
|
2860
|
+
];
|
|
2861
|
+
const allKeys = Object.keys(config);
|
|
2862
|
+
const foundLegacy = allKeys.filter(
|
|
2863
|
+
(k) => legacyKeys.includes(k) || rootLevelTools.includes(k)
|
|
2864
|
+
);
|
|
2865
|
+
if (foundLegacy.length > 0) {
|
|
2866
|
+
console.warn(
|
|
2867
|
+
`\u26A0\uFE0F Legacy configuration keys found: ${foundLegacy.join(
|
|
2868
|
+
", "
|
|
2869
|
+
)}. These are deprecated and should be moved under the "tools" key.`
|
|
2870
|
+
);
|
|
2781
2871
|
}
|
|
2782
|
-
return config;
|
|
2872
|
+
return AIReadyConfigSchema.parse(config);
|
|
2783
2873
|
} catch (error) {
|
|
2784
2874
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2785
2875
|
const configError = new Error(
|
|
@@ -2807,12 +2897,10 @@ function mergeConfigWithDefaults(userConfig, defaults) {
|
|
|
2807
2897
|
if (userConfig.scan.include) mergedConfig.include = userConfig.scan.include;
|
|
2808
2898
|
if (userConfig.scan.exclude) mergedConfig.exclude = userConfig.scan.exclude;
|
|
2809
2899
|
}
|
|
2810
|
-
|
|
2811
|
-
if (toolOverrides) {
|
|
2900
|
+
if (userConfig.tools) {
|
|
2812
2901
|
if (!mergedConfig.toolConfigs) mergedConfig.toolConfigs = {};
|
|
2813
|
-
for (const [toolName, toolConfig] of Object.entries(
|
|
2902
|
+
for (const [toolName, toolConfig] of Object.entries(userConfig.tools)) {
|
|
2814
2903
|
if (typeof toolConfig === "object" && toolConfig !== null) {
|
|
2815
|
-
mergedConfig[toolName] = { ...mergedConfig[toolName], ...toolConfig };
|
|
2816
2904
|
mergedConfig.toolConfigs[toolName] = {
|
|
2817
2905
|
...mergedConfig.toolConfigs[toolName],
|
|
2818
2906
|
...toolConfig
|
|
@@ -2828,6 +2916,13 @@ function mergeConfigWithDefaults(userConfig, defaults) {
|
|
|
2828
2916
|
|
|
2829
2917
|
// src/business/pricing-models.ts
|
|
2830
2918
|
var MODEL_PRICING_PRESETS = {
|
|
2919
|
+
"gpt-5.4-mini": {
|
|
2920
|
+
name: "GPT-5.4 Mini",
|
|
2921
|
+
pricePer1KInputTokens: 1e-4,
|
|
2922
|
+
pricePer1KOutputTokens: 4e-4,
|
|
2923
|
+
contextTier: "extended",
|
|
2924
|
+
typicalQueriesPerDevPerDay: 200
|
|
2925
|
+
},
|
|
2831
2926
|
"gpt-5.3": {
|
|
2832
2927
|
name: "GPT-5.3",
|
|
2833
2928
|
pricePer1KInputTokens: 2e-3,
|
|
@@ -2849,20 +2944,6 @@ var MODEL_PRICING_PRESETS = {
|
|
|
2849
2944
|
contextTier: "frontier",
|
|
2850
2945
|
typicalQueriesPerDevPerDay: 120
|
|
2851
2946
|
},
|
|
2852
|
-
"gpt-4o": {
|
|
2853
|
-
name: "GPT-4o (legacy)",
|
|
2854
|
-
pricePer1KInputTokens: 5e-3,
|
|
2855
|
-
pricePer1KOutputTokens: 0.015,
|
|
2856
|
-
contextTier: "extended",
|
|
2857
|
-
typicalQueriesPerDevPerDay: 60
|
|
2858
|
-
},
|
|
2859
|
-
"claude-3-5-sonnet": {
|
|
2860
|
-
name: "Claude 3.5 Sonnet (legacy)",
|
|
2861
|
-
pricePer1KInputTokens: 3e-3,
|
|
2862
|
-
pricePer1KOutputTokens: 0.015,
|
|
2863
|
-
contextTier: "extended",
|
|
2864
|
-
typicalQueriesPerDevPerDay: 80
|
|
2865
|
-
},
|
|
2866
2947
|
"gemini-1-5-pro": {
|
|
2867
2948
|
name: "Gemini 1.5 Pro (legacy)",
|
|
2868
2949
|
pricePer1KInputTokens: 125e-5,
|
|
@@ -2886,7 +2967,7 @@ var MODEL_PRICING_PRESETS = {
|
|
|
2886
2967
|
}
|
|
2887
2968
|
};
|
|
2888
2969
|
function getModelPreset(modelId) {
|
|
2889
|
-
return MODEL_PRICING_PRESETS[modelId] ?? MODEL_PRICING_PRESETS["
|
|
2970
|
+
return MODEL_PRICING_PRESETS[modelId] ?? MODEL_PRICING_PRESETS["gpt-5.4-mini"];
|
|
2890
2971
|
}
|
|
2891
2972
|
|
|
2892
2973
|
// src/business/cost-metrics.ts
|
|
@@ -2907,7 +2988,7 @@ function calculateMonthlyCost(tokenWaste, config = {}) {
|
|
|
2907
2988
|
// Added baseline chattiness
|
|
2908
2989
|
}
|
|
2909
2990
|
});
|
|
2910
|
-
const preset = getModelPreset("
|
|
2991
|
+
const preset = getModelPreset("gpt-5.4-mini");
|
|
2911
2992
|
return estimateCostFromBudget(budget, preset, config);
|
|
2912
2993
|
}
|
|
2913
2994
|
function calculateTokenBudget(params) {
|
|
@@ -3753,12 +3834,12 @@ function calculateTestabilityIndex(params) {
|
|
|
3753
3834
|
const rawCoverageRatio = sourceFiles > 0 ? testFiles / sourceFiles : 0;
|
|
3754
3835
|
const testCoverageRatio = Math.min(100, Math.round(rawCoverageRatio * 100));
|
|
3755
3836
|
const purityScore = Math.round(
|
|
3756
|
-
(totalFunctions > 0 ? pureFunctions / totalFunctions : 0.
|
|
3837
|
+
(totalFunctions > 0 ? pureFunctions / totalFunctions : 0.7) * 100
|
|
3757
3838
|
);
|
|
3758
3839
|
const dependencyInjectionScore = Math.round(
|
|
3759
3840
|
Math.min(
|
|
3760
3841
|
100,
|
|
3761
|
-
(totalClasses > 0 ? injectionPatterns / totalClasses : 0.
|
|
3842
|
+
(totalClasses > 0 ? injectionPatterns / totalClasses : 0.8) * 100
|
|
3762
3843
|
)
|
|
3763
3844
|
);
|
|
3764
3845
|
const interfaceFocusScore = Math.max(
|
|
@@ -3839,9 +3920,9 @@ function calculateDocDrift(params) {
|
|
|
3839
3920
|
const outdatedRatio = totalExports > 0 ? outdatedComments / totalExports : 0;
|
|
3840
3921
|
const complexityRatio = totalExports > 0 ? undocumentedComplexity / totalExports : 0;
|
|
3841
3922
|
const driftRatio = totalExports > 0 ? actualDrift / totalExports : 0;
|
|
3842
|
-
const DRIFT_THRESHOLD = 0.
|
|
3843
|
-
const OUTDATED_THRESHOLD = 0.
|
|
3844
|
-
const COMPLEXITY_THRESHOLD = 0.
|
|
3923
|
+
const DRIFT_THRESHOLD = 0.35;
|
|
3924
|
+
const OUTDATED_THRESHOLD = 0.5;
|
|
3925
|
+
const COMPLEXITY_THRESHOLD = 0.3;
|
|
3845
3926
|
const UNCOMMENTED_THRESHOLD = 0.8;
|
|
3846
3927
|
const driftRisk = Math.min(100, driftRatio / DRIFT_THRESHOLD * 100);
|
|
3847
3928
|
const outdatedRisk = Math.min(
|
|
@@ -4306,6 +4387,7 @@ function emitIssuesAsAnnotations(issues) {
|
|
|
4306
4387
|
});
|
|
4307
4388
|
}
|
|
4308
4389
|
export {
|
|
4390
|
+
AIReadyConfigSchema,
|
|
4309
4391
|
AnalysisResultSchema,
|
|
4310
4392
|
AnalysisStatus,
|
|
4311
4393
|
AnalysisStatusSchema,
|
|
@@ -4387,8 +4469,6 @@ export {
|
|
|
4387
4469
|
estimateCostFromBudget,
|
|
4388
4470
|
estimateTokens,
|
|
4389
4471
|
exportHistory,
|
|
4390
|
-
extractFunctions,
|
|
4391
|
-
extractImports,
|
|
4392
4472
|
findLatestReport,
|
|
4393
4473
|
findLatestScanReport,
|
|
4394
4474
|
formatAcceptanceRate,
|
|
@@ -4433,8 +4513,11 @@ export {
|
|
|
4433
4513
|
loadMergedConfig,
|
|
4434
4514
|
loadScoreHistory,
|
|
4435
4515
|
mergeConfigWithDefaults,
|
|
4516
|
+
normalizeAnalysisResult,
|
|
4517
|
+
normalizeIssue,
|
|
4518
|
+
normalizeMetrics,
|
|
4519
|
+
normalizeSpokeOutput,
|
|
4436
4520
|
normalizeToolName,
|
|
4437
|
-
parseCode,
|
|
4438
4521
|
parseFileExports,
|
|
4439
4522
|
parseWeightString,
|
|
4440
4523
|
predictAcceptanceRate,
|