depwire-cli 1.0.8 → 1.1.1
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/README.md +44 -25
- package/dist/{chunk-W3ZVSDFL.js → chunk-R263B2GF.js} +8 -8
- package/dist/{chunk-WLKW7X7G.js → chunk-Y2CGCAMZ.js} +997 -201
- package/dist/index.js +120 -50
- package/dist/mcpb-entry.js +2 -2
- package/dist/parser/grammars/tree-sitter-swift.wasm +0 -0
- package/dist/sdk.js +1 -1
- package/package.json +3 -2
|
@@ -37,8 +37,9 @@ function scanDirectory(rootDir, baseDir = rootDir) {
|
|
|
37
37
|
const isJava = entry.endsWith(".java") || entry === "pom.xml" || entry === "build.gradle" || entry === "build.gradle.kts";
|
|
38
38
|
const isKotlin = entry.endsWith(".kt") || entry.endsWith(".kts") || entry === "settings.gradle.kts" || entry === "settings.gradle";
|
|
39
39
|
const isPhp = entry.endsWith(".php");
|
|
40
|
+
const isSwift = entry.endsWith(".swift");
|
|
40
41
|
const isCppBuild = entry === "CMakeLists.txt" || entry === "conanfile.txt" || entry === "vcpkg.json";
|
|
41
|
-
if (isTypeScript || isJavaScript || isPython || isGo || isRust || isC || isCpp || isCSharp || isJava || isKotlin || isPhp || isCppBuild) {
|
|
42
|
+
if (isTypeScript || isJavaScript || isPython || isGo || isRust || isC || isCpp || isCSharp || isJava || isKotlin || isPhp || isSwift || isCppBuild) {
|
|
42
43
|
files.push(relative(rootDir, fullPath));
|
|
43
44
|
}
|
|
44
45
|
}
|
|
@@ -84,6 +85,8 @@ function findProjectRoot(startDir = process.cwd()) {
|
|
|
84
85
|
// Kotlin (Gradle KTS)
|
|
85
86
|
"composer.json",
|
|
86
87
|
// PHP
|
|
88
|
+
"Package.swift",
|
|
89
|
+
// Swift (SPM)
|
|
87
90
|
".git"
|
|
88
91
|
// Any git repo
|
|
89
92
|
];
|
|
@@ -117,11 +120,11 @@ function findProjectRoot(startDir = process.cwd()) {
|
|
|
117
120
|
}
|
|
118
121
|
|
|
119
122
|
// src/parser/index.ts
|
|
120
|
-
import { readFileSync as
|
|
121
|
-
import { join as
|
|
123
|
+
import { readFileSync as readFileSync11, statSync as statSync8 } from "fs";
|
|
124
|
+
import { join as join14, resolve as resolve8 } from "path";
|
|
122
125
|
|
|
123
126
|
// src/parser/detect.ts
|
|
124
|
-
import { extname as
|
|
127
|
+
import { extname as extname9, basename as basename7 } from "path";
|
|
125
128
|
|
|
126
129
|
// src/parser/wasm-init.ts
|
|
127
130
|
import { Parser, Language } from "web-tree-sitter";
|
|
@@ -153,7 +156,8 @@ async function initParser() {
|
|
|
153
156
|
"java": "tree-sitter-java.wasm",
|
|
154
157
|
"cpp": "tree-sitter-cpp.wasm",
|
|
155
158
|
"kotlin": "tree-sitter-kotlin.wasm",
|
|
156
|
-
"php": "tree-sitter-php.wasm"
|
|
159
|
+
"php": "tree-sitter-php.wasm",
|
|
160
|
+
"swift": "tree-sitter-swift.wasm"
|
|
157
161
|
};
|
|
158
162
|
for (const [name, file] of Object.entries(grammarFiles)) {
|
|
159
163
|
const wasmPath = path.join(grammarsDir, file);
|
|
@@ -6151,13 +6155,601 @@ function resolvePhpInclude(includePath, currentFile, projectRoot) {
|
|
|
6151
6155
|
if (existsSync12(relativePath)) {
|
|
6152
6156
|
return relativeToRoot;
|
|
6153
6157
|
}
|
|
6154
|
-
const fromRoot = join12(projectRoot, includePath);
|
|
6155
|
-
if (existsSync12(fromRoot)) {
|
|
6156
|
-
return includePath;
|
|
6158
|
+
const fromRoot = join12(projectRoot, includePath);
|
|
6159
|
+
if (existsSync12(fromRoot)) {
|
|
6160
|
+
return includePath;
|
|
6161
|
+
}
|
|
6162
|
+
return null;
|
|
6163
|
+
}
|
|
6164
|
+
function resolveSymbol10(name, context) {
|
|
6165
|
+
if (context.imports.has(name)) {
|
|
6166
|
+
return context.imports.get(name) || null;
|
|
6167
|
+
}
|
|
6168
|
+
const currentFileId = `${context.filePath}::${name}`;
|
|
6169
|
+
if (context.symbols.find((s) => s.id === currentFileId)) {
|
|
6170
|
+
return currentFileId;
|
|
6171
|
+
}
|
|
6172
|
+
if (context.currentClass) {
|
|
6173
|
+
const classMethodId = `${context.filePath}::${context.currentClass}.${name}`;
|
|
6174
|
+
if (context.symbols.find((s) => s.id === classMethodId)) {
|
|
6175
|
+
return classMethodId;
|
|
6176
|
+
}
|
|
6177
|
+
}
|
|
6178
|
+
return null;
|
|
6179
|
+
}
|
|
6180
|
+
function getModifiers2(node, context) {
|
|
6181
|
+
const modifiers = [];
|
|
6182
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
6183
|
+
const child = node.child(i);
|
|
6184
|
+
if (!child) continue;
|
|
6185
|
+
const type = child.type;
|
|
6186
|
+
if (type === "visibility_modifier" || type === "static_modifier" || type === "abstract_modifier" || type === "final_modifier" || type === "readonly_modifier") {
|
|
6187
|
+
modifiers.push(nodeText10(child, context).trim());
|
|
6188
|
+
}
|
|
6189
|
+
}
|
|
6190
|
+
return modifiers;
|
|
6191
|
+
}
|
|
6192
|
+
function extractQualifiedName(node, context) {
|
|
6193
|
+
const nameNode = findDescendantByTypes3(node, ["name", "qualified_name", "namespace_name"]);
|
|
6194
|
+
if (!nameNode) return null;
|
|
6195
|
+
const text = nodeText10(nameNode, context).trim();
|
|
6196
|
+
if (!text) return null;
|
|
6197
|
+
const parts = text.split("\\");
|
|
6198
|
+
return parts[parts.length - 1];
|
|
6199
|
+
}
|
|
6200
|
+
function findChildByType11(node, type) {
|
|
6201
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
6202
|
+
const child = node.child(i);
|
|
6203
|
+
if (child && child.type === type) return child;
|
|
6204
|
+
}
|
|
6205
|
+
return null;
|
|
6206
|
+
}
|
|
6207
|
+
function findChildrenByType5(node, type) {
|
|
6208
|
+
const results = [];
|
|
6209
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
6210
|
+
const child = node.child(i);
|
|
6211
|
+
if (child && child.type === type) results.push(child);
|
|
6212
|
+
}
|
|
6213
|
+
return results;
|
|
6214
|
+
}
|
|
6215
|
+
function findDescendantByTypes3(node, types) {
|
|
6216
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
6217
|
+
const child = node.child(i);
|
|
6218
|
+
if (!child) continue;
|
|
6219
|
+
if (types.includes(child.type)) return child;
|
|
6220
|
+
const found = findDescendantByTypes3(child, types);
|
|
6221
|
+
if (found) return found;
|
|
6222
|
+
}
|
|
6223
|
+
return null;
|
|
6224
|
+
}
|
|
6225
|
+
function nodeText10(node, context) {
|
|
6226
|
+
return context.sourceCode.substring(node.startIndex, node.endIndex);
|
|
6227
|
+
}
|
|
6228
|
+
function getCurrentSymbolId11(context) {
|
|
6229
|
+
if (context.currentScope.length === 0) return null;
|
|
6230
|
+
return `${context.filePath}::${context.currentScope[context.currentScope.length - 1]}`;
|
|
6231
|
+
}
|
|
6232
|
+
var phpParser = {
|
|
6233
|
+
name: "php",
|
|
6234
|
+
extensions: [".php"],
|
|
6235
|
+
parseFile: parsePhpFile
|
|
6236
|
+
};
|
|
6237
|
+
|
|
6238
|
+
// src/parser/swift.ts
|
|
6239
|
+
import { dirname as dirname12, join as join13, basename as basename6 } from "path";
|
|
6240
|
+
import { existsSync as existsSync13, readdirSync as readdirSync10, statSync as statSync7 } from "fs";
|
|
6241
|
+
function parseSwiftFile(filePath, sourceCode, projectRoot) {
|
|
6242
|
+
if (filePath.endsWith("Package.swift")) {
|
|
6243
|
+
return parsePackageSwift(filePath, sourceCode, projectRoot);
|
|
6244
|
+
}
|
|
6245
|
+
const parser = getParser("swift");
|
|
6246
|
+
const tree = parser.parse(sourceCode, null, { bufferSize: 1024 * 1024 });
|
|
6247
|
+
const context = {
|
|
6248
|
+
filePath,
|
|
6249
|
+
projectRoot,
|
|
6250
|
+
sourceCode,
|
|
6251
|
+
symbols: [],
|
|
6252
|
+
edges: [],
|
|
6253
|
+
currentScope: [],
|
|
6254
|
+
currentClass: null,
|
|
6255
|
+
currentModule: null,
|
|
6256
|
+
imports: /* @__PURE__ */ new Map(),
|
|
6257
|
+
isPackageFile: false
|
|
6258
|
+
};
|
|
6259
|
+
walkNode12(tree.rootNode, context);
|
|
6260
|
+
return {
|
|
6261
|
+
filePath,
|
|
6262
|
+
symbols: context.symbols,
|
|
6263
|
+
edges: context.edges
|
|
6264
|
+
};
|
|
6265
|
+
}
|
|
6266
|
+
function walkNode12(node, context) {
|
|
6267
|
+
const handled = processNode12(node, context);
|
|
6268
|
+
if (handled) return;
|
|
6269
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
6270
|
+
const child = node.child(i);
|
|
6271
|
+
if (child) {
|
|
6272
|
+
walkNode12(child, context);
|
|
6273
|
+
}
|
|
6274
|
+
}
|
|
6275
|
+
}
|
|
6276
|
+
function processNode12(node, context) {
|
|
6277
|
+
switch (node.type) {
|
|
6278
|
+
case "import_declaration":
|
|
6279
|
+
processImportDeclaration3(node, context);
|
|
6280
|
+
return false;
|
|
6281
|
+
case "class_declaration":
|
|
6282
|
+
processClassDeclaration7(node, context);
|
|
6283
|
+
return true;
|
|
6284
|
+
// handles its own children
|
|
6285
|
+
case "protocol_declaration":
|
|
6286
|
+
processProtocolDeclaration(node, context);
|
|
6287
|
+
return true;
|
|
6288
|
+
// handles its own children
|
|
6289
|
+
case "function_declaration":
|
|
6290
|
+
processFunctionDeclaration5(node, context);
|
|
6291
|
+
return true;
|
|
6292
|
+
// handles its own children
|
|
6293
|
+
case "init_declaration":
|
|
6294
|
+
processInitDeclaration(node, context);
|
|
6295
|
+
return true;
|
|
6296
|
+
case "deinit_declaration":
|
|
6297
|
+
processDeinitDeclaration(node, context);
|
|
6298
|
+
return true;
|
|
6299
|
+
case "property_declaration":
|
|
6300
|
+
case "variable_declaration":
|
|
6301
|
+
processPropertyDeclaration4(node, context);
|
|
6302
|
+
return false;
|
|
6303
|
+
case "typealias_declaration":
|
|
6304
|
+
processTypealiasDeclaration(node, context);
|
|
6305
|
+
return false;
|
|
6306
|
+
case "associatedtype_declaration":
|
|
6307
|
+
processAssociatedTypeDeclaration(node, context);
|
|
6308
|
+
return false;
|
|
6309
|
+
case "call_expression":
|
|
6310
|
+
processCallExpression12(node, context);
|
|
6311
|
+
return false;
|
|
6312
|
+
default:
|
|
6313
|
+
return false;
|
|
6314
|
+
}
|
|
6315
|
+
}
|
|
6316
|
+
function processImportDeclaration3(node, context) {
|
|
6317
|
+
const text = nodeText11(node, context).trim();
|
|
6318
|
+
const match = text.match(/^import\s+(?:(?:typealias|struct|class|enum|protocol|let|var|func)\s+)?(.+)$/);
|
|
6319
|
+
if (!match) return;
|
|
6320
|
+
const importPath = match[1].trim();
|
|
6321
|
+
const resolvedPath = resolveSwiftImport(importPath, context.filePath, context.projectRoot);
|
|
6322
|
+
if (resolvedPath) {
|
|
6323
|
+
const sourceId = `${context.filePath}::__file__`;
|
|
6324
|
+
const targetId = `${resolvedPath}::__file__`;
|
|
6325
|
+
context.edges.push({
|
|
6326
|
+
source: sourceId,
|
|
6327
|
+
target: targetId,
|
|
6328
|
+
kind: "imports",
|
|
6329
|
+
filePath: context.filePath,
|
|
6330
|
+
line: node.startPosition.row + 1
|
|
6331
|
+
});
|
|
6332
|
+
const parts = importPath.split(".");
|
|
6333
|
+
const simpleName = parts[parts.length - 1];
|
|
6334
|
+
context.imports.set(simpleName, `${resolvedPath}::${simpleName}`);
|
|
6335
|
+
}
|
|
6336
|
+
const symbolId = `${context.filePath}::import:${importPath}`;
|
|
6337
|
+
context.symbols.push({
|
|
6338
|
+
id: symbolId,
|
|
6339
|
+
name: importPath,
|
|
6340
|
+
kind: "import",
|
|
6341
|
+
filePath: context.filePath,
|
|
6342
|
+
startLine: node.startPosition.row + 1,
|
|
6343
|
+
endLine: node.endPosition.row + 1,
|
|
6344
|
+
exported: false
|
|
6345
|
+
});
|
|
6346
|
+
}
|
|
6347
|
+
function processClassDeclaration7(node, context) {
|
|
6348
|
+
let keyword = "class";
|
|
6349
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
6350
|
+
const child = node.child(i);
|
|
6351
|
+
if (child && ["class", "struct", "actor", "enum", "extension"].includes(child.type)) {
|
|
6352
|
+
keyword = child.type;
|
|
6353
|
+
break;
|
|
6354
|
+
}
|
|
6355
|
+
}
|
|
6356
|
+
if (keyword === "extension") {
|
|
6357
|
+
const typeNode = findChildByType12(node, "user_type") || findChildByType12(node, "type_identifier");
|
|
6358
|
+
const extName = typeNode ? nodeText11(typeNode, context).trim() : "Unknown";
|
|
6359
|
+
const name2 = `${extName}+ext`;
|
|
6360
|
+
const symbolId2 = `${context.filePath}::${name2}`;
|
|
6361
|
+
context.symbols.push({
|
|
6362
|
+
id: symbolId2,
|
|
6363
|
+
name: name2,
|
|
6364
|
+
kind: "class",
|
|
6365
|
+
filePath: context.filePath,
|
|
6366
|
+
startLine: node.startPosition.row + 1,
|
|
6367
|
+
endLine: node.endPosition.row + 1,
|
|
6368
|
+
exported: true
|
|
6369
|
+
});
|
|
6370
|
+
const oldClass2 = context.currentClass;
|
|
6371
|
+
context.currentClass = extName;
|
|
6372
|
+
context.currentScope.push(extName);
|
|
6373
|
+
const body2 = findChildByType12(node, "class_body");
|
|
6374
|
+
if (body2) {
|
|
6375
|
+
walkNode12(body2, context);
|
|
6376
|
+
}
|
|
6377
|
+
context.currentScope.pop();
|
|
6378
|
+
context.currentClass = oldClass2;
|
|
6379
|
+
return;
|
|
6380
|
+
}
|
|
6381
|
+
const nameNode = findChildByType12(node, "type_identifier") || findChildByType12(node, "simple_identifier");
|
|
6382
|
+
if (!nameNode) return;
|
|
6383
|
+
const name = nodeText11(nameNode, context);
|
|
6384
|
+
const modifiers = getModifiers3(node, context);
|
|
6385
|
+
const exported = !modifiers.includes("private") && !modifiers.includes("fileprivate");
|
|
6386
|
+
const scope = context.currentClass || void 0;
|
|
6387
|
+
const symbolId = `${context.filePath}::${name}`;
|
|
6388
|
+
let kind = "class";
|
|
6389
|
+
if (keyword === "enum") kind = "enum";
|
|
6390
|
+
else if (keyword === "struct" || keyword === "actor") kind = "class";
|
|
6391
|
+
context.symbols.push({
|
|
6392
|
+
id: symbolId,
|
|
6393
|
+
name,
|
|
6394
|
+
kind,
|
|
6395
|
+
filePath: context.filePath,
|
|
6396
|
+
startLine: node.startPosition.row + 1,
|
|
6397
|
+
endLine: node.endPosition.row + 1,
|
|
6398
|
+
exported,
|
|
6399
|
+
scope
|
|
6400
|
+
});
|
|
6401
|
+
processInheritance(node, symbolId, context);
|
|
6402
|
+
if (keyword === "enum") {
|
|
6403
|
+
processEnumCases(node, name, context);
|
|
6404
|
+
}
|
|
6405
|
+
const oldClass = context.currentClass;
|
|
6406
|
+
context.currentClass = name;
|
|
6407
|
+
context.currentScope.push(name);
|
|
6408
|
+
const body = findChildByType12(node, "class_body");
|
|
6409
|
+
if (body) {
|
|
6410
|
+
walkNode12(body, context);
|
|
6411
|
+
}
|
|
6412
|
+
context.currentScope.pop();
|
|
6413
|
+
context.currentClass = oldClass;
|
|
6414
|
+
}
|
|
6415
|
+
function processProtocolDeclaration(node, context) {
|
|
6416
|
+
const nameNode = findChildByType12(node, "type_identifier") || findChildByType12(node, "simple_identifier");
|
|
6417
|
+
if (!nameNode) return;
|
|
6418
|
+
const name = nodeText11(nameNode, context);
|
|
6419
|
+
const modifiers = getModifiers3(node, context);
|
|
6420
|
+
const exported = !modifiers.includes("private") && !modifiers.includes("fileprivate");
|
|
6421
|
+
const symbolId = `${context.filePath}::${name}`;
|
|
6422
|
+
context.symbols.push({
|
|
6423
|
+
id: symbolId,
|
|
6424
|
+
name,
|
|
6425
|
+
kind: "interface",
|
|
6426
|
+
filePath: context.filePath,
|
|
6427
|
+
startLine: node.startPosition.row + 1,
|
|
6428
|
+
endLine: node.endPosition.row + 1,
|
|
6429
|
+
exported
|
|
6430
|
+
});
|
|
6431
|
+
processInheritance(node, symbolId, context);
|
|
6432
|
+
const oldClass = context.currentClass;
|
|
6433
|
+
context.currentClass = name;
|
|
6434
|
+
context.currentScope.push(name);
|
|
6435
|
+
const body = findChildByType12(node, "protocol_body");
|
|
6436
|
+
if (body) {
|
|
6437
|
+
walkNode12(body, context);
|
|
6438
|
+
}
|
|
6439
|
+
context.currentScope.pop();
|
|
6440
|
+
context.currentClass = oldClass;
|
|
6441
|
+
}
|
|
6442
|
+
function processFunctionDeclaration5(node, context) {
|
|
6443
|
+
const nameNode = findChildByType12(node, "simple_identifier");
|
|
6444
|
+
if (!nameNode) return;
|
|
6445
|
+
const name = nodeText11(nameNode, context);
|
|
6446
|
+
const modifiers = getModifiers3(node, context);
|
|
6447
|
+
const exported = !modifiers.includes("private") && !modifiers.includes("fileprivate");
|
|
6448
|
+
const scope = context.currentClass || void 0;
|
|
6449
|
+
const symbolId = scope ? `${context.filePath}::${scope}.${name}` : `${context.filePath}::${name}`;
|
|
6450
|
+
context.symbols.push({
|
|
6451
|
+
id: symbolId,
|
|
6452
|
+
name,
|
|
6453
|
+
kind: context.currentClass ? "method" : "function",
|
|
6454
|
+
filePath: context.filePath,
|
|
6455
|
+
startLine: node.startPosition.row + 1,
|
|
6456
|
+
endLine: node.endPosition.row + 1,
|
|
6457
|
+
exported,
|
|
6458
|
+
scope
|
|
6459
|
+
});
|
|
6460
|
+
const scopeName = scope ? `${scope}.${name}` : name;
|
|
6461
|
+
context.currentScope.push(scopeName);
|
|
6462
|
+
const body = findChildByType12(node, "function_body") || findChildByType12(node, "code_block");
|
|
6463
|
+
if (body) {
|
|
6464
|
+
walkNode12(body, context);
|
|
6465
|
+
}
|
|
6466
|
+
context.currentScope.pop();
|
|
6467
|
+
}
|
|
6468
|
+
function processInitDeclaration(node, context) {
|
|
6469
|
+
const scope = context.currentClass || void 0;
|
|
6470
|
+
if (!scope) return;
|
|
6471
|
+
const name = "init";
|
|
6472
|
+
const symbolId = `${context.filePath}::${scope}.${name}:${node.startPosition.row + 1}`;
|
|
6473
|
+
context.symbols.push({
|
|
6474
|
+
id: symbolId,
|
|
6475
|
+
name,
|
|
6476
|
+
kind: "method",
|
|
6477
|
+
filePath: context.filePath,
|
|
6478
|
+
startLine: node.startPosition.row + 1,
|
|
6479
|
+
endLine: node.endPosition.row + 1,
|
|
6480
|
+
exported: true,
|
|
6481
|
+
scope
|
|
6482
|
+
});
|
|
6483
|
+
const scopeName = `${scope}.${name}`;
|
|
6484
|
+
context.currentScope.push(scopeName);
|
|
6485
|
+
const body = findChildByType12(node, "function_body") || findChildByType12(node, "code_block");
|
|
6486
|
+
if (body) {
|
|
6487
|
+
walkNode12(body, context);
|
|
6488
|
+
}
|
|
6489
|
+
context.currentScope.pop();
|
|
6490
|
+
}
|
|
6491
|
+
function processDeinitDeclaration(node, context) {
|
|
6492
|
+
const scope = context.currentClass || void 0;
|
|
6493
|
+
if (!scope) return;
|
|
6494
|
+
const name = "deinit";
|
|
6495
|
+
const symbolId = `${context.filePath}::${scope}.${name}`;
|
|
6496
|
+
context.symbols.push({
|
|
6497
|
+
id: symbolId,
|
|
6498
|
+
name,
|
|
6499
|
+
kind: "method",
|
|
6500
|
+
filePath: context.filePath,
|
|
6501
|
+
startLine: node.startPosition.row + 1,
|
|
6502
|
+
endLine: node.endPosition.row + 1,
|
|
6503
|
+
exported: true,
|
|
6504
|
+
scope
|
|
6505
|
+
});
|
|
6506
|
+
}
|
|
6507
|
+
function processPropertyDeclaration4(node, context) {
|
|
6508
|
+
const nameNode = findChildByType12(node, "simple_identifier") || findChildByType12(node, "pattern");
|
|
6509
|
+
if (!nameNode) return;
|
|
6510
|
+
const name = nodeText11(nameNode, context).trim();
|
|
6511
|
+
if (!name || name.includes(" ")) return;
|
|
6512
|
+
const modifiers = getModifiers3(node, context);
|
|
6513
|
+
const exported = !modifiers.includes("private") && !modifiers.includes("fileprivate");
|
|
6514
|
+
const scope = context.currentClass || void 0;
|
|
6515
|
+
const text = nodeText11(node, context);
|
|
6516
|
+
const isConst = text.trimStart().startsWith("let");
|
|
6517
|
+
const symbolId = scope ? `${context.filePath}::${scope}.${name}` : `${context.filePath}::${name}`;
|
|
6518
|
+
context.symbols.push({
|
|
6519
|
+
id: symbolId,
|
|
6520
|
+
name,
|
|
6521
|
+
kind: isConst ? "constant" : "property",
|
|
6522
|
+
filePath: context.filePath,
|
|
6523
|
+
startLine: node.startPosition.row + 1,
|
|
6524
|
+
endLine: node.endPosition.row + 1,
|
|
6525
|
+
exported,
|
|
6526
|
+
scope
|
|
6527
|
+
});
|
|
6528
|
+
}
|
|
6529
|
+
function processTypealiasDeclaration(node, context) {
|
|
6530
|
+
const nameNode = findChildByType12(node, "type_identifier") || findChildByType12(node, "simple_identifier");
|
|
6531
|
+
if (!nameNode) return;
|
|
6532
|
+
const name = nodeText11(nameNode, context);
|
|
6533
|
+
const symbolId = `${context.filePath}::${name}`;
|
|
6534
|
+
context.symbols.push({
|
|
6535
|
+
id: symbolId,
|
|
6536
|
+
name,
|
|
6537
|
+
kind: "type_alias",
|
|
6538
|
+
filePath: context.filePath,
|
|
6539
|
+
startLine: node.startPosition.row + 1,
|
|
6540
|
+
endLine: node.endPosition.row + 1,
|
|
6541
|
+
exported: true
|
|
6542
|
+
});
|
|
6543
|
+
}
|
|
6544
|
+
function processAssociatedTypeDeclaration(node, context) {
|
|
6545
|
+
const nameNode = findChildByType12(node, "type_identifier") || findChildByType12(node, "simple_identifier");
|
|
6546
|
+
if (!nameNode) return;
|
|
6547
|
+
const name = nodeText11(nameNode, context);
|
|
6548
|
+
const scope = context.currentClass || void 0;
|
|
6549
|
+
const symbolId = scope ? `${context.filePath}::${scope}.${name}` : `${context.filePath}::${name}`;
|
|
6550
|
+
context.symbols.push({
|
|
6551
|
+
id: symbolId,
|
|
6552
|
+
name,
|
|
6553
|
+
kind: "type_alias",
|
|
6554
|
+
filePath: context.filePath,
|
|
6555
|
+
startLine: node.startPosition.row + 1,
|
|
6556
|
+
endLine: node.endPosition.row + 1,
|
|
6557
|
+
exported: true,
|
|
6558
|
+
scope
|
|
6559
|
+
});
|
|
6560
|
+
}
|
|
6561
|
+
function processCallExpression12(node, context) {
|
|
6562
|
+
if (context.currentScope.length === 0) return;
|
|
6563
|
+
const firstChild = node.child(0);
|
|
6564
|
+
if (!firstChild) return;
|
|
6565
|
+
let calleeName = null;
|
|
6566
|
+
if (firstChild.type === "simple_identifier") {
|
|
6567
|
+
calleeName = nodeText11(firstChild, context);
|
|
6568
|
+
} else if (firstChild.type === "navigation_expression" || firstChild.type === "member_access") {
|
|
6569
|
+
for (let i = firstChild.childCount - 1; i >= 0; i--) {
|
|
6570
|
+
const child = firstChild.child(i);
|
|
6571
|
+
if (child && (child.type === "simple_identifier" || child.type === "navigation_suffix")) {
|
|
6572
|
+
calleeName = nodeText11(child, context).replace(/^\./, "");
|
|
6573
|
+
break;
|
|
6574
|
+
}
|
|
6575
|
+
}
|
|
6576
|
+
}
|
|
6577
|
+
if (!calleeName) return;
|
|
6578
|
+
const builtins = /* @__PURE__ */ new Set([
|
|
6579
|
+
"print",
|
|
6580
|
+
"debugPrint",
|
|
6581
|
+
"dump",
|
|
6582
|
+
"fatalError",
|
|
6583
|
+
"precondition",
|
|
6584
|
+
"assert",
|
|
6585
|
+
"preconditionFailure",
|
|
6586
|
+
"assertionFailure",
|
|
6587
|
+
"map",
|
|
6588
|
+
"filter",
|
|
6589
|
+
"reduce",
|
|
6590
|
+
"forEach",
|
|
6591
|
+
"flatMap",
|
|
6592
|
+
"compactMap",
|
|
6593
|
+
"sorted",
|
|
6594
|
+
"contains",
|
|
6595
|
+
"first",
|
|
6596
|
+
"last",
|
|
6597
|
+
"count",
|
|
6598
|
+
"isEmpty",
|
|
6599
|
+
"append",
|
|
6600
|
+
"remove",
|
|
6601
|
+
"insert",
|
|
6602
|
+
"removeAll",
|
|
6603
|
+
"String",
|
|
6604
|
+
"Int",
|
|
6605
|
+
"Double",
|
|
6606
|
+
"Float",
|
|
6607
|
+
"Bool",
|
|
6608
|
+
"Array",
|
|
6609
|
+
"Dictionary",
|
|
6610
|
+
"Set",
|
|
6611
|
+
"DispatchQueue",
|
|
6612
|
+
"Task",
|
|
6613
|
+
"withCheckedContinuation",
|
|
6614
|
+
"withCheckedThrowingContinuation"
|
|
6615
|
+
]);
|
|
6616
|
+
if (builtins.has(calleeName)) return;
|
|
6617
|
+
const callerId = getCurrentSymbolId12(context);
|
|
6618
|
+
if (!callerId) return;
|
|
6619
|
+
const calleeId = resolveSymbol11(calleeName, context);
|
|
6620
|
+
if (calleeId) {
|
|
6621
|
+
context.edges.push({
|
|
6622
|
+
source: callerId,
|
|
6623
|
+
target: calleeId,
|
|
6624
|
+
kind: "calls",
|
|
6625
|
+
filePath: context.filePath,
|
|
6626
|
+
line: node.startPosition.row + 1
|
|
6627
|
+
});
|
|
6628
|
+
}
|
|
6629
|
+
}
|
|
6630
|
+
function processInheritance(node, sourceId, context) {
|
|
6631
|
+
const inheritanceClause = findChildByType12(node, "inheritance_specifier") || findChildByType12(node, "type_inheritance_clause");
|
|
6632
|
+
if (!inheritanceClause) return;
|
|
6633
|
+
const text = nodeText11(node, context);
|
|
6634
|
+
const colonMatch = text.match(/:\s*([^{]+)/);
|
|
6635
|
+
if (!colonMatch) return;
|
|
6636
|
+
const types = colonMatch[1].split(",").map((t) => t.trim().split("<")[0].trim());
|
|
6637
|
+
for (const typeName of types) {
|
|
6638
|
+
if (!typeName || typeName.includes("{") || typeName.includes("where")) break;
|
|
6639
|
+
const baseId = resolveSymbol11(typeName, context);
|
|
6640
|
+
if (baseId) {
|
|
6641
|
+
context.edges.push({
|
|
6642
|
+
source: sourceId,
|
|
6643
|
+
target: baseId,
|
|
6644
|
+
kind: "implements",
|
|
6645
|
+
filePath: context.filePath,
|
|
6646
|
+
line: node.startPosition.row + 1
|
|
6647
|
+
});
|
|
6648
|
+
}
|
|
6649
|
+
}
|
|
6650
|
+
}
|
|
6651
|
+
function processEnumCases(node, enumName, context) {
|
|
6652
|
+
const text = nodeText11(node, context);
|
|
6653
|
+
const caseMatches = text.matchAll(/\bcase\s+(\w+)/g);
|
|
6654
|
+
for (const match of caseMatches) {
|
|
6655
|
+
const caseName = match[1];
|
|
6656
|
+
if (caseName === enumName) continue;
|
|
6657
|
+
const constId = `${context.filePath}::${enumName}.${caseName}`;
|
|
6658
|
+
context.symbols.push({
|
|
6659
|
+
id: constId,
|
|
6660
|
+
name: caseName,
|
|
6661
|
+
kind: "constant",
|
|
6662
|
+
filePath: context.filePath,
|
|
6663
|
+
startLine: node.startPosition.row + 1,
|
|
6664
|
+
endLine: node.endPosition.row + 1,
|
|
6665
|
+
exported: true,
|
|
6666
|
+
scope: enumName
|
|
6667
|
+
});
|
|
6668
|
+
}
|
|
6669
|
+
}
|
|
6670
|
+
function parsePackageSwift(filePath, sourceCode, projectRoot) {
|
|
6671
|
+
const symbols = [];
|
|
6672
|
+
const edges = [];
|
|
6673
|
+
const lines = sourceCode.split("\n");
|
|
6674
|
+
const nameMatch = sourceCode.match(/name\s*:\s*["']([^"']+)["']/);
|
|
6675
|
+
const packageName = nameMatch ? nameMatch[1] : basename6(dirname12(join13(projectRoot, filePath)));
|
|
6676
|
+
symbols.push({
|
|
6677
|
+
id: `${filePath}::${packageName}`,
|
|
6678
|
+
name: packageName,
|
|
6679
|
+
kind: "module",
|
|
6680
|
+
filePath,
|
|
6681
|
+
startLine: 1,
|
|
6682
|
+
endLine: lines.length,
|
|
6683
|
+
exported: true
|
|
6684
|
+
});
|
|
6685
|
+
for (let i = 0; i < lines.length; i++) {
|
|
6686
|
+
const line = lines[i].trim();
|
|
6687
|
+
const lineNum = i + 1;
|
|
6688
|
+
const depMatch = line.match(/\.package\s*\(\s*(?:url\s*:\s*)?["']([^"']+)["']/);
|
|
6689
|
+
if (depMatch) {
|
|
6690
|
+
const depUrl = depMatch[1];
|
|
6691
|
+
const depName = depUrl.split("/").pop()?.replace(/\.git$/, "") || depUrl;
|
|
6692
|
+
symbols.push({
|
|
6693
|
+
id: `${filePath}::dep:${depName}`,
|
|
6694
|
+
name: depName,
|
|
6695
|
+
kind: "import",
|
|
6696
|
+
filePath,
|
|
6697
|
+
startLine: lineNum,
|
|
6698
|
+
endLine: lineNum,
|
|
6699
|
+
exported: false
|
|
6700
|
+
});
|
|
6701
|
+
}
|
|
6702
|
+
const targetMatch = line.match(/\.(?:target|executableTarget|testTarget)\s*\(\s*name\s*:\s*["']([^"']+)["']/);
|
|
6703
|
+
if (targetMatch) {
|
|
6704
|
+
symbols.push({
|
|
6705
|
+
id: `${filePath}::target:${targetMatch[1]}`,
|
|
6706
|
+
name: targetMatch[1],
|
|
6707
|
+
kind: "module",
|
|
6708
|
+
filePath,
|
|
6709
|
+
startLine: lineNum,
|
|
6710
|
+
endLine: lineNum,
|
|
6711
|
+
exported: true
|
|
6712
|
+
});
|
|
6713
|
+
}
|
|
6714
|
+
}
|
|
6715
|
+
return { filePath, symbols, edges };
|
|
6716
|
+
}
|
|
6717
|
+
function resolveSwiftImport(importPath, currentFile, projectRoot) {
|
|
6718
|
+
const parts = importPath.split(".");
|
|
6719
|
+
const moduleName = parts[0];
|
|
6720
|
+
const sourceRoots = [
|
|
6721
|
+
"",
|
|
6722
|
+
"Sources",
|
|
6723
|
+
`Sources/${moduleName}`,
|
|
6724
|
+
"src",
|
|
6725
|
+
`src/${moduleName}`
|
|
6726
|
+
];
|
|
6727
|
+
for (const root of sourceRoots) {
|
|
6728
|
+
const candidate = root ? join13(root, moduleName + ".swift") : moduleName + ".swift";
|
|
6729
|
+
const fullPath = join13(projectRoot, candidate);
|
|
6730
|
+
if (existsSync13(fullPath)) {
|
|
6731
|
+
return candidate;
|
|
6732
|
+
}
|
|
6733
|
+
}
|
|
6734
|
+
for (const root of sourceRoots) {
|
|
6735
|
+
const dirCandidate = root || moduleName;
|
|
6736
|
+
const fullDir = join13(projectRoot, dirCandidate);
|
|
6737
|
+
if (existsSync13(fullDir)) {
|
|
6738
|
+
try {
|
|
6739
|
+
const stats = statSync7(fullDir);
|
|
6740
|
+
if (stats.isDirectory()) {
|
|
6741
|
+
const swiftFiles = readdirSync10(fullDir).filter((f) => f.endsWith(".swift"));
|
|
6742
|
+
if (swiftFiles.length > 0) {
|
|
6743
|
+
return join13(dirCandidate, swiftFiles[0]);
|
|
6744
|
+
}
|
|
6745
|
+
}
|
|
6746
|
+
} catch {
|
|
6747
|
+
}
|
|
6748
|
+
}
|
|
6157
6749
|
}
|
|
6158
6750
|
return null;
|
|
6159
6751
|
}
|
|
6160
|
-
function
|
|
6752
|
+
function resolveSymbol11(name, context) {
|
|
6161
6753
|
if (context.imports.has(name)) {
|
|
6162
6754
|
return context.imports.get(name) || null;
|
|
6163
6755
|
}
|
|
@@ -6173,62 +6765,44 @@ function resolveSymbol10(name, context) {
|
|
|
6173
6765
|
}
|
|
6174
6766
|
return null;
|
|
6175
6767
|
}
|
|
6176
|
-
function
|
|
6768
|
+
function getModifiers3(node, context) {
|
|
6177
6769
|
const modifiers = [];
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6770
|
+
const modList = findChildByType12(node, "modifiers") || findChildByType12(node, "modifier");
|
|
6771
|
+
if (modList) {
|
|
6772
|
+
for (let i = 0; i < modList.childCount; i++) {
|
|
6773
|
+
const child = modList.child(i);
|
|
6774
|
+
if (child) {
|
|
6775
|
+
const text2 = nodeText11(child, context).trim();
|
|
6776
|
+
if (text2) modifiers.push(text2);
|
|
6777
|
+
}
|
|
6184
6778
|
}
|
|
6185
6779
|
}
|
|
6780
|
+
const text = nodeText11(node, context);
|
|
6781
|
+
if (text.match(/\bprivate\b/)) modifiers.push("private");
|
|
6782
|
+
if (text.match(/\bfileprivate\b/)) modifiers.push("fileprivate");
|
|
6783
|
+
if (text.match(/\binternal\b/)) modifiers.push("internal");
|
|
6784
|
+
if (text.match(/\bpublic\b/)) modifiers.push("public");
|
|
6785
|
+
if (text.match(/\bopen\b/)) modifiers.push("open");
|
|
6186
6786
|
return modifiers;
|
|
6187
6787
|
}
|
|
6188
|
-
function
|
|
6189
|
-
const nameNode = findDescendantByTypes3(node, ["name", "qualified_name", "namespace_name"]);
|
|
6190
|
-
if (!nameNode) return null;
|
|
6191
|
-
const text = nodeText10(nameNode, context).trim();
|
|
6192
|
-
if (!text) return null;
|
|
6193
|
-
const parts = text.split("\\");
|
|
6194
|
-
return parts[parts.length - 1];
|
|
6195
|
-
}
|
|
6196
|
-
function findChildByType11(node, type) {
|
|
6788
|
+
function findChildByType12(node, type) {
|
|
6197
6789
|
for (let i = 0; i < node.childCount; i++) {
|
|
6198
6790
|
const child = node.child(i);
|
|
6199
6791
|
if (child && child.type === type) return child;
|
|
6200
6792
|
}
|
|
6201
6793
|
return null;
|
|
6202
6794
|
}
|
|
6203
|
-
function
|
|
6204
|
-
const results = [];
|
|
6205
|
-
for (let i = 0; i < node.childCount; i++) {
|
|
6206
|
-
const child = node.child(i);
|
|
6207
|
-
if (child && child.type === type) results.push(child);
|
|
6208
|
-
}
|
|
6209
|
-
return results;
|
|
6210
|
-
}
|
|
6211
|
-
function findDescendantByTypes3(node, types) {
|
|
6212
|
-
for (let i = 0; i < node.childCount; i++) {
|
|
6213
|
-
const child = node.child(i);
|
|
6214
|
-
if (!child) continue;
|
|
6215
|
-
if (types.includes(child.type)) return child;
|
|
6216
|
-
const found = findDescendantByTypes3(child, types);
|
|
6217
|
-
if (found) return found;
|
|
6218
|
-
}
|
|
6219
|
-
return null;
|
|
6220
|
-
}
|
|
6221
|
-
function nodeText10(node, context) {
|
|
6795
|
+
function nodeText11(node, context) {
|
|
6222
6796
|
return context.sourceCode.substring(node.startIndex, node.endIndex);
|
|
6223
6797
|
}
|
|
6224
|
-
function
|
|
6798
|
+
function getCurrentSymbolId12(context) {
|
|
6225
6799
|
if (context.currentScope.length === 0) return null;
|
|
6226
6800
|
return `${context.filePath}::${context.currentScope[context.currentScope.length - 1]}`;
|
|
6227
6801
|
}
|
|
6228
|
-
var
|
|
6229
|
-
name: "
|
|
6230
|
-
extensions: [".
|
|
6231
|
-
parseFile:
|
|
6802
|
+
var swiftParser = {
|
|
6803
|
+
name: "swift",
|
|
6804
|
+
extensions: [".swift", "Package.swift"],
|
|
6805
|
+
parseFile: parseSwiftFile
|
|
6232
6806
|
};
|
|
6233
6807
|
|
|
6234
6808
|
// src/parser/detect.ts
|
|
@@ -6243,12 +6817,13 @@ var parsers = [
|
|
|
6243
6817
|
javaParser,
|
|
6244
6818
|
cppParser,
|
|
6245
6819
|
kotlinParser,
|
|
6246
|
-
phpParser
|
|
6820
|
+
phpParser,
|
|
6821
|
+
swiftParser
|
|
6247
6822
|
];
|
|
6248
6823
|
var CPP_KEYWORDS = /\b(?:class|namespace|template|public:|private:|protected:|virtual|nullptr|constexpr|auto\s+\w+\s*=|using\s+\w+\s*=|static_cast|dynamic_cast|reinterpret_cast|const_cast|noexcept|override|final|decltype|concept|requires|co_await|co_yield|co_return|std::)\b/;
|
|
6249
6824
|
function getParserForFile(filePath, content) {
|
|
6250
|
-
const ext =
|
|
6251
|
-
const fileName =
|
|
6825
|
+
const ext = extname9(filePath).toLowerCase();
|
|
6826
|
+
const fileName = basename7(filePath);
|
|
6252
6827
|
if (ext === ".h" && content) {
|
|
6253
6828
|
if (CPP_KEYWORDS.test(content)) {
|
|
6254
6829
|
return cppParser;
|
|
@@ -6266,7 +6841,7 @@ import { minimatch } from "minimatch";
|
|
|
6266
6841
|
var MAX_FILE_SIZE = 1e6;
|
|
6267
6842
|
function shouldParseFile(fullPath) {
|
|
6268
6843
|
try {
|
|
6269
|
-
const stats =
|
|
6844
|
+
const stats = statSync8(fullPath);
|
|
6270
6845
|
if (stats.size > MAX_FILE_SIZE) {
|
|
6271
6846
|
console.error(`[Parser] Skipping ${fullPath} \u2014 file too large (${(stats.size / 1024).toFixed(0)}KB)`);
|
|
6272
6847
|
return false;
|
|
@@ -6284,8 +6859,8 @@ async function parseProject(projectRoot, options) {
|
|
|
6284
6859
|
let errorFiles = 0;
|
|
6285
6860
|
for (const file of files) {
|
|
6286
6861
|
try {
|
|
6287
|
-
const fullPath =
|
|
6288
|
-
if (!
|
|
6862
|
+
const fullPath = join14(projectRoot, file);
|
|
6863
|
+
if (!resolve8(fullPath).startsWith(resolve8(projectRoot))) {
|
|
6289
6864
|
skippedFiles++;
|
|
6290
6865
|
continue;
|
|
6291
6866
|
}
|
|
@@ -6308,7 +6883,7 @@ async function parseProject(projectRoot, options) {
|
|
|
6308
6883
|
if (options?.verbose) {
|
|
6309
6884
|
console.error(`[Parser] Parsing: ${file}`);
|
|
6310
6885
|
}
|
|
6311
|
-
const sourceCode =
|
|
6886
|
+
const sourceCode = readFileSync11(fullPath, "utf-8");
|
|
6312
6887
|
const parser = getParserForFile(file, sourceCode);
|
|
6313
6888
|
if (!parser) {
|
|
6314
6889
|
console.error(`No parser found for file: ${file}`);
|
|
@@ -6337,8 +6912,8 @@ async function parseProject(projectRoot, options) {
|
|
|
6337
6912
|
}
|
|
6338
6913
|
|
|
6339
6914
|
// src/cross-language/detectors/rest-api.ts
|
|
6340
|
-
import { readFileSync as
|
|
6341
|
-
import { join as
|
|
6915
|
+
import { readFileSync as readFileSync12 } from "fs";
|
|
6916
|
+
import { join as join15, resolve as resolve9 } from "path";
|
|
6342
6917
|
function getLanguage(filePath) {
|
|
6343
6918
|
if (filePath.endsWith(".ts") || filePath.endsWith(".tsx")) return "typescript";
|
|
6344
6919
|
if (filePath.endsWith(".js") || filePath.endsWith(".jsx") || filePath.endsWith(".mjs") || filePath.endsWith(".cjs")) return "javascript";
|
|
@@ -6348,6 +6923,7 @@ function getLanguage(filePath) {
|
|
|
6348
6923
|
if (filePath.endsWith(".java")) return "java";
|
|
6349
6924
|
if (filePath.endsWith(".kt") || filePath.endsWith(".kts")) return "kotlin";
|
|
6350
6925
|
if (filePath.endsWith(".php")) return "php";
|
|
6926
|
+
if (filePath.endsWith(".swift")) return "swift";
|
|
6351
6927
|
if (filePath.endsWith(".cpp") || filePath.endsWith(".cc") || filePath.endsWith(".cxx") || filePath.endsWith(".c++") || filePath.endsWith(".hpp") || filePath.endsWith(".hh") || filePath.endsWith(".hxx") || filePath.endsWith(".h++") || filePath.endsWith(".h") || filePath.endsWith(".inl") || filePath.endsWith(".ipp")) return "cpp";
|
|
6352
6928
|
return "unknown";
|
|
6353
6929
|
}
|
|
@@ -6767,6 +7343,45 @@ function extractRouteDefinitions(source, filePath) {
|
|
|
6767
7343
|
});
|
|
6768
7344
|
}
|
|
6769
7345
|
}
|
|
7346
|
+
if (lang === "swift") {
|
|
7347
|
+
const vaporMatch = line.match(/(?:app|router|routes)\s*\.\s*(get|post|put|delete|patch)\s*\(\s*["']([^"']+)["']/i);
|
|
7348
|
+
if (vaporMatch) {
|
|
7349
|
+
let path6 = vaporMatch[2];
|
|
7350
|
+
if (!path6.startsWith("/")) path6 = "/" + path6;
|
|
7351
|
+
routes.push({
|
|
7352
|
+
method: vaporMatch[1].toUpperCase(),
|
|
7353
|
+
path: path6,
|
|
7354
|
+
normalizedPath: normalizePath(path6),
|
|
7355
|
+
file: filePath,
|
|
7356
|
+
line: i + 1
|
|
7357
|
+
});
|
|
7358
|
+
}
|
|
7359
|
+
const hbMatch = line.match(/router\s*\.\s*(get|post|put|delete|patch)\s*\(\s*["']([^"']+)["']/i);
|
|
7360
|
+
if (hbMatch && !vaporMatch) {
|
|
7361
|
+
let path6 = hbMatch[2];
|
|
7362
|
+
if (!path6.startsWith("/")) path6 = "/" + path6;
|
|
7363
|
+
routes.push({
|
|
7364
|
+
method: hbMatch[1].toUpperCase(),
|
|
7365
|
+
path: path6,
|
|
7366
|
+
normalizedPath: normalizePath(path6),
|
|
7367
|
+
file: filePath,
|
|
7368
|
+
line: i + 1
|
|
7369
|
+
});
|
|
7370
|
+
}
|
|
7371
|
+
const perfectMatch = line.match(/routes\s*\.\s*add\s*\([^)]*uri\s*:\s*["']([^"']+)["']/);
|
|
7372
|
+
if (perfectMatch) {
|
|
7373
|
+
const path6 = perfectMatch[1].startsWith("/") ? perfectMatch[1] : "/" + perfectMatch[1];
|
|
7374
|
+
const methodMatch = line.match(/method\s*:\s*\.(\w+)/);
|
|
7375
|
+
const method = methodMatch ? methodMatch[1].toUpperCase() : "ANY";
|
|
7376
|
+
routes.push({
|
|
7377
|
+
method,
|
|
7378
|
+
path: path6,
|
|
7379
|
+
normalizedPath: normalizePath(path6),
|
|
7380
|
+
file: filePath,
|
|
7381
|
+
line: i + 1
|
|
7382
|
+
});
|
|
7383
|
+
}
|
|
7384
|
+
}
|
|
6770
7385
|
if (lang === "cpp") {
|
|
6771
7386
|
const crowMatch = line.match(/CROW_ROUTE\s*\(\s*\w+\s*,\s*"([^"]+)"/);
|
|
6772
7387
|
if (crowMatch) {
|
|
@@ -6881,11 +7496,11 @@ function detectRestApiEdges(files, projectRoot) {
|
|
|
6881
7496
|
const allCalls = [];
|
|
6882
7497
|
const allRoutes = [];
|
|
6883
7498
|
for (const file of files) {
|
|
6884
|
-
const fullPath =
|
|
6885
|
-
if (!
|
|
7499
|
+
const fullPath = join15(projectRoot, file.filePath);
|
|
7500
|
+
if (!resolve9(fullPath).startsWith(resolve9(projectRoot))) continue;
|
|
6886
7501
|
let source;
|
|
6887
7502
|
try {
|
|
6888
|
-
source =
|
|
7503
|
+
source = readFileSync12(fullPath, "utf-8");
|
|
6889
7504
|
} catch {
|
|
6890
7505
|
continue;
|
|
6891
7506
|
}
|
|
@@ -6905,6 +7520,30 @@ function detectRestApiEdges(files, projectRoot) {
|
|
|
6905
7520
|
}
|
|
6906
7521
|
}
|
|
6907
7522
|
}
|
|
7523
|
+
if (lang === "swift") {
|
|
7524
|
+
const swiftLines = source.split("\n");
|
|
7525
|
+
for (let i = 0; i < swiftLines.length; i++) {
|
|
7526
|
+
const line = swiftLines[i];
|
|
7527
|
+
const urlMatch = line.match(/URL\s*\(\s*string\s*:\s*["']([^"']+)["']/);
|
|
7528
|
+
if (urlMatch) {
|
|
7529
|
+
const path6 = urlMatch[1];
|
|
7530
|
+
if (isLocalApiPath(path6)) {
|
|
7531
|
+
const methodMatch = line.match(/httpMethod\s*=\s*["'](\w+)["']/);
|
|
7532
|
+
const method = methodMatch ? methodMatch[1].toUpperCase() : "GET";
|
|
7533
|
+
allCalls.push({ method, path: cleanPath(path6), file: file.filePath, line: i + 1 });
|
|
7534
|
+
}
|
|
7535
|
+
}
|
|
7536
|
+
const afMatch = line.match(/AF\s*\.\s*(?:request|upload|download)\s*\(\s*["']([^"']+)["']/);
|
|
7537
|
+
if (afMatch) {
|
|
7538
|
+
const path6 = afMatch[1];
|
|
7539
|
+
if (isLocalApiPath(path6)) {
|
|
7540
|
+
const methodMatch = line.match(/method\s*:\s*\.(\w+)/);
|
|
7541
|
+
const method = methodMatch ? methodMatch[1].toUpperCase() : "GET";
|
|
7542
|
+
allCalls.push({ method, path: cleanPath(path6), file: file.filePath, line: i + 1 });
|
|
7543
|
+
}
|
|
7544
|
+
}
|
|
7545
|
+
}
|
|
7546
|
+
}
|
|
6908
7547
|
if (lang === "php") {
|
|
6909
7548
|
const phpLines = source.split("\n");
|
|
6910
7549
|
for (let i = 0; i < phpLines.length; i++) {
|
|
@@ -6961,8 +7600,8 @@ function detectRestApiEdges(files, projectRoot) {
|
|
|
6961
7600
|
}
|
|
6962
7601
|
|
|
6963
7602
|
// src/cross-language/detectors/subprocess.ts
|
|
6964
|
-
import { readFileSync as
|
|
6965
|
-
import { join as
|
|
7603
|
+
import { readFileSync as readFileSync13 } from "fs";
|
|
7604
|
+
import { join as join16, resolve as resolve10, basename as basename8 } from "path";
|
|
6966
7605
|
var SCRIPT_EXTENSIONS = [".py", ".js", ".ts", ".go", ".rs"];
|
|
6967
7606
|
function getLanguage2(filePath) {
|
|
6968
7607
|
if (filePath.endsWith(".ts") || filePath.endsWith(".tsx")) return "typescript";
|
|
@@ -7061,16 +7700,16 @@ function detectSubprocessEdges(files, projectRoot) {
|
|
|
7061
7700
|
const knownFiles = new Set(files.map((f) => f.filePath));
|
|
7062
7701
|
const basenameMap = /* @__PURE__ */ new Map();
|
|
7063
7702
|
for (const f of files) {
|
|
7064
|
-
const base =
|
|
7703
|
+
const base = basename8(f.filePath);
|
|
7065
7704
|
if (!basenameMap.has(base)) basenameMap.set(base, []);
|
|
7066
7705
|
basenameMap.get(base).push(f.filePath);
|
|
7067
7706
|
}
|
|
7068
7707
|
for (const file of files) {
|
|
7069
|
-
const fullPath =
|
|
7070
|
-
if (!
|
|
7708
|
+
const fullPath = join16(projectRoot, file.filePath);
|
|
7709
|
+
if (!resolve10(fullPath).startsWith(resolve10(projectRoot))) continue;
|
|
7071
7710
|
let source;
|
|
7072
7711
|
try {
|
|
7073
|
-
source =
|
|
7712
|
+
source = readFileSync13(fullPath, "utf-8");
|
|
7074
7713
|
} catch {
|
|
7075
7714
|
continue;
|
|
7076
7715
|
}
|
|
@@ -7082,7 +7721,7 @@ function detectSubprocessEdges(files, projectRoot) {
|
|
|
7082
7721
|
targetFile = call.calledFile;
|
|
7083
7722
|
confidence = "high";
|
|
7084
7723
|
} else {
|
|
7085
|
-
const base =
|
|
7724
|
+
const base = basename8(call.calledFile);
|
|
7086
7725
|
const candidates = basenameMap.get(base);
|
|
7087
7726
|
if (candidates && candidates.length > 0) {
|
|
7088
7727
|
const exactCandidate = candidates.find((c) => c.endsWith(call.calledFile));
|
|
@@ -7461,7 +8100,7 @@ function getArchitectureSummary(graph) {
|
|
|
7461
8100
|
}
|
|
7462
8101
|
|
|
7463
8102
|
// src/health/metrics.ts
|
|
7464
|
-
import { dirname as
|
|
8103
|
+
import { dirname as dirname13 } from "path";
|
|
7465
8104
|
function scoreToGrade(score) {
|
|
7466
8105
|
if (score >= 90) return "A";
|
|
7467
8106
|
if (score >= 80) return "B";
|
|
@@ -7494,8 +8133,8 @@ function calculateCouplingScore(graph) {
|
|
|
7494
8133
|
totalEdges++;
|
|
7495
8134
|
fileConnections.set(sourceAttrs.filePath, (fileConnections.get(sourceAttrs.filePath) || 0) + 1);
|
|
7496
8135
|
fileConnections.set(targetAttrs.filePath, (fileConnections.get(targetAttrs.filePath) || 0) + 1);
|
|
7497
|
-
const sourceDir =
|
|
7498
|
-
const targetDir =
|
|
8136
|
+
const sourceDir = dirname13(sourceAttrs.filePath).split("/")[0];
|
|
8137
|
+
const targetDir = dirname13(targetAttrs.filePath).split("/")[0];
|
|
7499
8138
|
if (sourceDir !== targetDir) {
|
|
7500
8139
|
crossDirEdges++;
|
|
7501
8140
|
}
|
|
@@ -7542,8 +8181,8 @@ function calculateCohesionScore(graph) {
|
|
|
7542
8181
|
const sourceAttrs = graph.getNodeAttributes(source);
|
|
7543
8182
|
const targetAttrs = graph.getNodeAttributes(target);
|
|
7544
8183
|
if (sourceAttrs.filePath !== targetAttrs.filePath) {
|
|
7545
|
-
const sourceDir =
|
|
7546
|
-
const targetDir =
|
|
8184
|
+
const sourceDir = dirname13(sourceAttrs.filePath);
|
|
8185
|
+
const targetDir = dirname13(targetAttrs.filePath);
|
|
7547
8186
|
if (!dirEdges.has(sourceDir)) {
|
|
7548
8187
|
dirEdges.set(sourceDir, { internal: 0, total: 0 });
|
|
7549
8188
|
}
|
|
@@ -7825,8 +8464,8 @@ function calculateDepthScore(graph) {
|
|
|
7825
8464
|
}
|
|
7826
8465
|
|
|
7827
8466
|
// src/health/index.ts
|
|
7828
|
-
import { readFileSync as
|
|
7829
|
-
import { dirname as
|
|
8467
|
+
import { readFileSync as readFileSync14, writeFileSync, existsSync as existsSync14, mkdirSync } from "fs";
|
|
8468
|
+
import { dirname as dirname14, resolve as resolve11 } from "path";
|
|
7830
8469
|
function calculateHealthScore(graph, projectRoot) {
|
|
7831
8470
|
const coupling = calculateCouplingScore(graph);
|
|
7832
8471
|
const cohesion = calculateCohesionScore(graph);
|
|
@@ -7925,8 +8564,8 @@ function getHealthTrend(projectRoot, currentScore) {
|
|
|
7925
8564
|
}
|
|
7926
8565
|
}
|
|
7927
8566
|
function saveHealthHistory(projectRoot, report) {
|
|
7928
|
-
const resolvedRoot =
|
|
7929
|
-
const historyFile =
|
|
8567
|
+
const resolvedRoot = resolve11(projectRoot);
|
|
8568
|
+
const historyFile = resolve11(resolvedRoot, ".depwire", "health-history.json");
|
|
7930
8569
|
if (!historyFile.startsWith(resolvedRoot)) {
|
|
7931
8570
|
return;
|
|
7932
8571
|
}
|
|
@@ -7941,10 +8580,10 @@ function saveHealthHistory(projectRoot, report) {
|
|
|
7941
8580
|
}))
|
|
7942
8581
|
};
|
|
7943
8582
|
let history = [];
|
|
7944
|
-
if (
|
|
8583
|
+
if (existsSync14(historyFile)) {
|
|
7945
8584
|
try {
|
|
7946
8585
|
if (!historyFile.startsWith(resolvedRoot)) return;
|
|
7947
|
-
const content =
|
|
8586
|
+
const content = readFileSync14(historyFile, "utf-8");
|
|
7948
8587
|
history = JSON.parse(content);
|
|
7949
8588
|
} catch {
|
|
7950
8589
|
}
|
|
@@ -7953,19 +8592,19 @@ function saveHealthHistory(projectRoot, report) {
|
|
|
7953
8592
|
if (history.length > 50) {
|
|
7954
8593
|
history = history.slice(-50);
|
|
7955
8594
|
}
|
|
7956
|
-
mkdirSync(
|
|
8595
|
+
mkdirSync(dirname14(historyFile), { recursive: true });
|
|
7957
8596
|
if (!historyFile.startsWith(resolvedRoot)) return;
|
|
7958
8597
|
writeFileSync(historyFile, JSON.stringify(history, null, 2), "utf-8");
|
|
7959
8598
|
}
|
|
7960
8599
|
function loadHealthHistory(projectRoot) {
|
|
7961
|
-
const resolvedRoot =
|
|
7962
|
-
const historyFile =
|
|
7963
|
-
if (!historyFile.startsWith(resolvedRoot) || !
|
|
8600
|
+
const resolvedRoot = resolve11(projectRoot);
|
|
8601
|
+
const historyFile = resolve11(resolvedRoot, ".depwire", "health-history.json");
|
|
8602
|
+
if (!historyFile.startsWith(resolvedRoot) || !existsSync14(historyFile)) {
|
|
7964
8603
|
return [];
|
|
7965
8604
|
}
|
|
7966
8605
|
try {
|
|
7967
8606
|
if (!historyFile.startsWith(resolvedRoot)) return [];
|
|
7968
|
-
const content =
|
|
8607
|
+
const content = readFileSync14(historyFile, "utf-8");
|
|
7969
8608
|
return JSON.parse(content);
|
|
7970
8609
|
} catch {
|
|
7971
8610
|
return [];
|
|
@@ -7974,7 +8613,7 @@ function loadHealthHistory(projectRoot) {
|
|
|
7974
8613
|
|
|
7975
8614
|
// src/dead-code/detector.ts
|
|
7976
8615
|
import path2 from "path";
|
|
7977
|
-
import { readFileSync as
|
|
8616
|
+
import { readFileSync as readFileSync15, existsSync as existsSync15 } from "fs";
|
|
7978
8617
|
function findDeadSymbols(graph, projectRoot, includeTests = false, debug = false) {
|
|
7979
8618
|
const deadSymbols = [];
|
|
7980
8619
|
const context = { graph, projectRoot };
|
|
@@ -8107,11 +8746,11 @@ function getPackageEntryPoints(projectRoot) {
|
|
|
8107
8746
|
const entryPoints = /* @__PURE__ */ new Set();
|
|
8108
8747
|
const resolvedRoot = path2.resolve(projectRoot);
|
|
8109
8748
|
const packageJsonPath = path2.resolve(resolvedRoot, "package.json");
|
|
8110
|
-
if (!packageJsonPath.startsWith(resolvedRoot) || !
|
|
8749
|
+
if (!packageJsonPath.startsWith(resolvedRoot) || !existsSync15(packageJsonPath)) {
|
|
8111
8750
|
return entryPoints;
|
|
8112
8751
|
}
|
|
8113
8752
|
try {
|
|
8114
|
-
const packageJson = JSON.parse(
|
|
8753
|
+
const packageJson = JSON.parse(readFileSync15(packageJsonPath, "utf-8"));
|
|
8115
8754
|
if (packageJson.main) {
|
|
8116
8755
|
entryPoints.add(path2.resolve(projectRoot, packageJson.main));
|
|
8117
8756
|
}
|
|
@@ -8171,6 +8810,9 @@ function shouldExclude(attrs, context, includeTests, packageEntryPoints) {
|
|
|
8171
8810
|
if (isPhpExcluded(attrs)) {
|
|
8172
8811
|
return "framework";
|
|
8173
8812
|
}
|
|
8813
|
+
if (isSwiftExcluded(attrs)) {
|
|
8814
|
+
return "framework";
|
|
8815
|
+
}
|
|
8174
8816
|
return null;
|
|
8175
8817
|
}
|
|
8176
8818
|
function isRealPackageEntryPoint(filePath, packageEntryPoints) {
|
|
@@ -8301,6 +8943,45 @@ function isPhpExcluded(attrs) {
|
|
|
8301
8943
|
if (name.startsWith("test") || name === "setUp" || name === "tearDown" || name === "setUpBeforeClass" || name === "tearDownAfterClass") return true;
|
|
8302
8944
|
return false;
|
|
8303
8945
|
}
|
|
8946
|
+
function isSwiftExcluded(attrs) {
|
|
8947
|
+
const filePath = attrs.file || attrs.filePath || "";
|
|
8948
|
+
const name = attrs.name || "";
|
|
8949
|
+
if (!filePath.endsWith(".swift")) return false;
|
|
8950
|
+
if (name === "main") return true;
|
|
8951
|
+
const appLifecycle = [
|
|
8952
|
+
"application",
|
|
8953
|
+
"applicationDidFinishLaunching",
|
|
8954
|
+
"applicationWillTerminate",
|
|
8955
|
+
"applicationDidBecomeActive",
|
|
8956
|
+
"applicationWillResignActive",
|
|
8957
|
+
"applicationDidEnterBackground",
|
|
8958
|
+
"applicationWillEnterForeground",
|
|
8959
|
+
"scene",
|
|
8960
|
+
"sceneDidDisconnect",
|
|
8961
|
+
"sceneDidBecomeActive",
|
|
8962
|
+
"sceneWillResignActive",
|
|
8963
|
+
"sceneWillEnterForeground",
|
|
8964
|
+
"sceneDidEnterBackground"
|
|
8965
|
+
];
|
|
8966
|
+
if (appLifecycle.includes(name)) return true;
|
|
8967
|
+
if (name === "body" || name === "previews") return true;
|
|
8968
|
+
const protocolMethods = [
|
|
8969
|
+
"hash",
|
|
8970
|
+
"encode",
|
|
8971
|
+
"init",
|
|
8972
|
+
"deinit",
|
|
8973
|
+
"tableView",
|
|
8974
|
+
"collectionView",
|
|
8975
|
+
"numberOfSections",
|
|
8976
|
+
"numberOfRowsInSection",
|
|
8977
|
+
"cellForRowAt",
|
|
8978
|
+
"didSelectRowAt"
|
|
8979
|
+
];
|
|
8980
|
+
if (protocolMethods.includes(name)) return true;
|
|
8981
|
+
if (["encode", "decode", "init(from:)"].includes(name)) return true;
|
|
8982
|
+
if (name.startsWith("test") || name === "setUp" || name === "tearDown" || name === "setUpWithError" || name === "tearDownWithError") return true;
|
|
8983
|
+
return false;
|
|
8984
|
+
}
|
|
8304
8985
|
|
|
8305
8986
|
// src/dead-code/classifier.ts
|
|
8306
8987
|
import path3 from "path";
|
|
@@ -8367,8 +9048,8 @@ function generateReason(symbol, confidence) {
|
|
|
8367
9048
|
return "Potentially unused";
|
|
8368
9049
|
}
|
|
8369
9050
|
function isBarrelFile(filePath) {
|
|
8370
|
-
const
|
|
8371
|
-
return
|
|
9051
|
+
const basename12 = path3.basename(filePath);
|
|
9052
|
+
return basename12 === "index.ts" || basename12 === "index.js";
|
|
8372
9053
|
}
|
|
8373
9054
|
function isTestFile2(filePath) {
|
|
8374
9055
|
return filePath.includes("__tests__/") || filePath.includes(".test.") || filePath.includes(".spec.") || filePath.includes("/test/") || filePath.includes("/tests/");
|
|
@@ -8547,11 +9228,11 @@ function filterByConfidence(symbols, minConfidence) {
|
|
|
8547
9228
|
}
|
|
8548
9229
|
|
|
8549
9230
|
// src/docs/generator.ts
|
|
8550
|
-
import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, existsSync as
|
|
8551
|
-
import { join as
|
|
9231
|
+
import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, existsSync as existsSync18 } from "fs";
|
|
9232
|
+
import { join as join20 } from "path";
|
|
8552
9233
|
|
|
8553
9234
|
// src/docs/architecture.ts
|
|
8554
|
-
import { dirname as
|
|
9235
|
+
import { dirname as dirname15 } from "path";
|
|
8555
9236
|
|
|
8556
9237
|
// src/docs/templates.ts
|
|
8557
9238
|
function header(text, level = 1) {
|
|
@@ -8702,7 +9383,7 @@ function generateModuleStructure(graph) {
|
|
|
8702
9383
|
function getDirectoryStats(graph) {
|
|
8703
9384
|
const dirMap = /* @__PURE__ */ new Map();
|
|
8704
9385
|
graph.forEachNode((node, attrs) => {
|
|
8705
|
-
const dir =
|
|
9386
|
+
const dir = dirname15(attrs.filePath);
|
|
8706
9387
|
if (dir === ".") return;
|
|
8707
9388
|
if (!dirMap.has(dir)) {
|
|
8708
9389
|
dirMap.set(dir, {
|
|
@@ -8727,7 +9408,7 @@ function getDirectoryStats(graph) {
|
|
|
8727
9408
|
});
|
|
8728
9409
|
const filesPerDir = /* @__PURE__ */ new Map();
|
|
8729
9410
|
graph.forEachNode((node, attrs) => {
|
|
8730
|
-
const dir =
|
|
9411
|
+
const dir = dirname15(attrs.filePath);
|
|
8731
9412
|
if (!filesPerDir.has(dir)) {
|
|
8732
9413
|
filesPerDir.set(dir, /* @__PURE__ */ new Set());
|
|
8733
9414
|
}
|
|
@@ -8742,8 +9423,8 @@ function getDirectoryStats(graph) {
|
|
|
8742
9423
|
graph.forEachEdge((edge, attrs, source, target) => {
|
|
8743
9424
|
const sourceAttrs = graph.getNodeAttributes(source);
|
|
8744
9425
|
const targetAttrs = graph.getNodeAttributes(target);
|
|
8745
|
-
const sourceDir =
|
|
8746
|
-
const targetDir =
|
|
9426
|
+
const sourceDir = dirname15(sourceAttrs.filePath);
|
|
9427
|
+
const targetDir = dirname15(targetAttrs.filePath);
|
|
8747
9428
|
if (sourceDir !== targetDir) {
|
|
8748
9429
|
if (!dirEdges.has(sourceDir)) {
|
|
8749
9430
|
dirEdges.set(sourceDir, { in: 0, out: 0 });
|
|
@@ -8950,7 +9631,7 @@ function detectCycles(graph) {
|
|
|
8950
9631
|
}
|
|
8951
9632
|
|
|
8952
9633
|
// src/docs/conventions.ts
|
|
8953
|
-
import { basename as
|
|
9634
|
+
import { basename as basename9, extname as extname10 } from "path";
|
|
8954
9635
|
function generateConventions(graph, projectRoot, version) {
|
|
8955
9636
|
let output = "";
|
|
8956
9637
|
const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
@@ -8988,7 +9669,7 @@ function generateFileOrganization(graph) {
|
|
|
8988
9669
|
graph.forEachNode((node, attrs) => {
|
|
8989
9670
|
if (!files.has(attrs.filePath)) {
|
|
8990
9671
|
files.add(attrs.filePath);
|
|
8991
|
-
const fileName =
|
|
9672
|
+
const fileName = basename9(attrs.filePath);
|
|
8992
9673
|
if (fileName === "index.ts" || fileName === "index.js" || fileName === "index.tsx" || fileName === "index.jsx") {
|
|
8993
9674
|
barrelFileCount++;
|
|
8994
9675
|
}
|
|
@@ -9047,7 +9728,7 @@ function generateNamingPatterns(graph) {
|
|
|
9047
9728
|
graph.forEachNode((node, attrs) => {
|
|
9048
9729
|
if (!files.has(attrs.filePath)) {
|
|
9049
9730
|
files.add(attrs.filePath);
|
|
9050
|
-
const fileName =
|
|
9731
|
+
const fileName = basename9(attrs.filePath, extname10(attrs.filePath));
|
|
9051
9732
|
if (isCamelCase(fileName)) patterns.files.camelCase++;
|
|
9052
9733
|
else if (isPascalCase(fileName)) patterns.files.PascalCase++;
|
|
9053
9734
|
else if (isKebabCase(fileName)) patterns.files.kebabCase++;
|
|
@@ -9724,7 +10405,7 @@ function detectCyclesDetailed(graph) {
|
|
|
9724
10405
|
}
|
|
9725
10406
|
|
|
9726
10407
|
// src/docs/onboarding.ts
|
|
9727
|
-
import { dirname as
|
|
10408
|
+
import { dirname as dirname16 } from "path";
|
|
9728
10409
|
function generateOnboarding(graph, projectRoot, version) {
|
|
9729
10410
|
let output = "";
|
|
9730
10411
|
const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
@@ -9783,7 +10464,7 @@ function generateQuickOrientation(graph) {
|
|
|
9783
10464
|
const primaryLang = Object.entries(languages2).sort((a, b) => b[1] - a[1])[0];
|
|
9784
10465
|
const dirs = /* @__PURE__ */ new Set();
|
|
9785
10466
|
graph.forEachNode((node, attrs) => {
|
|
9786
|
-
const dir =
|
|
10467
|
+
const dir = dirname16(attrs.filePath);
|
|
9787
10468
|
if (dir !== ".") {
|
|
9788
10469
|
const topLevel = dir.split("/")[0];
|
|
9789
10470
|
dirs.add(topLevel);
|
|
@@ -9887,7 +10568,7 @@ function generateModuleMap(graph) {
|
|
|
9887
10568
|
function getDirectoryStats2(graph) {
|
|
9888
10569
|
const dirMap = /* @__PURE__ */ new Map();
|
|
9889
10570
|
graph.forEachNode((node, attrs) => {
|
|
9890
|
-
const dir =
|
|
10571
|
+
const dir = dirname16(attrs.filePath);
|
|
9891
10572
|
if (dir === ".") return;
|
|
9892
10573
|
if (!dirMap.has(dir)) {
|
|
9893
10574
|
dirMap.set(dir, {
|
|
@@ -9902,7 +10583,7 @@ function getDirectoryStats2(graph) {
|
|
|
9902
10583
|
});
|
|
9903
10584
|
const filesPerDir = /* @__PURE__ */ new Map();
|
|
9904
10585
|
graph.forEachNode((node, attrs) => {
|
|
9905
|
-
const dir =
|
|
10586
|
+
const dir = dirname16(attrs.filePath);
|
|
9906
10587
|
if (!filesPerDir.has(dir)) {
|
|
9907
10588
|
filesPerDir.set(dir, /* @__PURE__ */ new Set());
|
|
9908
10589
|
}
|
|
@@ -9917,8 +10598,8 @@ function getDirectoryStats2(graph) {
|
|
|
9917
10598
|
graph.forEachEdge((edge, attrs, source, target) => {
|
|
9918
10599
|
const sourceAttrs = graph.getNodeAttributes(source);
|
|
9919
10600
|
const targetAttrs = graph.getNodeAttributes(target);
|
|
9920
|
-
const sourceDir =
|
|
9921
|
-
const targetDir =
|
|
10601
|
+
const sourceDir = dirname16(sourceAttrs.filePath);
|
|
10602
|
+
const targetDir = dirname16(targetAttrs.filePath);
|
|
9922
10603
|
if (sourceDir !== targetDir) {
|
|
9923
10604
|
if (!dirEdges.has(sourceDir)) {
|
|
9924
10605
|
dirEdges.set(sourceDir, { in: 0, out: 0 });
|
|
@@ -9999,7 +10680,7 @@ function detectClusters(graph) {
|
|
|
9999
10680
|
const dirFiles = /* @__PURE__ */ new Map();
|
|
10000
10681
|
const fileEdges = /* @__PURE__ */ new Map();
|
|
10001
10682
|
graph.forEachNode((node, attrs) => {
|
|
10002
|
-
const dir =
|
|
10683
|
+
const dir = dirname16(attrs.filePath);
|
|
10003
10684
|
if (!dirFiles.has(dir)) {
|
|
10004
10685
|
dirFiles.set(dir, /* @__PURE__ */ new Set());
|
|
10005
10686
|
}
|
|
@@ -10053,8 +10734,8 @@ function inferClusterName(files) {
|
|
|
10053
10734
|
if (sortedWords.length > 0 && sortedWords[0][1] > 1) {
|
|
10054
10735
|
return capitalizeFirst2(sortedWords[0][0]);
|
|
10055
10736
|
}
|
|
10056
|
-
const commonDir =
|
|
10057
|
-
if (files.every((f) =>
|
|
10737
|
+
const commonDir = dirname16(files[0]);
|
|
10738
|
+
if (files.every((f) => dirname16(f) === commonDir)) {
|
|
10058
10739
|
return capitalizeFirst2(commonDir.split("/").pop() || "Core");
|
|
10059
10740
|
}
|
|
10060
10741
|
return "Core";
|
|
@@ -10112,7 +10793,7 @@ function generateDepwireUsage(projectRoot) {
|
|
|
10112
10793
|
}
|
|
10113
10794
|
|
|
10114
10795
|
// src/docs/files.ts
|
|
10115
|
-
import { dirname as
|
|
10796
|
+
import { dirname as dirname17, basename as basename10 } from "path";
|
|
10116
10797
|
function generateFiles(graph, projectRoot, version) {
|
|
10117
10798
|
let output = "";
|
|
10118
10799
|
const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
@@ -10216,7 +10897,7 @@ function generateDirectoryBreakdown(graph) {
|
|
|
10216
10897
|
const fileStats = getFileStats2(graph);
|
|
10217
10898
|
const dirMap = /* @__PURE__ */ new Map();
|
|
10218
10899
|
for (const file of fileStats) {
|
|
10219
|
-
const dir =
|
|
10900
|
+
const dir = dirname17(file.filePath);
|
|
10220
10901
|
const topDir = dir === "." ? "." : dir.split("/")[0];
|
|
10221
10902
|
if (!dirMap.has(topDir)) {
|
|
10222
10903
|
dirMap.set(topDir, {
|
|
@@ -10231,7 +10912,7 @@ function generateDirectoryBreakdown(graph) {
|
|
|
10231
10912
|
dirStats.symbolCount += file.symbolCount;
|
|
10232
10913
|
if (file.totalConnections > dirStats.maxConnections) {
|
|
10233
10914
|
dirStats.maxConnections = file.totalConnections;
|
|
10234
|
-
dirStats.mostConnectedFile =
|
|
10915
|
+
dirStats.mostConnectedFile = basename10(file.filePath);
|
|
10235
10916
|
}
|
|
10236
10917
|
}
|
|
10237
10918
|
if (dirMap.size === 0) {
|
|
@@ -10859,7 +11540,7 @@ function generateRecommendations(graph) {
|
|
|
10859
11540
|
}
|
|
10860
11541
|
|
|
10861
11542
|
// src/docs/tests.ts
|
|
10862
|
-
import { basename as
|
|
11543
|
+
import { basename as basename11, dirname as dirname18 } from "path";
|
|
10863
11544
|
function generateTests(graph, projectRoot, version) {
|
|
10864
11545
|
let output = "";
|
|
10865
11546
|
const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
@@ -10887,8 +11568,8 @@ function getFileCount8(graph) {
|
|
|
10887
11568
|
return files.size;
|
|
10888
11569
|
}
|
|
10889
11570
|
function isTestFile3(filePath) {
|
|
10890
|
-
const fileName =
|
|
10891
|
-
const dirPath =
|
|
11571
|
+
const fileName = basename11(filePath).toLowerCase();
|
|
11572
|
+
const dirPath = dirname18(filePath).toLowerCase();
|
|
10892
11573
|
if (dirPath.includes("test") || dirPath.includes("spec") || dirPath.includes("__tests__")) {
|
|
10893
11574
|
return true;
|
|
10894
11575
|
}
|
|
@@ -10946,13 +11627,13 @@ function generateTestFileInventory(graph) {
|
|
|
10946
11627
|
return output;
|
|
10947
11628
|
}
|
|
10948
11629
|
function matchTestToSource(testFile) {
|
|
10949
|
-
const testFileName =
|
|
10950
|
-
const testDir =
|
|
11630
|
+
const testFileName = basename11(testFile);
|
|
11631
|
+
const testDir = dirname18(testFile);
|
|
10951
11632
|
let sourceFileName = testFileName.replace(/\.test\./g, ".").replace(/\.spec\./g, ".").replace(/_test\./g, ".").replace(/_spec\./g, ".");
|
|
10952
11633
|
const possiblePaths = [];
|
|
10953
11634
|
possiblePaths.push(testDir + "/" + sourceFileName);
|
|
10954
11635
|
if (testDir.endsWith("/test") || testDir.endsWith("/tests") || testDir.endsWith("/__tests__")) {
|
|
10955
|
-
const parentDir =
|
|
11636
|
+
const parentDir = dirname18(testDir);
|
|
10956
11637
|
possiblePaths.push(parentDir + "/" + sourceFileName);
|
|
10957
11638
|
}
|
|
10958
11639
|
if (testDir.includes("test")) {
|
|
@@ -11108,7 +11789,7 @@ function generateTestCoverageMap(graph) {
|
|
|
11108
11789
|
const rows = mappings.slice(0, 30).map((m) => [
|
|
11109
11790
|
`\`${m.sourceFile}\``,
|
|
11110
11791
|
m.hasTest ? "\u2705" : "\u274C",
|
|
11111
|
-
m.testFile ? `\`${
|
|
11792
|
+
m.testFile ? `\`${basename11(m.testFile)}\`` : "-",
|
|
11112
11793
|
formatNumber(m.symbolCount)
|
|
11113
11794
|
]);
|
|
11114
11795
|
let output = table(headers, rows);
|
|
@@ -11149,7 +11830,7 @@ function generateTestStatistics(graph) {
|
|
|
11149
11830
|
`;
|
|
11150
11831
|
const dirTestCoverage = /* @__PURE__ */ new Map();
|
|
11151
11832
|
for (const sourceFile of sourceFiles) {
|
|
11152
|
-
const dir =
|
|
11833
|
+
const dir = dirname18(sourceFile).split("/")[0];
|
|
11153
11834
|
if (!dirTestCoverage.has(dir)) {
|
|
11154
11835
|
dirTestCoverage.set(dir, { total: 0, tested: 0 });
|
|
11155
11836
|
}
|
|
@@ -11172,7 +11853,7 @@ function generateTestStatistics(graph) {
|
|
|
11172
11853
|
}
|
|
11173
11854
|
|
|
11174
11855
|
// src/docs/history.ts
|
|
11175
|
-
import { dirname as
|
|
11856
|
+
import { dirname as dirname19 } from "path";
|
|
11176
11857
|
import { execSync } from "child_process";
|
|
11177
11858
|
function generateHistory(graph, projectRoot, version) {
|
|
11178
11859
|
let output = "";
|
|
@@ -11453,7 +12134,7 @@ function generateFeatureClusters(graph) {
|
|
|
11453
12134
|
const dirFiles = /* @__PURE__ */ new Map();
|
|
11454
12135
|
const fileEdges = /* @__PURE__ */ new Map();
|
|
11455
12136
|
graph.forEachNode((node, attrs) => {
|
|
11456
|
-
const dir =
|
|
12137
|
+
const dir = dirname19(attrs.filePath);
|
|
11457
12138
|
if (!dirFiles.has(dir)) {
|
|
11458
12139
|
dirFiles.set(dir, /* @__PURE__ */ new Set());
|
|
11459
12140
|
}
|
|
@@ -11535,7 +12216,7 @@ function capitalizeFirst3(str) {
|
|
|
11535
12216
|
}
|
|
11536
12217
|
|
|
11537
12218
|
// src/docs/current.ts
|
|
11538
|
-
import { dirname as
|
|
12219
|
+
import { dirname as dirname20 } from "path";
|
|
11539
12220
|
function generateCurrent(graph, projectRoot, version) {
|
|
11540
12221
|
let output = "";
|
|
11541
12222
|
const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
@@ -11673,7 +12354,7 @@ function generateCompleteFileIndex(graph) {
|
|
|
11673
12354
|
fileInfos.sort((a, b) => a.filePath.localeCompare(b.filePath));
|
|
11674
12355
|
const dirGroups = /* @__PURE__ */ new Map();
|
|
11675
12356
|
for (const info of fileInfos) {
|
|
11676
|
-
const dir =
|
|
12357
|
+
const dir = dirname20(info.filePath);
|
|
11677
12358
|
const topDir = dir === "." ? "root" : dir.split("/")[0];
|
|
11678
12359
|
if (!dirGroups.has(topDir)) {
|
|
11679
12360
|
dirGroups.set(topDir, []);
|
|
@@ -11884,8 +12565,8 @@ function getTopLevelDir2(filePath) {
|
|
|
11884
12565
|
}
|
|
11885
12566
|
|
|
11886
12567
|
// src/docs/status.ts
|
|
11887
|
-
import { readFileSync as
|
|
11888
|
-
import { resolve as
|
|
12568
|
+
import { readFileSync as readFileSync16, existsSync as existsSync16 } from "fs";
|
|
12569
|
+
import { resolve as resolve12 } from "path";
|
|
11889
12570
|
function generateStatus(graph, projectRoot, version) {
|
|
11890
12571
|
let output = "";
|
|
11891
12572
|
const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
@@ -11918,16 +12599,16 @@ function getFileCount11(graph) {
|
|
|
11918
12599
|
}
|
|
11919
12600
|
function extractComments(projectRoot, filePath) {
|
|
11920
12601
|
const comments = [];
|
|
11921
|
-
const resolvedRoot =
|
|
11922
|
-
const fullPath =
|
|
12602
|
+
const resolvedRoot = resolve12(projectRoot);
|
|
12603
|
+
const fullPath = resolve12(resolvedRoot, filePath);
|
|
11923
12604
|
if (!fullPath.startsWith(resolvedRoot)) {
|
|
11924
12605
|
return comments;
|
|
11925
12606
|
}
|
|
11926
|
-
if (!
|
|
12607
|
+
if (!existsSync16(fullPath)) {
|
|
11927
12608
|
return comments;
|
|
11928
12609
|
}
|
|
11929
12610
|
try {
|
|
11930
|
-
const content =
|
|
12611
|
+
const content = readFileSync16(fullPath, "utf-8");
|
|
11931
12612
|
const lines = content.split("\n");
|
|
11932
12613
|
const patterns = [
|
|
11933
12614
|
{ type: "TODO", regex: /(?:\/\/|#|\/\*)\s*TODO:?\s*(.+)/i },
|
|
@@ -12506,16 +13187,16 @@ function generateConfidenceSection(title, description, symbols, projectRoot) {
|
|
|
12506
13187
|
}
|
|
12507
13188
|
|
|
12508
13189
|
// src/docs/metadata.ts
|
|
12509
|
-
import { existsSync as
|
|
12510
|
-
import { resolve as
|
|
13190
|
+
import { existsSync as existsSync17, readFileSync as readFileSync17, writeFileSync as writeFileSync2 } from "fs";
|
|
13191
|
+
import { resolve as resolve13 } from "path";
|
|
12511
13192
|
function loadMetadata(outputDir) {
|
|
12512
|
-
const resolvedDir =
|
|
12513
|
-
const metadataPath =
|
|
12514
|
-
if (!metadataPath.startsWith(resolvedDir) || !
|
|
13193
|
+
const resolvedDir = resolve13(outputDir);
|
|
13194
|
+
const metadataPath = resolve13(resolvedDir, "metadata.json");
|
|
13195
|
+
if (!metadataPath.startsWith(resolvedDir) || !existsSync17(metadataPath)) {
|
|
12515
13196
|
return null;
|
|
12516
13197
|
}
|
|
12517
13198
|
try {
|
|
12518
|
-
const content =
|
|
13199
|
+
const content = readFileSync17(metadataPath, "utf-8");
|
|
12519
13200
|
return JSON.parse(content);
|
|
12520
13201
|
} catch (err) {
|
|
12521
13202
|
console.error("Failed to load metadata:", err);
|
|
@@ -12523,8 +13204,8 @@ function loadMetadata(outputDir) {
|
|
|
12523
13204
|
}
|
|
12524
13205
|
}
|
|
12525
13206
|
function saveMetadata(outputDir, metadata) {
|
|
12526
|
-
const resolvedDir =
|
|
12527
|
-
const metadataPath =
|
|
13207
|
+
const resolvedDir = resolve13(outputDir);
|
|
13208
|
+
const metadataPath = resolve13(resolvedDir, "metadata.json");
|
|
12528
13209
|
if (!metadataPath.startsWith(resolvedDir)) {
|
|
12529
13210
|
throw new Error(`Path traversal attempt blocked: ${metadataPath}`);
|
|
12530
13211
|
}
|
|
@@ -12570,7 +13251,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
12570
13251
|
const generated = [];
|
|
12571
13252
|
const errors = [];
|
|
12572
13253
|
try {
|
|
12573
|
-
if (!
|
|
13254
|
+
if (!existsSync18(options.outputDir)) {
|
|
12574
13255
|
mkdirSync2(options.outputDir, { recursive: true });
|
|
12575
13256
|
if (options.verbose) {
|
|
12576
13257
|
console.log(`Created output directory: ${options.outputDir}`);
|
|
@@ -12609,7 +13290,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
12609
13290
|
try {
|
|
12610
13291
|
if (options.verbose) console.log("Generating ARCHITECTURE.md...");
|
|
12611
13292
|
const content = generateArchitecture(graph, projectRoot, version, parseTime);
|
|
12612
|
-
const filePath =
|
|
13293
|
+
const filePath = join20(options.outputDir, "ARCHITECTURE.md");
|
|
12613
13294
|
writeFileSync3(filePath, content, "utf-8");
|
|
12614
13295
|
generated.push("ARCHITECTURE.md");
|
|
12615
13296
|
} catch (err) {
|
|
@@ -12620,7 +13301,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
12620
13301
|
try {
|
|
12621
13302
|
if (options.verbose) console.log("Generating CONVENTIONS.md...");
|
|
12622
13303
|
const content = generateConventions(graph, projectRoot, version);
|
|
12623
|
-
const filePath =
|
|
13304
|
+
const filePath = join20(options.outputDir, "CONVENTIONS.md");
|
|
12624
13305
|
writeFileSync3(filePath, content, "utf-8");
|
|
12625
13306
|
generated.push("CONVENTIONS.md");
|
|
12626
13307
|
} catch (err) {
|
|
@@ -12631,7 +13312,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
12631
13312
|
try {
|
|
12632
13313
|
if (options.verbose) console.log("Generating DEPENDENCIES.md...");
|
|
12633
13314
|
const content = generateDependencies(graph, projectRoot, version);
|
|
12634
|
-
const filePath =
|
|
13315
|
+
const filePath = join20(options.outputDir, "DEPENDENCIES.md");
|
|
12635
13316
|
writeFileSync3(filePath, content, "utf-8");
|
|
12636
13317
|
generated.push("DEPENDENCIES.md");
|
|
12637
13318
|
} catch (err) {
|
|
@@ -12642,7 +13323,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
12642
13323
|
try {
|
|
12643
13324
|
if (options.verbose) console.log("Generating ONBOARDING.md...");
|
|
12644
13325
|
const content = generateOnboarding(graph, projectRoot, version);
|
|
12645
|
-
const filePath =
|
|
13326
|
+
const filePath = join20(options.outputDir, "ONBOARDING.md");
|
|
12646
13327
|
writeFileSync3(filePath, content, "utf-8");
|
|
12647
13328
|
generated.push("ONBOARDING.md");
|
|
12648
13329
|
} catch (err) {
|
|
@@ -12653,7 +13334,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
12653
13334
|
try {
|
|
12654
13335
|
if (options.verbose) console.log("Generating FILES.md...");
|
|
12655
13336
|
const content = generateFiles(graph, projectRoot, version);
|
|
12656
|
-
const filePath =
|
|
13337
|
+
const filePath = join20(options.outputDir, "FILES.md");
|
|
12657
13338
|
writeFileSync3(filePath, content, "utf-8");
|
|
12658
13339
|
generated.push("FILES.md");
|
|
12659
13340
|
} catch (err) {
|
|
@@ -12664,7 +13345,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
12664
13345
|
try {
|
|
12665
13346
|
if (options.verbose) console.log("Generating API_SURFACE.md...");
|
|
12666
13347
|
const content = generateApiSurface(graph, projectRoot, version);
|
|
12667
|
-
const filePath =
|
|
13348
|
+
const filePath = join20(options.outputDir, "API_SURFACE.md");
|
|
12668
13349
|
writeFileSync3(filePath, content, "utf-8");
|
|
12669
13350
|
generated.push("API_SURFACE.md");
|
|
12670
13351
|
} catch (err) {
|
|
@@ -12675,7 +13356,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
12675
13356
|
try {
|
|
12676
13357
|
if (options.verbose) console.log("Generating ERRORS.md...");
|
|
12677
13358
|
const content = generateErrors(graph, projectRoot, version);
|
|
12678
|
-
const filePath =
|
|
13359
|
+
const filePath = join20(options.outputDir, "ERRORS.md");
|
|
12679
13360
|
writeFileSync3(filePath, content, "utf-8");
|
|
12680
13361
|
generated.push("ERRORS.md");
|
|
12681
13362
|
} catch (err) {
|
|
@@ -12686,7 +13367,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
12686
13367
|
try {
|
|
12687
13368
|
if (options.verbose) console.log("Generating TESTS.md...");
|
|
12688
13369
|
const content = generateTests(graph, projectRoot, version);
|
|
12689
|
-
const filePath =
|
|
13370
|
+
const filePath = join20(options.outputDir, "TESTS.md");
|
|
12690
13371
|
writeFileSync3(filePath, content, "utf-8");
|
|
12691
13372
|
generated.push("TESTS.md");
|
|
12692
13373
|
} catch (err) {
|
|
@@ -12697,7 +13378,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
12697
13378
|
try {
|
|
12698
13379
|
if (options.verbose) console.log("Generating HISTORY.md...");
|
|
12699
13380
|
const content = generateHistory(graph, projectRoot, version);
|
|
12700
|
-
const filePath =
|
|
13381
|
+
const filePath = join20(options.outputDir, "HISTORY.md");
|
|
12701
13382
|
writeFileSync3(filePath, content, "utf-8");
|
|
12702
13383
|
generated.push("HISTORY.md");
|
|
12703
13384
|
} catch (err) {
|
|
@@ -12708,7 +13389,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
12708
13389
|
try {
|
|
12709
13390
|
if (options.verbose) console.log("Generating CURRENT.md...");
|
|
12710
13391
|
const content = generateCurrent(graph, projectRoot, version);
|
|
12711
|
-
const filePath =
|
|
13392
|
+
const filePath = join20(options.outputDir, "CURRENT.md");
|
|
12712
13393
|
writeFileSync3(filePath, content, "utf-8");
|
|
12713
13394
|
generated.push("CURRENT.md");
|
|
12714
13395
|
} catch (err) {
|
|
@@ -12719,7 +13400,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
12719
13400
|
try {
|
|
12720
13401
|
if (options.verbose) console.log("Generating STATUS.md...");
|
|
12721
13402
|
const content = generateStatus(graph, projectRoot, version);
|
|
12722
|
-
const filePath =
|
|
13403
|
+
const filePath = join20(options.outputDir, "STATUS.md");
|
|
12723
13404
|
writeFileSync3(filePath, content, "utf-8");
|
|
12724
13405
|
generated.push("STATUS.md");
|
|
12725
13406
|
} catch (err) {
|
|
@@ -12730,7 +13411,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
12730
13411
|
try {
|
|
12731
13412
|
if (options.verbose) console.log("Generating HEALTH.md...");
|
|
12732
13413
|
const content = generateHealth(graph, projectRoot, version);
|
|
12733
|
-
const filePath =
|
|
13414
|
+
const filePath = join20(options.outputDir, "HEALTH.md");
|
|
12734
13415
|
writeFileSync3(filePath, content, "utf-8");
|
|
12735
13416
|
generated.push("HEALTH.md");
|
|
12736
13417
|
} catch (err) {
|
|
@@ -12741,7 +13422,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
12741
13422
|
try {
|
|
12742
13423
|
if (options.verbose) console.log("Generating DEAD_CODE.md...");
|
|
12743
13424
|
const content = generateDeadCode(graph, projectRoot, version);
|
|
12744
|
-
const filePath =
|
|
13425
|
+
const filePath = join20(options.outputDir, "DEAD_CODE.md");
|
|
12745
13426
|
writeFileSync3(filePath, content, "utf-8");
|
|
12746
13427
|
generated.push("DEAD_CODE.md");
|
|
12747
13428
|
} catch (err) {
|
|
@@ -12785,7 +13466,7 @@ function getFileCount13(graph) {
|
|
|
12785
13466
|
}
|
|
12786
13467
|
|
|
12787
13468
|
// src/simulation/engine.ts
|
|
12788
|
-
import { dirname as
|
|
13469
|
+
import { dirname as dirname21, join as join21 } from "path";
|
|
12789
13470
|
function normalizePath2(p) {
|
|
12790
13471
|
return p.replace(/^\.\//, "").replace(/\/+$/, "");
|
|
12791
13472
|
}
|
|
@@ -12917,7 +13598,7 @@ var SimulationEngine = class {
|
|
|
12917
13598
|
}
|
|
12918
13599
|
}
|
|
12919
13600
|
applyRename(clone, target, newName, brokenImports) {
|
|
12920
|
-
const destination =
|
|
13601
|
+
const destination = join21(dirname21(target), newName);
|
|
12921
13602
|
this.applyMove(clone, target, destination, brokenImports);
|
|
12922
13603
|
}
|
|
12923
13604
|
applySplit(clone, target, newFile, symbols, brokenImports) {
|
|
@@ -13117,13 +13798,13 @@ var SimulationEngine = class {
|
|
|
13117
13798
|
};
|
|
13118
13799
|
|
|
13119
13800
|
// src/security/scanner.ts
|
|
13120
|
-
import { existsSync as
|
|
13121
|
-
import { join as
|
|
13801
|
+
import { existsSync as existsSync20 } from "fs";
|
|
13802
|
+
import { join as join31 } from "path";
|
|
13122
13803
|
|
|
13123
13804
|
// src/security/checks/dependencies.ts
|
|
13124
13805
|
import { execSync as execSync2 } from "child_process";
|
|
13125
|
-
import { existsSync as
|
|
13126
|
-
import { join as
|
|
13806
|
+
import { existsSync as existsSync19, readFileSync as readFileSync18, readdirSync as readdirSync11 } from "fs";
|
|
13807
|
+
import { join as join22 } from "path";
|
|
13127
13808
|
function cvssToSeverity(score) {
|
|
13128
13809
|
if (score >= 9) return "critical";
|
|
13129
13810
|
if (score >= 7) return "high";
|
|
@@ -13133,18 +13814,18 @@ function cvssToSeverity(score) {
|
|
|
13133
13814
|
async function checkDependencies(_files, projectRoot) {
|
|
13134
13815
|
const findings = [];
|
|
13135
13816
|
try {
|
|
13136
|
-
if (
|
|
13817
|
+
if (existsSync19(join22(projectRoot, "package.json"))) {
|
|
13137
13818
|
findings.push(...checkNpmAudit(projectRoot));
|
|
13138
13819
|
findings.push(...checkPackageJsonPatterns(projectRoot));
|
|
13139
13820
|
findings.push(...checkPostinstallScripts(projectRoot));
|
|
13140
13821
|
}
|
|
13141
|
-
if (
|
|
13822
|
+
if (existsSync19(join22(projectRoot, "requirements.txt")) || existsSync19(join22(projectRoot, "pyproject.toml"))) {
|
|
13142
13823
|
findings.push(...checkPipAudit(projectRoot));
|
|
13143
13824
|
}
|
|
13144
|
-
if (
|
|
13825
|
+
if (existsSync19(join22(projectRoot, "Cargo.toml"))) {
|
|
13145
13826
|
findings.push(...checkCargoAudit(projectRoot));
|
|
13146
13827
|
}
|
|
13147
|
-
if (
|
|
13828
|
+
if (existsSync19(join22(projectRoot, "go.mod"))) {
|
|
13148
13829
|
findings.push(...checkGoVerify(projectRoot));
|
|
13149
13830
|
}
|
|
13150
13831
|
} catch (err) {
|
|
@@ -13233,8 +13914,8 @@ function checkNpmAudit(projectRoot) {
|
|
|
13233
13914
|
function checkPackageJsonPatterns(projectRoot) {
|
|
13234
13915
|
const findings = [];
|
|
13235
13916
|
try {
|
|
13236
|
-
const pkgPath =
|
|
13237
|
-
const pkg = JSON.parse(
|
|
13917
|
+
const pkgPath = join22(projectRoot, "package.json");
|
|
13918
|
+
const pkg = JSON.parse(readFileSync18(pkgPath, "utf-8"));
|
|
13238
13919
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
13239
13920
|
for (const [name, version] of Object.entries(allDeps)) {
|
|
13240
13921
|
if (version.startsWith("^") || version.startsWith("~")) {
|
|
@@ -13256,15 +13937,15 @@ function checkPackageJsonPatterns(projectRoot) {
|
|
|
13256
13937
|
}
|
|
13257
13938
|
function checkPostinstallScripts(projectRoot) {
|
|
13258
13939
|
const findings = [];
|
|
13259
|
-
const nodeModules =
|
|
13260
|
-
if (!
|
|
13940
|
+
const nodeModules = join22(projectRoot, "node_modules");
|
|
13941
|
+
if (!existsSync19(nodeModules)) return findings;
|
|
13261
13942
|
try {
|
|
13262
|
-
const topLevelDeps =
|
|
13943
|
+
const topLevelDeps = readdirSync11(nodeModules).filter((d) => !d.startsWith("."));
|
|
13263
13944
|
for (const dep of topLevelDeps) {
|
|
13264
|
-
const depPkgPath =
|
|
13265
|
-
if (!
|
|
13945
|
+
const depPkgPath = join22(nodeModules, dep, "package.json");
|
|
13946
|
+
if (!existsSync19(depPkgPath)) continue;
|
|
13266
13947
|
try {
|
|
13267
|
-
const depPkg = JSON.parse(
|
|
13948
|
+
const depPkg = JSON.parse(readFileSync18(depPkgPath, "utf-8"));
|
|
13268
13949
|
const scripts = depPkg.scripts || {};
|
|
13269
13950
|
if (scripts.postinstall || scripts.preinstall || scripts.install) {
|
|
13270
13951
|
const scriptName = scripts.postinstall ? "postinstall" : scripts.preinstall ? "preinstall" : "install";
|
|
@@ -13302,7 +13983,7 @@ function checkPipAudit(projectRoot) {
|
|
|
13302
13983
|
id: "",
|
|
13303
13984
|
severity: cvssToSeverity(vuln.cvss?.score || 5),
|
|
13304
13985
|
vulnerabilityClass: "dependency-cve",
|
|
13305
|
-
file:
|
|
13986
|
+
file: existsSync19(join22(projectRoot, "requirements.txt")) ? "requirements.txt" : "pyproject.toml",
|
|
13306
13987
|
title: `Vulnerable Python dependency: ${vuln.name}`,
|
|
13307
13988
|
description: `${vuln.name}@${vuln.version} \u2014 ${vuln.id}: ${vuln.description || "Known vulnerability"}`,
|
|
13308
13989
|
attackScenario: `An attacker could exploit the vulnerability in ${vuln.name}.`,
|
|
@@ -13399,8 +14080,8 @@ function checkGoVerify(projectRoot) {
|
|
|
13399
14080
|
}
|
|
13400
14081
|
|
|
13401
14082
|
// src/security/checks/injection.ts
|
|
13402
|
-
import { readFileSync as
|
|
13403
|
-
import { join as
|
|
14083
|
+
import { readFileSync as readFileSync19 } from "fs";
|
|
14084
|
+
import { join as join23 } from "path";
|
|
13404
14085
|
var SKIP_DIRS = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
|
|
13405
14086
|
var TEST_PATTERNS = ["test", "spec", "fixture", "mock", "__tests__", "__mocks__"];
|
|
13406
14087
|
var USER_INPUT_NAMES = /(?:input|user|name|path|query|branch|hash|cmd|command|req\.|params|body|args|url|dir|file|subdirectory)/i;
|
|
@@ -13687,6 +14368,43 @@ var PATTERNS = [
|
|
|
13687
14368
|
description: "extract() on $_GET/$_POST/$_REQUEST overwrites local variables \u2014 can bypass security checks.",
|
|
13688
14369
|
attackScenario: "An attacker could set arbitrary variables by crafting request parameters, potentially overwriting auth flags or config values.",
|
|
13689
14370
|
suggestedFix: "Avoid extract() on user input. Access superglobals directly or use a whitelist of expected keys."
|
|
14371
|
+
},
|
|
14372
|
+
// Swift injection patterns
|
|
14373
|
+
{
|
|
14374
|
+
regex: /["'](?:SELECT|INSERT|UPDATE|DELETE)\b[^"']*\\\(/,
|
|
14375
|
+
title: "Swift SQL injection via string interpolation",
|
|
14376
|
+
vulnClass: "code-injection",
|
|
14377
|
+
baseSeverity: "high",
|
|
14378
|
+
description: "SQL query built using Swift string interpolation \u2014 vulnerable to SQL injection.",
|
|
14379
|
+
attackScenario: "An attacker could inject SQL through interpolated variables to read, modify, or delete database data.",
|
|
14380
|
+
suggestedFix: "Use parameterized queries with your database library (e.g., Fluent ORM, SQLite.swift bindings)."
|
|
14381
|
+
},
|
|
14382
|
+
{
|
|
14383
|
+
regex: /Process\s*\(\s*\)/,
|
|
14384
|
+
title: "Swift command injection via Process class",
|
|
14385
|
+
vulnClass: "shell-injection",
|
|
14386
|
+
baseSeverity: "medium",
|
|
14387
|
+
description: "Process() class executes external commands \u2014 vulnerable if user input reaches arguments.",
|
|
14388
|
+
attackScenario: "An attacker could inject shell metacharacters to execute arbitrary commands on the server.",
|
|
14389
|
+
suggestedFix: "Validate all arguments against a strict allowlist before passing to Process. Avoid shell execution."
|
|
14390
|
+
},
|
|
14391
|
+
{
|
|
14392
|
+
regex: /Unsafe(?:Raw|Mutable|Buffer)?Pointer/,
|
|
14393
|
+
title: "Swift unsafe pointer usage",
|
|
14394
|
+
vulnClass: "code-injection",
|
|
14395
|
+
baseSeverity: "medium",
|
|
14396
|
+
description: "Unsafe pointer usage bypasses Swift memory safety \u2014 potential for memory corruption.",
|
|
14397
|
+
attackScenario: "An attacker could exploit unsafe pointer operations to corrupt memory or execute arbitrary code.",
|
|
14398
|
+
suggestedFix: "Prefer safe Swift alternatives. If unsafe pointers are necessary, validate all bounds and lifetimes."
|
|
14399
|
+
},
|
|
14400
|
+
{
|
|
14401
|
+
regex: /UserDefaults\s*\.\s*(?:standard\s*\.\s*)?set\s*\([^)]*(?:password|secret|token|apiKey|api_key)/i,
|
|
14402
|
+
title: "Swift sensitive data in UserDefaults (unencrypted)",
|
|
14403
|
+
vulnClass: "code-injection",
|
|
14404
|
+
baseSeverity: "high",
|
|
14405
|
+
description: "Sensitive data stored in UserDefaults without encryption \u2014 easily accessible on jailbroken devices.",
|
|
14406
|
+
attackScenario: "An attacker with device access could read UserDefaults plist to extract credentials.",
|
|
14407
|
+
suggestedFix: "Use Keychain Services for storing sensitive data. Never store passwords or tokens in UserDefaults."
|
|
13690
14408
|
}
|
|
13691
14409
|
];
|
|
13692
14410
|
function shouldSkip(filePath) {
|
|
@@ -13703,7 +14421,7 @@ async function checkInjection(files, projectRoot) {
|
|
|
13703
14421
|
if (shouldSkip(file.filePath) || isTestFile4(file.filePath)) continue;
|
|
13704
14422
|
let content;
|
|
13705
14423
|
try {
|
|
13706
|
-
content =
|
|
14424
|
+
content = readFileSync19(join23(projectRoot, file.filePath), "utf-8");
|
|
13707
14425
|
} catch {
|
|
13708
14426
|
continue;
|
|
13709
14427
|
}
|
|
@@ -13741,8 +14459,8 @@ async function checkInjection(files, projectRoot) {
|
|
|
13741
14459
|
}
|
|
13742
14460
|
|
|
13743
14461
|
// src/security/checks/secrets.ts
|
|
13744
|
-
import { readFileSync as
|
|
13745
|
-
import { join as
|
|
14462
|
+
import { readFileSync as readFileSync20 } from "fs";
|
|
14463
|
+
import { join as join24 } from "path";
|
|
13746
14464
|
var SKIP_DIRS2 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
|
|
13747
14465
|
var TEST_PATTERNS2 = ["test", "spec", "fixture", "mock", "__tests__", "__mocks__", ".example", ".sample"];
|
|
13748
14466
|
var SECRET_PATTERNS = [
|
|
@@ -13775,7 +14493,7 @@ async function checkSecrets(files, projectRoot) {
|
|
|
13775
14493
|
if (shouldSkip2(file.filePath) || isTestFile5(file.filePath)) continue;
|
|
13776
14494
|
let content;
|
|
13777
14495
|
try {
|
|
13778
|
-
content =
|
|
14496
|
+
content = readFileSync20(join24(projectRoot, file.filePath), "utf-8");
|
|
13779
14497
|
} catch {
|
|
13780
14498
|
continue;
|
|
13781
14499
|
}
|
|
@@ -13808,8 +14526,8 @@ async function checkSecrets(files, projectRoot) {
|
|
|
13808
14526
|
}
|
|
13809
14527
|
|
|
13810
14528
|
// src/security/checks/path-traversal.ts
|
|
13811
|
-
import { readFileSync as
|
|
13812
|
-
import { join as
|
|
14529
|
+
import { readFileSync as readFileSync21 } from "fs";
|
|
14530
|
+
import { join as join25 } from "path";
|
|
13813
14531
|
var SKIP_DIRS3 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
|
|
13814
14532
|
var USER_INPUT_VARS = /(?:req\.|params|query|body|input|path|dir|subdirectory|file|userInput|fileName|filePath)/i;
|
|
13815
14533
|
var PATTERNS2 = [
|
|
@@ -13856,7 +14574,7 @@ async function checkPathTraversal(files, projectRoot) {
|
|
|
13856
14574
|
if (shouldSkip3(file.filePath)) continue;
|
|
13857
14575
|
let content;
|
|
13858
14576
|
try {
|
|
13859
|
-
content =
|
|
14577
|
+
content = readFileSync21(join25(projectRoot, file.filePath), "utf-8");
|
|
13860
14578
|
} catch {
|
|
13861
14579
|
continue;
|
|
13862
14580
|
}
|
|
@@ -13898,8 +14616,8 @@ async function checkPathTraversal(files, projectRoot) {
|
|
|
13898
14616
|
}
|
|
13899
14617
|
|
|
13900
14618
|
// src/security/checks/auth.ts
|
|
13901
|
-
import { readFileSync as
|
|
13902
|
-
import { join as
|
|
14619
|
+
import { readFileSync as readFileSync22 } from "fs";
|
|
14620
|
+
import { join as join26 } from "path";
|
|
13903
14621
|
var SKIP_DIRS4 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
|
|
13904
14622
|
function shouldSkip4(filePath) {
|
|
13905
14623
|
return SKIP_DIRS4.some((d) => filePath.includes(d));
|
|
@@ -13915,7 +14633,7 @@ async function checkAuth(files, projectRoot) {
|
|
|
13915
14633
|
if (shouldSkip4(file.filePath)) continue;
|
|
13916
14634
|
let content;
|
|
13917
14635
|
try {
|
|
13918
|
-
content =
|
|
14636
|
+
content = readFileSync22(join26(projectRoot, file.filePath), "utf-8");
|
|
13919
14637
|
} catch {
|
|
13920
14638
|
continue;
|
|
13921
14639
|
}
|
|
@@ -14006,8 +14724,8 @@ async function checkAuth(files, projectRoot) {
|
|
|
14006
14724
|
}
|
|
14007
14725
|
|
|
14008
14726
|
// src/security/checks/input-validation.ts
|
|
14009
|
-
import { readFileSync as
|
|
14010
|
-
import { join as
|
|
14727
|
+
import { readFileSync as readFileSync23 } from "fs";
|
|
14728
|
+
import { join as join27 } from "path";
|
|
14011
14729
|
var SKIP_DIRS5 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
|
|
14012
14730
|
function shouldSkip5(filePath) {
|
|
14013
14731
|
return SKIP_DIRS5.some((d) => filePath.includes(d));
|
|
@@ -14019,7 +14737,7 @@ async function checkInputValidation(files, projectRoot) {
|
|
|
14019
14737
|
if (shouldSkip5(file.filePath)) continue;
|
|
14020
14738
|
let content;
|
|
14021
14739
|
try {
|
|
14022
|
-
content =
|
|
14740
|
+
content = readFileSync23(join27(projectRoot, file.filePath), "utf-8");
|
|
14023
14741
|
} catch {
|
|
14024
14742
|
continue;
|
|
14025
14743
|
}
|
|
@@ -14096,8 +14814,8 @@ async function checkInputValidation(files, projectRoot) {
|
|
|
14096
14814
|
}
|
|
14097
14815
|
|
|
14098
14816
|
// src/security/checks/information-disclosure.ts
|
|
14099
|
-
import { readFileSync as
|
|
14100
|
-
import { join as
|
|
14817
|
+
import { readFileSync as readFileSync24 } from "fs";
|
|
14818
|
+
import { join as join28 } from "path";
|
|
14101
14819
|
var SKIP_DIRS6 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
|
|
14102
14820
|
function shouldSkip6(filePath) {
|
|
14103
14821
|
return SKIP_DIRS6.some((d) => filePath.includes(d));
|
|
@@ -14109,7 +14827,7 @@ async function checkInformationDisclosure(files, projectRoot) {
|
|
|
14109
14827
|
if (shouldSkip6(file.filePath)) continue;
|
|
14110
14828
|
let content;
|
|
14111
14829
|
try {
|
|
14112
|
-
content =
|
|
14830
|
+
content = readFileSync24(join28(projectRoot, file.filePath), "utf-8");
|
|
14113
14831
|
} catch {
|
|
14114
14832
|
continue;
|
|
14115
14833
|
}
|
|
@@ -14179,8 +14897,8 @@ async function checkInformationDisclosure(files, projectRoot) {
|
|
|
14179
14897
|
}
|
|
14180
14898
|
|
|
14181
14899
|
// src/security/checks/cryptography.ts
|
|
14182
|
-
import { readFileSync as
|
|
14183
|
-
import { join as
|
|
14900
|
+
import { readFileSync as readFileSync25 } from "fs";
|
|
14901
|
+
import { join as join29 } from "path";
|
|
14184
14902
|
var SKIP_DIRS7 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
|
|
14185
14903
|
var USER_INPUT_NAMES2 = /(?:input|user|name|path|query|param|request|body|args|url)/i;
|
|
14186
14904
|
function shouldSkip7(filePath) {
|
|
@@ -14197,7 +14915,7 @@ async function checkCryptography(files, projectRoot) {
|
|
|
14197
14915
|
if (shouldSkip7(file.filePath)) continue;
|
|
14198
14916
|
let content;
|
|
14199
14917
|
try {
|
|
14200
|
-
content =
|
|
14918
|
+
content = readFileSync25(join29(projectRoot, file.filePath), "utf-8");
|
|
14201
14919
|
} catch {
|
|
14202
14920
|
continue;
|
|
14203
14921
|
}
|
|
@@ -14455,6 +15173,84 @@ async function checkCryptography(files, projectRoot) {
|
|
|
14455
15173
|
suggestedFix: "Load credentials from environment variables using getenv() or $_ENV."
|
|
14456
15174
|
});
|
|
14457
15175
|
}
|
|
15176
|
+
if (/\bCC_MD5\b/.test(line) || /Insecure\s*\.\s*MD5/.test(line)) {
|
|
15177
|
+
findings.push({
|
|
15178
|
+
id: "",
|
|
15179
|
+
severity: isCryptoFile ? "high" : "medium",
|
|
15180
|
+
vulnerabilityClass: "cryptography",
|
|
15181
|
+
file: file.filePath,
|
|
15182
|
+
line: i + 1,
|
|
15183
|
+
title: "Weak hash algorithm: MD5 in Swift",
|
|
15184
|
+
description: "MD5 is cryptographically broken \u2014 collisions can be generated in seconds.",
|
|
15185
|
+
attackScenario: "An attacker could generate MD5 collisions to bypass integrity checks or forge hashes.",
|
|
15186
|
+
suggestedFix: "Use SHA256 from CryptoKit: SHA256.hash(data: data)"
|
|
15187
|
+
});
|
|
15188
|
+
}
|
|
15189
|
+
if (/\bCC_SHA1\b/.test(line) || /Insecure\s*\.\s*SHA1/.test(line)) {
|
|
15190
|
+
findings.push({
|
|
15191
|
+
id: "",
|
|
15192
|
+
severity: isCryptoFile ? "high" : "medium",
|
|
15193
|
+
vulnerabilityClass: "cryptography",
|
|
15194
|
+
file: file.filePath,
|
|
15195
|
+
line: i + 1,
|
|
15196
|
+
title: "Weak hash algorithm: SHA-1 in Swift",
|
|
15197
|
+
description: "SHA-1 has known collision attacks \u2014 should not be used for security purposes.",
|
|
15198
|
+
attackScenario: "An attacker could generate SHA-1 collisions to bypass integrity checks.",
|
|
15199
|
+
suggestedFix: "Use SHA256 from CryptoKit: SHA256.hash(data: data)"
|
|
15200
|
+
});
|
|
15201
|
+
}
|
|
15202
|
+
if (/(?:let|var)\s+(?:password|secret|apiKey|api_key|token)\s*(?::\s*String\s*)?=\s*["']/i.test(line)) {
|
|
15203
|
+
findings.push({
|
|
15204
|
+
id: "",
|
|
15205
|
+
severity: "high",
|
|
15206
|
+
vulnerabilityClass: "cryptography",
|
|
15207
|
+
file: file.filePath,
|
|
15208
|
+
line: i + 1,
|
|
15209
|
+
title: "Hardcoded credentials in Swift source",
|
|
15210
|
+
description: "A password, secret, or API key is hardcoded as a string literal.",
|
|
15211
|
+
attackScenario: "An attacker with access to the binary or source could extract the credential.",
|
|
15212
|
+
suggestedFix: "Load credentials from Keychain, environment variables, or a secure configuration service."
|
|
15213
|
+
});
|
|
15214
|
+
}
|
|
15215
|
+
if (/\barc4random\b/.test(line) && isCryptoFile) {
|
|
15216
|
+
findings.push({
|
|
15217
|
+
id: "",
|
|
15218
|
+
severity: "medium",
|
|
15219
|
+
vulnerabilityClass: "cryptography",
|
|
15220
|
+
file: file.filePath,
|
|
15221
|
+
line: i + 1,
|
|
15222
|
+
title: "arc4random in Swift security context",
|
|
15223
|
+
description: "arc4random is not suitable for cryptographic key generation.",
|
|
15224
|
+
attackScenario: "An attacker could predict random values if used for cryptographic purposes.",
|
|
15225
|
+
suggestedFix: "Use SecRandomCopyBytes or SystemRandomNumberGenerator for security-sensitive randomness."
|
|
15226
|
+
});
|
|
15227
|
+
}
|
|
15228
|
+
if (/allowsArbitraryLoads\s*:\s*true/.test(line) || /NSAllowsArbitraryLoads.*true/.test(line)) {
|
|
15229
|
+
findings.push({
|
|
15230
|
+
id: "",
|
|
15231
|
+
severity: "medium",
|
|
15232
|
+
vulnerabilityClass: "cryptography",
|
|
15233
|
+
file: file.filePath,
|
|
15234
|
+
line: i + 1,
|
|
15235
|
+
title: "Swift App Transport Security disabled",
|
|
15236
|
+
description: "allowsArbitraryLoads is set to true \u2014 all HTTP traffic is permitted without encryption.",
|
|
15237
|
+
attackScenario: "An attacker on the network path could intercept, read, or modify data in transit.",
|
|
15238
|
+
suggestedFix: "Remove allowsArbitraryLoads or set to false. Add specific exceptions only for domains that require HTTP."
|
|
15239
|
+
});
|
|
15240
|
+
}
|
|
15241
|
+
if (/(?:let|var)\s+\w*[Uu]rl\w*\s*=\s*["']http:\/\/(?!(?:localhost|127\.))/.test(line)) {
|
|
15242
|
+
findings.push({
|
|
15243
|
+
id: "",
|
|
15244
|
+
severity: "medium",
|
|
15245
|
+
vulnerabilityClass: "cryptography",
|
|
15246
|
+
file: file.filePath,
|
|
15247
|
+
line: i + 1,
|
|
15248
|
+
title: "Hardcoded HTTP URL in Swift source",
|
|
15249
|
+
description: "An HTTP (not HTTPS) URL is hardcoded \u2014 data is transmitted unencrypted.",
|
|
15250
|
+
attackScenario: "An attacker on the network path could intercept, read, or modify data in transit.",
|
|
15251
|
+
suggestedFix: "Use HTTPS for all external URLs to ensure data confidentiality and integrity."
|
|
15252
|
+
});
|
|
15253
|
+
}
|
|
14458
15254
|
}
|
|
14459
15255
|
}
|
|
14460
15256
|
} catch {
|
|
@@ -14463,8 +15259,8 @@ async function checkCryptography(files, projectRoot) {
|
|
|
14463
15259
|
}
|
|
14464
15260
|
|
|
14465
15261
|
// src/security/checks/frontend.ts
|
|
14466
|
-
import { readFileSync as
|
|
14467
|
-
import { join as
|
|
15262
|
+
import { readFileSync as readFileSync26 } from "fs";
|
|
15263
|
+
import { join as join30 } from "path";
|
|
14468
15264
|
var SKIP_DIRS8 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
|
|
14469
15265
|
function shouldSkip8(filePath) {
|
|
14470
15266
|
return SKIP_DIRS8.some((d) => filePath.includes(d));
|
|
@@ -14480,7 +15276,7 @@ async function checkFrontend(files, projectRoot) {
|
|
|
14480
15276
|
if (!isFrontendFile(file.filePath)) continue;
|
|
14481
15277
|
let content;
|
|
14482
15278
|
try {
|
|
14483
|
-
content =
|
|
15279
|
+
content = readFileSync26(join30(projectRoot, file.filePath), "utf-8");
|
|
14484
15280
|
} catch {
|
|
14485
15281
|
continue;
|
|
14486
15282
|
}
|
|
@@ -14940,13 +15736,13 @@ async function scanSecurity(projectRoot, graph, options = {}) {
|
|
|
14940
15736
|
};
|
|
14941
15737
|
}
|
|
14942
15738
|
function detectPackageManager(projectRoot) {
|
|
14943
|
-
if (
|
|
14944
|
-
if (
|
|
14945
|
-
if (
|
|
14946
|
-
if (
|
|
14947
|
-
if (
|
|
14948
|
-
if (
|
|
14949
|
-
if (
|
|
15739
|
+
if (existsSync20(join31(projectRoot, "package.json"))) return "npm";
|
|
15740
|
+
if (existsSync20(join31(projectRoot, "requirements.txt"))) return "pip";
|
|
15741
|
+
if (existsSync20(join31(projectRoot, "pyproject.toml"))) return "pip";
|
|
15742
|
+
if (existsSync20(join31(projectRoot, "Cargo.toml"))) return "cargo";
|
|
15743
|
+
if (existsSync20(join31(projectRoot, "go.mod"))) return "go";
|
|
15744
|
+
if (existsSync20(join31(projectRoot, "pom.xml"))) return "maven";
|
|
15745
|
+
if (existsSync20(join31(projectRoot, "build.gradle")) || existsSync20(join31(projectRoot, "build.gradle.kts"))) return "gradle";
|
|
14950
15746
|
return "unknown";
|
|
14951
15747
|
}
|
|
14952
15748
|
|