depwire-cli 1.0.1 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -2
- package/dist/{chunk-LV32EDYQ.js → chunk-7HLVFIVW.js} +1134 -146
- package/dist/{chunk-5D36PY3Q.js → chunk-JPDK7SOI.js} +8 -8
- package/dist/index.js +2 -2
- package/dist/mcpb-entry.js +2 -2
- package/dist/parser/grammars/tree-sitter-cpp.wasm +0 -0
- package/dist/sdk.js +1 -1
- package/package.json +2 -1
|
@@ -31,10 +31,12 @@ function scanDirectory(rootDir, baseDir = rootDir) {
|
|
|
31
31
|
const isPython = entry.endsWith(".py");
|
|
32
32
|
const isGo = entry.endsWith(".go") && !entry.endsWith("_test.go");
|
|
33
33
|
const isRust = entry.endsWith(".rs");
|
|
34
|
-
const isC = entry.endsWith(".c")
|
|
34
|
+
const isC = entry.endsWith(".c");
|
|
35
|
+
const isCpp = entry.endsWith(".cpp") || entry.endsWith(".cc") || entry.endsWith(".cxx") || entry.endsWith(".c++") || entry.endsWith(".hpp") || entry.endsWith(".hh") || entry.endsWith(".hxx") || entry.endsWith(".h++") || entry.endsWith(".h") || entry.endsWith(".inl") || entry.endsWith(".ipp");
|
|
35
36
|
const isCSharp = entry.endsWith(".cs") || entry.endsWith(".csx") || entry.endsWith(".csproj");
|
|
36
37
|
const isJava = entry.endsWith(".java") || entry === "pom.xml" || entry === "build.gradle" || entry === "build.gradle.kts";
|
|
37
|
-
|
|
38
|
+
const isCppBuild = entry === "CMakeLists.txt" || entry === "conanfile.txt" || entry === "vcpkg.json";
|
|
39
|
+
if (isTypeScript || isJavaScript || isPython || isGo || isRust || isC || isCpp || isCSharp || isJava || isCppBuild) {
|
|
38
40
|
files.push(relative(rootDir, fullPath));
|
|
39
41
|
}
|
|
40
42
|
}
|
|
@@ -109,11 +111,11 @@ function findProjectRoot(startDir = process.cwd()) {
|
|
|
109
111
|
}
|
|
110
112
|
|
|
111
113
|
// src/parser/index.ts
|
|
112
|
-
import { readFileSync as
|
|
113
|
-
import { join as
|
|
114
|
+
import { readFileSync as readFileSync8, statSync as statSync5 } from "fs";
|
|
115
|
+
import { join as join11, resolve as resolve5 } from "path";
|
|
114
116
|
|
|
115
117
|
// src/parser/detect.ts
|
|
116
|
-
import { extname as
|
|
118
|
+
import { extname as extname6, basename as basename4 } from "path";
|
|
117
119
|
|
|
118
120
|
// src/parser/wasm-init.ts
|
|
119
121
|
import { Parser, Language } from "web-tree-sitter";
|
|
@@ -142,7 +144,8 @@ async function initParser() {
|
|
|
142
144
|
"rust": "tree-sitter-rust.wasm",
|
|
143
145
|
"c": "tree-sitter-c.wasm",
|
|
144
146
|
"c_sharp": "tree-sitter-c_sharp.wasm",
|
|
145
|
-
"java": "tree-sitter-java.wasm"
|
|
147
|
+
"java": "tree-sitter-java.wasm",
|
|
148
|
+
"cpp": "tree-sitter-cpp.wasm"
|
|
146
149
|
};
|
|
147
150
|
for (const [name, file] of Object.entries(grammarFiles)) {
|
|
148
151
|
const wasmPath = path.join(grammarsDir, file);
|
|
@@ -2786,7 +2789,7 @@ function getCurrentSymbolId6(context) {
|
|
|
2786
2789
|
}
|
|
2787
2790
|
var cParser = {
|
|
2788
2791
|
name: "c",
|
|
2789
|
-
extensions: [".c"
|
|
2792
|
+
extensions: [".c"],
|
|
2790
2793
|
parseFile: parseCFile
|
|
2791
2794
|
};
|
|
2792
2795
|
|
|
@@ -4096,6 +4099,834 @@ var javaParser = {
|
|
|
4096
4099
|
parseFile: parseJavaFile
|
|
4097
4100
|
};
|
|
4098
4101
|
|
|
4102
|
+
// src/parser/cpp.ts
|
|
4103
|
+
import { dirname as dirname9, join as join10, relative as relative5, basename as basename3 } from "path";
|
|
4104
|
+
import { existsSync as existsSync10 } from "fs";
|
|
4105
|
+
function parseCppFile(filePath, sourceCode, projectRoot) {
|
|
4106
|
+
if (basename3(filePath) === "CMakeLists.txt") {
|
|
4107
|
+
return parseCMakeLists(filePath, sourceCode, projectRoot);
|
|
4108
|
+
}
|
|
4109
|
+
if (basename3(filePath) === "conanfile.txt") {
|
|
4110
|
+
return parseConanfileTxt(filePath, sourceCode, projectRoot);
|
|
4111
|
+
}
|
|
4112
|
+
if (basename3(filePath) === "vcpkg.json") {
|
|
4113
|
+
return parseVcpkgJson(filePath, sourceCode, projectRoot);
|
|
4114
|
+
}
|
|
4115
|
+
const parser = getParser("cpp");
|
|
4116
|
+
const tree = parser.parse(sourceCode, null, { bufferSize: 1024 * 1024 });
|
|
4117
|
+
const context = {
|
|
4118
|
+
filePath,
|
|
4119
|
+
projectRoot,
|
|
4120
|
+
sourceCode,
|
|
4121
|
+
symbols: [],
|
|
4122
|
+
edges: [],
|
|
4123
|
+
currentScope: [],
|
|
4124
|
+
currentClass: null,
|
|
4125
|
+
currentNamespace: null,
|
|
4126
|
+
imports: /* @__PURE__ */ new Map(),
|
|
4127
|
+
isBuildFile: false
|
|
4128
|
+
};
|
|
4129
|
+
walkNode9(tree.rootNode, context);
|
|
4130
|
+
return {
|
|
4131
|
+
filePath,
|
|
4132
|
+
symbols: context.symbols,
|
|
4133
|
+
edges: context.edges
|
|
4134
|
+
};
|
|
4135
|
+
}
|
|
4136
|
+
function walkNode9(node, context) {
|
|
4137
|
+
processNode9(node, context);
|
|
4138
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
4139
|
+
const child = node.child(i);
|
|
4140
|
+
if (child) {
|
|
4141
|
+
walkNode9(child, context);
|
|
4142
|
+
}
|
|
4143
|
+
}
|
|
4144
|
+
}
|
|
4145
|
+
function processNode9(node, context) {
|
|
4146
|
+
switch (node.type) {
|
|
4147
|
+
case "namespace_definition":
|
|
4148
|
+
processNamespaceDefinition(node, context);
|
|
4149
|
+
break;
|
|
4150
|
+
case "class_specifier":
|
|
4151
|
+
processClassSpecifier(node, context);
|
|
4152
|
+
break;
|
|
4153
|
+
case "struct_specifier":
|
|
4154
|
+
processStructSpecifier2(node, context);
|
|
4155
|
+
break;
|
|
4156
|
+
case "union_specifier":
|
|
4157
|
+
processUnionSpecifier(node, context);
|
|
4158
|
+
break;
|
|
4159
|
+
case "enum_specifier":
|
|
4160
|
+
processEnumSpecifier2(node, context);
|
|
4161
|
+
break;
|
|
4162
|
+
case "function_definition":
|
|
4163
|
+
processFunctionDefinition3(node, context);
|
|
4164
|
+
break;
|
|
4165
|
+
case "declaration":
|
|
4166
|
+
processDeclaration2(node, context);
|
|
4167
|
+
break;
|
|
4168
|
+
case "alias_declaration":
|
|
4169
|
+
processAliasDeclaration(node, context);
|
|
4170
|
+
break;
|
|
4171
|
+
case "type_definition":
|
|
4172
|
+
processTypeDefinition2(node, context);
|
|
4173
|
+
break;
|
|
4174
|
+
case "preproc_include":
|
|
4175
|
+
processIncludeDirective2(node, context);
|
|
4176
|
+
break;
|
|
4177
|
+
case "preproc_def":
|
|
4178
|
+
case "preproc_function_def":
|
|
4179
|
+
processMacroDefinition2(node, context);
|
|
4180
|
+
break;
|
|
4181
|
+
case "template_declaration":
|
|
4182
|
+
processTemplateDeclaration(node, context);
|
|
4183
|
+
break;
|
|
4184
|
+
case "call_expression":
|
|
4185
|
+
processCallExpression9(node, context);
|
|
4186
|
+
break;
|
|
4187
|
+
case "static_assert_declaration":
|
|
4188
|
+
processStaticAssert(node, context);
|
|
4189
|
+
break;
|
|
4190
|
+
}
|
|
4191
|
+
}
|
|
4192
|
+
function processNamespaceDefinition(node, context) {
|
|
4193
|
+
const nameNode = node.childForFieldName("name");
|
|
4194
|
+
const name = nameNode ? nodeText8(nameNode, context) : "<anonymous>";
|
|
4195
|
+
if (name !== "<anonymous>") {
|
|
4196
|
+
const symbolId = `${context.filePath}::${name}`;
|
|
4197
|
+
context.symbols.push({
|
|
4198
|
+
id: symbolId,
|
|
4199
|
+
name,
|
|
4200
|
+
kind: "module",
|
|
4201
|
+
filePath: context.filePath,
|
|
4202
|
+
startLine: node.startPosition.row + 1,
|
|
4203
|
+
endLine: node.endPosition.row + 1,
|
|
4204
|
+
exported: true
|
|
4205
|
+
});
|
|
4206
|
+
}
|
|
4207
|
+
const oldNamespace = context.currentNamespace;
|
|
4208
|
+
context.currentNamespace = name !== "<anonymous>" ? name : oldNamespace;
|
|
4209
|
+
if (name !== "<anonymous>") context.currentScope.push(name);
|
|
4210
|
+
const body = node.childForFieldName("body") || findChildByType9(node, "declaration_list");
|
|
4211
|
+
if (body) {
|
|
4212
|
+
walkNode9(body, context);
|
|
4213
|
+
}
|
|
4214
|
+
if (name !== "<anonymous>") context.currentScope.pop();
|
|
4215
|
+
context.currentNamespace = oldNamespace;
|
|
4216
|
+
}
|
|
4217
|
+
function processClassSpecifier(node, context) {
|
|
4218
|
+
processTypeSpecifier(node, context, "class");
|
|
4219
|
+
}
|
|
4220
|
+
function processStructSpecifier2(node, context) {
|
|
4221
|
+
processTypeSpecifier(node, context, "class");
|
|
4222
|
+
}
|
|
4223
|
+
function processUnionSpecifier(node, context) {
|
|
4224
|
+
processTypeSpecifier(node, context, "class");
|
|
4225
|
+
}
|
|
4226
|
+
function processTypeSpecifier(node, context, kind) {
|
|
4227
|
+
let nameNode = node.childForFieldName("name");
|
|
4228
|
+
let name = null;
|
|
4229
|
+
if (nameNode) {
|
|
4230
|
+
name = nodeText8(nameNode, context);
|
|
4231
|
+
const angleBracketIdx = name.indexOf("<");
|
|
4232
|
+
if (angleBracketIdx > 0) {
|
|
4233
|
+
name = name.substring(0, angleBracketIdx);
|
|
4234
|
+
}
|
|
4235
|
+
}
|
|
4236
|
+
if (!name) {
|
|
4237
|
+
const parent = node.parent;
|
|
4238
|
+
if (parent && parent.type === "type_definition") {
|
|
4239
|
+
const typedefDecl = parent.childForFieldName("declarator");
|
|
4240
|
+
if (typedefDecl) {
|
|
4241
|
+
name = extractIdentifierFromDeclarator2(typedefDecl, context);
|
|
4242
|
+
}
|
|
4243
|
+
}
|
|
4244
|
+
}
|
|
4245
|
+
if (!name) return;
|
|
4246
|
+
const exported = true;
|
|
4247
|
+
const scope = context.currentClass || void 0;
|
|
4248
|
+
const symbolId = `${context.filePath}::${name}`;
|
|
4249
|
+
context.symbols.push({
|
|
4250
|
+
id: symbolId,
|
|
4251
|
+
name,
|
|
4252
|
+
kind,
|
|
4253
|
+
filePath: context.filePath,
|
|
4254
|
+
startLine: node.startPosition.row + 1,
|
|
4255
|
+
endLine: node.endPosition.row + 1,
|
|
4256
|
+
exported,
|
|
4257
|
+
scope
|
|
4258
|
+
});
|
|
4259
|
+
const baseClause = findChildByType9(node, "base_class_clause");
|
|
4260
|
+
if (baseClause) {
|
|
4261
|
+
processBaseClassClause(baseClause, symbolId, context);
|
|
4262
|
+
}
|
|
4263
|
+
const oldClass = context.currentClass;
|
|
4264
|
+
context.currentClass = name;
|
|
4265
|
+
context.currentScope.push(name);
|
|
4266
|
+
const body = node.childForFieldName("body") || findChildByType9(node, "field_declaration_list");
|
|
4267
|
+
if (body) {
|
|
4268
|
+
walkNode9(body, context);
|
|
4269
|
+
}
|
|
4270
|
+
context.currentScope.pop();
|
|
4271
|
+
context.currentClass = oldClass;
|
|
4272
|
+
}
|
|
4273
|
+
function processBaseClassClause(node, sourceId, context) {
|
|
4274
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
4275
|
+
const child = node.child(i);
|
|
4276
|
+
if (!child) continue;
|
|
4277
|
+
if (child.type === "base_class_specifier" || child.type === "type_identifier" || child.type === "qualified_identifier" || child.type === "template_type") {
|
|
4278
|
+
const baseName = extractTypeName4(child, context);
|
|
4279
|
+
if (baseName) {
|
|
4280
|
+
const baseId = resolveSymbol8(baseName, context);
|
|
4281
|
+
if (baseId) {
|
|
4282
|
+
context.edges.push({
|
|
4283
|
+
source: sourceId,
|
|
4284
|
+
target: baseId,
|
|
4285
|
+
kind: "inherits",
|
|
4286
|
+
filePath: context.filePath,
|
|
4287
|
+
line: child.startPosition.row + 1
|
|
4288
|
+
});
|
|
4289
|
+
}
|
|
4290
|
+
}
|
|
4291
|
+
}
|
|
4292
|
+
}
|
|
4293
|
+
}
|
|
4294
|
+
function processEnumSpecifier2(node, context) {
|
|
4295
|
+
let nameNode = node.childForFieldName("name");
|
|
4296
|
+
let name = null;
|
|
4297
|
+
if (nameNode) {
|
|
4298
|
+
name = nodeText8(nameNode, context);
|
|
4299
|
+
}
|
|
4300
|
+
if (!name) {
|
|
4301
|
+
const parent = node.parent;
|
|
4302
|
+
if (parent && parent.type === "type_definition") {
|
|
4303
|
+
const typedefDecl = parent.childForFieldName("declarator");
|
|
4304
|
+
if (typedefDecl) {
|
|
4305
|
+
name = extractIdentifierFromDeclarator2(typedefDecl, context);
|
|
4306
|
+
}
|
|
4307
|
+
}
|
|
4308
|
+
}
|
|
4309
|
+
if (!name) return;
|
|
4310
|
+
const symbolId = `${context.filePath}::${name}`;
|
|
4311
|
+
context.symbols.push({
|
|
4312
|
+
id: symbolId,
|
|
4313
|
+
name,
|
|
4314
|
+
kind: "enum",
|
|
4315
|
+
filePath: context.filePath,
|
|
4316
|
+
startLine: node.startPosition.row + 1,
|
|
4317
|
+
endLine: node.endPosition.row + 1,
|
|
4318
|
+
exported: true
|
|
4319
|
+
});
|
|
4320
|
+
const body = node.childForFieldName("body") || findChildByType9(node, "enumerator_list");
|
|
4321
|
+
if (body) {
|
|
4322
|
+
for (let i = 0; i < body.childCount; i++) {
|
|
4323
|
+
const child = body.child(i);
|
|
4324
|
+
if (child && child.type === "enumerator") {
|
|
4325
|
+
const constNameNode = child.childForFieldName("name");
|
|
4326
|
+
if (!constNameNode) continue;
|
|
4327
|
+
const constName = nodeText8(constNameNode, context);
|
|
4328
|
+
const constId = `${context.filePath}::${name}.${constName}`;
|
|
4329
|
+
context.symbols.push({
|
|
4330
|
+
id: constId,
|
|
4331
|
+
name: constName,
|
|
4332
|
+
kind: "constant",
|
|
4333
|
+
filePath: context.filePath,
|
|
4334
|
+
startLine: child.startPosition.row + 1,
|
|
4335
|
+
endLine: child.endPosition.row + 1,
|
|
4336
|
+
exported: true,
|
|
4337
|
+
scope: name
|
|
4338
|
+
});
|
|
4339
|
+
}
|
|
4340
|
+
}
|
|
4341
|
+
}
|
|
4342
|
+
}
|
|
4343
|
+
function processFunctionDefinition3(node, context) {
|
|
4344
|
+
const declarator = node.childForFieldName("declarator");
|
|
4345
|
+
if (!declarator) return;
|
|
4346
|
+
const nameNode = extractFunctionName2(declarator);
|
|
4347
|
+
if (!nameNode) return;
|
|
4348
|
+
let name = nodeText8(nameNode, context);
|
|
4349
|
+
if (name === "operator") {
|
|
4350
|
+
const fullText = nodeText8(declarator, context);
|
|
4351
|
+
const opMatch = fullText.match(/operator\s*([^\s(]+)/);
|
|
4352
|
+
if (opMatch) {
|
|
4353
|
+
name = `operator${opMatch[1]}`;
|
|
4354
|
+
}
|
|
4355
|
+
}
|
|
4356
|
+
const fullDeclText = nodeText8(declarator, context);
|
|
4357
|
+
if (fullDeclText.includes("~")) {
|
|
4358
|
+
const tildeMatch = fullDeclText.match(/~\s*(\w+)/);
|
|
4359
|
+
if (tildeMatch) {
|
|
4360
|
+
name = `~${tildeMatch[1]}`;
|
|
4361
|
+
}
|
|
4362
|
+
}
|
|
4363
|
+
const isConstructor = context.currentClass !== null && name === context.currentClass;
|
|
4364
|
+
const isDestructor = name.startsWith("~");
|
|
4365
|
+
const isStatic = hasStorageClass2(node, "static", context);
|
|
4366
|
+
const exported = !isStatic;
|
|
4367
|
+
const scope = context.currentClass || void 0;
|
|
4368
|
+
const symbolId = scope ? `${context.filePath}::${scope}.${name}` : `${context.filePath}::${name}`;
|
|
4369
|
+
context.symbols.push({
|
|
4370
|
+
id: symbolId,
|
|
4371
|
+
name,
|
|
4372
|
+
kind: context.currentClass ? "method" : "function",
|
|
4373
|
+
filePath: context.filePath,
|
|
4374
|
+
startLine: node.startPosition.row + 1,
|
|
4375
|
+
endLine: node.endPosition.row + 1,
|
|
4376
|
+
exported,
|
|
4377
|
+
scope
|
|
4378
|
+
});
|
|
4379
|
+
const scopeName = scope ? `${scope}.${name}` : name;
|
|
4380
|
+
context.currentScope.push(scopeName);
|
|
4381
|
+
const body = node.childForFieldName("body");
|
|
4382
|
+
if (body) {
|
|
4383
|
+
walkNode9(body, context);
|
|
4384
|
+
}
|
|
4385
|
+
context.currentScope.pop();
|
|
4386
|
+
}
|
|
4387
|
+
function processDeclaration2(node, context) {
|
|
4388
|
+
if (context.currentClass) {
|
|
4389
|
+
processFieldDeclaration2(node, context);
|
|
4390
|
+
return;
|
|
4391
|
+
}
|
|
4392
|
+
const parent = node.parent;
|
|
4393
|
+
if (!parent || parent.type !== "translation_unit" && parent.type !== "declaration_list") {
|
|
4394
|
+
return;
|
|
4395
|
+
}
|
|
4396
|
+
const declarator = node.childForFieldName("declarator");
|
|
4397
|
+
if (!declarator) return;
|
|
4398
|
+
if (containsType(declarator, "function_declarator")) {
|
|
4399
|
+
return;
|
|
4400
|
+
}
|
|
4401
|
+
const name = extractIdentifierFromDeclarator2(declarator, context);
|
|
4402
|
+
if (!name) return;
|
|
4403
|
+
const isStatic = hasStorageClass2(node, "static", context);
|
|
4404
|
+
const isConst = nodeText8(node, context).includes("const");
|
|
4405
|
+
const symbolId = `${context.filePath}::${name}`;
|
|
4406
|
+
context.symbols.push({
|
|
4407
|
+
id: symbolId,
|
|
4408
|
+
name,
|
|
4409
|
+
kind: isConst ? "constant" : "variable",
|
|
4410
|
+
filePath: context.filePath,
|
|
4411
|
+
startLine: node.startPosition.row + 1,
|
|
4412
|
+
endLine: node.endPosition.row + 1,
|
|
4413
|
+
exported: !isStatic
|
|
4414
|
+
});
|
|
4415
|
+
}
|
|
4416
|
+
function processFieldDeclaration2(node, context) {
|
|
4417
|
+
const declarator = node.childForFieldName("declarator");
|
|
4418
|
+
if (!declarator) return;
|
|
4419
|
+
if (containsType(declarator, "function_declarator")) {
|
|
4420
|
+
const fnName = extractFunctionName2(declarator);
|
|
4421
|
+
if (fnName) {
|
|
4422
|
+
let name2 = nodeText8(fnName, context);
|
|
4423
|
+
const scope2 = context.currentClass || void 0;
|
|
4424
|
+
const symbolId2 = scope2 ? `${context.filePath}::${scope2}.${name2}` : `${context.filePath}::${name2}`;
|
|
4425
|
+
if (!context.symbols.find((s) => s.id === symbolId2)) {
|
|
4426
|
+
const exported = !hasAccessSpecifier(node, "private", context);
|
|
4427
|
+
context.symbols.push({
|
|
4428
|
+
id: symbolId2,
|
|
4429
|
+
name: name2,
|
|
4430
|
+
kind: "method",
|
|
4431
|
+
filePath: context.filePath,
|
|
4432
|
+
startLine: node.startPosition.row + 1,
|
|
4433
|
+
endLine: node.endPosition.row + 1,
|
|
4434
|
+
exported,
|
|
4435
|
+
scope: scope2
|
|
4436
|
+
});
|
|
4437
|
+
}
|
|
4438
|
+
}
|
|
4439
|
+
return;
|
|
4440
|
+
}
|
|
4441
|
+
const name = extractIdentifierFromDeclarator2(declarator, context);
|
|
4442
|
+
if (!name) return;
|
|
4443
|
+
const scope = context.currentClass || void 0;
|
|
4444
|
+
const symbolId = scope ? `${context.filePath}::${scope}.${name}` : `${context.filePath}::${name}`;
|
|
4445
|
+
const isConst = nodeText8(node, context).includes("const");
|
|
4446
|
+
const isStatic = nodeText8(node, context).includes("static");
|
|
4447
|
+
context.symbols.push({
|
|
4448
|
+
id: symbolId,
|
|
4449
|
+
name,
|
|
4450
|
+
kind: isConst && isStatic ? "constant" : "property",
|
|
4451
|
+
filePath: context.filePath,
|
|
4452
|
+
startLine: node.startPosition.row + 1,
|
|
4453
|
+
endLine: node.endPosition.row + 1,
|
|
4454
|
+
exported: !hasAccessSpecifier(node, "private", context),
|
|
4455
|
+
scope
|
|
4456
|
+
});
|
|
4457
|
+
}
|
|
4458
|
+
function processAliasDeclaration(node, context) {
|
|
4459
|
+
const nameNode = node.childForFieldName("name");
|
|
4460
|
+
if (!nameNode) return;
|
|
4461
|
+
const name = nodeText8(nameNode, context);
|
|
4462
|
+
const symbolId = `${context.filePath}::${name}`;
|
|
4463
|
+
context.symbols.push({
|
|
4464
|
+
id: symbolId,
|
|
4465
|
+
name,
|
|
4466
|
+
kind: "type_alias",
|
|
4467
|
+
filePath: context.filePath,
|
|
4468
|
+
startLine: node.startPosition.row + 1,
|
|
4469
|
+
endLine: node.endPosition.row + 1,
|
|
4470
|
+
exported: true
|
|
4471
|
+
});
|
|
4472
|
+
}
|
|
4473
|
+
function processTypeDefinition2(node, context) {
|
|
4474
|
+
const typeNode = node.childForFieldName("type");
|
|
4475
|
+
if (!typeNode) return;
|
|
4476
|
+
if (typeNode.type === "struct_specifier" || typeNode.type === "enum_specifier" || typeNode.type === "union_specifier") {
|
|
4477
|
+
return;
|
|
4478
|
+
}
|
|
4479
|
+
const declarator = node.childForFieldName("declarator");
|
|
4480
|
+
if (!declarator) return;
|
|
4481
|
+
const name = extractIdentifierFromDeclarator2(declarator, context);
|
|
4482
|
+
if (!name) return;
|
|
4483
|
+
const symbolId = `${context.filePath}::${name}`;
|
|
4484
|
+
context.symbols.push({
|
|
4485
|
+
id: symbolId,
|
|
4486
|
+
name,
|
|
4487
|
+
kind: "type_alias",
|
|
4488
|
+
filePath: context.filePath,
|
|
4489
|
+
startLine: node.startPosition.row + 1,
|
|
4490
|
+
endLine: node.endPosition.row + 1,
|
|
4491
|
+
exported: true
|
|
4492
|
+
});
|
|
4493
|
+
}
|
|
4494
|
+
function processTemplateDeclaration(node, context) {
|
|
4495
|
+
}
|
|
4496
|
+
function processStaticAssert(node, context) {
|
|
4497
|
+
const symbolId = `${context.filePath}::static_assert:${node.startPosition.row + 1}`;
|
|
4498
|
+
context.symbols.push({
|
|
4499
|
+
id: symbolId,
|
|
4500
|
+
name: "static_assert",
|
|
4501
|
+
kind: "constant",
|
|
4502
|
+
filePath: context.filePath,
|
|
4503
|
+
startLine: node.startPosition.row + 1,
|
|
4504
|
+
endLine: node.endPosition.row + 1,
|
|
4505
|
+
exported: false
|
|
4506
|
+
});
|
|
4507
|
+
}
|
|
4508
|
+
function processMacroDefinition2(node, context) {
|
|
4509
|
+
const nameNode = node.childForFieldName("name");
|
|
4510
|
+
if (!nameNode) return;
|
|
4511
|
+
const name = nodeText8(nameNode, context);
|
|
4512
|
+
const kind = node.type === "preproc_function_def" ? "function" : "constant";
|
|
4513
|
+
const symbolId = `${context.filePath}::${name}`;
|
|
4514
|
+
context.symbols.push({
|
|
4515
|
+
id: symbolId,
|
|
4516
|
+
name,
|
|
4517
|
+
kind,
|
|
4518
|
+
filePath: context.filePath,
|
|
4519
|
+
startLine: node.startPosition.row + 1,
|
|
4520
|
+
endLine: node.endPosition.row + 1,
|
|
4521
|
+
exported: true
|
|
4522
|
+
});
|
|
4523
|
+
}
|
|
4524
|
+
function processIncludeDirective2(node, context) {
|
|
4525
|
+
const pathNode = node.childForFieldName("path");
|
|
4526
|
+
if (!pathNode) return;
|
|
4527
|
+
const pathText = nodeText8(pathNode, context);
|
|
4528
|
+
const isLocalInclude = pathText.startsWith('"') && pathText.endsWith('"');
|
|
4529
|
+
if (!isLocalInclude) {
|
|
4530
|
+
const includeName = pathText.replace(/[<>"]/g, "");
|
|
4531
|
+
const symbolId = `${context.filePath}::include:${includeName}`;
|
|
4532
|
+
context.symbols.push({
|
|
4533
|
+
id: symbolId,
|
|
4534
|
+
name: includeName,
|
|
4535
|
+
kind: "import",
|
|
4536
|
+
filePath: context.filePath,
|
|
4537
|
+
startLine: node.startPosition.row + 1,
|
|
4538
|
+
endLine: node.endPosition.row + 1,
|
|
4539
|
+
exported: false
|
|
4540
|
+
});
|
|
4541
|
+
return;
|
|
4542
|
+
}
|
|
4543
|
+
const includePath = pathText.slice(1, -1);
|
|
4544
|
+
const resolvedFiles = resolveIncludePath2(includePath, context.filePath, context.projectRoot);
|
|
4545
|
+
if (resolvedFiles.length === 0) return;
|
|
4546
|
+
const sourceId = `${context.filePath}::__file__`;
|
|
4547
|
+
for (const targetPath of resolvedFiles) {
|
|
4548
|
+
const targetId = `${targetPath}::__file__`;
|
|
4549
|
+
context.edges.push({
|
|
4550
|
+
source: sourceId,
|
|
4551
|
+
target: targetId,
|
|
4552
|
+
kind: "imports",
|
|
4553
|
+
filePath: context.filePath,
|
|
4554
|
+
line: node.startPosition.row + 1
|
|
4555
|
+
});
|
|
4556
|
+
}
|
|
4557
|
+
}
|
|
4558
|
+
function processCallExpression9(node, context) {
|
|
4559
|
+
if (context.currentScope.length === 0) return;
|
|
4560
|
+
const functionNode = node.childForFieldName("function");
|
|
4561
|
+
if (!functionNode) return;
|
|
4562
|
+
let calleeName = null;
|
|
4563
|
+
if (functionNode.type === "identifier") {
|
|
4564
|
+
calleeName = nodeText8(functionNode, context);
|
|
4565
|
+
} else if (functionNode.type === "field_expression" || functionNode.type === "qualified_identifier") {
|
|
4566
|
+
const nameNode = functionNode.childForFieldName("name") || functionNode.childForFieldName("field");
|
|
4567
|
+
if (nameNode) {
|
|
4568
|
+
calleeName = nodeText8(nameNode, context);
|
|
4569
|
+
}
|
|
4570
|
+
} else if (functionNode.type === "template_function") {
|
|
4571
|
+
const nameNode = functionNode.childForFieldName("name");
|
|
4572
|
+
if (nameNode) {
|
|
4573
|
+
calleeName = nodeText8(nameNode, context);
|
|
4574
|
+
}
|
|
4575
|
+
}
|
|
4576
|
+
if (!calleeName) return;
|
|
4577
|
+
const builtins = /* @__PURE__ */ new Set([
|
|
4578
|
+
"printf",
|
|
4579
|
+
"scanf",
|
|
4580
|
+
"malloc",
|
|
4581
|
+
"free",
|
|
4582
|
+
"memcpy",
|
|
4583
|
+
"strlen",
|
|
4584
|
+
"strcmp",
|
|
4585
|
+
"strcpy",
|
|
4586
|
+
"strcat",
|
|
4587
|
+
"cout",
|
|
4588
|
+
"cin",
|
|
4589
|
+
"cerr",
|
|
4590
|
+
"endl",
|
|
4591
|
+
"make_shared",
|
|
4592
|
+
"make_unique",
|
|
4593
|
+
"make_pair",
|
|
4594
|
+
"make_tuple",
|
|
4595
|
+
"move",
|
|
4596
|
+
"forward",
|
|
4597
|
+
"swap",
|
|
4598
|
+
"begin",
|
|
4599
|
+
"end",
|
|
4600
|
+
"size",
|
|
4601
|
+
"empty",
|
|
4602
|
+
"push_back",
|
|
4603
|
+
"emplace_back",
|
|
4604
|
+
"insert",
|
|
4605
|
+
"erase",
|
|
4606
|
+
"find",
|
|
4607
|
+
"sort",
|
|
4608
|
+
"transform",
|
|
4609
|
+
"for_each",
|
|
4610
|
+
"accumulate",
|
|
4611
|
+
"static_cast",
|
|
4612
|
+
"dynamic_cast",
|
|
4613
|
+
"reinterpret_cast",
|
|
4614
|
+
"const_cast"
|
|
4615
|
+
]);
|
|
4616
|
+
if (builtins.has(calleeName)) return;
|
|
4617
|
+
const callerId = getCurrentSymbolId9(context);
|
|
4618
|
+
if (!callerId) return;
|
|
4619
|
+
const calleeId = resolveSymbol8(calleeName, context);
|
|
4620
|
+
if (calleeId) {
|
|
4621
|
+
context.edges.push({
|
|
4622
|
+
source: callerId,
|
|
4623
|
+
target: calleeId,
|
|
4624
|
+
kind: "calls",
|
|
4625
|
+
filePath: context.filePath,
|
|
4626
|
+
line: node.startPosition.row + 1
|
|
4627
|
+
});
|
|
4628
|
+
}
|
|
4629
|
+
}
|
|
4630
|
+
function parseCMakeLists(filePath, sourceCode, projectRoot) {
|
|
4631
|
+
const symbols = [];
|
|
4632
|
+
const edges = [];
|
|
4633
|
+
const lines = sourceCode.split("\n");
|
|
4634
|
+
const projectName = basename3(dirname9(join10(projectRoot, filePath)));
|
|
4635
|
+
symbols.push({
|
|
4636
|
+
id: `${filePath}::${projectName}`,
|
|
4637
|
+
name: projectName,
|
|
4638
|
+
kind: "module",
|
|
4639
|
+
filePath,
|
|
4640
|
+
startLine: 1,
|
|
4641
|
+
endLine: lines.length,
|
|
4642
|
+
exported: true
|
|
4643
|
+
});
|
|
4644
|
+
for (let i = 0; i < lines.length; i++) {
|
|
4645
|
+
const line = lines[i].trim();
|
|
4646
|
+
const lineNum = i + 1;
|
|
4647
|
+
const findPkgMatch = line.match(/find_package\s*\(\s*(\w+)/i);
|
|
4648
|
+
if (findPkgMatch) {
|
|
4649
|
+
symbols.push({
|
|
4650
|
+
id: `${filePath}::dep:${findPkgMatch[1]}`,
|
|
4651
|
+
name: findPkgMatch[1],
|
|
4652
|
+
kind: "import",
|
|
4653
|
+
filePath,
|
|
4654
|
+
startLine: lineNum,
|
|
4655
|
+
endLine: lineNum,
|
|
4656
|
+
exported: false
|
|
4657
|
+
});
|
|
4658
|
+
}
|
|
4659
|
+
const linkLibsMatch = line.match(/target_link_libraries\s*\(\s*\w+\s+(?:PRIVATE|PUBLIC|INTERFACE)?\s*(.*)\)/i);
|
|
4660
|
+
if (linkLibsMatch) {
|
|
4661
|
+
const libs = linkLibsMatch[1].trim().split(/\s+/).filter((l) => l && !["PRIVATE", "PUBLIC", "INTERFACE"].includes(l));
|
|
4662
|
+
for (const lib of libs) {
|
|
4663
|
+
symbols.push({
|
|
4664
|
+
id: `${filePath}::dep:${lib}`,
|
|
4665
|
+
name: lib,
|
|
4666
|
+
kind: "import",
|
|
4667
|
+
filePath,
|
|
4668
|
+
startLine: lineNum,
|
|
4669
|
+
endLine: lineNum,
|
|
4670
|
+
exported: false
|
|
4671
|
+
});
|
|
4672
|
+
}
|
|
4673
|
+
}
|
|
4674
|
+
const addSubdirMatch = line.match(/add_subdirectory\s*\(\s*([^\s)]+)/i);
|
|
4675
|
+
if (addSubdirMatch) {
|
|
4676
|
+
const subdir = addSubdirMatch[1];
|
|
4677
|
+
const cmakeDir = dirname9(join10(projectRoot, filePath));
|
|
4678
|
+
const subdirCMake = join10(relative5(projectRoot, cmakeDir), subdir, "CMakeLists.txt");
|
|
4679
|
+
if (existsSync10(join10(projectRoot, subdirCMake))) {
|
|
4680
|
+
edges.push({
|
|
4681
|
+
source: `${filePath}::__file__`,
|
|
4682
|
+
target: `${subdirCMake}::__file__`,
|
|
4683
|
+
kind: "imports",
|
|
4684
|
+
filePath,
|
|
4685
|
+
line: lineNum
|
|
4686
|
+
});
|
|
4687
|
+
}
|
|
4688
|
+
}
|
|
4689
|
+
const projectMatch = line.match(/project\s*\(\s*(\w+)/i);
|
|
4690
|
+
if (projectMatch) {
|
|
4691
|
+
symbols.push({
|
|
4692
|
+
id: `${filePath}::project:${projectMatch[1]}`,
|
|
4693
|
+
name: projectMatch[1],
|
|
4694
|
+
kind: "module",
|
|
4695
|
+
filePath,
|
|
4696
|
+
startLine: lineNum,
|
|
4697
|
+
endLine: lineNum,
|
|
4698
|
+
exported: true
|
|
4699
|
+
});
|
|
4700
|
+
}
|
|
4701
|
+
}
|
|
4702
|
+
return { filePath, symbols, edges };
|
|
4703
|
+
}
|
|
4704
|
+
function parseConanfileTxt(filePath, sourceCode, _projectRoot) {
|
|
4705
|
+
const symbols = [];
|
|
4706
|
+
const lines = sourceCode.split("\n");
|
|
4707
|
+
let inRequires = false;
|
|
4708
|
+
for (let i = 0; i < lines.length; i++) {
|
|
4709
|
+
const line = lines[i].trim();
|
|
4710
|
+
const lineNum = i + 1;
|
|
4711
|
+
if (line === "[requires]") {
|
|
4712
|
+
inRequires = true;
|
|
4713
|
+
continue;
|
|
4714
|
+
}
|
|
4715
|
+
if (line.startsWith("[") && line.endsWith("]")) {
|
|
4716
|
+
inRequires = false;
|
|
4717
|
+
continue;
|
|
4718
|
+
}
|
|
4719
|
+
if (inRequires && line.length > 0) {
|
|
4720
|
+
symbols.push({
|
|
4721
|
+
id: `${filePath}::dep:${line}`,
|
|
4722
|
+
name: line,
|
|
4723
|
+
kind: "import",
|
|
4724
|
+
filePath,
|
|
4725
|
+
startLine: lineNum,
|
|
4726
|
+
endLine: lineNum,
|
|
4727
|
+
exported: false
|
|
4728
|
+
});
|
|
4729
|
+
}
|
|
4730
|
+
}
|
|
4731
|
+
return { filePath, symbols, edges: [] };
|
|
4732
|
+
}
|
|
4733
|
+
function parseVcpkgJson(filePath, sourceCode, _projectRoot) {
|
|
4734
|
+
const symbols = [];
|
|
4735
|
+
try {
|
|
4736
|
+
const vcpkg = JSON.parse(sourceCode);
|
|
4737
|
+
if (vcpkg.dependencies && Array.isArray(vcpkg.dependencies)) {
|
|
4738
|
+
for (let i = 0; i < vcpkg.dependencies.length; i++) {
|
|
4739
|
+
const dep = vcpkg.dependencies[i];
|
|
4740
|
+
const name = typeof dep === "string" ? dep : dep.name || "";
|
|
4741
|
+
if (name) {
|
|
4742
|
+
symbols.push({
|
|
4743
|
+
id: `${filePath}::dep:${name}`,
|
|
4744
|
+
name,
|
|
4745
|
+
kind: "import",
|
|
4746
|
+
filePath,
|
|
4747
|
+
startLine: 1,
|
|
4748
|
+
endLine: 1,
|
|
4749
|
+
exported: false
|
|
4750
|
+
});
|
|
4751
|
+
}
|
|
4752
|
+
}
|
|
4753
|
+
}
|
|
4754
|
+
} catch {
|
|
4755
|
+
}
|
|
4756
|
+
return { filePath, symbols, edges: [] };
|
|
4757
|
+
}
|
|
4758
|
+
function resolveIncludePath2(includePath, currentFile, projectRoot) {
|
|
4759
|
+
const currentFileAbs = join10(projectRoot, currentFile);
|
|
4760
|
+
const currentDir = dirname9(currentFileAbs);
|
|
4761
|
+
const possibleFiles = [
|
|
4762
|
+
join10(currentDir, includePath),
|
|
4763
|
+
join10(projectRoot, includePath),
|
|
4764
|
+
join10(projectRoot, "include", includePath),
|
|
4765
|
+
join10(projectRoot, "src", includePath)
|
|
4766
|
+
];
|
|
4767
|
+
const resolvedFiles = [];
|
|
4768
|
+
for (const absPath of possibleFiles) {
|
|
4769
|
+
if (existsSync10(absPath)) {
|
|
4770
|
+
const relPath = relative5(projectRoot, absPath);
|
|
4771
|
+
if (!resolvedFiles.includes(relPath)) {
|
|
4772
|
+
resolvedFiles.push(relPath);
|
|
4773
|
+
}
|
|
4774
|
+
}
|
|
4775
|
+
}
|
|
4776
|
+
return resolvedFiles;
|
|
4777
|
+
}
|
|
4778
|
+
function resolveSymbol8(name, context) {
|
|
4779
|
+
if (context.imports.has(name)) {
|
|
4780
|
+
return context.imports.get(name) || null;
|
|
4781
|
+
}
|
|
4782
|
+
const currentFileId = `${context.filePath}::${name}`;
|
|
4783
|
+
if (context.symbols.find((s) => s.id === currentFileId)) {
|
|
4784
|
+
return currentFileId;
|
|
4785
|
+
}
|
|
4786
|
+
if (context.currentClass) {
|
|
4787
|
+
const classMethodId = `${context.filePath}::${context.currentClass}.${name}`;
|
|
4788
|
+
if (context.symbols.find((s) => s.id === classMethodId)) {
|
|
4789
|
+
return classMethodId;
|
|
4790
|
+
}
|
|
4791
|
+
}
|
|
4792
|
+
return null;
|
|
4793
|
+
}
|
|
4794
|
+
function hasStorageClass2(node, className, context) {
|
|
4795
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
4796
|
+
const child = node.child(i);
|
|
4797
|
+
if (child && child.type === "storage_class_specifier") {
|
|
4798
|
+
if (nodeText8(child, context) === className) {
|
|
4799
|
+
return true;
|
|
4800
|
+
}
|
|
4801
|
+
}
|
|
4802
|
+
}
|
|
4803
|
+
return false;
|
|
4804
|
+
}
|
|
4805
|
+
function hasAccessSpecifier(node, specifier, context) {
|
|
4806
|
+
const parent = node.parent;
|
|
4807
|
+
if (!parent) return false;
|
|
4808
|
+
let lastAccess = "";
|
|
4809
|
+
for (let i = 0; i < parent.childCount; i++) {
|
|
4810
|
+
const child = parent.child(i);
|
|
4811
|
+
if (!child) continue;
|
|
4812
|
+
if (child.type === "access_specifier") {
|
|
4813
|
+
lastAccess = nodeText8(child, context).replace(":", "").trim();
|
|
4814
|
+
}
|
|
4815
|
+
if (child === node) break;
|
|
4816
|
+
}
|
|
4817
|
+
return lastAccess === specifier;
|
|
4818
|
+
}
|
|
4819
|
+
function extractFunctionName2(declarator) {
|
|
4820
|
+
if (declarator.type === "identifier") {
|
|
4821
|
+
return declarator;
|
|
4822
|
+
}
|
|
4823
|
+
if (declarator.type === "function_declarator") {
|
|
4824
|
+
const innerDeclarator = declarator.childForFieldName("declarator");
|
|
4825
|
+
if (innerDeclarator) {
|
|
4826
|
+
return extractFunctionName2(innerDeclarator);
|
|
4827
|
+
}
|
|
4828
|
+
}
|
|
4829
|
+
if (declarator.type === "pointer_declarator" || declarator.type === "reference_declarator") {
|
|
4830
|
+
const innerDeclarator = declarator.childForFieldName("declarator");
|
|
4831
|
+
if (innerDeclarator) {
|
|
4832
|
+
return extractFunctionName2(innerDeclarator);
|
|
4833
|
+
}
|
|
4834
|
+
}
|
|
4835
|
+
if (declarator.type === "qualified_identifier" || declarator.type === "template_function") {
|
|
4836
|
+
const nameNode = declarator.childForFieldName("name");
|
|
4837
|
+
if (nameNode) {
|
|
4838
|
+
return extractFunctionName2(nameNode);
|
|
4839
|
+
}
|
|
4840
|
+
}
|
|
4841
|
+
if (declarator.type === "destructor_name") {
|
|
4842
|
+
return declarator;
|
|
4843
|
+
}
|
|
4844
|
+
if (declarator.type === "operator_name") {
|
|
4845
|
+
return declarator;
|
|
4846
|
+
}
|
|
4847
|
+
for (let i = 0; i < declarator.childCount; i++) {
|
|
4848
|
+
const child = declarator.child(i);
|
|
4849
|
+
if (child && child.type === "identifier") {
|
|
4850
|
+
return child;
|
|
4851
|
+
}
|
|
4852
|
+
}
|
|
4853
|
+
return null;
|
|
4854
|
+
}
|
|
4855
|
+
function extractIdentifierFromDeclarator2(declarator, context) {
|
|
4856
|
+
if (declarator.type === "identifier") {
|
|
4857
|
+
return nodeText8(declarator, context);
|
|
4858
|
+
}
|
|
4859
|
+
if (declarator.type === "type_identifier") {
|
|
4860
|
+
return nodeText8(declarator, context);
|
|
4861
|
+
}
|
|
4862
|
+
const identifierNode = findChildByType9(declarator, "identifier");
|
|
4863
|
+
if (identifierNode) {
|
|
4864
|
+
return nodeText8(identifierNode, context);
|
|
4865
|
+
}
|
|
4866
|
+
const typeIdNode = findChildByType9(declarator, "type_identifier");
|
|
4867
|
+
if (typeIdNode) {
|
|
4868
|
+
return nodeText8(typeIdNode, context);
|
|
4869
|
+
}
|
|
4870
|
+
for (let i = 0; i < declarator.childCount; i++) {
|
|
4871
|
+
const child = declarator.child(i);
|
|
4872
|
+
if (child) {
|
|
4873
|
+
const name = extractIdentifierFromDeclarator2(child, context);
|
|
4874
|
+
if (name) return name;
|
|
4875
|
+
}
|
|
4876
|
+
}
|
|
4877
|
+
return null;
|
|
4878
|
+
}
|
|
4879
|
+
function extractTypeName4(node, context) {
|
|
4880
|
+
const text = nodeText8(node, context).trim();
|
|
4881
|
+
if (!text || text === ":" || text === ",") return null;
|
|
4882
|
+
const accessStripped = text.replace(/^(?:public|protected|private|virtual)\s+/g, "");
|
|
4883
|
+
const angleBracketIdx = accessStripped.indexOf("<");
|
|
4884
|
+
const name = angleBracketIdx > 0 ? accessStripped.substring(0, angleBracketIdx) : accessStripped;
|
|
4885
|
+
const colonIdx = name.lastIndexOf("::");
|
|
4886
|
+
return colonIdx >= 0 ? name.substring(colonIdx + 2) : name;
|
|
4887
|
+
}
|
|
4888
|
+
function containsType(node, type) {
|
|
4889
|
+
if (node.type === type) return true;
|
|
4890
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
4891
|
+
const child = node.child(i);
|
|
4892
|
+
if (child && containsType(child, type)) return true;
|
|
4893
|
+
}
|
|
4894
|
+
return false;
|
|
4895
|
+
}
|
|
4896
|
+
function findChildByType9(node, type) {
|
|
4897
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
4898
|
+
const child = node.child(i);
|
|
4899
|
+
if (child && child.type === type) return child;
|
|
4900
|
+
}
|
|
4901
|
+
return null;
|
|
4902
|
+
}
|
|
4903
|
+
function nodeText8(node, context) {
|
|
4904
|
+
return context.sourceCode.substring(node.startIndex, node.endIndex);
|
|
4905
|
+
}
|
|
4906
|
+
function getCurrentSymbolId9(context) {
|
|
4907
|
+
if (context.currentScope.length === 0) return null;
|
|
4908
|
+
return `${context.filePath}::${context.currentScope[context.currentScope.length - 1]}`;
|
|
4909
|
+
}
|
|
4910
|
+
var cppParser = {
|
|
4911
|
+
name: "cpp",
|
|
4912
|
+
extensions: [
|
|
4913
|
+
".cpp",
|
|
4914
|
+
".cc",
|
|
4915
|
+
".cxx",
|
|
4916
|
+
".c++",
|
|
4917
|
+
".hpp",
|
|
4918
|
+
".hh",
|
|
4919
|
+
".hxx",
|
|
4920
|
+
".h++",
|
|
4921
|
+
".inl",
|
|
4922
|
+
".ipp",
|
|
4923
|
+
"CMakeLists.txt",
|
|
4924
|
+
"conanfile.txt",
|
|
4925
|
+
"vcpkg.json"
|
|
4926
|
+
],
|
|
4927
|
+
parseFile: parseCppFile
|
|
4928
|
+
};
|
|
4929
|
+
|
|
4099
4930
|
// src/parser/detect.ts
|
|
4100
4931
|
var parsers = [
|
|
4101
4932
|
typescriptParser,
|
|
@@ -4105,11 +4936,22 @@ var parsers = [
|
|
|
4105
4936
|
rustParser,
|
|
4106
4937
|
cParser,
|
|
4107
4938
|
csharpParser,
|
|
4108
|
-
javaParser
|
|
4939
|
+
javaParser,
|
|
4940
|
+
cppParser
|
|
4109
4941
|
];
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
const
|
|
4942
|
+
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/;
|
|
4943
|
+
function getParserForFile(filePath, content) {
|
|
4944
|
+
const ext = extname6(filePath).toLowerCase();
|
|
4945
|
+
const fileName = basename4(filePath);
|
|
4946
|
+
if (ext === ".h" && content) {
|
|
4947
|
+
if (CPP_KEYWORDS.test(content)) {
|
|
4948
|
+
return cppParser;
|
|
4949
|
+
}
|
|
4950
|
+
return cParser;
|
|
4951
|
+
}
|
|
4952
|
+
if (ext === ".h") {
|
|
4953
|
+
return cParser;
|
|
4954
|
+
}
|
|
4113
4955
|
return parsers.find((p) => p.extensions.includes(ext) || p.extensions.includes(fileName)) || null;
|
|
4114
4956
|
}
|
|
4115
4957
|
|
|
@@ -4118,7 +4960,7 @@ import { minimatch } from "minimatch";
|
|
|
4118
4960
|
var MAX_FILE_SIZE = 1e6;
|
|
4119
4961
|
function shouldParseFile(fullPath) {
|
|
4120
4962
|
try {
|
|
4121
|
-
const stats =
|
|
4963
|
+
const stats = statSync5(fullPath);
|
|
4122
4964
|
if (stats.size > MAX_FILE_SIZE) {
|
|
4123
4965
|
console.error(`[Parser] Skipping ${fullPath} \u2014 file too large (${(stats.size / 1024).toFixed(0)}KB)`);
|
|
4124
4966
|
return false;
|
|
@@ -4136,7 +4978,7 @@ async function parseProject(projectRoot, options) {
|
|
|
4136
4978
|
let errorFiles = 0;
|
|
4137
4979
|
for (const file of files) {
|
|
4138
4980
|
try {
|
|
4139
|
-
const fullPath =
|
|
4981
|
+
const fullPath = join11(projectRoot, file);
|
|
4140
4982
|
if (!resolve5(fullPath).startsWith(resolve5(projectRoot))) {
|
|
4141
4983
|
skippedFiles++;
|
|
4142
4984
|
continue;
|
|
@@ -4160,13 +5002,13 @@ async function parseProject(projectRoot, options) {
|
|
|
4160
5002
|
if (options?.verbose) {
|
|
4161
5003
|
console.error(`[Parser] Parsing: ${file}`);
|
|
4162
5004
|
}
|
|
4163
|
-
const
|
|
5005
|
+
const sourceCode = readFileSync8(fullPath, "utf-8");
|
|
5006
|
+
const parser = getParserForFile(file, sourceCode);
|
|
4164
5007
|
if (!parser) {
|
|
4165
5008
|
console.error(`No parser found for file: ${file}`);
|
|
4166
5009
|
skippedFiles++;
|
|
4167
5010
|
continue;
|
|
4168
5011
|
}
|
|
4169
|
-
const sourceCode = readFileSync7(fullPath, "utf-8");
|
|
4170
5012
|
const parsed = parser.parseFile(file, sourceCode, projectRoot);
|
|
4171
5013
|
parsedFiles.push(parsed);
|
|
4172
5014
|
} catch (err) {
|
|
@@ -4189,8 +5031,8 @@ async function parseProject(projectRoot, options) {
|
|
|
4189
5031
|
}
|
|
4190
5032
|
|
|
4191
5033
|
// src/cross-language/detectors/rest-api.ts
|
|
4192
|
-
import { readFileSync as
|
|
4193
|
-
import { join as
|
|
5034
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
5035
|
+
import { join as join12, resolve as resolve6 } from "path";
|
|
4194
5036
|
function getLanguage(filePath) {
|
|
4195
5037
|
if (filePath.endsWith(".ts") || filePath.endsWith(".tsx")) return "typescript";
|
|
4196
5038
|
if (filePath.endsWith(".js") || filePath.endsWith(".jsx") || filePath.endsWith(".mjs") || filePath.endsWith(".cjs")) return "javascript";
|
|
@@ -4198,6 +5040,7 @@ function getLanguage(filePath) {
|
|
|
4198
5040
|
if (filePath.endsWith(".go")) return "go";
|
|
4199
5041
|
if (filePath.endsWith(".cs") || filePath.endsWith(".csx")) return "csharp";
|
|
4200
5042
|
if (filePath.endsWith(".java")) return "java";
|
|
5043
|
+
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";
|
|
4201
5044
|
return "unknown";
|
|
4202
5045
|
}
|
|
4203
5046
|
function normalizePath(routePath) {
|
|
@@ -4451,6 +5294,72 @@ function extractRouteDefinitions(source, filePath) {
|
|
|
4451
5294
|
});
|
|
4452
5295
|
}
|
|
4453
5296
|
}
|
|
5297
|
+
if (lang === "cpp") {
|
|
5298
|
+
const crowMatch = line.match(/CROW_ROUTE\s*\(\s*\w+\s*,\s*"([^"]+)"/);
|
|
5299
|
+
if (crowMatch) {
|
|
5300
|
+
const path6 = crowMatch[1];
|
|
5301
|
+
if (path6.startsWith("/")) {
|
|
5302
|
+
const methodsMatch = line.match(/methods\s*\(\s*"([^"]+)"_method/);
|
|
5303
|
+
const method = methodsMatch ? methodsMatch[1].toUpperCase() : "ANY";
|
|
5304
|
+
routes.push({
|
|
5305
|
+
method,
|
|
5306
|
+
path: path6,
|
|
5307
|
+
normalizedPath: normalizePath(path6),
|
|
5308
|
+
file: filePath,
|
|
5309
|
+
line: i + 1
|
|
5310
|
+
});
|
|
5311
|
+
}
|
|
5312
|
+
}
|
|
5313
|
+
const drogonMatch = line.match(/ADD_METHOD_TO\s*\(\s*[^,]+,\s*"([^"]+)"\s*,\s*(\w+)/);
|
|
5314
|
+
if (drogonMatch) {
|
|
5315
|
+
const path6 = drogonMatch[1].startsWith("/") ? drogonMatch[1] : "/" + drogonMatch[1];
|
|
5316
|
+
routes.push({
|
|
5317
|
+
method: drogonMatch[2].toUpperCase(),
|
|
5318
|
+
path: path6,
|
|
5319
|
+
normalizedPath: normalizePath(path6),
|
|
5320
|
+
file: filePath,
|
|
5321
|
+
line: i + 1
|
|
5322
|
+
});
|
|
5323
|
+
}
|
|
5324
|
+
const pathAddMatch = line.match(/PATH_ADD\s*\(\s*"([^"]+)"\s*,\s*(\w+)/);
|
|
5325
|
+
if (pathAddMatch) {
|
|
5326
|
+
const path6 = pathAddMatch[1].startsWith("/") ? pathAddMatch[1] : "/" + pathAddMatch[1];
|
|
5327
|
+
routes.push({
|
|
5328
|
+
method: pathAddMatch[2].toUpperCase(),
|
|
5329
|
+
path: path6,
|
|
5330
|
+
normalizedPath: normalizePath(path6),
|
|
5331
|
+
file: filePath,
|
|
5332
|
+
line: i + 1
|
|
5333
|
+
});
|
|
5334
|
+
}
|
|
5335
|
+
const pistacheMatch = line.match(/router\s*\.\s*(get|post|put|del|patch)\s*\(\s*"([^"]+)"/i);
|
|
5336
|
+
if (pistacheMatch) {
|
|
5337
|
+
const method = pistacheMatch[1].toUpperCase() === "DEL" ? "DELETE" : pistacheMatch[1].toUpperCase();
|
|
5338
|
+
const path6 = pistacheMatch[2];
|
|
5339
|
+
if (path6.startsWith("/")) {
|
|
5340
|
+
routes.push({
|
|
5341
|
+
method,
|
|
5342
|
+
path: path6,
|
|
5343
|
+
normalizedPath: normalizePath(path6),
|
|
5344
|
+
file: filePath,
|
|
5345
|
+
line: i + 1
|
|
5346
|
+
});
|
|
5347
|
+
}
|
|
5348
|
+
}
|
|
5349
|
+
const httplibMatch = line.match(/(?:svr|server)\s*\.\s*(Get|Post|Put|Delete|Patch)\s*\(\s*"([^"]+)"/);
|
|
5350
|
+
if (httplibMatch) {
|
|
5351
|
+
const path6 = httplibMatch[2];
|
|
5352
|
+
if (path6.startsWith("/")) {
|
|
5353
|
+
routes.push({
|
|
5354
|
+
method: httplibMatch[1].toUpperCase(),
|
|
5355
|
+
path: path6,
|
|
5356
|
+
normalizedPath: normalizePath(path6),
|
|
5357
|
+
file: filePath,
|
|
5358
|
+
line: i + 1
|
|
5359
|
+
});
|
|
5360
|
+
}
|
|
5361
|
+
}
|
|
5362
|
+
}
|
|
4454
5363
|
}
|
|
4455
5364
|
return routes;
|
|
4456
5365
|
}
|
|
@@ -4499,11 +5408,11 @@ function detectRestApiEdges(files, projectRoot) {
|
|
|
4499
5408
|
const allCalls = [];
|
|
4500
5409
|
const allRoutes = [];
|
|
4501
5410
|
for (const file of files) {
|
|
4502
|
-
const fullPath =
|
|
5411
|
+
const fullPath = join12(projectRoot, file.filePath);
|
|
4503
5412
|
if (!resolve6(fullPath).startsWith(resolve6(projectRoot))) continue;
|
|
4504
5413
|
let source;
|
|
4505
5414
|
try {
|
|
4506
|
-
source =
|
|
5415
|
+
source = readFileSync9(fullPath, "utf-8");
|
|
4507
5416
|
} catch {
|
|
4508
5417
|
continue;
|
|
4509
5418
|
}
|
|
@@ -4539,8 +5448,8 @@ function detectRestApiEdges(files, projectRoot) {
|
|
|
4539
5448
|
}
|
|
4540
5449
|
|
|
4541
5450
|
// src/cross-language/detectors/subprocess.ts
|
|
4542
|
-
import { readFileSync as
|
|
4543
|
-
import { join as
|
|
5451
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
5452
|
+
import { join as join13, resolve as resolve7, basename as basename5 } from "path";
|
|
4544
5453
|
var SCRIPT_EXTENSIONS = [".py", ".js", ".ts", ".go", ".rs"];
|
|
4545
5454
|
function getLanguage2(filePath) {
|
|
4546
5455
|
if (filePath.endsWith(".ts") || filePath.endsWith(".tsx")) return "typescript";
|
|
@@ -4639,16 +5548,16 @@ function detectSubprocessEdges(files, projectRoot) {
|
|
|
4639
5548
|
const knownFiles = new Set(files.map((f) => f.filePath));
|
|
4640
5549
|
const basenameMap = /* @__PURE__ */ new Map();
|
|
4641
5550
|
for (const f of files) {
|
|
4642
|
-
const base =
|
|
5551
|
+
const base = basename5(f.filePath);
|
|
4643
5552
|
if (!basenameMap.has(base)) basenameMap.set(base, []);
|
|
4644
5553
|
basenameMap.get(base).push(f.filePath);
|
|
4645
5554
|
}
|
|
4646
5555
|
for (const file of files) {
|
|
4647
|
-
const fullPath =
|
|
5556
|
+
const fullPath = join13(projectRoot, file.filePath);
|
|
4648
5557
|
if (!resolve7(fullPath).startsWith(resolve7(projectRoot))) continue;
|
|
4649
5558
|
let source;
|
|
4650
5559
|
try {
|
|
4651
|
-
source =
|
|
5560
|
+
source = readFileSync10(fullPath, "utf-8");
|
|
4652
5561
|
} catch {
|
|
4653
5562
|
continue;
|
|
4654
5563
|
}
|
|
@@ -4660,7 +5569,7 @@ function detectSubprocessEdges(files, projectRoot) {
|
|
|
4660
5569
|
targetFile = call.calledFile;
|
|
4661
5570
|
confidence = "high";
|
|
4662
5571
|
} else {
|
|
4663
|
-
const base =
|
|
5572
|
+
const base = basename5(call.calledFile);
|
|
4664
5573
|
const candidates = basenameMap.get(base);
|
|
4665
5574
|
if (candidates && candidates.length > 0) {
|
|
4666
5575
|
const exactCandidate = candidates.find((c) => c.endsWith(call.calledFile));
|
|
@@ -5039,7 +5948,7 @@ function getArchitectureSummary(graph) {
|
|
|
5039
5948
|
}
|
|
5040
5949
|
|
|
5041
5950
|
// src/health/metrics.ts
|
|
5042
|
-
import { dirname as
|
|
5951
|
+
import { dirname as dirname10 } from "path";
|
|
5043
5952
|
function scoreToGrade(score) {
|
|
5044
5953
|
if (score >= 90) return "A";
|
|
5045
5954
|
if (score >= 80) return "B";
|
|
@@ -5072,8 +5981,8 @@ function calculateCouplingScore(graph) {
|
|
|
5072
5981
|
totalEdges++;
|
|
5073
5982
|
fileConnections.set(sourceAttrs.filePath, (fileConnections.get(sourceAttrs.filePath) || 0) + 1);
|
|
5074
5983
|
fileConnections.set(targetAttrs.filePath, (fileConnections.get(targetAttrs.filePath) || 0) + 1);
|
|
5075
|
-
const sourceDir =
|
|
5076
|
-
const targetDir =
|
|
5984
|
+
const sourceDir = dirname10(sourceAttrs.filePath).split("/")[0];
|
|
5985
|
+
const targetDir = dirname10(targetAttrs.filePath).split("/")[0];
|
|
5077
5986
|
if (sourceDir !== targetDir) {
|
|
5078
5987
|
crossDirEdges++;
|
|
5079
5988
|
}
|
|
@@ -5120,8 +6029,8 @@ function calculateCohesionScore(graph) {
|
|
|
5120
6029
|
const sourceAttrs = graph.getNodeAttributes(source);
|
|
5121
6030
|
const targetAttrs = graph.getNodeAttributes(target);
|
|
5122
6031
|
if (sourceAttrs.filePath !== targetAttrs.filePath) {
|
|
5123
|
-
const sourceDir =
|
|
5124
|
-
const targetDir =
|
|
6032
|
+
const sourceDir = dirname10(sourceAttrs.filePath);
|
|
6033
|
+
const targetDir = dirname10(targetAttrs.filePath);
|
|
5125
6034
|
if (!dirEdges.has(sourceDir)) {
|
|
5126
6035
|
dirEdges.set(sourceDir, { internal: 0, total: 0 });
|
|
5127
6036
|
}
|
|
@@ -5403,8 +6312,8 @@ function calculateDepthScore(graph) {
|
|
|
5403
6312
|
}
|
|
5404
6313
|
|
|
5405
6314
|
// src/health/index.ts
|
|
5406
|
-
import { readFileSync as
|
|
5407
|
-
import { dirname as
|
|
6315
|
+
import { readFileSync as readFileSync11, writeFileSync, existsSync as existsSync11, mkdirSync } from "fs";
|
|
6316
|
+
import { dirname as dirname11, resolve as resolve8 } from "path";
|
|
5408
6317
|
function calculateHealthScore(graph, projectRoot) {
|
|
5409
6318
|
const coupling = calculateCouplingScore(graph);
|
|
5410
6319
|
const cohesion = calculateCohesionScore(graph);
|
|
@@ -5519,10 +6428,10 @@ function saveHealthHistory(projectRoot, report) {
|
|
|
5519
6428
|
}))
|
|
5520
6429
|
};
|
|
5521
6430
|
let history = [];
|
|
5522
|
-
if (
|
|
6431
|
+
if (existsSync11(historyFile)) {
|
|
5523
6432
|
try {
|
|
5524
6433
|
if (!historyFile.startsWith(resolvedRoot)) return;
|
|
5525
|
-
const content =
|
|
6434
|
+
const content = readFileSync11(historyFile, "utf-8");
|
|
5526
6435
|
history = JSON.parse(content);
|
|
5527
6436
|
} catch {
|
|
5528
6437
|
}
|
|
@@ -5531,19 +6440,19 @@ function saveHealthHistory(projectRoot, report) {
|
|
|
5531
6440
|
if (history.length > 50) {
|
|
5532
6441
|
history = history.slice(-50);
|
|
5533
6442
|
}
|
|
5534
|
-
mkdirSync(
|
|
6443
|
+
mkdirSync(dirname11(historyFile), { recursive: true });
|
|
5535
6444
|
if (!historyFile.startsWith(resolvedRoot)) return;
|
|
5536
6445
|
writeFileSync(historyFile, JSON.stringify(history, null, 2), "utf-8");
|
|
5537
6446
|
}
|
|
5538
6447
|
function loadHealthHistory(projectRoot) {
|
|
5539
6448
|
const resolvedRoot = resolve8(projectRoot);
|
|
5540
6449
|
const historyFile = resolve8(resolvedRoot, ".depwire", "health-history.json");
|
|
5541
|
-
if (!historyFile.startsWith(resolvedRoot) || !
|
|
6450
|
+
if (!historyFile.startsWith(resolvedRoot) || !existsSync11(historyFile)) {
|
|
5542
6451
|
return [];
|
|
5543
6452
|
}
|
|
5544
6453
|
try {
|
|
5545
6454
|
if (!historyFile.startsWith(resolvedRoot)) return [];
|
|
5546
|
-
const content =
|
|
6455
|
+
const content = readFileSync11(historyFile, "utf-8");
|
|
5547
6456
|
return JSON.parse(content);
|
|
5548
6457
|
} catch {
|
|
5549
6458
|
return [];
|
|
@@ -5552,7 +6461,7 @@ function loadHealthHistory(projectRoot) {
|
|
|
5552
6461
|
|
|
5553
6462
|
// src/dead-code/detector.ts
|
|
5554
6463
|
import path2 from "path";
|
|
5555
|
-
import { readFileSync as
|
|
6464
|
+
import { readFileSync as readFileSync12, existsSync as existsSync12 } from "fs";
|
|
5556
6465
|
function findDeadSymbols(graph, projectRoot, includeTests = false, debug = false) {
|
|
5557
6466
|
const deadSymbols = [];
|
|
5558
6467
|
const context = { graph, projectRoot };
|
|
@@ -5685,11 +6594,11 @@ function getPackageEntryPoints(projectRoot) {
|
|
|
5685
6594
|
const entryPoints = /* @__PURE__ */ new Set();
|
|
5686
6595
|
const resolvedRoot = path2.resolve(projectRoot);
|
|
5687
6596
|
const packageJsonPath = path2.resolve(resolvedRoot, "package.json");
|
|
5688
|
-
if (!packageJsonPath.startsWith(resolvedRoot) || !
|
|
6597
|
+
if (!packageJsonPath.startsWith(resolvedRoot) || !existsSync12(packageJsonPath)) {
|
|
5689
6598
|
return entryPoints;
|
|
5690
6599
|
}
|
|
5691
6600
|
try {
|
|
5692
|
-
const packageJson = JSON.parse(
|
|
6601
|
+
const packageJson = JSON.parse(readFileSync12(packageJsonPath, "utf-8"));
|
|
5693
6602
|
if (packageJson.main) {
|
|
5694
6603
|
entryPoints.add(path2.resolve(projectRoot, packageJson.main));
|
|
5695
6604
|
}
|
|
@@ -5740,6 +6649,9 @@ function shouldExclude(attrs, context, includeTests, packageEntryPoints) {
|
|
|
5740
6649
|
if (isFrameworkAutoLoadedFile(relativePath)) {
|
|
5741
6650
|
return "framework";
|
|
5742
6651
|
}
|
|
6652
|
+
if (isCppExcluded(attrs)) {
|
|
6653
|
+
return "framework";
|
|
6654
|
+
}
|
|
5743
6655
|
return null;
|
|
5744
6656
|
}
|
|
5745
6657
|
function isRealPackageEntryPoint(filePath, packageEntryPoints) {
|
|
@@ -5765,6 +6677,19 @@ function isFrameworkAutoLoadedFile(filePath) {
|
|
|
5765
6677
|
return filePath.includes("/pages/") || filePath.includes("/routes/") || filePath.includes("/middleware/") || filePath.includes("/commands/") || filePath.includes("/api/") || filePath.includes("/app/") || filePath.includes("/Controllers/") || filePath.includes("/Hubs/") || filePath.includes("/Migrations/") || // Java / Spring / Jakarta
|
|
5766
6678
|
filePath.includes("/controller/") || filePath.includes("/controllers/") || filePath.includes("/service/") || filePath.includes("/repository/") || filePath.includes("/config/") || filePath.includes("/configuration/");
|
|
5767
6679
|
}
|
|
6680
|
+
function isCppExcluded(attrs) {
|
|
6681
|
+
const filePath = attrs.file || attrs.filePath || "";
|
|
6682
|
+
const name = attrs.name || "";
|
|
6683
|
+
const kind = attrs.kind || "";
|
|
6684
|
+
if (/\.(?:h|hpp|hh|hxx|h\+\+|inl|ipp)$/.test(filePath)) {
|
|
6685
|
+
return true;
|
|
6686
|
+
}
|
|
6687
|
+
if (name === "main") return true;
|
|
6688
|
+
if (name.startsWith("operator")) return true;
|
|
6689
|
+
if (name.startsWith("~")) return true;
|
|
6690
|
+
if (kind === "constant" && /\.(?:h|hpp)$/.test(filePath)) return true;
|
|
6691
|
+
return false;
|
|
6692
|
+
}
|
|
5768
6693
|
|
|
5769
6694
|
// src/dead-code/classifier.ts
|
|
5770
6695
|
import path3 from "path";
|
|
@@ -5831,8 +6756,8 @@ function generateReason(symbol, confidence) {
|
|
|
5831
6756
|
return "Potentially unused";
|
|
5832
6757
|
}
|
|
5833
6758
|
function isBarrelFile(filePath) {
|
|
5834
|
-
const
|
|
5835
|
-
return
|
|
6759
|
+
const basename9 = path3.basename(filePath);
|
|
6760
|
+
return basename9 === "index.ts" || basename9 === "index.js";
|
|
5836
6761
|
}
|
|
5837
6762
|
function isTestFile2(filePath) {
|
|
5838
6763
|
return filePath.includes("__tests__/") || filePath.includes(".test.") || filePath.includes(".spec.") || filePath.includes("/test/") || filePath.includes("/tests/");
|
|
@@ -6011,11 +6936,11 @@ function filterByConfidence(symbols, minConfidence) {
|
|
|
6011
6936
|
}
|
|
6012
6937
|
|
|
6013
6938
|
// src/docs/generator.ts
|
|
6014
|
-
import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, existsSync as
|
|
6015
|
-
import { join as
|
|
6939
|
+
import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, existsSync as existsSync15 } from "fs";
|
|
6940
|
+
import { join as join17 } from "path";
|
|
6016
6941
|
|
|
6017
6942
|
// src/docs/architecture.ts
|
|
6018
|
-
import { dirname as
|
|
6943
|
+
import { dirname as dirname12 } from "path";
|
|
6019
6944
|
|
|
6020
6945
|
// src/docs/templates.ts
|
|
6021
6946
|
function header(text, level = 1) {
|
|
@@ -6166,7 +7091,7 @@ function generateModuleStructure(graph) {
|
|
|
6166
7091
|
function getDirectoryStats(graph) {
|
|
6167
7092
|
const dirMap = /* @__PURE__ */ new Map();
|
|
6168
7093
|
graph.forEachNode((node, attrs) => {
|
|
6169
|
-
const dir =
|
|
7094
|
+
const dir = dirname12(attrs.filePath);
|
|
6170
7095
|
if (dir === ".") return;
|
|
6171
7096
|
if (!dirMap.has(dir)) {
|
|
6172
7097
|
dirMap.set(dir, {
|
|
@@ -6191,7 +7116,7 @@ function getDirectoryStats(graph) {
|
|
|
6191
7116
|
});
|
|
6192
7117
|
const filesPerDir = /* @__PURE__ */ new Map();
|
|
6193
7118
|
graph.forEachNode((node, attrs) => {
|
|
6194
|
-
const dir =
|
|
7119
|
+
const dir = dirname12(attrs.filePath);
|
|
6195
7120
|
if (!filesPerDir.has(dir)) {
|
|
6196
7121
|
filesPerDir.set(dir, /* @__PURE__ */ new Set());
|
|
6197
7122
|
}
|
|
@@ -6206,8 +7131,8 @@ function getDirectoryStats(graph) {
|
|
|
6206
7131
|
graph.forEachEdge((edge, attrs, source, target) => {
|
|
6207
7132
|
const sourceAttrs = graph.getNodeAttributes(source);
|
|
6208
7133
|
const targetAttrs = graph.getNodeAttributes(target);
|
|
6209
|
-
const sourceDir =
|
|
6210
|
-
const targetDir =
|
|
7134
|
+
const sourceDir = dirname12(sourceAttrs.filePath);
|
|
7135
|
+
const targetDir = dirname12(targetAttrs.filePath);
|
|
6211
7136
|
if (sourceDir !== targetDir) {
|
|
6212
7137
|
if (!dirEdges.has(sourceDir)) {
|
|
6213
7138
|
dirEdges.set(sourceDir, { in: 0, out: 0 });
|
|
@@ -6414,7 +7339,7 @@ function detectCycles(graph) {
|
|
|
6414
7339
|
}
|
|
6415
7340
|
|
|
6416
7341
|
// src/docs/conventions.ts
|
|
6417
|
-
import { basename as
|
|
7342
|
+
import { basename as basename6, extname as extname7 } from "path";
|
|
6418
7343
|
function generateConventions(graph, projectRoot, version) {
|
|
6419
7344
|
let output = "";
|
|
6420
7345
|
const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
@@ -6452,7 +7377,7 @@ function generateFileOrganization(graph) {
|
|
|
6452
7377
|
graph.forEachNode((node, attrs) => {
|
|
6453
7378
|
if (!files.has(attrs.filePath)) {
|
|
6454
7379
|
files.add(attrs.filePath);
|
|
6455
|
-
const fileName =
|
|
7380
|
+
const fileName = basename6(attrs.filePath);
|
|
6456
7381
|
if (fileName === "index.ts" || fileName === "index.js" || fileName === "index.tsx" || fileName === "index.jsx") {
|
|
6457
7382
|
barrelFileCount++;
|
|
6458
7383
|
}
|
|
@@ -6511,7 +7436,7 @@ function generateNamingPatterns(graph) {
|
|
|
6511
7436
|
graph.forEachNode((node, attrs) => {
|
|
6512
7437
|
if (!files.has(attrs.filePath)) {
|
|
6513
7438
|
files.add(attrs.filePath);
|
|
6514
|
-
const fileName =
|
|
7439
|
+
const fileName = basename6(attrs.filePath, extname7(attrs.filePath));
|
|
6515
7440
|
if (isCamelCase(fileName)) patterns.files.camelCase++;
|
|
6516
7441
|
else if (isPascalCase(fileName)) patterns.files.PascalCase++;
|
|
6517
7442
|
else if (isKebabCase(fileName)) patterns.files.kebabCase++;
|
|
@@ -7188,7 +8113,7 @@ function detectCyclesDetailed(graph) {
|
|
|
7188
8113
|
}
|
|
7189
8114
|
|
|
7190
8115
|
// src/docs/onboarding.ts
|
|
7191
|
-
import { dirname as
|
|
8116
|
+
import { dirname as dirname13 } from "path";
|
|
7192
8117
|
function generateOnboarding(graph, projectRoot, version) {
|
|
7193
8118
|
let output = "";
|
|
7194
8119
|
const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
@@ -7247,7 +8172,7 @@ function generateQuickOrientation(graph) {
|
|
|
7247
8172
|
const primaryLang = Object.entries(languages2).sort((a, b) => b[1] - a[1])[0];
|
|
7248
8173
|
const dirs = /* @__PURE__ */ new Set();
|
|
7249
8174
|
graph.forEachNode((node, attrs) => {
|
|
7250
|
-
const dir =
|
|
8175
|
+
const dir = dirname13(attrs.filePath);
|
|
7251
8176
|
if (dir !== ".") {
|
|
7252
8177
|
const topLevel = dir.split("/")[0];
|
|
7253
8178
|
dirs.add(topLevel);
|
|
@@ -7351,7 +8276,7 @@ function generateModuleMap(graph) {
|
|
|
7351
8276
|
function getDirectoryStats2(graph) {
|
|
7352
8277
|
const dirMap = /* @__PURE__ */ new Map();
|
|
7353
8278
|
graph.forEachNode((node, attrs) => {
|
|
7354
|
-
const dir =
|
|
8279
|
+
const dir = dirname13(attrs.filePath);
|
|
7355
8280
|
if (dir === ".") return;
|
|
7356
8281
|
if (!dirMap.has(dir)) {
|
|
7357
8282
|
dirMap.set(dir, {
|
|
@@ -7366,7 +8291,7 @@ function getDirectoryStats2(graph) {
|
|
|
7366
8291
|
});
|
|
7367
8292
|
const filesPerDir = /* @__PURE__ */ new Map();
|
|
7368
8293
|
graph.forEachNode((node, attrs) => {
|
|
7369
|
-
const dir =
|
|
8294
|
+
const dir = dirname13(attrs.filePath);
|
|
7370
8295
|
if (!filesPerDir.has(dir)) {
|
|
7371
8296
|
filesPerDir.set(dir, /* @__PURE__ */ new Set());
|
|
7372
8297
|
}
|
|
@@ -7381,8 +8306,8 @@ function getDirectoryStats2(graph) {
|
|
|
7381
8306
|
graph.forEachEdge((edge, attrs, source, target) => {
|
|
7382
8307
|
const sourceAttrs = graph.getNodeAttributes(source);
|
|
7383
8308
|
const targetAttrs = graph.getNodeAttributes(target);
|
|
7384
|
-
const sourceDir =
|
|
7385
|
-
const targetDir =
|
|
8309
|
+
const sourceDir = dirname13(sourceAttrs.filePath);
|
|
8310
|
+
const targetDir = dirname13(targetAttrs.filePath);
|
|
7386
8311
|
if (sourceDir !== targetDir) {
|
|
7387
8312
|
if (!dirEdges.has(sourceDir)) {
|
|
7388
8313
|
dirEdges.set(sourceDir, { in: 0, out: 0 });
|
|
@@ -7463,7 +8388,7 @@ function detectClusters(graph) {
|
|
|
7463
8388
|
const dirFiles = /* @__PURE__ */ new Map();
|
|
7464
8389
|
const fileEdges = /* @__PURE__ */ new Map();
|
|
7465
8390
|
graph.forEachNode((node, attrs) => {
|
|
7466
|
-
const dir =
|
|
8391
|
+
const dir = dirname13(attrs.filePath);
|
|
7467
8392
|
if (!dirFiles.has(dir)) {
|
|
7468
8393
|
dirFiles.set(dir, /* @__PURE__ */ new Set());
|
|
7469
8394
|
}
|
|
@@ -7517,8 +8442,8 @@ function inferClusterName(files) {
|
|
|
7517
8442
|
if (sortedWords.length > 0 && sortedWords[0][1] > 1) {
|
|
7518
8443
|
return capitalizeFirst2(sortedWords[0][0]);
|
|
7519
8444
|
}
|
|
7520
|
-
const commonDir =
|
|
7521
|
-
if (files.every((f) =>
|
|
8445
|
+
const commonDir = dirname13(files[0]);
|
|
8446
|
+
if (files.every((f) => dirname13(f) === commonDir)) {
|
|
7522
8447
|
return capitalizeFirst2(commonDir.split("/").pop() || "Core");
|
|
7523
8448
|
}
|
|
7524
8449
|
return "Core";
|
|
@@ -7576,7 +8501,7 @@ function generateDepwireUsage(projectRoot) {
|
|
|
7576
8501
|
}
|
|
7577
8502
|
|
|
7578
8503
|
// src/docs/files.ts
|
|
7579
|
-
import { dirname as
|
|
8504
|
+
import { dirname as dirname14, basename as basename7 } from "path";
|
|
7580
8505
|
function generateFiles(graph, projectRoot, version) {
|
|
7581
8506
|
let output = "";
|
|
7582
8507
|
const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
@@ -7680,7 +8605,7 @@ function generateDirectoryBreakdown(graph) {
|
|
|
7680
8605
|
const fileStats = getFileStats2(graph);
|
|
7681
8606
|
const dirMap = /* @__PURE__ */ new Map();
|
|
7682
8607
|
for (const file of fileStats) {
|
|
7683
|
-
const dir =
|
|
8608
|
+
const dir = dirname14(file.filePath);
|
|
7684
8609
|
const topDir = dir === "." ? "." : dir.split("/")[0];
|
|
7685
8610
|
if (!dirMap.has(topDir)) {
|
|
7686
8611
|
dirMap.set(topDir, {
|
|
@@ -7695,7 +8620,7 @@ function generateDirectoryBreakdown(graph) {
|
|
|
7695
8620
|
dirStats.symbolCount += file.symbolCount;
|
|
7696
8621
|
if (file.totalConnections > dirStats.maxConnections) {
|
|
7697
8622
|
dirStats.maxConnections = file.totalConnections;
|
|
7698
|
-
dirStats.mostConnectedFile =
|
|
8623
|
+
dirStats.mostConnectedFile = basename7(file.filePath);
|
|
7699
8624
|
}
|
|
7700
8625
|
}
|
|
7701
8626
|
if (dirMap.size === 0) {
|
|
@@ -8323,7 +9248,7 @@ function generateRecommendations(graph) {
|
|
|
8323
9248
|
}
|
|
8324
9249
|
|
|
8325
9250
|
// src/docs/tests.ts
|
|
8326
|
-
import { basename as
|
|
9251
|
+
import { basename as basename8, dirname as dirname15 } from "path";
|
|
8327
9252
|
function generateTests(graph, projectRoot, version) {
|
|
8328
9253
|
let output = "";
|
|
8329
9254
|
const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
@@ -8351,8 +9276,8 @@ function getFileCount8(graph) {
|
|
|
8351
9276
|
return files.size;
|
|
8352
9277
|
}
|
|
8353
9278
|
function isTestFile3(filePath) {
|
|
8354
|
-
const fileName =
|
|
8355
|
-
const dirPath =
|
|
9279
|
+
const fileName = basename8(filePath).toLowerCase();
|
|
9280
|
+
const dirPath = dirname15(filePath).toLowerCase();
|
|
8356
9281
|
if (dirPath.includes("test") || dirPath.includes("spec") || dirPath.includes("__tests__")) {
|
|
8357
9282
|
return true;
|
|
8358
9283
|
}
|
|
@@ -8410,13 +9335,13 @@ function generateTestFileInventory(graph) {
|
|
|
8410
9335
|
return output;
|
|
8411
9336
|
}
|
|
8412
9337
|
function matchTestToSource(testFile) {
|
|
8413
|
-
const testFileName =
|
|
8414
|
-
const testDir =
|
|
9338
|
+
const testFileName = basename8(testFile);
|
|
9339
|
+
const testDir = dirname15(testFile);
|
|
8415
9340
|
let sourceFileName = testFileName.replace(/\.test\./g, ".").replace(/\.spec\./g, ".").replace(/_test\./g, ".").replace(/_spec\./g, ".");
|
|
8416
9341
|
const possiblePaths = [];
|
|
8417
9342
|
possiblePaths.push(testDir + "/" + sourceFileName);
|
|
8418
9343
|
if (testDir.endsWith("/test") || testDir.endsWith("/tests") || testDir.endsWith("/__tests__")) {
|
|
8419
|
-
const parentDir =
|
|
9344
|
+
const parentDir = dirname15(testDir);
|
|
8420
9345
|
possiblePaths.push(parentDir + "/" + sourceFileName);
|
|
8421
9346
|
}
|
|
8422
9347
|
if (testDir.includes("test")) {
|
|
@@ -8572,7 +9497,7 @@ function generateTestCoverageMap(graph) {
|
|
|
8572
9497
|
const rows = mappings.slice(0, 30).map((m) => [
|
|
8573
9498
|
`\`${m.sourceFile}\``,
|
|
8574
9499
|
m.hasTest ? "\u2705" : "\u274C",
|
|
8575
|
-
m.testFile ? `\`${
|
|
9500
|
+
m.testFile ? `\`${basename8(m.testFile)}\`` : "-",
|
|
8576
9501
|
formatNumber(m.symbolCount)
|
|
8577
9502
|
]);
|
|
8578
9503
|
let output = table(headers, rows);
|
|
@@ -8613,7 +9538,7 @@ function generateTestStatistics(graph) {
|
|
|
8613
9538
|
`;
|
|
8614
9539
|
const dirTestCoverage = /* @__PURE__ */ new Map();
|
|
8615
9540
|
for (const sourceFile of sourceFiles) {
|
|
8616
|
-
const dir =
|
|
9541
|
+
const dir = dirname15(sourceFile).split("/")[0];
|
|
8617
9542
|
if (!dirTestCoverage.has(dir)) {
|
|
8618
9543
|
dirTestCoverage.set(dir, { total: 0, tested: 0 });
|
|
8619
9544
|
}
|
|
@@ -8636,7 +9561,7 @@ function generateTestStatistics(graph) {
|
|
|
8636
9561
|
}
|
|
8637
9562
|
|
|
8638
9563
|
// src/docs/history.ts
|
|
8639
|
-
import { dirname as
|
|
9564
|
+
import { dirname as dirname16 } from "path";
|
|
8640
9565
|
import { execSync } from "child_process";
|
|
8641
9566
|
function generateHistory(graph, projectRoot, version) {
|
|
8642
9567
|
let output = "";
|
|
@@ -8917,7 +9842,7 @@ function generateFeatureClusters(graph) {
|
|
|
8917
9842
|
const dirFiles = /* @__PURE__ */ new Map();
|
|
8918
9843
|
const fileEdges = /* @__PURE__ */ new Map();
|
|
8919
9844
|
graph.forEachNode((node, attrs) => {
|
|
8920
|
-
const dir =
|
|
9845
|
+
const dir = dirname16(attrs.filePath);
|
|
8921
9846
|
if (!dirFiles.has(dir)) {
|
|
8922
9847
|
dirFiles.set(dir, /* @__PURE__ */ new Set());
|
|
8923
9848
|
}
|
|
@@ -8999,7 +9924,7 @@ function capitalizeFirst3(str) {
|
|
|
8999
9924
|
}
|
|
9000
9925
|
|
|
9001
9926
|
// src/docs/current.ts
|
|
9002
|
-
import { dirname as
|
|
9927
|
+
import { dirname as dirname17 } from "path";
|
|
9003
9928
|
function generateCurrent(graph, projectRoot, version) {
|
|
9004
9929
|
let output = "";
|
|
9005
9930
|
const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
@@ -9137,7 +10062,7 @@ function generateCompleteFileIndex(graph) {
|
|
|
9137
10062
|
fileInfos.sort((a, b) => a.filePath.localeCompare(b.filePath));
|
|
9138
10063
|
const dirGroups = /* @__PURE__ */ new Map();
|
|
9139
10064
|
for (const info of fileInfos) {
|
|
9140
|
-
const dir =
|
|
10065
|
+
const dir = dirname17(info.filePath);
|
|
9141
10066
|
const topDir = dir === "." ? "root" : dir.split("/")[0];
|
|
9142
10067
|
if (!dirGroups.has(topDir)) {
|
|
9143
10068
|
dirGroups.set(topDir, []);
|
|
@@ -9348,7 +10273,7 @@ function getTopLevelDir2(filePath) {
|
|
|
9348
10273
|
}
|
|
9349
10274
|
|
|
9350
10275
|
// src/docs/status.ts
|
|
9351
|
-
import { readFileSync as
|
|
10276
|
+
import { readFileSync as readFileSync13, existsSync as existsSync13 } from "fs";
|
|
9352
10277
|
import { resolve as resolve9 } from "path";
|
|
9353
10278
|
function generateStatus(graph, projectRoot, version) {
|
|
9354
10279
|
let output = "";
|
|
@@ -9387,11 +10312,11 @@ function extractComments(projectRoot, filePath) {
|
|
|
9387
10312
|
if (!fullPath.startsWith(resolvedRoot)) {
|
|
9388
10313
|
return comments;
|
|
9389
10314
|
}
|
|
9390
|
-
if (!
|
|
10315
|
+
if (!existsSync13(fullPath)) {
|
|
9391
10316
|
return comments;
|
|
9392
10317
|
}
|
|
9393
10318
|
try {
|
|
9394
|
-
const content =
|
|
10319
|
+
const content = readFileSync13(fullPath, "utf-8");
|
|
9395
10320
|
const lines = content.split("\n");
|
|
9396
10321
|
const patterns = [
|
|
9397
10322
|
{ type: "TODO", regex: /(?:\/\/|#|\/\*)\s*TODO:?\s*(.+)/i },
|
|
@@ -9970,16 +10895,16 @@ function generateConfidenceSection(title, description, symbols, projectRoot) {
|
|
|
9970
10895
|
}
|
|
9971
10896
|
|
|
9972
10897
|
// src/docs/metadata.ts
|
|
9973
|
-
import { existsSync as
|
|
10898
|
+
import { existsSync as existsSync14, readFileSync as readFileSync14, writeFileSync as writeFileSync2 } from "fs";
|
|
9974
10899
|
import { resolve as resolve10 } from "path";
|
|
9975
10900
|
function loadMetadata(outputDir) {
|
|
9976
10901
|
const resolvedDir = resolve10(outputDir);
|
|
9977
10902
|
const metadataPath = resolve10(resolvedDir, "metadata.json");
|
|
9978
|
-
if (!metadataPath.startsWith(resolvedDir) || !
|
|
10903
|
+
if (!metadataPath.startsWith(resolvedDir) || !existsSync14(metadataPath)) {
|
|
9979
10904
|
return null;
|
|
9980
10905
|
}
|
|
9981
10906
|
try {
|
|
9982
|
-
const content =
|
|
10907
|
+
const content = readFileSync14(metadataPath, "utf-8");
|
|
9983
10908
|
return JSON.parse(content);
|
|
9984
10909
|
} catch (err) {
|
|
9985
10910
|
console.error("Failed to load metadata:", err);
|
|
@@ -10034,7 +10959,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
10034
10959
|
const generated = [];
|
|
10035
10960
|
const errors = [];
|
|
10036
10961
|
try {
|
|
10037
|
-
if (!
|
|
10962
|
+
if (!existsSync15(options.outputDir)) {
|
|
10038
10963
|
mkdirSync2(options.outputDir, { recursive: true });
|
|
10039
10964
|
if (options.verbose) {
|
|
10040
10965
|
console.log(`Created output directory: ${options.outputDir}`);
|
|
@@ -10073,7 +10998,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
10073
10998
|
try {
|
|
10074
10999
|
if (options.verbose) console.log("Generating ARCHITECTURE.md...");
|
|
10075
11000
|
const content = generateArchitecture(graph, projectRoot, version, parseTime);
|
|
10076
|
-
const filePath =
|
|
11001
|
+
const filePath = join17(options.outputDir, "ARCHITECTURE.md");
|
|
10077
11002
|
writeFileSync3(filePath, content, "utf-8");
|
|
10078
11003
|
generated.push("ARCHITECTURE.md");
|
|
10079
11004
|
} catch (err) {
|
|
@@ -10084,7 +11009,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
10084
11009
|
try {
|
|
10085
11010
|
if (options.verbose) console.log("Generating CONVENTIONS.md...");
|
|
10086
11011
|
const content = generateConventions(graph, projectRoot, version);
|
|
10087
|
-
const filePath =
|
|
11012
|
+
const filePath = join17(options.outputDir, "CONVENTIONS.md");
|
|
10088
11013
|
writeFileSync3(filePath, content, "utf-8");
|
|
10089
11014
|
generated.push("CONVENTIONS.md");
|
|
10090
11015
|
} catch (err) {
|
|
@@ -10095,7 +11020,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
10095
11020
|
try {
|
|
10096
11021
|
if (options.verbose) console.log("Generating DEPENDENCIES.md...");
|
|
10097
11022
|
const content = generateDependencies(graph, projectRoot, version);
|
|
10098
|
-
const filePath =
|
|
11023
|
+
const filePath = join17(options.outputDir, "DEPENDENCIES.md");
|
|
10099
11024
|
writeFileSync3(filePath, content, "utf-8");
|
|
10100
11025
|
generated.push("DEPENDENCIES.md");
|
|
10101
11026
|
} catch (err) {
|
|
@@ -10106,7 +11031,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
10106
11031
|
try {
|
|
10107
11032
|
if (options.verbose) console.log("Generating ONBOARDING.md...");
|
|
10108
11033
|
const content = generateOnboarding(graph, projectRoot, version);
|
|
10109
|
-
const filePath =
|
|
11034
|
+
const filePath = join17(options.outputDir, "ONBOARDING.md");
|
|
10110
11035
|
writeFileSync3(filePath, content, "utf-8");
|
|
10111
11036
|
generated.push("ONBOARDING.md");
|
|
10112
11037
|
} catch (err) {
|
|
@@ -10117,7 +11042,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
10117
11042
|
try {
|
|
10118
11043
|
if (options.verbose) console.log("Generating FILES.md...");
|
|
10119
11044
|
const content = generateFiles(graph, projectRoot, version);
|
|
10120
|
-
const filePath =
|
|
11045
|
+
const filePath = join17(options.outputDir, "FILES.md");
|
|
10121
11046
|
writeFileSync3(filePath, content, "utf-8");
|
|
10122
11047
|
generated.push("FILES.md");
|
|
10123
11048
|
} catch (err) {
|
|
@@ -10128,7 +11053,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
10128
11053
|
try {
|
|
10129
11054
|
if (options.verbose) console.log("Generating API_SURFACE.md...");
|
|
10130
11055
|
const content = generateApiSurface(graph, projectRoot, version);
|
|
10131
|
-
const filePath =
|
|
11056
|
+
const filePath = join17(options.outputDir, "API_SURFACE.md");
|
|
10132
11057
|
writeFileSync3(filePath, content, "utf-8");
|
|
10133
11058
|
generated.push("API_SURFACE.md");
|
|
10134
11059
|
} catch (err) {
|
|
@@ -10139,7 +11064,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
10139
11064
|
try {
|
|
10140
11065
|
if (options.verbose) console.log("Generating ERRORS.md...");
|
|
10141
11066
|
const content = generateErrors(graph, projectRoot, version);
|
|
10142
|
-
const filePath =
|
|
11067
|
+
const filePath = join17(options.outputDir, "ERRORS.md");
|
|
10143
11068
|
writeFileSync3(filePath, content, "utf-8");
|
|
10144
11069
|
generated.push("ERRORS.md");
|
|
10145
11070
|
} catch (err) {
|
|
@@ -10150,7 +11075,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
10150
11075
|
try {
|
|
10151
11076
|
if (options.verbose) console.log("Generating TESTS.md...");
|
|
10152
11077
|
const content = generateTests(graph, projectRoot, version);
|
|
10153
|
-
const filePath =
|
|
11078
|
+
const filePath = join17(options.outputDir, "TESTS.md");
|
|
10154
11079
|
writeFileSync3(filePath, content, "utf-8");
|
|
10155
11080
|
generated.push("TESTS.md");
|
|
10156
11081
|
} catch (err) {
|
|
@@ -10161,7 +11086,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
10161
11086
|
try {
|
|
10162
11087
|
if (options.verbose) console.log("Generating HISTORY.md...");
|
|
10163
11088
|
const content = generateHistory(graph, projectRoot, version);
|
|
10164
|
-
const filePath =
|
|
11089
|
+
const filePath = join17(options.outputDir, "HISTORY.md");
|
|
10165
11090
|
writeFileSync3(filePath, content, "utf-8");
|
|
10166
11091
|
generated.push("HISTORY.md");
|
|
10167
11092
|
} catch (err) {
|
|
@@ -10172,7 +11097,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
10172
11097
|
try {
|
|
10173
11098
|
if (options.verbose) console.log("Generating CURRENT.md...");
|
|
10174
11099
|
const content = generateCurrent(graph, projectRoot, version);
|
|
10175
|
-
const filePath =
|
|
11100
|
+
const filePath = join17(options.outputDir, "CURRENT.md");
|
|
10176
11101
|
writeFileSync3(filePath, content, "utf-8");
|
|
10177
11102
|
generated.push("CURRENT.md");
|
|
10178
11103
|
} catch (err) {
|
|
@@ -10183,7 +11108,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
10183
11108
|
try {
|
|
10184
11109
|
if (options.verbose) console.log("Generating STATUS.md...");
|
|
10185
11110
|
const content = generateStatus(graph, projectRoot, version);
|
|
10186
|
-
const filePath =
|
|
11111
|
+
const filePath = join17(options.outputDir, "STATUS.md");
|
|
10187
11112
|
writeFileSync3(filePath, content, "utf-8");
|
|
10188
11113
|
generated.push("STATUS.md");
|
|
10189
11114
|
} catch (err) {
|
|
@@ -10194,7 +11119,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
10194
11119
|
try {
|
|
10195
11120
|
if (options.verbose) console.log("Generating HEALTH.md...");
|
|
10196
11121
|
const content = generateHealth(graph, projectRoot, version);
|
|
10197
|
-
const filePath =
|
|
11122
|
+
const filePath = join17(options.outputDir, "HEALTH.md");
|
|
10198
11123
|
writeFileSync3(filePath, content, "utf-8");
|
|
10199
11124
|
generated.push("HEALTH.md");
|
|
10200
11125
|
} catch (err) {
|
|
@@ -10205,7 +11130,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
10205
11130
|
try {
|
|
10206
11131
|
if (options.verbose) console.log("Generating DEAD_CODE.md...");
|
|
10207
11132
|
const content = generateDeadCode(graph, projectRoot, version);
|
|
10208
|
-
const filePath =
|
|
11133
|
+
const filePath = join17(options.outputDir, "DEAD_CODE.md");
|
|
10209
11134
|
writeFileSync3(filePath, content, "utf-8");
|
|
10210
11135
|
generated.push("DEAD_CODE.md");
|
|
10211
11136
|
} catch (err) {
|
|
@@ -10249,7 +11174,7 @@ function getFileCount13(graph) {
|
|
|
10249
11174
|
}
|
|
10250
11175
|
|
|
10251
11176
|
// src/simulation/engine.ts
|
|
10252
|
-
import { dirname as
|
|
11177
|
+
import { dirname as dirname18, join as join18 } from "path";
|
|
10253
11178
|
function normalizePath2(p) {
|
|
10254
11179
|
return p.replace(/^\.\//, "").replace(/\/+$/, "");
|
|
10255
11180
|
}
|
|
@@ -10380,7 +11305,7 @@ var SimulationEngine = class {
|
|
|
10380
11305
|
}
|
|
10381
11306
|
}
|
|
10382
11307
|
applyRename(clone, target, newName, brokenImports) {
|
|
10383
|
-
const destination =
|
|
11308
|
+
const destination = join18(dirname18(target), newName);
|
|
10384
11309
|
this.applyMove(clone, target, destination, brokenImports);
|
|
10385
11310
|
}
|
|
10386
11311
|
applySplit(clone, target, newFile, symbols, brokenImports) {
|
|
@@ -10580,13 +11505,13 @@ var SimulationEngine = class {
|
|
|
10580
11505
|
};
|
|
10581
11506
|
|
|
10582
11507
|
// src/security/scanner.ts
|
|
10583
|
-
import { existsSync as
|
|
10584
|
-
import { join as
|
|
11508
|
+
import { existsSync as existsSync17 } from "fs";
|
|
11509
|
+
import { join as join28 } from "path";
|
|
10585
11510
|
|
|
10586
11511
|
// src/security/checks/dependencies.ts
|
|
10587
11512
|
import { execSync as execSync2 } from "child_process";
|
|
10588
|
-
import { existsSync as
|
|
10589
|
-
import { join as
|
|
11513
|
+
import { existsSync as existsSync16, readFileSync as readFileSync15, readdirSync as readdirSync8 } from "fs";
|
|
11514
|
+
import { join as join19 } from "path";
|
|
10590
11515
|
function cvssToSeverity(score) {
|
|
10591
11516
|
if (score >= 9) return "critical";
|
|
10592
11517
|
if (score >= 7) return "high";
|
|
@@ -10596,18 +11521,18 @@ function cvssToSeverity(score) {
|
|
|
10596
11521
|
async function checkDependencies(_files, projectRoot) {
|
|
10597
11522
|
const findings = [];
|
|
10598
11523
|
try {
|
|
10599
|
-
if (
|
|
11524
|
+
if (existsSync16(join19(projectRoot, "package.json"))) {
|
|
10600
11525
|
findings.push(...checkNpmAudit(projectRoot));
|
|
10601
11526
|
findings.push(...checkPackageJsonPatterns(projectRoot));
|
|
10602
11527
|
findings.push(...checkPostinstallScripts(projectRoot));
|
|
10603
11528
|
}
|
|
10604
|
-
if (
|
|
11529
|
+
if (existsSync16(join19(projectRoot, "requirements.txt")) || existsSync16(join19(projectRoot, "pyproject.toml"))) {
|
|
10605
11530
|
findings.push(...checkPipAudit(projectRoot));
|
|
10606
11531
|
}
|
|
10607
|
-
if (
|
|
11532
|
+
if (existsSync16(join19(projectRoot, "Cargo.toml"))) {
|
|
10608
11533
|
findings.push(...checkCargoAudit(projectRoot));
|
|
10609
11534
|
}
|
|
10610
|
-
if (
|
|
11535
|
+
if (existsSync16(join19(projectRoot, "go.mod"))) {
|
|
10611
11536
|
findings.push(...checkGoVerify(projectRoot));
|
|
10612
11537
|
}
|
|
10613
11538
|
} catch (err) {
|
|
@@ -10696,8 +11621,8 @@ function checkNpmAudit(projectRoot) {
|
|
|
10696
11621
|
function checkPackageJsonPatterns(projectRoot) {
|
|
10697
11622
|
const findings = [];
|
|
10698
11623
|
try {
|
|
10699
|
-
const pkgPath =
|
|
10700
|
-
const pkg = JSON.parse(
|
|
11624
|
+
const pkgPath = join19(projectRoot, "package.json");
|
|
11625
|
+
const pkg = JSON.parse(readFileSync15(pkgPath, "utf-8"));
|
|
10701
11626
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
10702
11627
|
for (const [name, version] of Object.entries(allDeps)) {
|
|
10703
11628
|
if (version.startsWith("^") || version.startsWith("~")) {
|
|
@@ -10719,15 +11644,15 @@ function checkPackageJsonPatterns(projectRoot) {
|
|
|
10719
11644
|
}
|
|
10720
11645
|
function checkPostinstallScripts(projectRoot) {
|
|
10721
11646
|
const findings = [];
|
|
10722
|
-
const nodeModules =
|
|
10723
|
-
if (!
|
|
11647
|
+
const nodeModules = join19(projectRoot, "node_modules");
|
|
11648
|
+
if (!existsSync16(nodeModules)) return findings;
|
|
10724
11649
|
try {
|
|
10725
|
-
const topLevelDeps =
|
|
11650
|
+
const topLevelDeps = readdirSync8(nodeModules).filter((d) => !d.startsWith("."));
|
|
10726
11651
|
for (const dep of topLevelDeps) {
|
|
10727
|
-
const depPkgPath =
|
|
10728
|
-
if (!
|
|
11652
|
+
const depPkgPath = join19(nodeModules, dep, "package.json");
|
|
11653
|
+
if (!existsSync16(depPkgPath)) continue;
|
|
10729
11654
|
try {
|
|
10730
|
-
const depPkg = JSON.parse(
|
|
11655
|
+
const depPkg = JSON.parse(readFileSync15(depPkgPath, "utf-8"));
|
|
10731
11656
|
const scripts = depPkg.scripts || {};
|
|
10732
11657
|
if (scripts.postinstall || scripts.preinstall || scripts.install) {
|
|
10733
11658
|
const scriptName = scripts.postinstall ? "postinstall" : scripts.preinstall ? "preinstall" : "install";
|
|
@@ -10765,7 +11690,7 @@ function checkPipAudit(projectRoot) {
|
|
|
10765
11690
|
id: "",
|
|
10766
11691
|
severity: cvssToSeverity(vuln.cvss?.score || 5),
|
|
10767
11692
|
vulnerabilityClass: "dependency-cve",
|
|
10768
|
-
file:
|
|
11693
|
+
file: existsSync16(join19(projectRoot, "requirements.txt")) ? "requirements.txt" : "pyproject.toml",
|
|
10769
11694
|
title: `Vulnerable Python dependency: ${vuln.name}`,
|
|
10770
11695
|
description: `${vuln.name}@${vuln.version} \u2014 ${vuln.id}: ${vuln.description || "Known vulnerability"}`,
|
|
10771
11696
|
attackScenario: `An attacker could exploit the vulnerability in ${vuln.name}.`,
|
|
@@ -10862,8 +11787,8 @@ function checkGoVerify(projectRoot) {
|
|
|
10862
11787
|
}
|
|
10863
11788
|
|
|
10864
11789
|
// src/security/checks/injection.ts
|
|
10865
|
-
import { readFileSync as
|
|
10866
|
-
import { join as
|
|
11790
|
+
import { readFileSync as readFileSync16 } from "fs";
|
|
11791
|
+
import { join as join20 } from "path";
|
|
10867
11792
|
var SKIP_DIRS = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
|
|
10868
11793
|
var TEST_PATTERNS = ["test", "spec", "fixture", "mock", "__tests__", "__mocks__"];
|
|
10869
11794
|
var USER_INPUT_NAMES = /(?:input|user|name|path|query|branch|hash|cmd|command|req\.|params|body|args|url|dir|file|subdirectory)/i;
|
|
@@ -11012,6 +11937,43 @@ var PATTERNS = [
|
|
|
11012
11937
|
description: "permitAll() applied to a path that appears security-sensitive.",
|
|
11013
11938
|
attackScenario: "An attacker could access administrative or destructive endpoints without authentication.",
|
|
11014
11939
|
suggestedFix: 'Use .hasRole("ADMIN") or .authenticated() for sensitive endpoints.'
|
|
11940
|
+
},
|
|
11941
|
+
// C++ injection patterns
|
|
11942
|
+
{
|
|
11943
|
+
regex: /\b(?:strcpy|strcat|sprintf|gets)\s*\(/,
|
|
11944
|
+
title: "C++ buffer overflow risk: unsafe string function",
|
|
11945
|
+
vulnClass: "shell-injection",
|
|
11946
|
+
baseSeverity: "high",
|
|
11947
|
+
description: "Unsafe C string functions (strcpy, strcat, sprintf, gets) with no bounds checking \u2014 buffer overflow risk.",
|
|
11948
|
+
attackScenario: "An attacker could provide oversized input to overflow the buffer, enabling arbitrary code execution.",
|
|
11949
|
+
suggestedFix: "Use bounded alternatives: strncpy, strncat, snprintf, or C++ std::string."
|
|
11950
|
+
},
|
|
11951
|
+
{
|
|
11952
|
+
regex: /printf\s*\(\s*(?!")[a-zA-Z_]\w*/,
|
|
11953
|
+
title: "C++ format string vulnerability",
|
|
11954
|
+
vulnClass: "shell-injection",
|
|
11955
|
+
baseSeverity: "high",
|
|
11956
|
+
description: "printf called with a variable as the format string \u2014 format string attack risk.",
|
|
11957
|
+
attackScenario: "An attacker could inject format specifiers (%x, %n) to read/write arbitrary memory.",
|
|
11958
|
+
suggestedFix: 'Always use a literal format string: printf("%s", userInput).'
|
|
11959
|
+
},
|
|
11960
|
+
{
|
|
11961
|
+
regex: /\bsystem\s*\(\s*(?!")[a-zA-Z_]\w*/,
|
|
11962
|
+
title: "C++ command injection via system()",
|
|
11963
|
+
vulnClass: "shell-injection",
|
|
11964
|
+
baseSeverity: "high",
|
|
11965
|
+
description: "system() called with a variable argument \u2014 potential command injection.",
|
|
11966
|
+
attackScenario: "An attacker could inject shell metacharacters to execute arbitrary commands.",
|
|
11967
|
+
suggestedFix: "Avoid system(). Use execvp with an argument array, or validate input with a strict allowlist."
|
|
11968
|
+
},
|
|
11969
|
+
{
|
|
11970
|
+
regex: /\bpopen\s*\(\s*(?!")[a-zA-Z_]\w*/,
|
|
11971
|
+
title: "C++ command injection via popen()",
|
|
11972
|
+
vulnClass: "shell-injection",
|
|
11973
|
+
baseSeverity: "high",
|
|
11974
|
+
description: "popen() called with a variable argument \u2014 potential command injection.",
|
|
11975
|
+
attackScenario: "An attacker could inject shell metacharacters to execute arbitrary commands.",
|
|
11976
|
+
suggestedFix: "Avoid popen(). Use pipe/fork/exec with argument arrays instead."
|
|
11015
11977
|
}
|
|
11016
11978
|
];
|
|
11017
11979
|
function shouldSkip(filePath) {
|
|
@@ -11028,7 +11990,7 @@ async function checkInjection(files, projectRoot) {
|
|
|
11028
11990
|
if (shouldSkip(file.filePath) || isTestFile4(file.filePath)) continue;
|
|
11029
11991
|
let content;
|
|
11030
11992
|
try {
|
|
11031
|
-
content =
|
|
11993
|
+
content = readFileSync16(join20(projectRoot, file.filePath), "utf-8");
|
|
11032
11994
|
} catch {
|
|
11033
11995
|
continue;
|
|
11034
11996
|
}
|
|
@@ -11066,8 +12028,8 @@ async function checkInjection(files, projectRoot) {
|
|
|
11066
12028
|
}
|
|
11067
12029
|
|
|
11068
12030
|
// src/security/checks/secrets.ts
|
|
11069
|
-
import { readFileSync as
|
|
11070
|
-
import { join as
|
|
12031
|
+
import { readFileSync as readFileSync17 } from "fs";
|
|
12032
|
+
import { join as join21 } from "path";
|
|
11071
12033
|
var SKIP_DIRS2 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
|
|
11072
12034
|
var TEST_PATTERNS2 = ["test", "spec", "fixture", "mock", "__tests__", "__mocks__", ".example", ".sample"];
|
|
11073
12035
|
var SECRET_PATTERNS = [
|
|
@@ -11100,7 +12062,7 @@ async function checkSecrets(files, projectRoot) {
|
|
|
11100
12062
|
if (shouldSkip2(file.filePath) || isTestFile5(file.filePath)) continue;
|
|
11101
12063
|
let content;
|
|
11102
12064
|
try {
|
|
11103
|
-
content =
|
|
12065
|
+
content = readFileSync17(join21(projectRoot, file.filePath), "utf-8");
|
|
11104
12066
|
} catch {
|
|
11105
12067
|
continue;
|
|
11106
12068
|
}
|
|
@@ -11133,8 +12095,8 @@ async function checkSecrets(files, projectRoot) {
|
|
|
11133
12095
|
}
|
|
11134
12096
|
|
|
11135
12097
|
// src/security/checks/path-traversal.ts
|
|
11136
|
-
import { readFileSync as
|
|
11137
|
-
import { join as
|
|
12098
|
+
import { readFileSync as readFileSync18 } from "fs";
|
|
12099
|
+
import { join as join22 } from "path";
|
|
11138
12100
|
var SKIP_DIRS3 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
|
|
11139
12101
|
var USER_INPUT_VARS = /(?:req\.|params|query|body|input|path|dir|subdirectory|file|userInput|fileName|filePath)/i;
|
|
11140
12102
|
var PATTERNS2 = [
|
|
@@ -11181,7 +12143,7 @@ async function checkPathTraversal(files, projectRoot) {
|
|
|
11181
12143
|
if (shouldSkip3(file.filePath)) continue;
|
|
11182
12144
|
let content;
|
|
11183
12145
|
try {
|
|
11184
|
-
content =
|
|
12146
|
+
content = readFileSync18(join22(projectRoot, file.filePath), "utf-8");
|
|
11185
12147
|
} catch {
|
|
11186
12148
|
continue;
|
|
11187
12149
|
}
|
|
@@ -11223,8 +12185,8 @@ async function checkPathTraversal(files, projectRoot) {
|
|
|
11223
12185
|
}
|
|
11224
12186
|
|
|
11225
12187
|
// src/security/checks/auth.ts
|
|
11226
|
-
import { readFileSync as
|
|
11227
|
-
import { join as
|
|
12188
|
+
import { readFileSync as readFileSync19 } from "fs";
|
|
12189
|
+
import { join as join23 } from "path";
|
|
11228
12190
|
var SKIP_DIRS4 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
|
|
11229
12191
|
function shouldSkip4(filePath) {
|
|
11230
12192
|
return SKIP_DIRS4.some((d) => filePath.includes(d));
|
|
@@ -11240,7 +12202,7 @@ async function checkAuth(files, projectRoot) {
|
|
|
11240
12202
|
if (shouldSkip4(file.filePath)) continue;
|
|
11241
12203
|
let content;
|
|
11242
12204
|
try {
|
|
11243
|
-
content =
|
|
12205
|
+
content = readFileSync19(join23(projectRoot, file.filePath), "utf-8");
|
|
11244
12206
|
} catch {
|
|
11245
12207
|
continue;
|
|
11246
12208
|
}
|
|
@@ -11331,8 +12293,8 @@ async function checkAuth(files, projectRoot) {
|
|
|
11331
12293
|
}
|
|
11332
12294
|
|
|
11333
12295
|
// src/security/checks/input-validation.ts
|
|
11334
|
-
import { readFileSync as
|
|
11335
|
-
import { join as
|
|
12296
|
+
import { readFileSync as readFileSync20 } from "fs";
|
|
12297
|
+
import { join as join24 } from "path";
|
|
11336
12298
|
var SKIP_DIRS5 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
|
|
11337
12299
|
function shouldSkip5(filePath) {
|
|
11338
12300
|
return SKIP_DIRS5.some((d) => filePath.includes(d));
|
|
@@ -11344,7 +12306,7 @@ async function checkInputValidation(files, projectRoot) {
|
|
|
11344
12306
|
if (shouldSkip5(file.filePath)) continue;
|
|
11345
12307
|
let content;
|
|
11346
12308
|
try {
|
|
11347
|
-
content =
|
|
12309
|
+
content = readFileSync20(join24(projectRoot, file.filePath), "utf-8");
|
|
11348
12310
|
} catch {
|
|
11349
12311
|
continue;
|
|
11350
12312
|
}
|
|
@@ -11421,8 +12383,8 @@ async function checkInputValidation(files, projectRoot) {
|
|
|
11421
12383
|
}
|
|
11422
12384
|
|
|
11423
12385
|
// src/security/checks/information-disclosure.ts
|
|
11424
|
-
import { readFileSync as
|
|
11425
|
-
import { join as
|
|
12386
|
+
import { readFileSync as readFileSync21 } from "fs";
|
|
12387
|
+
import { join as join25 } from "path";
|
|
11426
12388
|
var SKIP_DIRS6 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
|
|
11427
12389
|
function shouldSkip6(filePath) {
|
|
11428
12390
|
return SKIP_DIRS6.some((d) => filePath.includes(d));
|
|
@@ -11434,7 +12396,7 @@ async function checkInformationDisclosure(files, projectRoot) {
|
|
|
11434
12396
|
if (shouldSkip6(file.filePath)) continue;
|
|
11435
12397
|
let content;
|
|
11436
12398
|
try {
|
|
11437
|
-
content =
|
|
12399
|
+
content = readFileSync21(join25(projectRoot, file.filePath), "utf-8");
|
|
11438
12400
|
} catch {
|
|
11439
12401
|
continue;
|
|
11440
12402
|
}
|
|
@@ -11504,8 +12466,8 @@ async function checkInformationDisclosure(files, projectRoot) {
|
|
|
11504
12466
|
}
|
|
11505
12467
|
|
|
11506
12468
|
// src/security/checks/cryptography.ts
|
|
11507
|
-
import { readFileSync as
|
|
11508
|
-
import { join as
|
|
12469
|
+
import { readFileSync as readFileSync22 } from "fs";
|
|
12470
|
+
import { join as join26 } from "path";
|
|
11509
12471
|
var SKIP_DIRS7 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
|
|
11510
12472
|
var USER_INPUT_NAMES2 = /(?:input|user|name|path|query|param|request|body|args|url)/i;
|
|
11511
12473
|
function shouldSkip7(filePath) {
|
|
@@ -11522,7 +12484,7 @@ async function checkCryptography(files, projectRoot) {
|
|
|
11522
12484
|
if (shouldSkip7(file.filePath)) continue;
|
|
11523
12485
|
let content;
|
|
11524
12486
|
try {
|
|
11525
|
-
content =
|
|
12487
|
+
content = readFileSync22(join26(projectRoot, file.filePath), "utf-8");
|
|
11526
12488
|
} catch {
|
|
11527
12489
|
continue;
|
|
11528
12490
|
}
|
|
@@ -11624,6 +12586,32 @@ async function checkCryptography(files, projectRoot) {
|
|
|
11624
12586
|
suggestedFix: "Generate a unique random salt per user using crypto.randomBytes(16)."
|
|
11625
12587
|
});
|
|
11626
12588
|
}
|
|
12589
|
+
if (/\brand\s*\(\s*\)/.test(line) && isCryptoFile) {
|
|
12590
|
+
findings.push({
|
|
12591
|
+
id: "",
|
|
12592
|
+
severity: "medium",
|
|
12593
|
+
vulnerabilityClass: "cryptography",
|
|
12594
|
+
file: file.filePath,
|
|
12595
|
+
line: i + 1,
|
|
12596
|
+
title: "Weak random: rand() in security context",
|
|
12597
|
+
description: "rand() is not cryptographically secure \u2014 its output can be predicted.",
|
|
12598
|
+
attackScenario: "An attacker could predict rand() values to forge tokens or bypass security checks.",
|
|
12599
|
+
suggestedFix: "Use std::random_device or platform-specific CSPRNG (e.g., /dev/urandom, BCryptGenRandom)."
|
|
12600
|
+
});
|
|
12601
|
+
}
|
|
12602
|
+
if (/(?:const\s+(?:char|std::string)\s*\*?\s*(?:password|secret|api_key|apiKey|token)\s*=\s*["'])/i.test(line)) {
|
|
12603
|
+
findings.push({
|
|
12604
|
+
id: "",
|
|
12605
|
+
severity: "high",
|
|
12606
|
+
vulnerabilityClass: "cryptography",
|
|
12607
|
+
file: file.filePath,
|
|
12608
|
+
line: i + 1,
|
|
12609
|
+
title: "Hardcoded credentials in C++ source",
|
|
12610
|
+
description: "A password, secret, or API key is hardcoded as a string literal.",
|
|
12611
|
+
attackScenario: "An attacker with access to the binary or source could extract the credential.",
|
|
12612
|
+
suggestedFix: "Load credentials from environment variables or a secure vault at runtime."
|
|
12613
|
+
});
|
|
12614
|
+
}
|
|
11627
12615
|
}
|
|
11628
12616
|
}
|
|
11629
12617
|
} catch {
|
|
@@ -11632,8 +12620,8 @@ async function checkCryptography(files, projectRoot) {
|
|
|
11632
12620
|
}
|
|
11633
12621
|
|
|
11634
12622
|
// src/security/checks/frontend.ts
|
|
11635
|
-
import { readFileSync as
|
|
11636
|
-
import { join as
|
|
12623
|
+
import { readFileSync as readFileSync23 } from "fs";
|
|
12624
|
+
import { join as join27 } from "path";
|
|
11637
12625
|
var SKIP_DIRS8 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
|
|
11638
12626
|
function shouldSkip8(filePath) {
|
|
11639
12627
|
return SKIP_DIRS8.some((d) => filePath.includes(d));
|
|
@@ -11649,7 +12637,7 @@ async function checkFrontend(files, projectRoot) {
|
|
|
11649
12637
|
if (!isFrontendFile(file.filePath)) continue;
|
|
11650
12638
|
let content;
|
|
11651
12639
|
try {
|
|
11652
|
-
content =
|
|
12640
|
+
content = readFileSync23(join27(projectRoot, file.filePath), "utf-8");
|
|
11653
12641
|
} catch {
|
|
11654
12642
|
continue;
|
|
11655
12643
|
}
|
|
@@ -12109,13 +13097,13 @@ async function scanSecurity(projectRoot, graph, options = {}) {
|
|
|
12109
13097
|
};
|
|
12110
13098
|
}
|
|
12111
13099
|
function detectPackageManager(projectRoot) {
|
|
12112
|
-
if (
|
|
12113
|
-
if (
|
|
12114
|
-
if (
|
|
12115
|
-
if (
|
|
12116
|
-
if (
|
|
12117
|
-
if (
|
|
12118
|
-
if (
|
|
13100
|
+
if (existsSync17(join28(projectRoot, "package.json"))) return "npm";
|
|
13101
|
+
if (existsSync17(join28(projectRoot, "requirements.txt"))) return "pip";
|
|
13102
|
+
if (existsSync17(join28(projectRoot, "pyproject.toml"))) return "pip";
|
|
13103
|
+
if (existsSync17(join28(projectRoot, "Cargo.toml"))) return "cargo";
|
|
13104
|
+
if (existsSync17(join28(projectRoot, "go.mod"))) return "go";
|
|
13105
|
+
if (existsSync17(join28(projectRoot, "pom.xml"))) return "maven";
|
|
13106
|
+
if (existsSync17(join28(projectRoot, "build.gradle")) || existsSync17(join28(projectRoot, "build.gradle.kts"))) return "gradle";
|
|
12119
13107
|
return "unknown";
|
|
12120
13108
|
}
|
|
12121
13109
|
|