@aiready/core 0.23.2 → 0.23.4
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 -1098
- package/dist/client.d.ts +2 -1098
- package/dist/client.js +23 -43
- package/dist/client.mjs +3 -25
- package/dist/index.d.mts +329 -107
- package/dist/index.d.ts +329 -107
- package/dist/index.js +329 -340
- package/dist/index.mjs +305 -322
- 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 +1 -1
package/dist/index.mjs
CHANGED
|
@@ -38,12 +38,13 @@ import {
|
|
|
38
38
|
getProjectSizeTier,
|
|
39
39
|
getRating,
|
|
40
40
|
getRatingDisplay,
|
|
41
|
+
getRatingSlug,
|
|
41
42
|
getRatingWithContext,
|
|
42
43
|
getRecommendedThreshold,
|
|
43
44
|
getToolWeight,
|
|
44
45
|
normalizeToolName,
|
|
45
46
|
parseWeightString
|
|
46
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-NGHT7JOG.mjs";
|
|
47
48
|
|
|
48
49
|
// src/types/contract.ts
|
|
49
50
|
function validateSpokeOutput(toolName, output) {
|
|
@@ -303,7 +304,7 @@ async function scanFiles(options) {
|
|
|
303
304
|
try {
|
|
304
305
|
const txt = await readFile(ignoreFilePath, "utf-8");
|
|
305
306
|
ignoreFromFile = txt.split(/\r?\n/).map((s) => s.trim()).filter(Boolean).filter((l) => !l.startsWith("#")).filter((l) => !l.startsWith("!"));
|
|
306
|
-
} catch
|
|
307
|
+
} catch {
|
|
307
308
|
ignoreFromFile = [];
|
|
308
309
|
}
|
|
309
310
|
}
|
|
@@ -357,7 +358,7 @@ async function scanFiles(options) {
|
|
|
357
358
|
return !ig.ignores(rel);
|
|
358
359
|
});
|
|
359
360
|
return filtered;
|
|
360
|
-
} catch
|
|
361
|
+
} catch {
|
|
361
362
|
return files;
|
|
362
363
|
}
|
|
363
364
|
}
|
|
@@ -365,14 +366,14 @@ async function scanFiles(options) {
|
|
|
365
366
|
}
|
|
366
367
|
async function scanEntries(options) {
|
|
367
368
|
const files = await scanFiles(options);
|
|
368
|
-
const { rootDir,
|
|
369
|
+
const { rootDir, exclude, includeTests } = options;
|
|
369
370
|
const ignoreFilePath = join(rootDir || ".", ".aireadyignore");
|
|
370
371
|
let ignoreFromFile = [];
|
|
371
372
|
if (existsSync(ignoreFilePath)) {
|
|
372
373
|
try {
|
|
373
374
|
const txt = await readFile(ignoreFilePath, "utf-8");
|
|
374
375
|
ignoreFromFile = txt.split(/\r?\n/).map((s) => s.trim()).filter(Boolean).filter((l) => !l.startsWith("#")).filter((l) => !l.startsWith("!"));
|
|
375
|
-
} catch
|
|
376
|
+
} catch {
|
|
376
377
|
ignoreFromFile = [];
|
|
377
378
|
}
|
|
378
379
|
}
|
|
@@ -447,6 +448,7 @@ import {
|
|
|
447
448
|
statSync
|
|
448
449
|
} from "fs";
|
|
449
450
|
import { join as join2, dirname as dirname2, resolve as resolvePath } from "path";
|
|
451
|
+
import chalk from "chalk";
|
|
450
452
|
function resolveOutputPath(userPath, defaultFilename, workingDir = process.cwd()) {
|
|
451
453
|
let outputPath;
|
|
452
454
|
if (userPath) {
|
|
@@ -514,22 +516,72 @@ function emitProgress(processed, total, toolId, message, onProgress, throttleCou
|
|
|
514
516
|
onProgress(processed, total, `${message} (${processed}/${total})`);
|
|
515
517
|
}
|
|
516
518
|
}
|
|
517
|
-
function getSeverityColor(severity, chalk) {
|
|
519
|
+
function getSeverityColor(severity, chalkInstance = chalk) {
|
|
518
520
|
switch (severity.toLowerCase()) {
|
|
519
521
|
case "critical":
|
|
520
522
|
case "high-risk":
|
|
521
523
|
case "blind-risk":
|
|
522
|
-
return
|
|
524
|
+
return chalkInstance.red;
|
|
523
525
|
case "major":
|
|
524
526
|
case "moderate-risk":
|
|
525
|
-
return
|
|
527
|
+
return chalkInstance.yellow;
|
|
526
528
|
case "minor":
|
|
527
529
|
case "safe":
|
|
528
|
-
return
|
|
530
|
+
return chalkInstance.green;
|
|
531
|
+
case "info":
|
|
532
|
+
return chalkInstance.blue;
|
|
533
|
+
default:
|
|
534
|
+
return chalkInstance.white;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
function getSeverityValue(s) {
|
|
538
|
+
if (!s) return 0;
|
|
539
|
+
switch (s.toLowerCase()) {
|
|
540
|
+
case "critical":
|
|
541
|
+
return 4;
|
|
542
|
+
case "major":
|
|
543
|
+
return 3;
|
|
544
|
+
case "minor":
|
|
545
|
+
return 2;
|
|
529
546
|
case "info":
|
|
530
|
-
return
|
|
547
|
+
return 1;
|
|
531
548
|
default:
|
|
532
|
-
return
|
|
549
|
+
return 0;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
function getSeverityLevel(s) {
|
|
553
|
+
return getSeverityValue(s);
|
|
554
|
+
}
|
|
555
|
+
function getSeverityBadge(severity, chalkInstance = chalk) {
|
|
556
|
+
const val = getSeverityValue(
|
|
557
|
+
typeof severity === "string" ? severity : severity
|
|
558
|
+
);
|
|
559
|
+
switch (val) {
|
|
560
|
+
case 4:
|
|
561
|
+
return chalkInstance.bgRed.white.bold(" CRITICAL ");
|
|
562
|
+
case 3:
|
|
563
|
+
return chalkInstance.bgYellow.black.bold(" MAJOR ");
|
|
564
|
+
case 2:
|
|
565
|
+
return chalkInstance.bgBlue.white.bold(" MINOR ");
|
|
566
|
+
case 1:
|
|
567
|
+
return chalkInstance.bgCyan.black(" INFO ");
|
|
568
|
+
default:
|
|
569
|
+
return chalkInstance.bgCyan.black(" INFO ");
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
function getSeverityEnum(s) {
|
|
573
|
+
const level = getSeverityLevel(s);
|
|
574
|
+
switch (level) {
|
|
575
|
+
case 4:
|
|
576
|
+
return "critical";
|
|
577
|
+
case 3:
|
|
578
|
+
return "major";
|
|
579
|
+
case 2:
|
|
580
|
+
return "minor";
|
|
581
|
+
case 1:
|
|
582
|
+
return "info";
|
|
583
|
+
default:
|
|
584
|
+
return "info";
|
|
533
585
|
}
|
|
534
586
|
}
|
|
535
587
|
function findLatestReport(dirPath) {
|
|
@@ -978,94 +1030,6 @@ var TypeScriptParser = class {
|
|
|
978
1030
|
}
|
|
979
1031
|
};
|
|
980
1032
|
|
|
981
|
-
// src/parsers/tree-sitter-utils.ts
|
|
982
|
-
import * as Parser from "web-tree-sitter";
|
|
983
|
-
import * as path from "path";
|
|
984
|
-
import * as fs from "fs";
|
|
985
|
-
var isTreeSitterInitialized = false;
|
|
986
|
-
async function initTreeSitter() {
|
|
987
|
-
if (isTreeSitterInitialized) return;
|
|
988
|
-
try {
|
|
989
|
-
const wasmPath = getWasmPath("web-tree-sitter");
|
|
990
|
-
await Parser.Parser.init({
|
|
991
|
-
locateFile() {
|
|
992
|
-
return wasmPath || "web-tree-sitter.wasm";
|
|
993
|
-
}
|
|
994
|
-
});
|
|
995
|
-
isTreeSitterInitialized = true;
|
|
996
|
-
} catch (error) {
|
|
997
|
-
console.error("Failed to initialize web-tree-sitter:", error);
|
|
998
|
-
isTreeSitterInitialized = true;
|
|
999
|
-
}
|
|
1000
|
-
}
|
|
1001
|
-
function findInPnpmStore(startDir, fileName, depth = 0) {
|
|
1002
|
-
if (depth > 8) return null;
|
|
1003
|
-
const pnpmDir = path.join(startDir, "node_modules", ".pnpm");
|
|
1004
|
-
if (fs.existsSync(pnpmDir)) {
|
|
1005
|
-
return findFileRecursively(pnpmDir, fileName, 0);
|
|
1006
|
-
}
|
|
1007
|
-
const parent = path.dirname(startDir);
|
|
1008
|
-
if (parent === startDir) return null;
|
|
1009
|
-
return findInPnpmStore(parent, fileName, depth + 1);
|
|
1010
|
-
}
|
|
1011
|
-
function findFileRecursively(dir, fileName, depth) {
|
|
1012
|
-
if (depth > 6) return null;
|
|
1013
|
-
try {
|
|
1014
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
1015
|
-
for (const entry of entries) {
|
|
1016
|
-
if (entry.isFile() && entry.name === fileName) {
|
|
1017
|
-
return path.join(dir, entry.name);
|
|
1018
|
-
}
|
|
1019
|
-
}
|
|
1020
|
-
for (const entry of entries) {
|
|
1021
|
-
if (entry.isDirectory()) {
|
|
1022
|
-
const found = findFileRecursively(
|
|
1023
|
-
path.join(dir, entry.name),
|
|
1024
|
-
fileName,
|
|
1025
|
-
depth + 1
|
|
1026
|
-
);
|
|
1027
|
-
if (found) return found;
|
|
1028
|
-
}
|
|
1029
|
-
}
|
|
1030
|
-
} catch (err) {
|
|
1031
|
-
}
|
|
1032
|
-
return null;
|
|
1033
|
-
}
|
|
1034
|
-
function getWasmPath(language) {
|
|
1035
|
-
const wasmFileName = language === "web-tree-sitter" ? "web-tree-sitter.wasm" : `tree-sitter-${language}.wasm`;
|
|
1036
|
-
const immediatePaths = [
|
|
1037
|
-
path.join(process.cwd(), wasmFileName),
|
|
1038
|
-
path.join(__dirname, wasmFileName),
|
|
1039
|
-
path.join(__dirname, "assets", wasmFileName)
|
|
1040
|
-
];
|
|
1041
|
-
for (const p of immediatePaths) {
|
|
1042
|
-
if (fs.existsSync(p)) return p;
|
|
1043
|
-
}
|
|
1044
|
-
const pnpmPath = findInPnpmStore(__dirname, wasmFileName);
|
|
1045
|
-
if (pnpmPath) return pnpmPath;
|
|
1046
|
-
const pnpmPathCwd = findInPnpmStore(process.cwd(), wasmFileName);
|
|
1047
|
-
if (pnpmPathCwd) return pnpmPathCwd;
|
|
1048
|
-
console.warn(
|
|
1049
|
-
`[Parser] WASM file for ${language} not found. CWD: ${process.cwd()}, DIR: ${__dirname}`
|
|
1050
|
-
);
|
|
1051
|
-
return null;
|
|
1052
|
-
}
|
|
1053
|
-
async function setupParser(language) {
|
|
1054
|
-
await initTreeSitter();
|
|
1055
|
-
const wasmPath = getWasmPath(language);
|
|
1056
|
-
if (!wasmPath) {
|
|
1057
|
-
return null;
|
|
1058
|
-
}
|
|
1059
|
-
try {
|
|
1060
|
-
const parser = new Parser.Parser();
|
|
1061
|
-
const Lang = await Parser.Language.load(wasmPath);
|
|
1062
|
-
parser.setLanguage(Lang);
|
|
1063
|
-
return parser;
|
|
1064
|
-
} catch (error) {
|
|
1065
|
-
return null;
|
|
1066
|
-
}
|
|
1067
|
-
}
|
|
1068
|
-
|
|
1069
1033
|
// src/parsers/metadata-utils.ts
|
|
1070
1034
|
function analyzeNodeMetadata(node, code, options) {
|
|
1071
1035
|
const metadata = {
|
|
@@ -1161,11 +1125,97 @@ function analyzeNodeMetadata(node, code, options) {
|
|
|
1161
1125
|
return metadata;
|
|
1162
1126
|
}
|
|
1163
1127
|
|
|
1164
|
-
// src/parsers/
|
|
1165
|
-
|
|
1128
|
+
// src/parsers/tree-sitter-utils.ts
|
|
1129
|
+
import * as Parser from "web-tree-sitter";
|
|
1130
|
+
import * as path from "path";
|
|
1131
|
+
import * as fs from "fs";
|
|
1132
|
+
var isTreeSitterInitialized = false;
|
|
1133
|
+
async function initTreeSitter() {
|
|
1134
|
+
if (isTreeSitterInitialized) return;
|
|
1135
|
+
try {
|
|
1136
|
+
const wasmPath = getWasmPath("web-tree-sitter");
|
|
1137
|
+
await Parser.Parser.init({
|
|
1138
|
+
locateFile() {
|
|
1139
|
+
return wasmPath || "web-tree-sitter.wasm";
|
|
1140
|
+
}
|
|
1141
|
+
});
|
|
1142
|
+
isTreeSitterInitialized = true;
|
|
1143
|
+
} catch (error) {
|
|
1144
|
+
console.error("Failed to initialize web-tree-sitter:", error);
|
|
1145
|
+
isTreeSitterInitialized = true;
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
function findInPnpmStore(startDir, fileName, depth = 0) {
|
|
1149
|
+
if (depth > 8) return null;
|
|
1150
|
+
const pnpmDir = path.join(startDir, "node_modules", ".pnpm");
|
|
1151
|
+
if (fs.existsSync(pnpmDir)) {
|
|
1152
|
+
return findFileRecursively(pnpmDir, fileName, 0);
|
|
1153
|
+
}
|
|
1154
|
+
const parent = path.dirname(startDir);
|
|
1155
|
+
if (parent === startDir) return null;
|
|
1156
|
+
return findInPnpmStore(parent, fileName, depth + 1);
|
|
1157
|
+
}
|
|
1158
|
+
function findFileRecursively(dir, fileName, depth) {
|
|
1159
|
+
if (depth > 6) return null;
|
|
1160
|
+
try {
|
|
1161
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
1162
|
+
for (const entry of entries) {
|
|
1163
|
+
if (entry.isFile() && entry.name === fileName) {
|
|
1164
|
+
return path.join(dir, entry.name);
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
for (const entry of entries) {
|
|
1168
|
+
if (entry.isDirectory()) {
|
|
1169
|
+
const found = findFileRecursively(
|
|
1170
|
+
path.join(dir, entry.name),
|
|
1171
|
+
fileName,
|
|
1172
|
+
depth + 1
|
|
1173
|
+
);
|
|
1174
|
+
if (found) return found;
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
} catch {
|
|
1178
|
+
}
|
|
1179
|
+
return null;
|
|
1180
|
+
}
|
|
1181
|
+
function getWasmPath(language) {
|
|
1182
|
+
const wasmFileName = language === "web-tree-sitter" ? "web-tree-sitter.wasm" : `tree-sitter-${language}.wasm`;
|
|
1183
|
+
const immediatePaths = [
|
|
1184
|
+
path.join(process.cwd(), wasmFileName),
|
|
1185
|
+
path.join(__dirname, wasmFileName),
|
|
1186
|
+
path.join(__dirname, "assets", wasmFileName)
|
|
1187
|
+
];
|
|
1188
|
+
for (const p of immediatePaths) {
|
|
1189
|
+
if (fs.existsSync(p)) return p;
|
|
1190
|
+
}
|
|
1191
|
+
const pnpmPath = findInPnpmStore(__dirname, wasmFileName);
|
|
1192
|
+
if (pnpmPath) return pnpmPath;
|
|
1193
|
+
const pnpmPathCwd = findInPnpmStore(process.cwd(), wasmFileName);
|
|
1194
|
+
if (pnpmPathCwd) return pnpmPathCwd;
|
|
1195
|
+
console.warn(
|
|
1196
|
+
`[Parser] WASM file for ${language} not found. CWD: ${process.cwd()}, DIR: ${__dirname}`
|
|
1197
|
+
);
|
|
1198
|
+
return null;
|
|
1199
|
+
}
|
|
1200
|
+
async function setupParser(language) {
|
|
1201
|
+
await initTreeSitter();
|
|
1202
|
+
const wasmPath = getWasmPath(language);
|
|
1203
|
+
if (!wasmPath) {
|
|
1204
|
+
return null;
|
|
1205
|
+
}
|
|
1206
|
+
try {
|
|
1207
|
+
const parser = new Parser.Parser();
|
|
1208
|
+
const Lang = await Parser.Language.load(wasmPath);
|
|
1209
|
+
parser.setLanguage(Lang);
|
|
1210
|
+
return parser;
|
|
1211
|
+
} catch {
|
|
1212
|
+
return null;
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
// src/parsers/base-parser.ts
|
|
1217
|
+
var BaseLanguageParser = class {
|
|
1166
1218
|
constructor() {
|
|
1167
|
-
this.language = "python" /* Python */;
|
|
1168
|
-
this.extensions = [".py"];
|
|
1169
1219
|
this.parser = null;
|
|
1170
1220
|
this.initialized = false;
|
|
1171
1221
|
}
|
|
@@ -1174,19 +1224,19 @@ var PythonParser = class {
|
|
|
1174
1224
|
*/
|
|
1175
1225
|
async initialize() {
|
|
1176
1226
|
if (this.initialized) return;
|
|
1177
|
-
|
|
1178
|
-
|
|
1227
|
+
try {
|
|
1228
|
+
this.parser = await setupParser(this.getParserName());
|
|
1229
|
+
this.initialized = true;
|
|
1230
|
+
} catch (error) {
|
|
1231
|
+
console.warn(`Failed to initialize ${this.language} parser:`, error);
|
|
1232
|
+
}
|
|
1179
1233
|
}
|
|
1180
|
-
async getAST(code,
|
|
1234
|
+
async getAST(code, _filePath) {
|
|
1235
|
+
void _filePath;
|
|
1181
1236
|
if (!this.initialized) await this.initialize();
|
|
1182
1237
|
if (!this.parser) return null;
|
|
1183
1238
|
return this.parser.parse(code);
|
|
1184
1239
|
}
|
|
1185
|
-
analyzeMetadata(node, code) {
|
|
1186
|
-
return analyzeNodeMetadata(node, code, {
|
|
1187
|
-
sideEffectSignatures: ["print(", "input(", "open("]
|
|
1188
|
-
});
|
|
1189
|
-
}
|
|
1190
1240
|
parse(code, filePath) {
|
|
1191
1241
|
if (!this.initialized || !this.parser) {
|
|
1192
1242
|
return this.parseRegex(code, filePath);
|
|
@@ -1196,19 +1246,42 @@ var PythonParser = class {
|
|
|
1196
1246
|
if (!tree || tree.rootNode.type === "ERROR" || tree.rootNode.hasError) {
|
|
1197
1247
|
return this.parseRegex(code, filePath);
|
|
1198
1248
|
}
|
|
1199
|
-
const
|
|
1200
|
-
const
|
|
1201
|
-
const exports = this.extractExportsAST(rootNode, code);
|
|
1249
|
+
const imports = this.extractImportsAST(tree.rootNode);
|
|
1250
|
+
const exports = this.extractExportsAST(tree.rootNode, code);
|
|
1202
1251
|
return {
|
|
1203
1252
|
exports,
|
|
1204
1253
|
imports,
|
|
1205
|
-
language:
|
|
1254
|
+
language: this.language,
|
|
1206
1255
|
warnings: []
|
|
1207
1256
|
};
|
|
1208
1257
|
} catch (error) {
|
|
1258
|
+
console.warn(
|
|
1259
|
+
`AST parsing failed for ${filePath}, falling back to regex: ${error.message}`
|
|
1260
|
+
);
|
|
1209
1261
|
return this.parseRegex(code, filePath);
|
|
1210
1262
|
}
|
|
1211
1263
|
}
|
|
1264
|
+
canHandle(filePath) {
|
|
1265
|
+
const lowerPath = filePath.toLowerCase();
|
|
1266
|
+
return this.extensions.some((ext) => lowerPath.endsWith(ext));
|
|
1267
|
+
}
|
|
1268
|
+
};
|
|
1269
|
+
|
|
1270
|
+
// src/parsers/python-parser.ts
|
|
1271
|
+
var PythonParser = class extends BaseLanguageParser {
|
|
1272
|
+
constructor() {
|
|
1273
|
+
super(...arguments);
|
|
1274
|
+
this.language = "python" /* Python */;
|
|
1275
|
+
this.extensions = [".py"];
|
|
1276
|
+
}
|
|
1277
|
+
getParserName() {
|
|
1278
|
+
return "python";
|
|
1279
|
+
}
|
|
1280
|
+
analyzeMetadata(node, code) {
|
|
1281
|
+
return analyzeNodeMetadata(node, code, {
|
|
1282
|
+
sideEffectSignatures: ["print(", "input(", "open("]
|
|
1283
|
+
});
|
|
1284
|
+
}
|
|
1212
1285
|
extractImportsAST(rootNode) {
|
|
1213
1286
|
const imports = [];
|
|
1214
1287
|
const processImportNode = (node) => {
|
|
@@ -1394,10 +1467,11 @@ var PythonParser = class {
|
|
|
1394
1467
|
]
|
|
1395
1468
|
};
|
|
1396
1469
|
} catch (error) {
|
|
1397
|
-
|
|
1398
|
-
`Failed to parse Python file ${filePath}: ${error.message}
|
|
1399
|
-
filePath
|
|
1470
|
+
const wrapper = new Error(
|
|
1471
|
+
`Failed to parse Python file ${filePath}: ${error.message}`
|
|
1400
1472
|
);
|
|
1473
|
+
wrapper.cause = error;
|
|
1474
|
+
throw wrapper;
|
|
1401
1475
|
}
|
|
1402
1476
|
}
|
|
1403
1477
|
getNamingConventions() {
|
|
@@ -1428,6 +1502,7 @@ var PythonParser = class {
|
|
|
1428
1502
|
return filePath.toLowerCase().endsWith(".py");
|
|
1429
1503
|
}
|
|
1430
1504
|
extractImportsRegex(code, _filePath) {
|
|
1505
|
+
void _filePath;
|
|
1431
1506
|
const imports = [];
|
|
1432
1507
|
const lines = code.split("\n");
|
|
1433
1508
|
const importRegex = /^\s*import\s+([a-zA-Z0-9_., ]+)/;
|
|
@@ -1478,6 +1553,7 @@ var PythonParser = class {
|
|
|
1478
1553
|
return imports;
|
|
1479
1554
|
}
|
|
1480
1555
|
extractExportsRegex(code, _filePath) {
|
|
1556
|
+
void _filePath;
|
|
1481
1557
|
const exports = [];
|
|
1482
1558
|
const lines = code.split("\n");
|
|
1483
1559
|
const funcRegex = /^def\s+([a-zA-Z0-9_]+)\s*\(/;
|
|
@@ -1642,25 +1718,14 @@ function extractParameterNames(node) {
|
|
|
1642
1718
|
}
|
|
1643
1719
|
|
|
1644
1720
|
// src/parsers/java-parser.ts
|
|
1645
|
-
var JavaParser = class {
|
|
1721
|
+
var JavaParser = class extends BaseLanguageParser {
|
|
1646
1722
|
constructor() {
|
|
1723
|
+
super(...arguments);
|
|
1647
1724
|
this.language = "java" /* Java */;
|
|
1648
1725
|
this.extensions = [".java"];
|
|
1649
|
-
this.parser = null;
|
|
1650
|
-
this.initialized = false;
|
|
1651
1726
|
}
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
*/
|
|
1655
|
-
async initialize() {
|
|
1656
|
-
if (this.initialized) return;
|
|
1657
|
-
this.parser = await setupParser("java");
|
|
1658
|
-
this.initialized = true;
|
|
1659
|
-
}
|
|
1660
|
-
async getAST(code, filePath) {
|
|
1661
|
-
if (!this.initialized) await this.initialize();
|
|
1662
|
-
if (!this.parser) return null;
|
|
1663
|
-
return this.parser.parse(code);
|
|
1727
|
+
getParserName() {
|
|
1728
|
+
return "java";
|
|
1664
1729
|
}
|
|
1665
1730
|
analyzeMetadata(node, code) {
|
|
1666
1731
|
return analyzeGeneralMetadata(node, code, {
|
|
@@ -1672,32 +1737,7 @@ var JavaParser = class {
|
|
|
1672
1737
|
]
|
|
1673
1738
|
});
|
|
1674
1739
|
}
|
|
1675
|
-
|
|
1676
|
-
if (!this.initialized || !this.parser) {
|
|
1677
|
-
return this.parseRegex(code, filePath);
|
|
1678
|
-
}
|
|
1679
|
-
try {
|
|
1680
|
-
const tree = this.parser.parse(code);
|
|
1681
|
-
if (!tree || tree.rootNode.type === "ERROR" || tree.rootNode.hasError) {
|
|
1682
|
-
return this.parseRegex(code, filePath);
|
|
1683
|
-
}
|
|
1684
|
-
const rootNode = tree.rootNode;
|
|
1685
|
-
const imports = this.extractImportsAST(rootNode);
|
|
1686
|
-
const exports = this.extractExportsAST(rootNode, code);
|
|
1687
|
-
return {
|
|
1688
|
-
exports,
|
|
1689
|
-
imports,
|
|
1690
|
-
language: "java" /* Java */,
|
|
1691
|
-
warnings: []
|
|
1692
|
-
};
|
|
1693
|
-
} catch (error) {
|
|
1694
|
-
console.warn(
|
|
1695
|
-
`AST parsing failed for ${filePath}, falling back to regex: ${error.message}`
|
|
1696
|
-
);
|
|
1697
|
-
return this.parseRegex(code, filePath);
|
|
1698
|
-
}
|
|
1699
|
-
}
|
|
1700
|
-
parseRegex(code, filePath) {
|
|
1740
|
+
parseRegex(code) {
|
|
1701
1741
|
const lines = code.split("\n");
|
|
1702
1742
|
const exports = [];
|
|
1703
1743
|
const imports = [];
|
|
@@ -1771,10 +1811,8 @@ var JavaParser = class {
|
|
|
1771
1811
|
for (const node of rootNode.children) {
|
|
1772
1812
|
if (node.type === "import_declaration") {
|
|
1773
1813
|
const sourceArr = [];
|
|
1774
|
-
let isStatic = false;
|
|
1775
1814
|
let isWildcard = false;
|
|
1776
1815
|
for (const child of node.children) {
|
|
1777
|
-
if (child.type === "static") isStatic = true;
|
|
1778
1816
|
if (child.type === "scoped_identifier" || child.type === "identifier") {
|
|
1779
1817
|
sourceArr.push(child.text);
|
|
1780
1818
|
}
|
|
@@ -1885,55 +1923,21 @@ var JavaParser = class {
|
|
|
1885
1923
|
};
|
|
1886
1924
|
|
|
1887
1925
|
// src/parsers/csharp-parser.ts
|
|
1888
|
-
var CSharpParser = class {
|
|
1926
|
+
var CSharpParser = class extends BaseLanguageParser {
|
|
1889
1927
|
constructor() {
|
|
1928
|
+
super(...arguments);
|
|
1890
1929
|
this.language = "csharp" /* CSharp */;
|
|
1891
1930
|
this.extensions = [".cs"];
|
|
1892
|
-
this.parser = null;
|
|
1893
|
-
this.initialized = false;
|
|
1894
1931
|
}
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
*/
|
|
1898
|
-
async initialize() {
|
|
1899
|
-
if (this.initialized) return;
|
|
1900
|
-
this.parser = await setupParser("c_sharp");
|
|
1901
|
-
this.initialized = true;
|
|
1902
|
-
}
|
|
1903
|
-
async getAST(code, filePath) {
|
|
1904
|
-
if (!this.initialized) await this.initialize();
|
|
1905
|
-
if (!this.parser) return null;
|
|
1906
|
-
return this.parser.parse(code);
|
|
1932
|
+
getParserName() {
|
|
1933
|
+
return "c_sharp";
|
|
1907
1934
|
}
|
|
1908
1935
|
analyzeMetadata(node, code) {
|
|
1909
1936
|
return analyzeGeneralMetadata(node, code, {
|
|
1910
1937
|
sideEffectSignatures: ["Console.Write", "File.Write", "Logging."]
|
|
1911
1938
|
});
|
|
1912
1939
|
}
|
|
1913
|
-
|
|
1914
|
-
if (!this.initialized || !this.parser) {
|
|
1915
|
-
return this.parseRegex(code, filePath);
|
|
1916
|
-
}
|
|
1917
|
-
try {
|
|
1918
|
-
const tree = this.parser.parse(code);
|
|
1919
|
-
if (!tree) throw new Error("Parser.parse(code) returned null");
|
|
1920
|
-
const rootNode = tree.rootNode;
|
|
1921
|
-
const imports = this.extractImportsAST(rootNode);
|
|
1922
|
-
const exports = this.extractExportsAST(rootNode, code);
|
|
1923
|
-
return {
|
|
1924
|
-
exports,
|
|
1925
|
-
imports,
|
|
1926
|
-
language: "csharp" /* CSharp */,
|
|
1927
|
-
warnings: []
|
|
1928
|
-
};
|
|
1929
|
-
} catch (error) {
|
|
1930
|
-
console.warn(
|
|
1931
|
-
`AST parsing failed for ${filePath}, falling back to regex: ${error.message}`
|
|
1932
|
-
);
|
|
1933
|
-
return this.parseRegex(code, filePath);
|
|
1934
|
-
}
|
|
1935
|
-
}
|
|
1936
|
-
parseRegex(code, filePath) {
|
|
1940
|
+
parseRegex(code) {
|
|
1937
1941
|
const lines = code.split("\n");
|
|
1938
1942
|
const exports = [];
|
|
1939
1943
|
const imports = [];
|
|
@@ -2129,57 +2133,21 @@ var CSharpParser = class {
|
|
|
2129
2133
|
};
|
|
2130
2134
|
|
|
2131
2135
|
// src/parsers/go-parser.ts
|
|
2132
|
-
var GoParser = class {
|
|
2136
|
+
var GoParser = class extends BaseLanguageParser {
|
|
2133
2137
|
constructor() {
|
|
2138
|
+
super(...arguments);
|
|
2134
2139
|
this.language = "go" /* Go */;
|
|
2135
2140
|
this.extensions = [".go"];
|
|
2136
|
-
this.parser = null;
|
|
2137
|
-
this.initialized = false;
|
|
2138
|
-
}
|
|
2139
|
-
/**
|
|
2140
|
-
* Initialize the tree-sitter parser
|
|
2141
|
-
*/
|
|
2142
|
-
async initialize() {
|
|
2143
|
-
if (this.initialized) return;
|
|
2144
|
-
this.parser = await setupParser("go");
|
|
2145
|
-
this.initialized = true;
|
|
2146
2141
|
}
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
if (!this.parser) return null;
|
|
2150
|
-
return this.parser.parse(code);
|
|
2142
|
+
getParserName() {
|
|
2143
|
+
return "go";
|
|
2151
2144
|
}
|
|
2152
2145
|
analyzeMetadata(node, code) {
|
|
2153
2146
|
return analyzeGeneralMetadata(node, code, {
|
|
2154
2147
|
sideEffectSignatures: ["<-", "fmt.Print", "fmt.Fprintf", "os.Exit"]
|
|
2155
2148
|
});
|
|
2156
2149
|
}
|
|
2157
|
-
|
|
2158
|
-
if (!this.initialized || !this.parser) {
|
|
2159
|
-
return this.parseRegex(code, filePath);
|
|
2160
|
-
}
|
|
2161
|
-
try {
|
|
2162
|
-
const tree = this.parser.parse(code);
|
|
2163
|
-
if (!tree || tree.rootNode.type === "ERROR" || tree.rootNode.hasError) {
|
|
2164
|
-
return this.parseRegex(code, filePath);
|
|
2165
|
-
}
|
|
2166
|
-
const rootNode = tree.rootNode;
|
|
2167
|
-
const imports = this.extractImportsAST(rootNode);
|
|
2168
|
-
const exports = this.extractExportsAST(rootNode, code);
|
|
2169
|
-
return {
|
|
2170
|
-
exports,
|
|
2171
|
-
imports,
|
|
2172
|
-
language: "go" /* Go */,
|
|
2173
|
-
warnings: []
|
|
2174
|
-
};
|
|
2175
|
-
} catch (error) {
|
|
2176
|
-
console.warn(
|
|
2177
|
-
`AST parsing failed for ${filePath}, falling back to regex: ${error.message}`
|
|
2178
|
-
);
|
|
2179
|
-
return this.parseRegex(code, filePath);
|
|
2180
|
-
}
|
|
2181
|
-
}
|
|
2182
|
-
parseRegex(code, filePath) {
|
|
2150
|
+
parseRegex(code) {
|
|
2183
2151
|
const lines = code.split("\n");
|
|
2184
2152
|
const exports = [];
|
|
2185
2153
|
const imports = [];
|
|
@@ -2505,48 +2473,7 @@ function getSupportedLanguages() {
|
|
|
2505
2473
|
return ParserFactory.getInstance().getSupportedLanguages();
|
|
2506
2474
|
}
|
|
2507
2475
|
|
|
2508
|
-
// src/utils/ast-
|
|
2509
|
-
function parseFileExports(code, filePath) {
|
|
2510
|
-
const parser = getParser(filePath);
|
|
2511
|
-
if (parser && parser.language !== "typescript" /* TypeScript */ && parser.language !== "javascript" /* JavaScript */) {
|
|
2512
|
-
try {
|
|
2513
|
-
const result = parser.parse(code, filePath);
|
|
2514
|
-
return {
|
|
2515
|
-
exports: result.exports.map((e) => ({
|
|
2516
|
-
name: e.name,
|
|
2517
|
-
type: e.type,
|
|
2518
|
-
imports: e.imports || [],
|
|
2519
|
-
dependencies: e.dependencies || [],
|
|
2520
|
-
typeReferences: e.typeReferences || [],
|
|
2521
|
-
loc: e.loc ? {
|
|
2522
|
-
start: { line: e.loc.start.line, column: e.loc.start.column },
|
|
2523
|
-
end: { line: e.loc.end.line, column: e.loc.end.column }
|
|
2524
|
-
} : void 0
|
|
2525
|
-
})),
|
|
2526
|
-
imports: result.imports.map((i) => ({
|
|
2527
|
-
source: i.source,
|
|
2528
|
-
specifiers: i.specifiers,
|
|
2529
|
-
isTypeOnly: i.isTypeOnly || false
|
|
2530
|
-
}))
|
|
2531
|
-
};
|
|
2532
|
-
} catch (e) {
|
|
2533
|
-
return { exports: [], imports: [] };
|
|
2534
|
-
}
|
|
2535
|
-
}
|
|
2536
|
-
try {
|
|
2537
|
-
const ast = parse2(code, {
|
|
2538
|
-
loc: true,
|
|
2539
|
-
range: true,
|
|
2540
|
-
jsx: filePath.endsWith(".tsx") || filePath.endsWith(".jsx"),
|
|
2541
|
-
filePath
|
|
2542
|
-
});
|
|
2543
|
-
const imports = extractFileImports(ast);
|
|
2544
|
-
const exports = extractExportsWithDependencies(ast, imports);
|
|
2545
|
-
return { exports, imports };
|
|
2546
|
-
} catch (error) {
|
|
2547
|
-
return { exports: [], imports: [] };
|
|
2548
|
-
}
|
|
2549
|
-
}
|
|
2476
|
+
// src/utils/ast-visitor.ts
|
|
2550
2477
|
function extractFileImports(ast) {
|
|
2551
2478
|
const imports = [];
|
|
2552
2479
|
for (const node of ast.body) {
|
|
@@ -2604,22 +2531,23 @@ function extractExportsWithDependencies(ast, fileImports) {
|
|
|
2604
2531
|
}
|
|
2605
2532
|
return exports;
|
|
2606
2533
|
}
|
|
2607
|
-
function extractFromDeclaration(
|
|
2534
|
+
function extractFromDeclaration(node) {
|
|
2535
|
+
if (!node) return [];
|
|
2608
2536
|
const results = [];
|
|
2609
|
-
if (
|
|
2610
|
-
results.push({ name:
|
|
2611
|
-
} else if (
|
|
2612
|
-
results.push({ name:
|
|
2613
|
-
} else if (
|
|
2614
|
-
for (const
|
|
2615
|
-
if (
|
|
2616
|
-
results.push({ name:
|
|
2537
|
+
if (node.type === "FunctionDeclaration" && node.id) {
|
|
2538
|
+
results.push({ name: node.id.name, type: "function" });
|
|
2539
|
+
} else if (node.type === "ClassDeclaration" && node.id) {
|
|
2540
|
+
results.push({ name: node.id.name, type: "class" });
|
|
2541
|
+
} else if (node.type === "VariableDeclaration") {
|
|
2542
|
+
for (const decl of node.declarations) {
|
|
2543
|
+
if (decl.id.type === "Identifier") {
|
|
2544
|
+
results.push({ name: decl.id.name, type: "const" });
|
|
2617
2545
|
}
|
|
2618
2546
|
}
|
|
2619
|
-
} else if (
|
|
2620
|
-
results.push({ name:
|
|
2621
|
-
} else if (
|
|
2622
|
-
results.push({ name:
|
|
2547
|
+
} else if (node.type === "TSInterfaceDeclaration" && node.id) {
|
|
2548
|
+
results.push({ name: node.id.name, type: "interface" });
|
|
2549
|
+
} else if (node.type === "TSTypeAliasDeclaration" && node.id) {
|
|
2550
|
+
results.push({ name: node.id.name, type: "type" });
|
|
2623
2551
|
}
|
|
2624
2552
|
return results;
|
|
2625
2553
|
}
|
|
@@ -2647,16 +2575,6 @@ function findUsedImports(node, importedNames) {
|
|
|
2647
2575
|
visit(node);
|
|
2648
2576
|
return Array.from(usedImports);
|
|
2649
2577
|
}
|
|
2650
|
-
function calculateImportSimilarity(export1, export2) {
|
|
2651
|
-
if (export1.imports.length === 0 && export2.imports.length === 0) {
|
|
2652
|
-
return 1;
|
|
2653
|
-
}
|
|
2654
|
-
const set1 = new Set(export1.imports);
|
|
2655
|
-
const set2 = new Set(export2.imports);
|
|
2656
|
-
const intersection = new Set([...set1].filter((x) => set2.has(x)));
|
|
2657
|
-
const union = /* @__PURE__ */ new Set([...set1, ...set2]);
|
|
2658
|
-
return intersection.size / union.size;
|
|
2659
|
-
}
|
|
2660
2578
|
function extractTypeReferences(node) {
|
|
2661
2579
|
const types = /* @__PURE__ */ new Set();
|
|
2662
2580
|
function visit(n) {
|
|
@@ -2694,13 +2612,70 @@ function extractTypeReferences(node) {
|
|
|
2694
2612
|
visit(node);
|
|
2695
2613
|
return Array.from(types);
|
|
2696
2614
|
}
|
|
2697
|
-
|
|
2615
|
+
|
|
2616
|
+
// src/utils/ast-parser.ts
|
|
2617
|
+
function parseFileExports(code, filePath) {
|
|
2618
|
+
const parser = getParser(filePath);
|
|
2619
|
+
if (parser && parser.language !== "typescript" /* TypeScript */ && parser.language !== "javascript" /* JavaScript */) {
|
|
2620
|
+
try {
|
|
2621
|
+
const result = parser.parse(code, filePath);
|
|
2622
|
+
return {
|
|
2623
|
+
exports: result.exports.map((e) => ({
|
|
2624
|
+
name: e.name,
|
|
2625
|
+
type: e.type,
|
|
2626
|
+
imports: e.imports || [],
|
|
2627
|
+
dependencies: e.dependencies || [],
|
|
2628
|
+
typeReferences: e.typeReferences || [],
|
|
2629
|
+
loc: e.loc ? {
|
|
2630
|
+
start: { line: e.loc.start.line, column: e.loc.start.column },
|
|
2631
|
+
end: { line: e.loc.end.line, column: e.loc.end.column }
|
|
2632
|
+
} : void 0
|
|
2633
|
+
})),
|
|
2634
|
+
imports: result.imports.map((i) => ({
|
|
2635
|
+
source: i.source,
|
|
2636
|
+
specifiers: i.specifiers,
|
|
2637
|
+
isTypeOnly: i.isTypeOnly || false
|
|
2638
|
+
}))
|
|
2639
|
+
};
|
|
2640
|
+
} catch {
|
|
2641
|
+
return { exports: [], imports: [] };
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2644
|
+
try {
|
|
2645
|
+
const ast = parse2(code, {
|
|
2646
|
+
loc: true,
|
|
2647
|
+
range: true,
|
|
2648
|
+
jsx: filePath.endsWith(".tsx") || filePath.endsWith(".jsx"),
|
|
2649
|
+
filePath
|
|
2650
|
+
});
|
|
2651
|
+
const imports = extractFileImports(ast);
|
|
2652
|
+
const exports = extractExportsWithDependencies(ast, imports);
|
|
2653
|
+
return { exports, imports };
|
|
2654
|
+
} catch {
|
|
2655
|
+
return { exports: [], imports: [] };
|
|
2656
|
+
}
|
|
2657
|
+
}
|
|
2658
|
+
function calculateImportSimilarity(export1, export2) {
|
|
2659
|
+
if (export1.imports.length === 0 && export2.imports.length === 0) {
|
|
2660
|
+
return 1;
|
|
2661
|
+
}
|
|
2662
|
+
const set1 = new Set(export1.imports);
|
|
2663
|
+
const set2 = new Set(export2.imports);
|
|
2664
|
+
const intersection = new Set([...set1].filter((x) => set2.has(x)));
|
|
2665
|
+
const union = /* @__PURE__ */ new Set([...set1, ...set2]);
|
|
2666
|
+
return intersection.size / union.size;
|
|
2667
|
+
}
|
|
2668
|
+
function parseCode(_code, _language) {
|
|
2669
|
+
void _code;
|
|
2670
|
+
void _language;
|
|
2698
2671
|
return null;
|
|
2699
2672
|
}
|
|
2700
|
-
function extractFunctions(
|
|
2673
|
+
function extractFunctions(_ast) {
|
|
2674
|
+
void _ast;
|
|
2701
2675
|
return [];
|
|
2702
2676
|
}
|
|
2703
|
-
function extractImports(
|
|
2677
|
+
function extractImports(_ast) {
|
|
2678
|
+
void _ast;
|
|
2704
2679
|
return [];
|
|
2705
2680
|
}
|
|
2706
2681
|
|
|
@@ -2757,14 +2732,14 @@ async function loadConfig(rootDir) {
|
|
|
2757
2732
|
return config;
|
|
2758
2733
|
} catch (error) {
|
|
2759
2734
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2760
|
-
const
|
|
2735
|
+
const configError = new Error(
|
|
2761
2736
|
`Failed to load config from ${configPath}: ${errorMessage}`
|
|
2762
2737
|
);
|
|
2763
2738
|
try {
|
|
2764
|
-
|
|
2739
|
+
configError.cause = error instanceof Error ? error : void 0;
|
|
2765
2740
|
} catch {
|
|
2766
2741
|
}
|
|
2767
|
-
throw
|
|
2742
|
+
throw configError;
|
|
2768
2743
|
}
|
|
2769
2744
|
}
|
|
2770
2745
|
const parent = dirname4(currentDir);
|
|
@@ -2777,28 +2752,28 @@ async function loadConfig(rootDir) {
|
|
|
2777
2752
|
}
|
|
2778
2753
|
function mergeConfigWithDefaults(userConfig, defaults) {
|
|
2779
2754
|
if (!userConfig) return defaults;
|
|
2780
|
-
const
|
|
2755
|
+
const mergedConfig = { ...defaults };
|
|
2781
2756
|
if (userConfig.scan) {
|
|
2782
|
-
if (userConfig.scan.include)
|
|
2783
|
-
if (userConfig.scan.exclude)
|
|
2757
|
+
if (userConfig.scan.include) mergedConfig.include = userConfig.scan.include;
|
|
2758
|
+
if (userConfig.scan.exclude) mergedConfig.exclude = userConfig.scan.exclude;
|
|
2784
2759
|
}
|
|
2785
2760
|
const toolOverrides = userConfig.tools && !Array.isArray(userConfig.tools) && typeof userConfig.tools === "object" ? userConfig.tools : userConfig.toolConfigs;
|
|
2786
2761
|
if (toolOverrides) {
|
|
2787
|
-
if (!
|
|
2762
|
+
if (!mergedConfig.toolConfigs) mergedConfig.toolConfigs = {};
|
|
2788
2763
|
for (const [toolName, toolConfig] of Object.entries(toolOverrides)) {
|
|
2789
2764
|
if (typeof toolConfig === "object" && toolConfig !== null) {
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
...
|
|
2765
|
+
mergedConfig[toolName] = { ...mergedConfig[toolName], ...toolConfig };
|
|
2766
|
+
mergedConfig.toolConfigs[toolName] = {
|
|
2767
|
+
...mergedConfig.toolConfigs[toolName],
|
|
2793
2768
|
...toolConfig
|
|
2794
2769
|
};
|
|
2795
2770
|
}
|
|
2796
2771
|
}
|
|
2797
2772
|
}
|
|
2798
2773
|
if (userConfig.output) {
|
|
2799
|
-
|
|
2774
|
+
mergedConfig.output = { ...mergedConfig.output, ...userConfig.output };
|
|
2800
2775
|
}
|
|
2801
|
-
return
|
|
2776
|
+
return mergedConfig;
|
|
2802
2777
|
}
|
|
2803
2778
|
|
|
2804
2779
|
// src/business/pricing-models.ts
|
|
@@ -3011,7 +2986,10 @@ function predictAcceptanceRate(toolOutputs) {
|
|
|
3011
2986
|
impact: Math.round((50 - aiSignalClarity.score) * 2e-3 * 100)
|
|
3012
2987
|
});
|
|
3013
2988
|
}
|
|
3014
|
-
const totalImpact = factors.reduce(
|
|
2989
|
+
const totalImpact = factors.reduce(
|
|
2990
|
+
(sum, f) => sum + f.impact / 100,
|
|
2991
|
+
0
|
|
2992
|
+
);
|
|
3015
2993
|
const rate = Math.max(0.05, Math.min(0.8, baseRate + totalImpact));
|
|
3016
2994
|
let confidence = 0.35;
|
|
3017
2995
|
if (toolOutputs.size >= 4) confidence = 0.75;
|
|
@@ -4350,12 +4328,17 @@ export {
|
|
|
4350
4328
|
getProjectSizeTier,
|
|
4351
4329
|
getRating,
|
|
4352
4330
|
getRatingDisplay,
|
|
4331
|
+
getRatingSlug,
|
|
4353
4332
|
getRatingWithContext,
|
|
4354
4333
|
getRecommendedThreshold,
|
|
4355
4334
|
getRepoMetadata,
|
|
4356
4335
|
getSafetyIcon,
|
|
4357
4336
|
getScoreBar,
|
|
4337
|
+
getSeverityBadge,
|
|
4358
4338
|
getSeverityColor,
|
|
4339
|
+
getSeverityEnum,
|
|
4340
|
+
getSeverityLevel,
|
|
4341
|
+
getSeverityValue,
|
|
4359
4342
|
getSupportedLanguages,
|
|
4360
4343
|
getToolWeight,
|
|
4361
4344
|
getWasmPath,
|