@aiready/core 0.23.1 → 0.23.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/parser-factory.test.d.ts +1 -1
- package/dist/__tests__/parser-factory.test.js +62 -50
- package/dist/__tests__/python-parser.test.d.ts +1 -1
- package/dist/__tests__/python-parser.test.js +111 -109
- package/dist/__tests__/scoring.test.d.ts +1 -1
- package/dist/__tests__/scoring.test.js +193 -176
- package/dist/chunk-3YI4IS3D.mjs +191 -173
- package/dist/chunk-5HIXDC3X.mjs +273 -251
- package/dist/chunk-5V3L53AE.mjs +805 -0
- package/dist/chunk-CKVKHN3G.mjs +228 -211
- package/dist/chunk-COHIBX3Q.mjs +213 -195
- package/dist/chunk-CWRCDSKZ.mjs +91 -82
- package/dist/chunk-D3D3NCRR.mjs +147 -129
- package/dist/chunk-HCFYP7UD.mjs +805 -0
- package/dist/chunk-HFLFBA6F.mjs +79 -72
- package/dist/chunk-HKSARRCD.mjs +66 -58
- package/dist/chunk-JJ5JL5FX.mjs +91 -82
- package/dist/chunk-KDSTXVLQ.mjs +724 -0
- package/dist/chunk-KI7XORTN.mjs +91 -82
- package/dist/chunk-LTMHFNFK.mjs +690 -0
- package/dist/chunk-LTNXTXRI.mjs +228 -211
- package/dist/chunk-M22BXHBR.mjs +805 -0
- package/dist/chunk-MH3A3LX6.mjs +200 -182
- package/dist/chunk-NGHT7JOG.mjs +697 -0
- package/dist/chunk-OQ6IGDXG.mjs +147 -129
- package/dist/chunk-QAFB3HXQ.mjs +181 -165
- package/dist/chunk-QQBKXHLU.mjs +678 -0
- package/dist/chunk-RDHYGES7.mjs +678 -0
- package/dist/chunk-SWTDBVYJ.mjs +228 -213
- package/dist/chunk-UIWL5JQB.mjs +79 -72
- package/dist/chunk-UQGI67WR.mjs +79 -72
- package/dist/chunk-UTZOO4XO.mjs +147 -131
- package/dist/chunk-X4F46I5L.mjs +213 -195
- package/dist/chunk-XKK7YHPX.mjs +204 -186
- package/dist/chunk-YCA4FTEK.mjs +190 -172
- package/dist/chunk-ZSZRRTJM.mjs +719 -0
- package/dist/client-BgmiMoil.d.mts +1344 -0
- package/dist/client-BgmiMoil.d.ts +1344 -0
- package/dist/client-BxGrPuuN.d.mts +1191 -0
- package/dist/client-BxGrPuuN.d.ts +1191 -0
- package/dist/client-D-cn9ydj.d.mts +1136 -0
- package/dist/client-D-cn9ydj.d.ts +1136 -0
- package/dist/client-D9seCH4K.d.mts +1334 -0
- package/dist/client-D9seCH4K.d.ts +1334 -0
- package/dist/client-DIXIh7rw.d.mts +1193 -0
- package/dist/client-DIXIh7rw.d.ts +1193 -0
- package/dist/client-DVHXWOHw.d.mts +1245 -0
- package/dist/client-DVHXWOHw.d.ts +1245 -0
- package/dist/client.d.mts +2 -1094
- package/dist/client.d.ts +2 -1094
- package/dist/client.js +23 -43
- package/dist/client.mjs +3 -25
- package/dist/index.d.mts +380 -108
- package/dist/index.d.ts +380 -108
- package/dist/index.js +609 -445
- package/dist/index.mjs +587 -429
- package/dist/parsers/parser-factory.d.ts +45 -45
- package/dist/parsers/parser-factory.js +86 -84
- package/dist/parsers/python-parser.d.ts +33 -28
- package/dist/parsers/python-parser.js +224 -222
- package/dist/parsers/typescript-parser.d.ts +15 -10
- package/dist/parsers/typescript-parser.js +223 -197
- package/dist/scoring.d.ts +59 -49
- package/dist/scoring.js +129 -127
- package/dist/types/language.d.ts +104 -93
- package/dist/types/language.js +23 -23
- package/dist/types.d.ts +105 -87
- package/dist/types.js +1 -1
- package/dist/utils/ast-parser.d.ts +42 -33
- package/dist/utils/ast-parser.js +159 -162
- package/dist/utils/cli-helpers.d.ts +27 -10
- package/dist/utils/cli-helpers.js +45 -43
- package/dist/utils/config.d.ts +8 -3
- package/dist/utils/config.js +67 -69
- package/dist/utils/file-scanner.d.ts +1 -1
- package/dist/utils/file-scanner.js +80 -76
- package/dist/utils/metrics.d.ts +1 -1
- package/dist/utils/metrics.js +2 -2
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -74,6 +74,8 @@ __export(index_exports, {
|
|
|
74
74
|
TypeScriptParser: () => TypeScriptParser,
|
|
75
75
|
UnifiedReportSchema: () => UnifiedReportSchema,
|
|
76
76
|
VAGUE_FILE_NAMES: () => VAGUE_FILE_NAMES,
|
|
77
|
+
buildSimpleProviderScore: () => buildSimpleProviderScore,
|
|
78
|
+
buildSpokeOutput: () => buildSpokeOutput,
|
|
77
79
|
calculateAgentGrounding: () => calculateAgentGrounding,
|
|
78
80
|
calculateAiSignalClarity: () => calculateAiSignalClarity,
|
|
79
81
|
calculateBusinessROI: () => calculateBusinessROI,
|
|
@@ -97,6 +99,7 @@ __export(index_exports, {
|
|
|
97
99
|
calculateTestabilityIndex: () => calculateTestabilityIndex,
|
|
98
100
|
calculateTokenBudget: () => calculateTokenBudget,
|
|
99
101
|
clearHistory: () => clearHistory,
|
|
102
|
+
createProvider: () => createProvider,
|
|
100
103
|
emitAnnotation: () => emitAnnotation,
|
|
101
104
|
emitIssuesAsAnnotations: () => emitIssuesAsAnnotations,
|
|
102
105
|
emitProgress: () => emitProgress,
|
|
@@ -105,6 +108,8 @@ __export(index_exports, {
|
|
|
105
108
|
exportHistory: () => exportHistory,
|
|
106
109
|
extractFunctions: () => extractFunctions,
|
|
107
110
|
extractImports: () => extractImports,
|
|
111
|
+
findLatestReport: () => findLatestReport,
|
|
112
|
+
findLatestScanReport: () => findLatestScanReport,
|
|
108
113
|
formatAcceptanceRate: () => formatAcceptanceRate,
|
|
109
114
|
formatCost: () => formatCost,
|
|
110
115
|
formatHours: () => formatHours,
|
|
@@ -122,15 +127,21 @@ __export(index_exports, {
|
|
|
122
127
|
getProjectSizeTier: () => getProjectSizeTier,
|
|
123
128
|
getRating: () => getRating,
|
|
124
129
|
getRatingDisplay: () => getRatingDisplay,
|
|
130
|
+
getRatingSlug: () => getRatingSlug,
|
|
125
131
|
getRatingWithContext: () => getRatingWithContext,
|
|
126
132
|
getRecommendedThreshold: () => getRecommendedThreshold,
|
|
127
133
|
getRepoMetadata: () => getRepoMetadata,
|
|
128
134
|
getSafetyIcon: () => getSafetyIcon,
|
|
129
135
|
getScoreBar: () => getScoreBar,
|
|
136
|
+
getSeverityBadge: () => getSeverityBadge,
|
|
130
137
|
getSeverityColor: () => getSeverityColor,
|
|
138
|
+
getSeverityEnum: () => getSeverityEnum,
|
|
139
|
+
getSeverityLevel: () => getSeverityLevel,
|
|
140
|
+
getSeverityValue: () => getSeverityValue,
|
|
131
141
|
getSupportedLanguages: () => getSupportedLanguages,
|
|
132
142
|
getToolWeight: () => getToolWeight,
|
|
133
143
|
getWasmPath: () => getWasmPath,
|
|
144
|
+
groupIssuesByFile: () => groupIssuesByFile,
|
|
134
145
|
handleCLIError: () => handleCLIError,
|
|
135
146
|
handleJSONOutput: () => handleJSONOutput,
|
|
136
147
|
initTreeSitter: () => initTreeSitter,
|
|
@@ -322,33 +333,28 @@ var UnifiedReportSchema = import_zod.z.object({
|
|
|
322
333
|
// src/types.ts
|
|
323
334
|
var GLOBAL_INFRA_OPTIONS = [
|
|
324
335
|
"rootDir",
|
|
325
|
-
// Essential for every tool
|
|
326
336
|
"include",
|
|
327
337
|
"exclude",
|
|
328
|
-
"onProgress",
|
|
329
|
-
"progressCallback",
|
|
330
|
-
"includeTests",
|
|
331
|
-
"useSmartDefaults",
|
|
332
|
-
"streamResults",
|
|
333
|
-
"batchSize",
|
|
334
|
-
"costConfig",
|
|
335
338
|
"tools",
|
|
336
|
-
"
|
|
339
|
+
"scoring"
|
|
340
|
+
];
|
|
341
|
+
var GLOBAL_SCAN_OPTIONS = [
|
|
342
|
+
"rootDir",
|
|
343
|
+
"include",
|
|
344
|
+
"exclude",
|
|
345
|
+
"config",
|
|
346
|
+
"threshold",
|
|
347
|
+
"output",
|
|
348
|
+
"format",
|
|
349
|
+
"parallel",
|
|
350
|
+
"showBreakdown"
|
|
337
351
|
];
|
|
338
352
|
var COMMON_FINE_TUNING_OPTIONS = [
|
|
339
353
|
"maxDepth",
|
|
340
354
|
"minSimilarity",
|
|
341
|
-
"
|
|
342
|
-
"
|
|
343
|
-
// AI Signal Clarity options
|
|
344
|
-
"checkMagicLiterals",
|
|
345
|
-
"checkBooleanTraps",
|
|
346
|
-
"checkAmbiguousNames",
|
|
347
|
-
"checkUndocumentedExports",
|
|
348
|
-
"checkImplicitSideEffects",
|
|
349
|
-
"checkDeepCallbacks"
|
|
355
|
+
"threshold",
|
|
356
|
+
"showBreakdown"
|
|
350
357
|
];
|
|
351
|
-
var GLOBAL_SCAN_OPTIONS = [...GLOBAL_INFRA_OPTIONS];
|
|
352
358
|
|
|
353
359
|
// src/types/language.ts
|
|
354
360
|
var Language = /* @__PURE__ */ ((Language3) => {
|
|
@@ -777,6 +783,7 @@ function isSourceFile(filePath) {
|
|
|
777
783
|
// src/utils/cli-helpers.ts
|
|
778
784
|
var import_fs2 = require("fs");
|
|
779
785
|
var import_path2 = require("path");
|
|
786
|
+
var import_chalk = __toESM(require("chalk"));
|
|
780
787
|
function resolveOutputPath(userPath, defaultFilename, workingDir = process.cwd()) {
|
|
781
788
|
let outputPath;
|
|
782
789
|
if (userPath) {
|
|
@@ -844,25 +851,180 @@ function emitProgress(processed, total, toolId, message, onProgress, throttleCou
|
|
|
844
851
|
onProgress(processed, total, `${message} (${processed}/${total})`);
|
|
845
852
|
}
|
|
846
853
|
}
|
|
847
|
-
function getSeverityColor(severity,
|
|
854
|
+
function getSeverityColor(severity, chalkInstance = import_chalk.default) {
|
|
848
855
|
switch (severity.toLowerCase()) {
|
|
849
856
|
case "critical":
|
|
850
857
|
case "high-risk":
|
|
851
858
|
case "blind-risk":
|
|
852
|
-
return
|
|
859
|
+
return chalkInstance.red;
|
|
853
860
|
case "major":
|
|
854
861
|
case "moderate-risk":
|
|
855
|
-
return
|
|
862
|
+
return chalkInstance.yellow;
|
|
856
863
|
case "minor":
|
|
857
864
|
case "safe":
|
|
858
|
-
return
|
|
865
|
+
return chalkInstance.green;
|
|
866
|
+
case "info":
|
|
867
|
+
return chalkInstance.blue;
|
|
868
|
+
default:
|
|
869
|
+
return chalkInstance.white;
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
function getSeverityValue(s) {
|
|
873
|
+
if (!s) return 0;
|
|
874
|
+
switch (s.toLowerCase()) {
|
|
875
|
+
case "critical":
|
|
876
|
+
return 4;
|
|
877
|
+
case "major":
|
|
878
|
+
return 3;
|
|
879
|
+
case "minor":
|
|
880
|
+
return 2;
|
|
859
881
|
case "info":
|
|
860
|
-
return
|
|
882
|
+
return 1;
|
|
883
|
+
default:
|
|
884
|
+
return 0;
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
function getSeverityLevel(s) {
|
|
888
|
+
return getSeverityValue(s);
|
|
889
|
+
}
|
|
890
|
+
function getSeverityBadge(severity, chalkInstance = import_chalk.default) {
|
|
891
|
+
const val = getSeverityValue(
|
|
892
|
+
typeof severity === "string" ? severity : severity
|
|
893
|
+
);
|
|
894
|
+
switch (val) {
|
|
895
|
+
case 4:
|
|
896
|
+
return chalkInstance.bgRed.white.bold(" CRITICAL ");
|
|
897
|
+
case 3:
|
|
898
|
+
return chalkInstance.bgYellow.black.bold(" MAJOR ");
|
|
899
|
+
case 2:
|
|
900
|
+
return chalkInstance.bgBlue.white.bold(" MINOR ");
|
|
901
|
+
case 1:
|
|
902
|
+
return chalkInstance.bgCyan.black(" INFO ");
|
|
861
903
|
default:
|
|
862
|
-
return
|
|
904
|
+
return chalkInstance.bgCyan.black(" INFO ");
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
function getSeverityEnum(s) {
|
|
908
|
+
const level = getSeverityLevel(s);
|
|
909
|
+
switch (level) {
|
|
910
|
+
case 4:
|
|
911
|
+
return "critical";
|
|
912
|
+
case 3:
|
|
913
|
+
return "major";
|
|
914
|
+
case 2:
|
|
915
|
+
return "minor";
|
|
916
|
+
case 1:
|
|
917
|
+
return "info";
|
|
918
|
+
default:
|
|
919
|
+
return "info";
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
function findLatestReport(dirPath) {
|
|
923
|
+
const aireadyDir = (0, import_path2.resolve)(dirPath, ".aiready");
|
|
924
|
+
if (!(0, import_fs2.existsSync)(aireadyDir)) {
|
|
925
|
+
return null;
|
|
926
|
+
}
|
|
927
|
+
let files = (0, import_fs2.readdirSync)(aireadyDir).filter(
|
|
928
|
+
(f) => f.startsWith("aiready-report-") && f.endsWith(".json")
|
|
929
|
+
);
|
|
930
|
+
if (files.length === 0) {
|
|
931
|
+
files = (0, import_fs2.readdirSync)(aireadyDir).filter(
|
|
932
|
+
(f) => f.startsWith("aiready-scan-") && f.endsWith(".json")
|
|
933
|
+
);
|
|
934
|
+
}
|
|
935
|
+
if (files.length === 0) {
|
|
936
|
+
return null;
|
|
937
|
+
}
|
|
938
|
+
const sortedFiles = files.map((f) => ({
|
|
939
|
+
name: f,
|
|
940
|
+
path: (0, import_path2.resolve)(aireadyDir, f),
|
|
941
|
+
mtime: (0, import_fs2.statSync)((0, import_path2.resolve)(aireadyDir, f)).mtime
|
|
942
|
+
})).sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
|
|
943
|
+
return sortedFiles[0].path;
|
|
944
|
+
}
|
|
945
|
+
function findLatestScanReport(scanReportsDir, reportFilePrefix) {
|
|
946
|
+
try {
|
|
947
|
+
let reportFiles = [];
|
|
948
|
+
if ((0, import_fs2.existsSync)(scanReportsDir)) {
|
|
949
|
+
const files = (0, import_fs2.readdirSync)(scanReportsDir);
|
|
950
|
+
if (files.length > 0) {
|
|
951
|
+
const prefixRegex = new RegExp(`^${reportFilePrefix}\\d+\\.json$`);
|
|
952
|
+
reportFiles = files.filter((file) => prefixRegex.test(file));
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
if (reportFiles.length === 0) return null;
|
|
956
|
+
reportFiles.sort((a, b) => {
|
|
957
|
+
const idA = parseInt(a.match(/\d+/)?.[0] || "0", 10);
|
|
958
|
+
const idB = parseInt(b.match(/\d+/)?.[0] || "0", 10);
|
|
959
|
+
return idB - idA;
|
|
960
|
+
});
|
|
961
|
+
return (0, import_path2.join)(scanReportsDir, reportFiles[0]);
|
|
962
|
+
} catch (e) {
|
|
963
|
+
console.error("Error while finding latest scan report:", e);
|
|
964
|
+
return null;
|
|
863
965
|
}
|
|
864
966
|
}
|
|
865
967
|
|
|
968
|
+
// src/utils/provider-utils.ts
|
|
969
|
+
function groupIssuesByFile(issues) {
|
|
970
|
+
const fileIssuesMap = /* @__PURE__ */ new Map();
|
|
971
|
+
for (const issue of issues) {
|
|
972
|
+
const file = issue.location?.file ?? "unknown";
|
|
973
|
+
if (!fileIssuesMap.has(file)) fileIssuesMap.set(file, []);
|
|
974
|
+
fileIssuesMap.get(file).push(issue);
|
|
975
|
+
}
|
|
976
|
+
return Array.from(fileIssuesMap.entries()).map(([fileName, issueList]) => ({
|
|
977
|
+
fileName,
|
|
978
|
+
issues: issueList,
|
|
979
|
+
metrics: {}
|
|
980
|
+
}));
|
|
981
|
+
}
|
|
982
|
+
function buildSimpleProviderScore(toolName, summary, rawData = {}) {
|
|
983
|
+
return {
|
|
984
|
+
toolName,
|
|
985
|
+
score: summary.score ?? 0,
|
|
986
|
+
rawMetrics: { ...summary, ...rawData },
|
|
987
|
+
factors: [],
|
|
988
|
+
recommendations: (summary.recommendations ?? []).map((action) => ({
|
|
989
|
+
action,
|
|
990
|
+
estimatedImpact: 5,
|
|
991
|
+
priority: "medium"
|
|
992
|
+
}))
|
|
993
|
+
};
|
|
994
|
+
}
|
|
995
|
+
function buildSpokeOutput(toolName, version, summary, results, metadata = {}) {
|
|
996
|
+
return SpokeOutputSchema.parse({
|
|
997
|
+
results,
|
|
998
|
+
summary,
|
|
999
|
+
metadata: {
|
|
1000
|
+
toolName,
|
|
1001
|
+
version,
|
|
1002
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1003
|
+
...metadata
|
|
1004
|
+
}
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
1007
|
+
function createProvider(config) {
|
|
1008
|
+
return {
|
|
1009
|
+
id: config.id,
|
|
1010
|
+
alias: config.alias,
|
|
1011
|
+
defaultWeight: config.defaultWeight,
|
|
1012
|
+
async analyze(options) {
|
|
1013
|
+
const report = await config.analyzeReport(options);
|
|
1014
|
+
return buildSpokeOutput(
|
|
1015
|
+
config.id,
|
|
1016
|
+
config.version,
|
|
1017
|
+
config.getSummary(report),
|
|
1018
|
+
config.getResults(report),
|
|
1019
|
+
config.getMetadata?.(report) ?? {}
|
|
1020
|
+
);
|
|
1021
|
+
},
|
|
1022
|
+
score(output, options) {
|
|
1023
|
+
return config.score(output, options);
|
|
1024
|
+
}
|
|
1025
|
+
};
|
|
1026
|
+
}
|
|
1027
|
+
|
|
866
1028
|
// src/utils/ast-parser.ts
|
|
867
1029
|
var import_typescript_estree2 = require("@typescript-eslint/typescript-estree");
|
|
868
1030
|
|
|
@@ -989,8 +1151,10 @@ var TypeScriptParser = class {
|
|
|
989
1151
|
// camelCase for variables and functions
|
|
990
1152
|
variablePattern: /^[a-z][a-zA-Z0-9]*$/,
|
|
991
1153
|
functionPattern: /^[a-z][a-zA-Z0-9]*$/,
|
|
992
|
-
// PascalCase for classes
|
|
1154
|
+
// PascalCase for classes, types and interfaces
|
|
993
1155
|
classPattern: /^[A-Z][a-zA-Z0-9]*$/,
|
|
1156
|
+
typePattern: /^[A-Z][a-zA-Z0-9]*$/,
|
|
1157
|
+
interfacePattern: /^[A-Z][a-zA-Z0-9]*$/,
|
|
994
1158
|
// UPPER_CASE for constants
|
|
995
1159
|
constantPattern: /^[A-Z][A-Z0-9_]*$/,
|
|
996
1160
|
// Common exceptions (React hooks, etc.)
|
|
@@ -1201,6 +1365,101 @@ var TypeScriptParser = class {
|
|
|
1201
1365
|
}
|
|
1202
1366
|
};
|
|
1203
1367
|
|
|
1368
|
+
// src/parsers/metadata-utils.ts
|
|
1369
|
+
function analyzeNodeMetadata(node, code, options) {
|
|
1370
|
+
const metadata = {
|
|
1371
|
+
isPure: true,
|
|
1372
|
+
hasSideEffects: false
|
|
1373
|
+
};
|
|
1374
|
+
try {
|
|
1375
|
+
let prev = node.previousSibling || null;
|
|
1376
|
+
while (prev && /comment/i.test(prev.type)) {
|
|
1377
|
+
const text = prev.text || "";
|
|
1378
|
+
if (text.trim().startsWith("/**") || text.trim().startsWith("/*")) {
|
|
1379
|
+
metadata.documentation = {
|
|
1380
|
+
content: text.replace(/^[/*]+|[/*]+$/g, "").trim(),
|
|
1381
|
+
type: "comment"
|
|
1382
|
+
};
|
|
1383
|
+
break;
|
|
1384
|
+
}
|
|
1385
|
+
if (text.trim().startsWith("///")) {
|
|
1386
|
+
metadata.documentation = {
|
|
1387
|
+
content: text.replace(/^\/\/\//, "").trim(),
|
|
1388
|
+
type: "xml-doc"
|
|
1389
|
+
};
|
|
1390
|
+
break;
|
|
1391
|
+
}
|
|
1392
|
+
if (text.trim().startsWith("//")) {
|
|
1393
|
+
metadata.documentation = {
|
|
1394
|
+
content: text.replace(/^\/\//, "").trim(),
|
|
1395
|
+
type: "comment"
|
|
1396
|
+
};
|
|
1397
|
+
break;
|
|
1398
|
+
}
|
|
1399
|
+
prev = prev.previousSibling;
|
|
1400
|
+
}
|
|
1401
|
+
if (node.type === "function_definition") {
|
|
1402
|
+
const body2 = node.childForFieldName ? node.childForFieldName("body") : node.children.find((c) => c.type === "block");
|
|
1403
|
+
if (body2 && body2.children.length > 0) {
|
|
1404
|
+
const firstStmt = body2.children[0];
|
|
1405
|
+
if (firstStmt.type === "expression_statement" && firstStmt.firstChild?.type === "string") {
|
|
1406
|
+
metadata.documentation = {
|
|
1407
|
+
content: firstStmt.firstChild.text.replace(/['"`]/g, "").trim(),
|
|
1408
|
+
type: "docstring"
|
|
1409
|
+
};
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
} catch {
|
|
1414
|
+
}
|
|
1415
|
+
const defaultSignatures = [
|
|
1416
|
+
"console.",
|
|
1417
|
+
"fmt.",
|
|
1418
|
+
"panic(",
|
|
1419
|
+
"os.Exit",
|
|
1420
|
+
"log.",
|
|
1421
|
+
"Console.Write",
|
|
1422
|
+
"File.Write",
|
|
1423
|
+
"System.out",
|
|
1424
|
+
"System.err",
|
|
1425
|
+
"Files.write",
|
|
1426
|
+
"process.exit",
|
|
1427
|
+
"exit("
|
|
1428
|
+
];
|
|
1429
|
+
const signatures = Array.from(
|
|
1430
|
+
/* @__PURE__ */ new Set([...options?.sideEffectSignatures || [], ...defaultSignatures])
|
|
1431
|
+
);
|
|
1432
|
+
const walk = (n) => {
|
|
1433
|
+
try {
|
|
1434
|
+
const t = n.type || "";
|
|
1435
|
+
if (/assign|assignment|assignment_statement|assignment_expression|throw|throw_statement|send_statement|global_statement|nonlocal_statement/i.test(
|
|
1436
|
+
t
|
|
1437
|
+
)) {
|
|
1438
|
+
metadata.isPure = false;
|
|
1439
|
+
metadata.hasSideEffects = true;
|
|
1440
|
+
}
|
|
1441
|
+
const text = n.text || "";
|
|
1442
|
+
for (const s of signatures) {
|
|
1443
|
+
if (text.includes(s)) {
|
|
1444
|
+
metadata.isPure = false;
|
|
1445
|
+
metadata.hasSideEffects = true;
|
|
1446
|
+
break;
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
for (let i = 0; i < n.childCount; i++) {
|
|
1450
|
+
const c = n.child(i);
|
|
1451
|
+
if (c) walk(c);
|
|
1452
|
+
}
|
|
1453
|
+
} catch {
|
|
1454
|
+
}
|
|
1455
|
+
};
|
|
1456
|
+
const body = node.childForFieldName?.("body") || node.children.find(
|
|
1457
|
+
(c) => /body|block|class_body|declaration_list|function_body/.test(c.type)
|
|
1458
|
+
);
|
|
1459
|
+
if (body) walk(body);
|
|
1460
|
+
return metadata;
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1204
1463
|
// src/parsers/tree-sitter-utils.ts
|
|
1205
1464
|
var Parser = __toESM(require("web-tree-sitter"));
|
|
1206
1465
|
var path = __toESM(require("path"));
|
|
@@ -1289,11 +1548,9 @@ async function setupParser(language) {
|
|
|
1289
1548
|
}
|
|
1290
1549
|
}
|
|
1291
1550
|
|
|
1292
|
-
// src/parsers/
|
|
1293
|
-
var
|
|
1551
|
+
// src/parsers/base-parser.ts
|
|
1552
|
+
var BaseLanguageParser = class {
|
|
1294
1553
|
constructor() {
|
|
1295
|
-
this.language = "python" /* Python */;
|
|
1296
|
-
this.extensions = [".py"];
|
|
1297
1554
|
this.parser = null;
|
|
1298
1555
|
this.initialized = false;
|
|
1299
1556
|
}
|
|
@@ -1302,48 +1559,18 @@ var PythonParser = class {
|
|
|
1302
1559
|
*/
|
|
1303
1560
|
async initialize() {
|
|
1304
1561
|
if (this.initialized) return;
|
|
1305
|
-
|
|
1306
|
-
|
|
1562
|
+
try {
|
|
1563
|
+
this.parser = await setupParser(this.getParserName());
|
|
1564
|
+
this.initialized = true;
|
|
1565
|
+
} catch (error) {
|
|
1566
|
+
console.warn(`Failed to initialize ${this.language} parser:`, error);
|
|
1567
|
+
}
|
|
1307
1568
|
}
|
|
1308
1569
|
async getAST(code, filePath) {
|
|
1309
1570
|
if (!this.initialized) await this.initialize();
|
|
1310
1571
|
if (!this.parser) return null;
|
|
1311
1572
|
return this.parser.parse(code);
|
|
1312
1573
|
}
|
|
1313
|
-
analyzeMetadata(node, code) {
|
|
1314
|
-
const metadata = {
|
|
1315
|
-
isPure: true,
|
|
1316
|
-
hasSideEffects: false
|
|
1317
|
-
};
|
|
1318
|
-
const body = node.childForFieldName("body");
|
|
1319
|
-
if (body && body.children.length > 0) {
|
|
1320
|
-
const firstStmt = body.children[0];
|
|
1321
|
-
if (firstStmt.type === "expression_statement" && firstStmt.firstChild?.type === "string") {
|
|
1322
|
-
metadata.documentation = {
|
|
1323
|
-
content: firstStmt.firstChild.text.replace(/['"`]/g, "").trim(),
|
|
1324
|
-
type: "docstring"
|
|
1325
|
-
};
|
|
1326
|
-
}
|
|
1327
|
-
}
|
|
1328
|
-
const walk = (n) => {
|
|
1329
|
-
if (n.type === "global_statement" || n.type === "nonlocal_statement") {
|
|
1330
|
-
metadata.isPure = false;
|
|
1331
|
-
metadata.hasSideEffects = true;
|
|
1332
|
-
}
|
|
1333
|
-
if (n.type === "call") {
|
|
1334
|
-
const functionNode = n.childForFieldName("function");
|
|
1335
|
-
if (functionNode && ["print", "input", "open"].includes(functionNode.text)) {
|
|
1336
|
-
metadata.isPure = false;
|
|
1337
|
-
metadata.hasSideEffects = true;
|
|
1338
|
-
}
|
|
1339
|
-
}
|
|
1340
|
-
for (const child of n.children) {
|
|
1341
|
-
walk(child);
|
|
1342
|
-
}
|
|
1343
|
-
};
|
|
1344
|
-
if (body) walk(body);
|
|
1345
|
-
return metadata;
|
|
1346
|
-
}
|
|
1347
1574
|
parse(code, filePath) {
|
|
1348
1575
|
if (!this.initialized || !this.parser) {
|
|
1349
1576
|
return this.parseRegex(code, filePath);
|
|
@@ -1353,19 +1580,42 @@ var PythonParser = class {
|
|
|
1353
1580
|
if (!tree || tree.rootNode.type === "ERROR" || tree.rootNode.hasError) {
|
|
1354
1581
|
return this.parseRegex(code, filePath);
|
|
1355
1582
|
}
|
|
1356
|
-
const
|
|
1357
|
-
const
|
|
1358
|
-
const exports2 = this.extractExportsAST(rootNode, code);
|
|
1583
|
+
const imports = this.extractImportsAST(tree.rootNode);
|
|
1584
|
+
const exports2 = this.extractExportsAST(tree.rootNode, code);
|
|
1359
1585
|
return {
|
|
1360
1586
|
exports: exports2,
|
|
1361
1587
|
imports,
|
|
1362
|
-
language:
|
|
1588
|
+
language: this.language,
|
|
1363
1589
|
warnings: []
|
|
1364
1590
|
};
|
|
1365
1591
|
} catch (error) {
|
|
1592
|
+
console.warn(
|
|
1593
|
+
`AST parsing failed for ${filePath}, falling back to regex: ${error.message}`
|
|
1594
|
+
);
|
|
1366
1595
|
return this.parseRegex(code, filePath);
|
|
1367
1596
|
}
|
|
1368
1597
|
}
|
|
1598
|
+
canHandle(filePath) {
|
|
1599
|
+
const lowerPath = filePath.toLowerCase();
|
|
1600
|
+
return this.extensions.some((ext) => lowerPath.endsWith(ext));
|
|
1601
|
+
}
|
|
1602
|
+
};
|
|
1603
|
+
|
|
1604
|
+
// src/parsers/python-parser.ts
|
|
1605
|
+
var PythonParser = class extends BaseLanguageParser {
|
|
1606
|
+
constructor() {
|
|
1607
|
+
super(...arguments);
|
|
1608
|
+
this.language = "python" /* Python */;
|
|
1609
|
+
this.extensions = [".py"];
|
|
1610
|
+
}
|
|
1611
|
+
getParserName() {
|
|
1612
|
+
return "python";
|
|
1613
|
+
}
|
|
1614
|
+
analyzeMetadata(node, code) {
|
|
1615
|
+
return analyzeNodeMetadata(node, code, {
|
|
1616
|
+
sideEffectSignatures: ["print(", "input(", "open("]
|
|
1617
|
+
});
|
|
1618
|
+
}
|
|
1369
1619
|
extractImportsAST(rootNode) {
|
|
1370
1620
|
const imports = [];
|
|
1371
1621
|
const processImportNode = (node) => {
|
|
@@ -1691,94 +1941,132 @@ var PythonParser = class {
|
|
|
1691
1941
|
}
|
|
1692
1942
|
};
|
|
1693
1943
|
|
|
1694
|
-
// src/parsers/
|
|
1695
|
-
var
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1944
|
+
// src/parsers/shared-parser-utils.ts
|
|
1945
|
+
var SIDE_EFFECT_KEYWORDS = [
|
|
1946
|
+
"print(",
|
|
1947
|
+
"console.",
|
|
1948
|
+
"System.out",
|
|
1949
|
+
"System.err",
|
|
1950
|
+
"fmt.",
|
|
1951
|
+
"File.Write",
|
|
1952
|
+
"Files.write",
|
|
1953
|
+
"os.Exit",
|
|
1954
|
+
"panic(",
|
|
1955
|
+
"throw ",
|
|
1956
|
+
"Logging.",
|
|
1957
|
+
"log."
|
|
1958
|
+
];
|
|
1959
|
+
function analyzeGeneralMetadata(node, code, options = {}) {
|
|
1960
|
+
const metadata = {
|
|
1961
|
+
isPure: true,
|
|
1962
|
+
hasSideEffects: false
|
|
1963
|
+
};
|
|
1964
|
+
try {
|
|
1965
|
+
let prev = node.previousSibling || null;
|
|
1966
|
+
while (prev && /comment/i.test(prev.type)) {
|
|
1967
|
+
const text = prev.text || "";
|
|
1968
|
+
if (text.trim().startsWith("/**")) {
|
|
1969
|
+
metadata.documentation = {
|
|
1970
|
+
content: text.replace(/^[/*]+|[/*]+$/g, "").trim(),
|
|
1971
|
+
type: "jsdoc"
|
|
1972
|
+
};
|
|
1973
|
+
break;
|
|
1974
|
+
}
|
|
1975
|
+
if (text.trim().startsWith("///")) {
|
|
1723
1976
|
metadata.documentation = {
|
|
1724
|
-
content:
|
|
1977
|
+
content: text.replace(/^\/\/\//, "").trim(),
|
|
1725
1978
|
type: "xml-doc"
|
|
1726
|
-
|
|
1979
|
+
};
|
|
1980
|
+
break;
|
|
1981
|
+
}
|
|
1982
|
+
if (text.trim().startsWith("//")) {
|
|
1983
|
+
metadata.documentation = {
|
|
1984
|
+
content: text.replace(/^\/\//, "").trim(),
|
|
1985
|
+
type: "comment"
|
|
1727
1986
|
};
|
|
1728
1987
|
break;
|
|
1729
1988
|
}
|
|
1730
1989
|
prev = prev.previousSibling;
|
|
1731
1990
|
}
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1991
|
+
} catch {
|
|
1992
|
+
}
|
|
1993
|
+
const signatures = [
|
|
1994
|
+
...SIDE_EFFECT_KEYWORDS,
|
|
1995
|
+
...options.sideEffectSignatures || []
|
|
1996
|
+
];
|
|
1997
|
+
const walk = (n) => {
|
|
1998
|
+
if (/assign|assignment|assignment_statement|assignment_expression/i.test(
|
|
1999
|
+
n.type
|
|
2000
|
+
)) {
|
|
2001
|
+
metadata.isPure = false;
|
|
2002
|
+
metadata.hasSideEffects = true;
|
|
2003
|
+
}
|
|
2004
|
+
const text = n.text;
|
|
2005
|
+
for (const sig of signatures) {
|
|
2006
|
+
if (text.includes(sig)) {
|
|
1745
2007
|
metadata.isPure = false;
|
|
1746
2008
|
metadata.hasSideEffects = true;
|
|
2009
|
+
break;
|
|
1747
2010
|
}
|
|
1748
|
-
for (const child of n.children) {
|
|
1749
|
-
walk(child);
|
|
1750
|
-
}
|
|
1751
|
-
};
|
|
1752
|
-
const body = node.children.find(
|
|
1753
|
-
(c) => c.type === "block" || c.type === "class_body"
|
|
1754
|
-
);
|
|
1755
|
-
if (body) walk(body);
|
|
1756
|
-
return metadata;
|
|
1757
|
-
}
|
|
1758
|
-
parse(code, filePath) {
|
|
1759
|
-
if (!this.initialized || !this.parser) {
|
|
1760
|
-
return this.parseRegex(code, filePath);
|
|
1761
2011
|
}
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
2012
|
+
if (!metadata.hasSideEffects) {
|
|
2013
|
+
for (let i = 0; i < n.childCount; i++) {
|
|
2014
|
+
const child = n.child(i);
|
|
2015
|
+
if (child) walk(child);
|
|
1766
2016
|
}
|
|
1767
|
-
const rootNode = tree.rootNode;
|
|
1768
|
-
const imports = this.extractImportsAST(rootNode);
|
|
1769
|
-
const exports2 = this.extractExportsAST(rootNode, code);
|
|
1770
|
-
return {
|
|
1771
|
-
exports: exports2,
|
|
1772
|
-
imports,
|
|
1773
|
-
language: "java" /* Java */,
|
|
1774
|
-
warnings: []
|
|
1775
|
-
};
|
|
1776
|
-
} catch (error) {
|
|
1777
|
-
console.warn(
|
|
1778
|
-
`AST parsing failed for ${filePath}, falling back to regex: ${error.message}`
|
|
1779
|
-
);
|
|
1780
|
-
return this.parseRegex(code, filePath);
|
|
1781
2017
|
}
|
|
2018
|
+
};
|
|
2019
|
+
walk(node);
|
|
2020
|
+
return metadata;
|
|
2021
|
+
}
|
|
2022
|
+
function extractParameterNames(node) {
|
|
2023
|
+
const params = [];
|
|
2024
|
+
const candidates = [
|
|
2025
|
+
// common field name
|
|
2026
|
+
node.childForFieldName ? node.childForFieldName("parameters") : null,
|
|
2027
|
+
node.childForFieldName ? node.childForFieldName("parameter_list") : null,
|
|
2028
|
+
node.children.find((c) => c.type === "parameter_list") || null,
|
|
2029
|
+
node.children.find((c) => c.type === "parameters") || null,
|
|
2030
|
+
node.children.find((c) => c.type === "formal_parameters") || null,
|
|
2031
|
+
node.children.find((c) => c.type === "formal_parameter") || null
|
|
2032
|
+
];
|
|
2033
|
+
const list = candidates.find(Boolean);
|
|
2034
|
+
if (!list) return params;
|
|
2035
|
+
for (const child of list.children) {
|
|
2036
|
+
if (!child) continue;
|
|
2037
|
+
const id = child.childForFieldName?.("name") || child.children.find(
|
|
2038
|
+
(c) => [
|
|
2039
|
+
"identifier",
|
|
2040
|
+
"variable_name",
|
|
2041
|
+
"name",
|
|
2042
|
+
"parameter",
|
|
2043
|
+
"formal_parameter"
|
|
2044
|
+
].includes(c.type)
|
|
2045
|
+
) || (child.type === "identifier" ? child : void 0);
|
|
2046
|
+
if (id && typeof id.text === "string") params.push(id.text);
|
|
2047
|
+
}
|
|
2048
|
+
return params;
|
|
2049
|
+
}
|
|
2050
|
+
|
|
2051
|
+
// src/parsers/java-parser.ts
|
|
2052
|
+
var JavaParser = class extends BaseLanguageParser {
|
|
2053
|
+
constructor() {
|
|
2054
|
+
super(...arguments);
|
|
2055
|
+
this.language = "java" /* Java */;
|
|
2056
|
+
this.extensions = [".java"];
|
|
2057
|
+
}
|
|
2058
|
+
getParserName() {
|
|
2059
|
+
return "java";
|
|
2060
|
+
}
|
|
2061
|
+
analyzeMetadata(node, code) {
|
|
2062
|
+
return analyzeGeneralMetadata(node, code, {
|
|
2063
|
+
sideEffectSignatures: [
|
|
2064
|
+
"System.out",
|
|
2065
|
+
"System.err",
|
|
2066
|
+
"Files.write",
|
|
2067
|
+
"Logging."
|
|
2068
|
+
]
|
|
2069
|
+
});
|
|
1782
2070
|
}
|
|
1783
2071
|
parseRegex(code, filePath) {
|
|
1784
2072
|
const lines = code.split("\n");
|
|
@@ -1853,7 +2141,7 @@ var JavaParser = class {
|
|
|
1853
2141
|
const imports = [];
|
|
1854
2142
|
for (const node of rootNode.children) {
|
|
1855
2143
|
if (node.type === "import_declaration") {
|
|
1856
|
-
|
|
2144
|
+
const sourceArr = [];
|
|
1857
2145
|
let isStatic = false;
|
|
1858
2146
|
let isWildcard = false;
|
|
1859
2147
|
for (const child of node.children) {
|
|
@@ -1951,14 +2239,7 @@ var JavaParser = class {
|
|
|
1951
2239
|
}
|
|
1952
2240
|
}
|
|
1953
2241
|
extractParameters(node) {
|
|
1954
|
-
|
|
1955
|
-
(c) => c.type === "formal_parameters"
|
|
1956
|
-
);
|
|
1957
|
-
if (!paramsNode) return [];
|
|
1958
|
-
return paramsNode.children.filter((c) => c.type === "formal_parameter").map((c) => {
|
|
1959
|
-
const idNode = c.children.find((child) => child.type === "identifier");
|
|
1960
|
-
return idNode ? idNode.text : "unknown";
|
|
1961
|
-
});
|
|
2242
|
+
return extractParameterNames(node);
|
|
1962
2243
|
}
|
|
1963
2244
|
getNamingConventions() {
|
|
1964
2245
|
return {
|
|
@@ -1975,91 +2256,19 @@ var JavaParser = class {
|
|
|
1975
2256
|
};
|
|
1976
2257
|
|
|
1977
2258
|
// src/parsers/csharp-parser.ts
|
|
1978
|
-
var CSharpParser = class {
|
|
2259
|
+
var CSharpParser = class extends BaseLanguageParser {
|
|
1979
2260
|
constructor() {
|
|
2261
|
+
super(...arguments);
|
|
1980
2262
|
this.language = "csharp" /* CSharp */;
|
|
1981
2263
|
this.extensions = [".cs"];
|
|
1982
|
-
this.parser = null;
|
|
1983
|
-
this.initialized = false;
|
|
1984
2264
|
}
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
*/
|
|
1988
|
-
async initialize() {
|
|
1989
|
-
if (this.initialized) return;
|
|
1990
|
-
this.parser = await setupParser("c_sharp");
|
|
1991
|
-
this.initialized = true;
|
|
1992
|
-
}
|
|
1993
|
-
async getAST(code, filePath) {
|
|
1994
|
-
if (!this.initialized) await this.initialize();
|
|
1995
|
-
if (!this.parser) return null;
|
|
1996
|
-
return this.parser.parse(code);
|
|
2265
|
+
getParserName() {
|
|
2266
|
+
return "c_sharp";
|
|
1997
2267
|
}
|
|
1998
2268
|
analyzeMetadata(node, code) {
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
};
|
|
2003
|
-
let prev = node.previousSibling;
|
|
2004
|
-
while (prev && (prev.type === "comment" || prev.type === "triple_slash_comment")) {
|
|
2005
|
-
if (prev.text.trim().startsWith("///") || prev.type === "triple_slash_comment") {
|
|
2006
|
-
metadata.documentation = {
|
|
2007
|
-
content: prev.text.replace("///", "").trim(),
|
|
2008
|
-
type: "xml-doc"
|
|
2009
|
-
};
|
|
2010
|
-
break;
|
|
2011
|
-
}
|
|
2012
|
-
prev = prev.previousSibling;
|
|
2013
|
-
}
|
|
2014
|
-
const walk = (n) => {
|
|
2015
|
-
if (n.type === "assignment_expression") {
|
|
2016
|
-
metadata.isPure = false;
|
|
2017
|
-
metadata.hasSideEffects = true;
|
|
2018
|
-
}
|
|
2019
|
-
if (n.type === "invocation_expression") {
|
|
2020
|
-
const text = n.text;
|
|
2021
|
-
if (text.includes("Console.Write") || text.includes("File.Write") || text.includes("Log.")) {
|
|
2022
|
-
metadata.isPure = false;
|
|
2023
|
-
metadata.hasSideEffects = true;
|
|
2024
|
-
}
|
|
2025
|
-
}
|
|
2026
|
-
if (n.type === "throw_statement") {
|
|
2027
|
-
metadata.isPure = false;
|
|
2028
|
-
metadata.hasSideEffects = true;
|
|
2029
|
-
}
|
|
2030
|
-
for (let i = 0; i < n.childCount; i++) {
|
|
2031
|
-
const child = n.child(i);
|
|
2032
|
-
if (child) walk(child);
|
|
2033
|
-
}
|
|
2034
|
-
};
|
|
2035
|
-
const body = node.children.find(
|
|
2036
|
-
(c) => c.type === "block" || c.type === "declaration_list"
|
|
2037
|
-
);
|
|
2038
|
-
if (body) walk(body);
|
|
2039
|
-
return metadata;
|
|
2040
|
-
}
|
|
2041
|
-
parse(code, filePath) {
|
|
2042
|
-
if (!this.initialized || !this.parser) {
|
|
2043
|
-
return this.parseRegex(code, filePath);
|
|
2044
|
-
}
|
|
2045
|
-
try {
|
|
2046
|
-
const tree = this.parser.parse(code);
|
|
2047
|
-
if (!tree) throw new Error("Parser.parse(code) returned null");
|
|
2048
|
-
const rootNode = tree.rootNode;
|
|
2049
|
-
const imports = this.extractImportsAST(rootNode);
|
|
2050
|
-
const exports2 = this.extractExportsAST(rootNode, code);
|
|
2051
|
-
return {
|
|
2052
|
-
exports: exports2,
|
|
2053
|
-
imports,
|
|
2054
|
-
language: "csharp" /* CSharp */,
|
|
2055
|
-
warnings: []
|
|
2056
|
-
};
|
|
2057
|
-
} catch (error) {
|
|
2058
|
-
console.warn(
|
|
2059
|
-
`AST parsing failed for ${filePath}, falling back to regex: ${error.message}`
|
|
2060
|
-
);
|
|
2061
|
-
return this.parseRegex(code, filePath);
|
|
2062
|
-
}
|
|
2269
|
+
return analyzeGeneralMetadata(node, code, {
|
|
2270
|
+
sideEffectSignatures: ["Console.Write", "File.Write", "Logging."]
|
|
2271
|
+
});
|
|
2063
2272
|
}
|
|
2064
2273
|
parseRegex(code, filePath) {
|
|
2065
2274
|
const lines = code.split("\n");
|
|
@@ -2241,19 +2450,7 @@ var CSharpParser = class {
|
|
|
2241
2450
|
return modifiers;
|
|
2242
2451
|
}
|
|
2243
2452
|
extractParameters(node) {
|
|
2244
|
-
|
|
2245
|
-
const parameterList = node.childForFieldName("parameters") || node.children.find((c) => c.type === "parameter_list");
|
|
2246
|
-
if (parameterList) {
|
|
2247
|
-
for (const param of parameterList.children) {
|
|
2248
|
-
if (param.type === "parameter") {
|
|
2249
|
-
const nameNode = param.childForFieldName("name") || param.children.find((c) => c.type === "identifier");
|
|
2250
|
-
if (nameNode) {
|
|
2251
|
-
params.push(nameNode.text);
|
|
2252
|
-
}
|
|
2253
|
-
}
|
|
2254
|
-
}
|
|
2255
|
-
}
|
|
2256
|
-
return params;
|
|
2453
|
+
return extractParameterNames(node);
|
|
2257
2454
|
}
|
|
2258
2455
|
getNamingConventions() {
|
|
2259
2456
|
return {
|
|
@@ -2269,86 +2466,19 @@ var CSharpParser = class {
|
|
|
2269
2466
|
};
|
|
2270
2467
|
|
|
2271
2468
|
// src/parsers/go-parser.ts
|
|
2272
|
-
var GoParser = class {
|
|
2469
|
+
var GoParser = class extends BaseLanguageParser {
|
|
2273
2470
|
constructor() {
|
|
2471
|
+
super(...arguments);
|
|
2274
2472
|
this.language = "go" /* Go */;
|
|
2275
2473
|
this.extensions = [".go"];
|
|
2276
|
-
this.parser = null;
|
|
2277
|
-
this.initialized = false;
|
|
2278
|
-
}
|
|
2279
|
-
/**
|
|
2280
|
-
* Initialize the tree-sitter parser
|
|
2281
|
-
*/
|
|
2282
|
-
async initialize() {
|
|
2283
|
-
if (this.initialized) return;
|
|
2284
|
-
this.parser = await setupParser("go");
|
|
2285
|
-
this.initialized = true;
|
|
2286
2474
|
}
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
if (!this.parser) return null;
|
|
2290
|
-
return this.parser.parse(code);
|
|
2475
|
+
getParserName() {
|
|
2476
|
+
return "go";
|
|
2291
2477
|
}
|
|
2292
2478
|
analyzeMetadata(node, code) {
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
};
|
|
2297
|
-
let prev = node.previousSibling;
|
|
2298
|
-
while (prev && prev.type === "comment") {
|
|
2299
|
-
metadata.documentation = {
|
|
2300
|
-
content: prev.text.replace(/\/\/|\/\*|\*\//g, "").trim(),
|
|
2301
|
-
type: "comment"
|
|
2302
|
-
};
|
|
2303
|
-
break;
|
|
2304
|
-
}
|
|
2305
|
-
const walk = (n) => {
|
|
2306
|
-
if (n.type === "send_statement" || n.type === "expression_statement" && n.text.includes("<-")) {
|
|
2307
|
-
metadata.isPure = false;
|
|
2308
|
-
metadata.hasSideEffects = true;
|
|
2309
|
-
}
|
|
2310
|
-
if (n.type === "assignment_statement" || n.type === "short_var_declaration") {
|
|
2311
|
-
}
|
|
2312
|
-
if (n.type === "call_expression") {
|
|
2313
|
-
const text = n.text;
|
|
2314
|
-
if (text.includes("fmt.Print") || text.includes("os.Exit") || text.includes("panic(") || text.includes("log.")) {
|
|
2315
|
-
metadata.isPure = false;
|
|
2316
|
-
metadata.hasSideEffects = true;
|
|
2317
|
-
}
|
|
2318
|
-
}
|
|
2319
|
-
for (let i = 0; i < n.childCount; i++) {
|
|
2320
|
-
const child = n.child(i);
|
|
2321
|
-
if (child) walk(child);
|
|
2322
|
-
}
|
|
2323
|
-
};
|
|
2324
|
-
const body = node.childForFieldName("body");
|
|
2325
|
-
if (body) walk(body);
|
|
2326
|
-
return metadata;
|
|
2327
|
-
}
|
|
2328
|
-
parse(code, filePath) {
|
|
2329
|
-
if (!this.initialized || !this.parser) {
|
|
2330
|
-
return this.parseRegex(code, filePath);
|
|
2331
|
-
}
|
|
2332
|
-
try {
|
|
2333
|
-
const tree = this.parser.parse(code);
|
|
2334
|
-
if (!tree || tree.rootNode.type === "ERROR" || tree.rootNode.hasError) {
|
|
2335
|
-
return this.parseRegex(code, filePath);
|
|
2336
|
-
}
|
|
2337
|
-
const rootNode = tree.rootNode;
|
|
2338
|
-
const imports = this.extractImportsAST(rootNode);
|
|
2339
|
-
const exports2 = this.extractExportsAST(rootNode, code);
|
|
2340
|
-
return {
|
|
2341
|
-
exports: exports2,
|
|
2342
|
-
imports,
|
|
2343
|
-
language: "go" /* Go */,
|
|
2344
|
-
warnings: []
|
|
2345
|
-
};
|
|
2346
|
-
} catch (error) {
|
|
2347
|
-
console.warn(
|
|
2348
|
-
`AST parsing failed for ${filePath}, falling back to regex: ${error.message}`
|
|
2349
|
-
);
|
|
2350
|
-
return this.parseRegex(code, filePath);
|
|
2351
|
-
}
|
|
2479
|
+
return analyzeGeneralMetadata(node, code, {
|
|
2480
|
+
sideEffectSignatures: ["<-", "fmt.Print", "fmt.Fprintf", "os.Exit"]
|
|
2481
|
+
});
|
|
2352
2482
|
}
|
|
2353
2483
|
parseRegex(code, filePath) {
|
|
2354
2484
|
const lines = code.split("\n");
|
|
@@ -2545,17 +2675,7 @@ var GoParser = class {
|
|
|
2545
2675
|
return exports2;
|
|
2546
2676
|
}
|
|
2547
2677
|
extractParameters(node) {
|
|
2548
|
-
|
|
2549
|
-
const parameterList = node.childForFieldName("parameters") || node.children.find((c) => c.type === "parameter_list");
|
|
2550
|
-
if (parameterList) {
|
|
2551
|
-
for (const param of parameterList.children) {
|
|
2552
|
-
if (param.type === "parameter_declaration") {
|
|
2553
|
-
const names = param.children.filter((c) => c.type === "identifier");
|
|
2554
|
-
names.forEach((n) => params.push(n.text));
|
|
2555
|
-
}
|
|
2556
|
-
}
|
|
2557
|
-
}
|
|
2558
|
-
return params;
|
|
2678
|
+
return extractParameterNames(node);
|
|
2559
2679
|
}
|
|
2560
2680
|
getNamingConventions() {
|
|
2561
2681
|
return {
|
|
@@ -2686,48 +2806,7 @@ function getSupportedLanguages() {
|
|
|
2686
2806
|
return ParserFactory.getInstance().getSupportedLanguages();
|
|
2687
2807
|
}
|
|
2688
2808
|
|
|
2689
|
-
// src/utils/ast-
|
|
2690
|
-
function parseFileExports(code, filePath) {
|
|
2691
|
-
const parser = getParser(filePath);
|
|
2692
|
-
if (parser && parser.language !== "typescript" /* TypeScript */ && parser.language !== "javascript" /* JavaScript */) {
|
|
2693
|
-
try {
|
|
2694
|
-
const result = parser.parse(code, filePath);
|
|
2695
|
-
return {
|
|
2696
|
-
exports: result.exports.map((e) => ({
|
|
2697
|
-
name: e.name,
|
|
2698
|
-
type: e.type,
|
|
2699
|
-
imports: e.imports || [],
|
|
2700
|
-
dependencies: e.dependencies || [],
|
|
2701
|
-
typeReferences: e.typeReferences || [],
|
|
2702
|
-
loc: e.loc ? {
|
|
2703
|
-
start: { line: e.loc.start.line, column: e.loc.start.column },
|
|
2704
|
-
end: { line: e.loc.end.line, column: e.loc.end.column }
|
|
2705
|
-
} : void 0
|
|
2706
|
-
})),
|
|
2707
|
-
imports: result.imports.map((i) => ({
|
|
2708
|
-
source: i.source,
|
|
2709
|
-
specifiers: i.specifiers,
|
|
2710
|
-
isTypeOnly: i.isTypeOnly || false
|
|
2711
|
-
}))
|
|
2712
|
-
};
|
|
2713
|
-
} catch (e) {
|
|
2714
|
-
return { exports: [], imports: [] };
|
|
2715
|
-
}
|
|
2716
|
-
}
|
|
2717
|
-
try {
|
|
2718
|
-
const ast = (0, import_typescript_estree2.parse)(code, {
|
|
2719
|
-
loc: true,
|
|
2720
|
-
range: true,
|
|
2721
|
-
jsx: filePath.endsWith(".tsx") || filePath.endsWith(".jsx"),
|
|
2722
|
-
filePath
|
|
2723
|
-
});
|
|
2724
|
-
const imports = extractFileImports(ast);
|
|
2725
|
-
const exports2 = extractExportsWithDependencies(ast, imports);
|
|
2726
|
-
return { exports: exports2, imports };
|
|
2727
|
-
} catch (error) {
|
|
2728
|
-
return { exports: [], imports: [] };
|
|
2729
|
-
}
|
|
2730
|
-
}
|
|
2809
|
+
// src/utils/ast-visitor.ts
|
|
2731
2810
|
function extractFileImports(ast) {
|
|
2732
2811
|
const imports = [];
|
|
2733
2812
|
for (const node of ast.body) {
|
|
@@ -2785,22 +2864,23 @@ function extractExportsWithDependencies(ast, fileImports) {
|
|
|
2785
2864
|
}
|
|
2786
2865
|
return exports2;
|
|
2787
2866
|
}
|
|
2788
|
-
function extractFromDeclaration(
|
|
2867
|
+
function extractFromDeclaration(node) {
|
|
2868
|
+
if (!node) return [];
|
|
2789
2869
|
const results = [];
|
|
2790
|
-
if (
|
|
2791
|
-
results.push({ name:
|
|
2792
|
-
} else if (
|
|
2793
|
-
results.push({ name:
|
|
2794
|
-
} else if (
|
|
2795
|
-
for (const
|
|
2796
|
-
if (
|
|
2797
|
-
results.push({ name:
|
|
2870
|
+
if (node.type === "FunctionDeclaration" && node.id) {
|
|
2871
|
+
results.push({ name: node.id.name, type: "function" });
|
|
2872
|
+
} else if (node.type === "ClassDeclaration" && node.id) {
|
|
2873
|
+
results.push({ name: node.id.name, type: "class" });
|
|
2874
|
+
} else if (node.type === "VariableDeclaration") {
|
|
2875
|
+
for (const decl of node.declarations) {
|
|
2876
|
+
if (decl.id.type === "Identifier") {
|
|
2877
|
+
results.push({ name: decl.id.name, type: "const" });
|
|
2798
2878
|
}
|
|
2799
2879
|
}
|
|
2800
|
-
} else if (
|
|
2801
|
-
results.push({ name:
|
|
2802
|
-
} else if (
|
|
2803
|
-
results.push({ name:
|
|
2880
|
+
} else if (node.type === "TSInterfaceDeclaration" && node.id) {
|
|
2881
|
+
results.push({ name: node.id.name, type: "interface" });
|
|
2882
|
+
} else if (node.type === "TSTypeAliasDeclaration" && node.id) {
|
|
2883
|
+
results.push({ name: node.id.name, type: "type" });
|
|
2804
2884
|
}
|
|
2805
2885
|
return results;
|
|
2806
2886
|
}
|
|
@@ -2828,16 +2908,6 @@ function findUsedImports(node, importedNames) {
|
|
|
2828
2908
|
visit(node);
|
|
2829
2909
|
return Array.from(usedImports);
|
|
2830
2910
|
}
|
|
2831
|
-
function calculateImportSimilarity(export1, export2) {
|
|
2832
|
-
if (export1.imports.length === 0 && export2.imports.length === 0) {
|
|
2833
|
-
return 1;
|
|
2834
|
-
}
|
|
2835
|
-
const set1 = new Set(export1.imports);
|
|
2836
|
-
const set2 = new Set(export2.imports);
|
|
2837
|
-
const intersection = new Set([...set1].filter((x) => set2.has(x)));
|
|
2838
|
-
const union = /* @__PURE__ */ new Set([...set1, ...set2]);
|
|
2839
|
-
return intersection.size / union.size;
|
|
2840
|
-
}
|
|
2841
2911
|
function extractTypeReferences(node) {
|
|
2842
2912
|
const types = /* @__PURE__ */ new Set();
|
|
2843
2913
|
function visit(n) {
|
|
@@ -2875,6 +2945,59 @@ function extractTypeReferences(node) {
|
|
|
2875
2945
|
visit(node);
|
|
2876
2946
|
return Array.from(types);
|
|
2877
2947
|
}
|
|
2948
|
+
|
|
2949
|
+
// src/utils/ast-parser.ts
|
|
2950
|
+
function parseFileExports(code, filePath) {
|
|
2951
|
+
const parser = getParser(filePath);
|
|
2952
|
+
if (parser && parser.language !== "typescript" /* TypeScript */ && parser.language !== "javascript" /* JavaScript */) {
|
|
2953
|
+
try {
|
|
2954
|
+
const result = parser.parse(code, filePath);
|
|
2955
|
+
return {
|
|
2956
|
+
exports: result.exports.map((e) => ({
|
|
2957
|
+
name: e.name,
|
|
2958
|
+
type: e.type,
|
|
2959
|
+
imports: e.imports || [],
|
|
2960
|
+
dependencies: e.dependencies || [],
|
|
2961
|
+
typeReferences: e.typeReferences || [],
|
|
2962
|
+
loc: e.loc ? {
|
|
2963
|
+
start: { line: e.loc.start.line, column: e.loc.start.column },
|
|
2964
|
+
end: { line: e.loc.end.line, column: e.loc.end.column }
|
|
2965
|
+
} : void 0
|
|
2966
|
+
})),
|
|
2967
|
+
imports: result.imports.map((i) => ({
|
|
2968
|
+
source: i.source,
|
|
2969
|
+
specifiers: i.specifiers,
|
|
2970
|
+
isTypeOnly: i.isTypeOnly || false
|
|
2971
|
+
}))
|
|
2972
|
+
};
|
|
2973
|
+
} catch (e) {
|
|
2974
|
+
return { exports: [], imports: [] };
|
|
2975
|
+
}
|
|
2976
|
+
}
|
|
2977
|
+
try {
|
|
2978
|
+
const ast = (0, import_typescript_estree2.parse)(code, {
|
|
2979
|
+
loc: true,
|
|
2980
|
+
range: true,
|
|
2981
|
+
jsx: filePath.endsWith(".tsx") || filePath.endsWith(".jsx"),
|
|
2982
|
+
filePath
|
|
2983
|
+
});
|
|
2984
|
+
const imports = extractFileImports(ast);
|
|
2985
|
+
const exports2 = extractExportsWithDependencies(ast, imports);
|
|
2986
|
+
return { exports: exports2, imports };
|
|
2987
|
+
} catch (error) {
|
|
2988
|
+
return { exports: [], imports: [] };
|
|
2989
|
+
}
|
|
2990
|
+
}
|
|
2991
|
+
function calculateImportSimilarity(export1, export2) {
|
|
2992
|
+
if (export1.imports.length === 0 && export2.imports.length === 0) {
|
|
2993
|
+
return 1;
|
|
2994
|
+
}
|
|
2995
|
+
const set1 = new Set(export1.imports);
|
|
2996
|
+
const set2 = new Set(export2.imports);
|
|
2997
|
+
const intersection = new Set([...set1].filter((x) => set2.has(x)));
|
|
2998
|
+
const union = /* @__PURE__ */ new Set([...set1, ...set2]);
|
|
2999
|
+
return intersection.size / union.size;
|
|
3000
|
+
}
|
|
2878
3001
|
function parseCode(code, language) {
|
|
2879
3002
|
return null;
|
|
2880
3003
|
}
|
|
@@ -2905,34 +3028,47 @@ var CONFIG_FILES = [
|
|
|
2905
3028
|
async function loadConfig(rootDir) {
|
|
2906
3029
|
let currentDir = (0, import_path3.resolve)(rootDir);
|
|
2907
3030
|
while (true) {
|
|
3031
|
+
const foundConfigs = [];
|
|
2908
3032
|
for (const configFile of CONFIG_FILES) {
|
|
3033
|
+
if ((0, import_fs3.existsSync)((0, import_path3.join)(currentDir, configFile))) {
|
|
3034
|
+
foundConfigs.push(configFile);
|
|
3035
|
+
}
|
|
3036
|
+
}
|
|
3037
|
+
if (foundConfigs.length > 0) {
|
|
3038
|
+
if (foundConfigs.length > 1) {
|
|
3039
|
+
console.warn(
|
|
3040
|
+
`\u26A0\uFE0F Multiple configuration files found in ${currentDir}: ${foundConfigs.join(
|
|
3041
|
+
", "
|
|
3042
|
+
)}. Using ${foundConfigs[0]}.`
|
|
3043
|
+
);
|
|
3044
|
+
} else {
|
|
3045
|
+
}
|
|
3046
|
+
const configFile = foundConfigs[0];
|
|
2909
3047
|
const configPath = (0, import_path3.join)(currentDir, configFile);
|
|
2910
|
-
|
|
3048
|
+
try {
|
|
3049
|
+
let config;
|
|
3050
|
+
if (configFile.endsWith(".js")) {
|
|
3051
|
+
const fileUrl = (0, import_url.pathToFileURL)(configPath).href;
|
|
3052
|
+
const module2 = await import(`${fileUrl}?t=${Date.now()}`);
|
|
3053
|
+
config = module2.default || module2;
|
|
3054
|
+
} else {
|
|
3055
|
+
const content = (0, import_fs3.readFileSync)(configPath, "utf-8");
|
|
3056
|
+
config = JSON.parse(content);
|
|
3057
|
+
}
|
|
3058
|
+
if (typeof config !== "object" || config === null) {
|
|
3059
|
+
throw new Error("Config must be an object");
|
|
3060
|
+
}
|
|
3061
|
+
return config;
|
|
3062
|
+
} catch (error) {
|
|
3063
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3064
|
+
const configError = new Error(
|
|
3065
|
+
`Failed to load config from ${configPath}: ${errorMessage}`
|
|
3066
|
+
);
|
|
2911
3067
|
try {
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
const fileUrl = (0, import_url.pathToFileURL)(configPath).href;
|
|
2915
|
-
const module2 = await import(`${fileUrl}?t=${Date.now()}`);
|
|
2916
|
-
config = module2.default || module2;
|
|
2917
|
-
} else {
|
|
2918
|
-
const content = (0, import_fs3.readFileSync)(configPath, "utf-8");
|
|
2919
|
-
config = JSON.parse(content);
|
|
2920
|
-
}
|
|
2921
|
-
if (typeof config !== "object" || config === null) {
|
|
2922
|
-
throw new Error("Config must be an object");
|
|
2923
|
-
}
|
|
2924
|
-
return config;
|
|
2925
|
-
} catch (error) {
|
|
2926
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2927
|
-
const e = new Error(
|
|
2928
|
-
`Failed to load config from ${configPath}: ${errorMessage}`
|
|
2929
|
-
);
|
|
2930
|
-
try {
|
|
2931
|
-
e.cause = error instanceof Error ? error : void 0;
|
|
2932
|
-
} catch {
|
|
2933
|
-
}
|
|
2934
|
-
throw e;
|
|
3068
|
+
configError.cause = error instanceof Error ? error : void 0;
|
|
3069
|
+
} catch {
|
|
2935
3070
|
}
|
|
3071
|
+
throw configError;
|
|
2936
3072
|
}
|
|
2937
3073
|
}
|
|
2938
3074
|
const parent = (0, import_path3.dirname)(currentDir);
|
|
@@ -2945,28 +3081,28 @@ async function loadConfig(rootDir) {
|
|
|
2945
3081
|
}
|
|
2946
3082
|
function mergeConfigWithDefaults(userConfig, defaults) {
|
|
2947
3083
|
if (!userConfig) return defaults;
|
|
2948
|
-
const
|
|
3084
|
+
const mergedConfig = { ...defaults };
|
|
2949
3085
|
if (userConfig.scan) {
|
|
2950
|
-
if (userConfig.scan.include)
|
|
2951
|
-
if (userConfig.scan.exclude)
|
|
3086
|
+
if (userConfig.scan.include) mergedConfig.include = userConfig.scan.include;
|
|
3087
|
+
if (userConfig.scan.exclude) mergedConfig.exclude = userConfig.scan.exclude;
|
|
2952
3088
|
}
|
|
2953
3089
|
const toolOverrides = userConfig.tools && !Array.isArray(userConfig.tools) && typeof userConfig.tools === "object" ? userConfig.tools : userConfig.toolConfigs;
|
|
2954
3090
|
if (toolOverrides) {
|
|
2955
|
-
if (!
|
|
3091
|
+
if (!mergedConfig.toolConfigs) mergedConfig.toolConfigs = {};
|
|
2956
3092
|
for (const [toolName, toolConfig] of Object.entries(toolOverrides)) {
|
|
2957
3093
|
if (typeof toolConfig === "object" && toolConfig !== null) {
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
...
|
|
3094
|
+
mergedConfig[toolName] = { ...mergedConfig[toolName], ...toolConfig };
|
|
3095
|
+
mergedConfig.toolConfigs[toolName] = {
|
|
3096
|
+
...mergedConfig.toolConfigs[toolName],
|
|
2961
3097
|
...toolConfig
|
|
2962
3098
|
};
|
|
2963
3099
|
}
|
|
2964
3100
|
}
|
|
2965
3101
|
}
|
|
2966
3102
|
if (userConfig.output) {
|
|
2967
|
-
|
|
3103
|
+
mergedConfig.output = { ...mergedConfig.output, ...userConfig.output };
|
|
2968
3104
|
}
|
|
2969
|
-
return
|
|
3105
|
+
return mergedConfig;
|
|
2970
3106
|
}
|
|
2971
3107
|
|
|
2972
3108
|
// src/utils/visualization.ts
|
|
@@ -3335,6 +3471,13 @@ function getRating(score) {
|
|
|
3335
3471
|
if (score >= 40) return "Needs Work" /* NeedsWork */;
|
|
3336
3472
|
return "Critical" /* Critical */;
|
|
3337
3473
|
}
|
|
3474
|
+
function getRatingSlug(score) {
|
|
3475
|
+
if (score >= 90) return "excellent";
|
|
3476
|
+
if (score >= 75) return "good";
|
|
3477
|
+
if (score >= 60) return "fair";
|
|
3478
|
+
if (score >= 40) return "needs-work";
|
|
3479
|
+
return "critical";
|
|
3480
|
+
}
|
|
3338
3481
|
function getRatingWithContext(score, fileCount, modelTier = "standard") {
|
|
3339
3482
|
const threshold = getRecommendedThreshold(fileCount, modelTier);
|
|
3340
3483
|
const normalized = score - threshold + 70;
|
|
@@ -3604,7 +3747,10 @@ function predictAcceptanceRate(toolOutputs) {
|
|
|
3604
3747
|
impact: Math.round((50 - aiSignalClarity.score) * 2e-3 * 100)
|
|
3605
3748
|
});
|
|
3606
3749
|
}
|
|
3607
|
-
const totalImpact = factors.reduce(
|
|
3750
|
+
const totalImpact = factors.reduce(
|
|
3751
|
+
(sum, f) => sum + f.impact / 100,
|
|
3752
|
+
0
|
|
3753
|
+
);
|
|
3608
3754
|
const rate = Math.max(0.05, Math.min(0.8, baseRate + totalImpact));
|
|
3609
3755
|
let confidence = 0.35;
|
|
3610
3756
|
if (toolOutputs.size >= 4) confidence = 0.75;
|
|
@@ -3847,6 +3993,24 @@ function collectFutureProofRecommendations(params) {
|
|
|
3847
3993
|
}
|
|
3848
3994
|
return recommendations;
|
|
3849
3995
|
}
|
|
3996
|
+
function collectBaseFutureProofRecommendations(params) {
|
|
3997
|
+
const recommendations = [];
|
|
3998
|
+
for (const rec of params.patternEntropy.recommendations) {
|
|
3999
|
+
recommendations.push({
|
|
4000
|
+
action: rec,
|
|
4001
|
+
estimatedImpact: 5,
|
|
4002
|
+
priority: "medium"
|
|
4003
|
+
});
|
|
4004
|
+
}
|
|
4005
|
+
if (params.conceptCohesion.rating === "poor") {
|
|
4006
|
+
recommendations.push({
|
|
4007
|
+
action: "Improve concept cohesion by grouping related exports",
|
|
4008
|
+
estimatedImpact: 8,
|
|
4009
|
+
priority: "high"
|
|
4010
|
+
});
|
|
4011
|
+
}
|
|
4012
|
+
return recommendations;
|
|
4013
|
+
}
|
|
3850
4014
|
|
|
3851
4015
|
// src/metrics/cognitive-load.ts
|
|
3852
4016
|
function calculateCognitiveLoad(params) {
|
|
@@ -4537,21 +4701,10 @@ function calculateFutureProofScore(params) {
|
|
|
4537
4701
|
description: params.conceptCohesion.rating
|
|
4538
4702
|
}
|
|
4539
4703
|
];
|
|
4540
|
-
const recommendations =
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
estimatedImpact: 5,
|
|
4545
|
-
priority: "medium"
|
|
4546
|
-
});
|
|
4547
|
-
}
|
|
4548
|
-
if (params.conceptCohesion.rating === "poor") {
|
|
4549
|
-
recommendations.push({
|
|
4550
|
-
action: "Improve concept cohesion by grouping related exports",
|
|
4551
|
-
estimatedImpact: 8,
|
|
4552
|
-
priority: "high"
|
|
4553
|
-
});
|
|
4554
|
-
}
|
|
4704
|
+
const recommendations = collectBaseFutureProofRecommendations({
|
|
4705
|
+
patternEntropy: params.patternEntropy,
|
|
4706
|
+
conceptCohesion: params.conceptCohesion
|
|
4707
|
+
});
|
|
4555
4708
|
const semanticDistanceAvg = params.semanticDistances?.length ? params.semanticDistances.reduce((s, d) => s + d.distance, 0) / params.semanticDistances.length : 0;
|
|
4556
4709
|
return {
|
|
4557
4710
|
toolName: "future-proof",
|
|
@@ -4884,6 +5037,8 @@ function emitIssuesAsAnnotations(issues) {
|
|
|
4884
5037
|
TypeScriptParser,
|
|
4885
5038
|
UnifiedReportSchema,
|
|
4886
5039
|
VAGUE_FILE_NAMES,
|
|
5040
|
+
buildSimpleProviderScore,
|
|
5041
|
+
buildSpokeOutput,
|
|
4887
5042
|
calculateAgentGrounding,
|
|
4888
5043
|
calculateAiSignalClarity,
|
|
4889
5044
|
calculateBusinessROI,
|
|
@@ -4907,6 +5062,7 @@ function emitIssuesAsAnnotations(issues) {
|
|
|
4907
5062
|
calculateTestabilityIndex,
|
|
4908
5063
|
calculateTokenBudget,
|
|
4909
5064
|
clearHistory,
|
|
5065
|
+
createProvider,
|
|
4910
5066
|
emitAnnotation,
|
|
4911
5067
|
emitIssuesAsAnnotations,
|
|
4912
5068
|
emitProgress,
|
|
@@ -4915,6 +5071,8 @@ function emitIssuesAsAnnotations(issues) {
|
|
|
4915
5071
|
exportHistory,
|
|
4916
5072
|
extractFunctions,
|
|
4917
5073
|
extractImports,
|
|
5074
|
+
findLatestReport,
|
|
5075
|
+
findLatestScanReport,
|
|
4918
5076
|
formatAcceptanceRate,
|
|
4919
5077
|
formatCost,
|
|
4920
5078
|
formatHours,
|
|
@@ -4932,15 +5090,21 @@ function emitIssuesAsAnnotations(issues) {
|
|
|
4932
5090
|
getProjectSizeTier,
|
|
4933
5091
|
getRating,
|
|
4934
5092
|
getRatingDisplay,
|
|
5093
|
+
getRatingSlug,
|
|
4935
5094
|
getRatingWithContext,
|
|
4936
5095
|
getRecommendedThreshold,
|
|
4937
5096
|
getRepoMetadata,
|
|
4938
5097
|
getSafetyIcon,
|
|
4939
5098
|
getScoreBar,
|
|
5099
|
+
getSeverityBadge,
|
|
4940
5100
|
getSeverityColor,
|
|
5101
|
+
getSeverityEnum,
|
|
5102
|
+
getSeverityLevel,
|
|
5103
|
+
getSeverityValue,
|
|
4941
5104
|
getSupportedLanguages,
|
|
4942
5105
|
getToolWeight,
|
|
4943
5106
|
getWasmPath,
|
|
5107
|
+
groupIssuesByFile,
|
|
4944
5108
|
handleCLIError,
|
|
4945
5109
|
handleJSONOutput,
|
|
4946
5110
|
initTreeSitter,
|