depwire-cli 1.0.0 → 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.
@@ -31,9 +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") || entry.endsWith(".h");
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
- if (isTypeScript || isJavaScript || isPython || isGo || isRust || isC || isCSharp) {
37
+ const isJava = entry.endsWith(".java") || entry === "pom.xml" || entry === "build.gradle" || entry === "build.gradle.kts";
38
+ const isCppBuild = entry === "CMakeLists.txt" || entry === "conanfile.txt" || entry === "vcpkg.json";
39
+ if (isTypeScript || isJavaScript || isPython || isGo || isRust || isC || isCpp || isCSharp || isJava || isCppBuild) {
37
40
  files.push(relative(rootDir, fullPath));
38
41
  }
39
42
  }
@@ -71,6 +74,10 @@ function findProjectRoot(startDir = process.cwd()) {
71
74
  // C/C++ (cmake-based)
72
75
  "configure.ac",
73
76
  // C/C++ (autotools)
77
+ "pom.xml",
78
+ // Java (Maven)
79
+ "build.gradle",
80
+ // Java (Gradle)
74
81
  ".git"
75
82
  // Any git repo
76
83
  ];
@@ -104,11 +111,11 @@ function findProjectRoot(startDir = process.cwd()) {
104
111
  }
105
112
 
106
113
  // src/parser/index.ts
107
- import { readFileSync as readFileSync6, statSync as statSync3 } from "fs";
108
- import { join as join9, resolve as resolve4 } from "path";
114
+ import { readFileSync as readFileSync8, statSync as statSync5 } from "fs";
115
+ import { join as join11, resolve as resolve5 } from "path";
109
116
 
110
117
  // src/parser/detect.ts
111
- import { extname as extname4 } from "path";
118
+ import { extname as extname6, basename as basename4 } from "path";
112
119
 
113
120
  // src/parser/wasm-init.ts
114
121
  import { Parser, Language } from "web-tree-sitter";
@@ -136,7 +143,9 @@ async function initParser() {
136
143
  "go": "tree-sitter-go.wasm",
137
144
  "rust": "tree-sitter-rust.wasm",
138
145
  "c": "tree-sitter-c.wasm",
139
- "c_sharp": "tree-sitter-c_sharp.wasm"
146
+ "c_sharp": "tree-sitter-c_sharp.wasm",
147
+ "java": "tree-sitter-java.wasm",
148
+ "cpp": "tree-sitter-cpp.wasm"
140
149
  };
141
150
  for (const [name, file] of Object.entries(grammarFiles)) {
142
151
  const wasmPath = path.join(grammarsDir, file);
@@ -2780,7 +2789,7 @@ function getCurrentSymbolId6(context) {
2780
2789
  }
2781
2790
  var cParser = {
2782
2791
  name: "c",
2783
- extensions: [".c", ".h"],
2792
+ extensions: [".c"],
2784
2793
  parseFile: parseCFile
2785
2794
  };
2786
2795
 
@@ -3342,6 +3351,1582 @@ var csharpParser = {
3342
3351
  parseFile: parseCSharpFile
3343
3352
  };
3344
3353
 
3354
+ // src/parser/java.ts
3355
+ import { dirname as dirname8, join as join9, resolve as resolve4, basename as basename2 } from "path";
3356
+ import { existsSync as existsSync9, readdirSync as readdirSync6, statSync as statSync3 } from "fs";
3357
+ function parseJavaFile(filePath, sourceCode, projectRoot) {
3358
+ if (filePath.endsWith("pom.xml")) {
3359
+ return parsePomXml(filePath, sourceCode, projectRoot);
3360
+ }
3361
+ if (filePath.endsWith("build.gradle") || filePath.endsWith("build.gradle.kts")) {
3362
+ return parseGradleBuild(filePath, sourceCode, projectRoot);
3363
+ }
3364
+ const parser = getParser("java");
3365
+ const tree = parser.parse(sourceCode, null, { bufferSize: 1024 * 1024 });
3366
+ const context = {
3367
+ filePath,
3368
+ projectRoot,
3369
+ sourceCode,
3370
+ symbols: [],
3371
+ edges: [],
3372
+ currentScope: [],
3373
+ currentClass: null,
3374
+ currentPackage: null,
3375
+ imports: /* @__PURE__ */ new Map(),
3376
+ isBuildFile: false
3377
+ };
3378
+ walkNode8(tree.rootNode, context);
3379
+ return {
3380
+ filePath,
3381
+ symbols: context.symbols,
3382
+ edges: context.edges
3383
+ };
3384
+ }
3385
+ function walkNode8(node, context) {
3386
+ processNode8(node, context);
3387
+ for (let i = 0; i < node.childCount; i++) {
3388
+ const child = node.child(i);
3389
+ if (child) {
3390
+ walkNode8(child, context);
3391
+ }
3392
+ }
3393
+ }
3394
+ function processNode8(node, context) {
3395
+ switch (node.type) {
3396
+ case "package_declaration":
3397
+ processPackageDeclaration(node, context);
3398
+ break;
3399
+ case "import_declaration":
3400
+ processImportDeclaration2(node, context);
3401
+ break;
3402
+ case "class_declaration":
3403
+ processClassDeclaration4(node, context);
3404
+ break;
3405
+ case "interface_declaration":
3406
+ processInterfaceDeclaration3(node, context);
3407
+ break;
3408
+ case "enum_declaration":
3409
+ processEnumDeclaration3(node, context);
3410
+ break;
3411
+ case "annotation_type_declaration":
3412
+ processAnnotationTypeDeclaration(node, context);
3413
+ break;
3414
+ case "record_declaration":
3415
+ processRecordDeclaration2(node, context);
3416
+ break;
3417
+ case "method_declaration":
3418
+ processMethodDeclaration3(node, context);
3419
+ break;
3420
+ case "constructor_declaration":
3421
+ processConstructorDeclaration2(node, context);
3422
+ break;
3423
+ case "field_declaration":
3424
+ processFieldDeclaration(node, context);
3425
+ break;
3426
+ case "constant_declaration":
3427
+ processConstantDeclaration(node, context);
3428
+ break;
3429
+ case "annotation_type_element_declaration":
3430
+ processAnnotationElement(node, context);
3431
+ break;
3432
+ case "method_invocation":
3433
+ processCallExpression8(node, context);
3434
+ break;
3435
+ case "object_creation_expression":
3436
+ processObjectCreation(node, context);
3437
+ break;
3438
+ case "lambda_expression":
3439
+ processLambdaExpression(node, context);
3440
+ break;
3441
+ }
3442
+ }
3443
+ function processPackageDeclaration(node, context) {
3444
+ const scopedIdent = findDescendantByTypes(node, ["scoped_identifier", "identifier"]);
3445
+ if (!scopedIdent) return;
3446
+ const name = nodeText7(scopedIdent, context);
3447
+ const symbolId = `${context.filePath}::${name}`;
3448
+ context.symbols.push({
3449
+ id: symbolId,
3450
+ name,
3451
+ kind: "module",
3452
+ filePath: context.filePath,
3453
+ startLine: node.startPosition.row + 1,
3454
+ endLine: node.endPosition.row + 1,
3455
+ exported: true
3456
+ });
3457
+ context.currentPackage = name;
3458
+ }
3459
+ function processImportDeclaration2(node, context) {
3460
+ const text = nodeText7(node, context).trim();
3461
+ const isStatic = text.includes("import static");
3462
+ const isWildcard = text.includes(".*");
3463
+ const scopedIdent = findDescendantByTypes(node, ["scoped_identifier", "identifier"]);
3464
+ if (!scopedIdent) return;
3465
+ let importPath = nodeText7(scopedIdent, context);
3466
+ const asterisk = findChildByType8(node, "asterisk");
3467
+ if (asterisk) {
3468
+ importPath = importPath + ".*";
3469
+ }
3470
+ const resolvedPath = resolveJavaImport(importPath, context.filePath, context.projectRoot);
3471
+ if (resolvedPath) {
3472
+ const sourceId = `${context.filePath}::__file__`;
3473
+ const targetId = `${resolvedPath}::__file__`;
3474
+ context.edges.push({
3475
+ source: sourceId,
3476
+ target: targetId,
3477
+ kind: "imports",
3478
+ filePath: context.filePath,
3479
+ line: node.startPosition.row + 1
3480
+ });
3481
+ const parts = importPath.split(".");
3482
+ if (!isWildcard) {
3483
+ const simpleName = parts[parts.length - 1];
3484
+ context.imports.set(simpleName, `${resolvedPath}::${simpleName}`);
3485
+ }
3486
+ }
3487
+ const symbolId = `${context.filePath}::import:${importPath}`;
3488
+ context.symbols.push({
3489
+ id: symbolId,
3490
+ name: importPath,
3491
+ kind: "import",
3492
+ filePath: context.filePath,
3493
+ startLine: node.startPosition.row + 1,
3494
+ endLine: node.endPosition.row + 1,
3495
+ exported: false
3496
+ });
3497
+ }
3498
+ function processClassDeclaration4(node, context) {
3499
+ processTypeDeclaration3(node, context, "class");
3500
+ }
3501
+ function processInterfaceDeclaration3(node, context) {
3502
+ processTypeDeclaration3(node, context, "interface");
3503
+ }
3504
+ function processRecordDeclaration2(node, context) {
3505
+ processTypeDeclaration3(node, context, "class");
3506
+ }
3507
+ function processAnnotationTypeDeclaration(node, context) {
3508
+ processTypeDeclaration3(node, context, "interface");
3509
+ }
3510
+ function processTypeDeclaration3(node, context, kind) {
3511
+ const nameNode = node.childForFieldName("name");
3512
+ if (!nameNode) return;
3513
+ let name = nodeText7(nameNode, context);
3514
+ const angleBracketIdx = name.indexOf("<");
3515
+ if (angleBracketIdx > 0) {
3516
+ name = name.substring(0, angleBracketIdx);
3517
+ }
3518
+ const exported = hasModifier2(node, context, "public");
3519
+ const scope = context.currentClass || void 0;
3520
+ const symbolId = `${context.filePath}::${name}`;
3521
+ context.symbols.push({
3522
+ id: symbolId,
3523
+ name,
3524
+ kind,
3525
+ filePath: context.filePath,
3526
+ startLine: node.startPosition.row + 1,
3527
+ endLine: node.endPosition.row + 1,
3528
+ exported,
3529
+ scope
3530
+ });
3531
+ const superclass = node.childForFieldName("superclass");
3532
+ if (superclass) {
3533
+ let baseName = extractTypeName3(superclass, context);
3534
+ if (baseName) {
3535
+ const baseId = resolveSymbol7(baseName, context);
3536
+ if (baseId) {
3537
+ context.edges.push({
3538
+ source: symbolId,
3539
+ target: baseId,
3540
+ kind: "inherits",
3541
+ filePath: context.filePath,
3542
+ line: superclass.startPosition.row + 1
3543
+ });
3544
+ }
3545
+ }
3546
+ }
3547
+ const interfaces = node.childForFieldName("interfaces");
3548
+ if (interfaces) {
3549
+ processInterfaceList(interfaces, symbolId, context);
3550
+ }
3551
+ const extendsInterfaces = node.childForFieldName("extends_interfaces") || findChildByType8(node, "extends_interfaces");
3552
+ if (extendsInterfaces) {
3553
+ processInterfaceList(extendsInterfaces, symbolId, context);
3554
+ }
3555
+ const oldClass = context.currentClass;
3556
+ context.currentClass = name;
3557
+ context.currentScope.push(name);
3558
+ const body = node.childForFieldName("body") || findChildByType8(node, "class_body") || findChildByType8(node, "interface_body") || findChildByType8(node, "enum_body") || findChildByType8(node, "annotation_type_body") || findChildByType8(node, "record_declaration_body");
3559
+ if (body) {
3560
+ walkNode8(body, context);
3561
+ }
3562
+ context.currentScope.pop();
3563
+ context.currentClass = oldClass;
3564
+ }
3565
+ function processInterfaceList(node, sourceId, context) {
3566
+ for (let i = 0; i < node.childCount; i++) {
3567
+ const child = node.child(i);
3568
+ if (!child) continue;
3569
+ if (child.type === "type_identifier" || child.type === "generic_type" || child.type === "scoped_type_identifier") {
3570
+ const baseName = extractTypeName3(child, context);
3571
+ if (baseName) {
3572
+ const baseId = resolveSymbol7(baseName, context);
3573
+ if (baseId) {
3574
+ context.edges.push({
3575
+ source: sourceId,
3576
+ target: baseId,
3577
+ kind: "implements",
3578
+ filePath: context.filePath,
3579
+ line: child.startPosition.row + 1
3580
+ });
3581
+ }
3582
+ }
3583
+ }
3584
+ }
3585
+ }
3586
+ function processEnumDeclaration3(node, context) {
3587
+ const nameNode = node.childForFieldName("name");
3588
+ if (!nameNode) return;
3589
+ const name = nodeText7(nameNode, context);
3590
+ const exported = hasModifier2(node, context, "public");
3591
+ const symbolId = `${context.filePath}::${name}`;
3592
+ context.symbols.push({
3593
+ id: symbolId,
3594
+ name,
3595
+ kind: "enum",
3596
+ filePath: context.filePath,
3597
+ startLine: node.startPosition.row + 1,
3598
+ endLine: node.endPosition.row + 1,
3599
+ exported
3600
+ });
3601
+ const body = node.childForFieldName("body") || findChildByType8(node, "enum_body");
3602
+ if (body) {
3603
+ const constants = findChildrenByType3(body, "enum_constant");
3604
+ for (const constant of constants) {
3605
+ const constNameNode = constant.childForFieldName("name");
3606
+ if (!constNameNode) continue;
3607
+ const constName = nodeText7(constNameNode, context);
3608
+ const constId = `${context.filePath}::${name}.${constName}`;
3609
+ context.symbols.push({
3610
+ id: constId,
3611
+ name: constName,
3612
+ kind: "constant",
3613
+ filePath: context.filePath,
3614
+ startLine: constant.startPosition.row + 1,
3615
+ endLine: constant.endPosition.row + 1,
3616
+ exported,
3617
+ scope: name
3618
+ });
3619
+ }
3620
+ const oldClass = context.currentClass;
3621
+ context.currentClass = name;
3622
+ context.currentScope.push(name);
3623
+ for (let i = 0; i < body.childCount; i++) {
3624
+ const child = body.child(i);
3625
+ if (child && child.type !== "enum_constant") {
3626
+ walkNode8(child, context);
3627
+ }
3628
+ }
3629
+ context.currentScope.pop();
3630
+ context.currentClass = oldClass;
3631
+ }
3632
+ }
3633
+ function processMethodDeclaration3(node, context) {
3634
+ const nameNode = node.childForFieldName("name");
3635
+ if (!nameNode) return;
3636
+ const name = nodeText7(nameNode, context);
3637
+ const exported = hasModifier2(node, context, "public");
3638
+ const scope = context.currentClass || void 0;
3639
+ const symbolId = scope ? `${context.filePath}::${scope}.${name}` : `${context.filePath}::${name}`;
3640
+ context.symbols.push({
3641
+ id: symbolId,
3642
+ name,
3643
+ kind: context.currentClass ? "method" : "function",
3644
+ filePath: context.filePath,
3645
+ startLine: node.startPosition.row + 1,
3646
+ endLine: node.endPosition.row + 1,
3647
+ exported,
3648
+ scope
3649
+ });
3650
+ const scopeName = scope ? `${scope}.${name}` : name;
3651
+ context.currentScope.push(scopeName);
3652
+ const body = node.childForFieldName("body");
3653
+ if (body) {
3654
+ walkNode8(body, context);
3655
+ }
3656
+ context.currentScope.pop();
3657
+ }
3658
+ function processConstructorDeclaration2(node, context) {
3659
+ const nameNode = node.childForFieldName("name");
3660
+ if (!nameNode) return;
3661
+ const name = nodeText7(nameNode, context);
3662
+ const exported = hasModifier2(node, context, "public");
3663
+ const scope = context.currentClass || void 0;
3664
+ const symbolId = scope ? `${context.filePath}::${scope}.${name}` : `${context.filePath}::${name}`;
3665
+ context.symbols.push({
3666
+ id: symbolId,
3667
+ name,
3668
+ kind: "method",
3669
+ filePath: context.filePath,
3670
+ startLine: node.startPosition.row + 1,
3671
+ endLine: node.endPosition.row + 1,
3672
+ exported,
3673
+ scope
3674
+ });
3675
+ const scopeName = scope ? `${scope}.${name}` : name;
3676
+ context.currentScope.push(scopeName);
3677
+ const body = node.childForFieldName("body");
3678
+ if (body) {
3679
+ walkNode8(body, context);
3680
+ }
3681
+ context.currentScope.pop();
3682
+ }
3683
+ function processFieldDeclaration(node, context) {
3684
+ const declarator = findDescendantByTypes(node, ["variable_declarator"]);
3685
+ if (!declarator) return;
3686
+ const nameNode = declarator.childForFieldName("name");
3687
+ if (!nameNode) return;
3688
+ const name = nodeText7(nameNode, context);
3689
+ const exported = hasModifier2(node, context, "public");
3690
+ const scope = context.currentClass || void 0;
3691
+ const symbolId = scope ? `${context.filePath}::${scope}.${name}` : `${context.filePath}::${name}`;
3692
+ const isConstant = hasModifier2(node, context, "static") && hasModifier2(node, context, "final");
3693
+ context.symbols.push({
3694
+ id: symbolId,
3695
+ name,
3696
+ kind: isConstant ? "constant" : "property",
3697
+ filePath: context.filePath,
3698
+ startLine: node.startPosition.row + 1,
3699
+ endLine: node.endPosition.row + 1,
3700
+ exported,
3701
+ scope
3702
+ });
3703
+ }
3704
+ function processConstantDeclaration(node, context) {
3705
+ const declarator = findDescendantByTypes(node, ["variable_declarator"]);
3706
+ if (!declarator) return;
3707
+ const nameNode = declarator.childForFieldName("name");
3708
+ if (!nameNode) return;
3709
+ const name = nodeText7(nameNode, context);
3710
+ const scope = context.currentClass || void 0;
3711
+ const symbolId = scope ? `${context.filePath}::${scope}.${name}` : `${context.filePath}::${name}`;
3712
+ context.symbols.push({
3713
+ id: symbolId,
3714
+ name,
3715
+ kind: "constant",
3716
+ filePath: context.filePath,
3717
+ startLine: node.startPosition.row + 1,
3718
+ endLine: node.endPosition.row + 1,
3719
+ exported: true,
3720
+ // Interface constants are always public
3721
+ scope
3722
+ });
3723
+ }
3724
+ function processAnnotationElement(node, context) {
3725
+ const nameNode = node.childForFieldName("name");
3726
+ if (!nameNode) return;
3727
+ const name = nodeText7(nameNode, context);
3728
+ const scope = context.currentClass || void 0;
3729
+ const symbolId = scope ? `${context.filePath}::${scope}.${name}` : `${context.filePath}::${name}`;
3730
+ context.symbols.push({
3731
+ id: symbolId,
3732
+ name,
3733
+ kind: "method",
3734
+ filePath: context.filePath,
3735
+ startLine: node.startPosition.row + 1,
3736
+ endLine: node.endPosition.row + 1,
3737
+ exported: true,
3738
+ scope
3739
+ });
3740
+ }
3741
+ function processCallExpression8(node, context) {
3742
+ const nameNode = node.childForFieldName("name");
3743
+ if (!nameNode) return;
3744
+ const calleeName = nodeText7(nameNode, context);
3745
+ const builtins = [
3746
+ "toString",
3747
+ "equals",
3748
+ "hashCode",
3749
+ "getClass",
3750
+ "println",
3751
+ "printf",
3752
+ "format",
3753
+ "parseInt",
3754
+ "valueOf",
3755
+ "length",
3756
+ "size",
3757
+ "get",
3758
+ "set",
3759
+ "add",
3760
+ "remove",
3761
+ "contains",
3762
+ "isEmpty",
3763
+ "stream",
3764
+ "collect",
3765
+ "map",
3766
+ "filter",
3767
+ "forEach",
3768
+ "of",
3769
+ "orElse",
3770
+ "orElseThrow",
3771
+ "isPresent",
3772
+ "ifPresent",
3773
+ "close",
3774
+ "flush",
3775
+ "write",
3776
+ "read"
3777
+ ];
3778
+ if (builtins.includes(calleeName)) return;
3779
+ const callerId = getCurrentSymbolId8(context);
3780
+ if (!callerId) return;
3781
+ const calleeId = resolveSymbol7(calleeName, context);
3782
+ if (calleeId) {
3783
+ context.edges.push({
3784
+ source: callerId,
3785
+ target: calleeId,
3786
+ kind: "calls",
3787
+ filePath: context.filePath,
3788
+ line: node.startPosition.row + 1
3789
+ });
3790
+ }
3791
+ }
3792
+ function processObjectCreation(node, context) {
3793
+ const typeNode = node.childForFieldName("type");
3794
+ if (!typeNode) return;
3795
+ const typeName = extractTypeName3(typeNode, context);
3796
+ if (!typeName) return;
3797
+ const callerId = getCurrentSymbolId8(context);
3798
+ if (!callerId) return;
3799
+ const targetId = resolveSymbol7(typeName, context);
3800
+ if (targetId) {
3801
+ context.edges.push({
3802
+ source: callerId,
3803
+ target: targetId,
3804
+ kind: "references",
3805
+ filePath: context.filePath,
3806
+ line: node.startPosition.row + 1
3807
+ });
3808
+ }
3809
+ const classBody = findChildByType8(node, "class_body");
3810
+ if (classBody) {
3811
+ const anonName = `<anonymous:${typeName}>`;
3812
+ const anonId = `${context.filePath}::${anonName}:${node.startPosition.row + 1}`;
3813
+ context.symbols.push({
3814
+ id: anonId,
3815
+ name: anonName,
3816
+ kind: "class",
3817
+ filePath: context.filePath,
3818
+ startLine: node.startPosition.row + 1,
3819
+ endLine: node.endPosition.row + 1,
3820
+ exported: false,
3821
+ scope: context.currentClass || void 0
3822
+ });
3823
+ const oldClass = context.currentClass;
3824
+ context.currentClass = anonName;
3825
+ context.currentScope.push(anonName);
3826
+ walkNode8(classBody, context);
3827
+ context.currentScope.pop();
3828
+ context.currentClass = oldClass;
3829
+ }
3830
+ }
3831
+ function processLambdaExpression(node, context) {
3832
+ const parent = node.parent;
3833
+ if (!parent) return;
3834
+ if (parent.type === "variable_declarator") {
3835
+ const nameNode = parent.childForFieldName("name");
3836
+ if (nameNode) {
3837
+ const name = nodeText7(nameNode, context);
3838
+ const scope = context.currentClass || void 0;
3839
+ const symbolId = scope ? `${context.filePath}::${scope}.${name}` : `${context.filePath}::${name}`;
3840
+ context.symbols.push({
3841
+ id: symbolId,
3842
+ name,
3843
+ kind: "function",
3844
+ filePath: context.filePath,
3845
+ startLine: node.startPosition.row + 1,
3846
+ endLine: node.endPosition.row + 1,
3847
+ exported: false,
3848
+ scope
3849
+ });
3850
+ }
3851
+ }
3852
+ }
3853
+ function parsePomXml(filePath, sourceCode, projectRoot) {
3854
+ const symbols = [];
3855
+ const edges = [];
3856
+ const lines = sourceCode.split("\n");
3857
+ const projectName = basename2(dirname8(join9(projectRoot, filePath)));
3858
+ symbols.push({
3859
+ id: `${filePath}::${projectName}`,
3860
+ name: projectName,
3861
+ kind: "module",
3862
+ filePath,
3863
+ startLine: 1,
3864
+ endLine: lines.length,
3865
+ exported: true
3866
+ });
3867
+ let inDependency = false;
3868
+ let groupId = "";
3869
+ let artifactId = "";
3870
+ let version = "";
3871
+ let depStartLine = 0;
3872
+ for (let i = 0; i < lines.length; i++) {
3873
+ const line = lines[i];
3874
+ const lineNum = i + 1;
3875
+ if (/<dependency>/.test(line)) {
3876
+ inDependency = true;
3877
+ groupId = "";
3878
+ artifactId = "";
3879
+ version = "";
3880
+ depStartLine = lineNum;
3881
+ }
3882
+ if (inDependency) {
3883
+ const gMatch = line.match(/<groupId>([^<]+)<\/groupId>/);
3884
+ if (gMatch) groupId = gMatch[1];
3885
+ const aMatch = line.match(/<artifactId>([^<]+)<\/artifactId>/);
3886
+ if (aMatch) artifactId = aMatch[1];
3887
+ const vMatch = line.match(/<version>([^<]+)<\/version>/);
3888
+ if (vMatch) version = vMatch[1];
3889
+ }
3890
+ if (/<\/dependency>/.test(line) && inDependency) {
3891
+ inDependency = false;
3892
+ if (groupId && artifactId) {
3893
+ const depName = `${groupId}:${artifactId}`;
3894
+ const displayVersion = version || "managed";
3895
+ symbols.push({
3896
+ id: `${filePath}::dep:${depName}`,
3897
+ name: `${depName}@${displayVersion}`,
3898
+ kind: "import",
3899
+ filePath,
3900
+ startLine: depStartLine,
3901
+ endLine: lineNum,
3902
+ exported: false
3903
+ });
3904
+ }
3905
+ }
3906
+ const moduleMatch = line.match(/<module>([^<]+)<\/module>/);
3907
+ if (moduleMatch) {
3908
+ const modulePath = moduleMatch[1];
3909
+ const pomDir = dirname8(join9(projectRoot, filePath));
3910
+ const resolvedModule = resolve4(pomDir, modulePath);
3911
+ const relativeModule = resolvedModule.startsWith(projectRoot + "/") ? resolvedModule.substring(projectRoot.length + 1) : null;
3912
+ if (relativeModule) {
3913
+ const modulePom = join9(relativeModule, "pom.xml");
3914
+ if (existsSync9(join9(projectRoot, modulePom))) {
3915
+ edges.push({
3916
+ source: `${filePath}::__file__`,
3917
+ target: `${modulePom}::__file__`,
3918
+ kind: "imports",
3919
+ filePath,
3920
+ line: lineNum
3921
+ });
3922
+ }
3923
+ }
3924
+ }
3925
+ }
3926
+ return { filePath, symbols, edges };
3927
+ }
3928
+ function parseGradleBuild(filePath, sourceCode, projectRoot) {
3929
+ const symbols = [];
3930
+ const edges = [];
3931
+ const lines = sourceCode.split("\n");
3932
+ const projectName = basename2(dirname8(join9(projectRoot, filePath)));
3933
+ symbols.push({
3934
+ id: `${filePath}::${projectName}`,
3935
+ name: projectName,
3936
+ kind: "module",
3937
+ filePath,
3938
+ startLine: 1,
3939
+ endLine: lines.length,
3940
+ exported: true
3941
+ });
3942
+ for (let i = 0; i < lines.length; i++) {
3943
+ const line = lines[i].trim();
3944
+ const lineNum = i + 1;
3945
+ const depMatch = line.match(
3946
+ /(?:implementation|api|compileOnly|runtimeOnly|testImplementation|testRuntimeOnly|annotationProcessor)\s*[\(]?\s*['"]([^'"]+)['"]\s*[\)]?/
3947
+ );
3948
+ if (depMatch) {
3949
+ const depCoord = depMatch[1];
3950
+ if (!depCoord.startsWith(":")) {
3951
+ symbols.push({
3952
+ id: `${filePath}::dep:${depCoord}`,
3953
+ name: depCoord,
3954
+ kind: "import",
3955
+ filePath,
3956
+ startLine: lineNum,
3957
+ endLine: lineNum,
3958
+ exported: false
3959
+ });
3960
+ }
3961
+ }
3962
+ const projectMatch = line.match(/project\s*\(\s*['":]+([^'")\s]+)['"]*\s*\)/);
3963
+ if (projectMatch) {
3964
+ const moduleName = projectMatch[1].replace(/^:/, "");
3965
+ const candidates = [
3966
+ join9(moduleName, "build.gradle"),
3967
+ join9(moduleName, "build.gradle.kts")
3968
+ ];
3969
+ for (const candidate of candidates) {
3970
+ if (existsSync9(join9(projectRoot, candidate))) {
3971
+ edges.push({
3972
+ source: `${filePath}::__file__`,
3973
+ target: `${candidate}::__file__`,
3974
+ kind: "imports",
3975
+ filePath,
3976
+ line: lineNum
3977
+ });
3978
+ break;
3979
+ }
3980
+ }
3981
+ }
3982
+ }
3983
+ return { filePath, symbols, edges };
3984
+ }
3985
+ function resolveJavaImport(importPath, currentFile, projectRoot) {
3986
+ const cleanPath2 = importPath.replace(/\.\*$/, "");
3987
+ const javaPath = cleanPath2.replace(/\./g, "/") + ".java";
3988
+ const sourceRoots = [
3989
+ "",
3990
+ "src/main/java",
3991
+ "src",
3992
+ "app/src/main/java"
3993
+ ];
3994
+ for (const root of sourceRoots) {
3995
+ const candidate = root ? join9(root, javaPath) : javaPath;
3996
+ const fullPath = join9(projectRoot, candidate);
3997
+ if (existsSync9(fullPath)) {
3998
+ return candidate;
3999
+ }
4000
+ }
4001
+ if (importPath.endsWith(".*")) {
4002
+ const packagePath = cleanPath2.replace(/\./g, "/");
4003
+ for (const root of sourceRoots) {
4004
+ const candidate = root ? join9(root, packagePath) : packagePath;
4005
+ const fullPath = join9(projectRoot, candidate);
4006
+ if (existsSync9(fullPath)) {
4007
+ try {
4008
+ const stats = statSync3(fullPath);
4009
+ if (stats.isDirectory()) {
4010
+ const javaFiles = readdirSync6(fullPath).filter((f) => f.endsWith(".java"));
4011
+ if (javaFiles.length > 0) {
4012
+ return join9(candidate, javaFiles[0]);
4013
+ }
4014
+ }
4015
+ } catch {
4016
+ }
4017
+ }
4018
+ }
4019
+ }
4020
+ return null;
4021
+ }
4022
+ function resolveSymbol7(name, context) {
4023
+ if (context.imports.has(name)) {
4024
+ return context.imports.get(name) || null;
4025
+ }
4026
+ const currentFileId = `${context.filePath}::${name}`;
4027
+ if (context.symbols.find((s) => s.id === currentFileId)) {
4028
+ return currentFileId;
4029
+ }
4030
+ if (context.currentClass) {
4031
+ const classMethodId = `${context.filePath}::${context.currentClass}.${name}`;
4032
+ if (context.symbols.find((s) => s.id === classMethodId)) {
4033
+ return classMethodId;
4034
+ }
4035
+ }
4036
+ return null;
4037
+ }
4038
+ function hasModifier2(node, context, modifier) {
4039
+ const modifiers = node.childForFieldName("modifiers") || findChildByType8(node, "modifiers");
4040
+ if (modifiers) {
4041
+ for (let i = 0; i < modifiers.childCount; i++) {
4042
+ const child = modifiers.child(i);
4043
+ if (child && nodeText7(child, context) === modifier) {
4044
+ return true;
4045
+ }
4046
+ }
4047
+ }
4048
+ for (let i = 0; i < node.childCount; i++) {
4049
+ const child = node.child(i);
4050
+ if (child && child.type === modifier) {
4051
+ return true;
4052
+ }
4053
+ }
4054
+ return false;
4055
+ }
4056
+ function extractTypeName3(node, context) {
4057
+ const text = nodeText7(node, context).trim();
4058
+ if (!text) return null;
4059
+ const angleBracketIdx = text.indexOf("<");
4060
+ const name = angleBracketIdx > 0 ? text.substring(0, angleBracketIdx) : text;
4061
+ const dotIdx = name.lastIndexOf(".");
4062
+ return dotIdx >= 0 ? name.substring(dotIdx + 1) : name;
4063
+ }
4064
+ function findChildByType8(node, type) {
4065
+ for (let i = 0; i < node.childCount; i++) {
4066
+ const child = node.child(i);
4067
+ if (child && child.type === type) return child;
4068
+ }
4069
+ return null;
4070
+ }
4071
+ function findChildrenByType3(node, type) {
4072
+ const results = [];
4073
+ for (let i = 0; i < node.childCount; i++) {
4074
+ const child = node.child(i);
4075
+ if (child && child.type === type) results.push(child);
4076
+ }
4077
+ return results;
4078
+ }
4079
+ function findDescendantByTypes(node, types) {
4080
+ for (let i = 0; i < node.childCount; i++) {
4081
+ const child = node.child(i);
4082
+ if (!child) continue;
4083
+ if (types.includes(child.type)) return child;
4084
+ const found = findDescendantByTypes(child, types);
4085
+ if (found) return found;
4086
+ }
4087
+ return null;
4088
+ }
4089
+ function nodeText7(node, context) {
4090
+ return context.sourceCode.substring(node.startIndex, node.endIndex);
4091
+ }
4092
+ function getCurrentSymbolId8(context) {
4093
+ if (context.currentScope.length === 0) return null;
4094
+ return `${context.filePath}::${context.currentScope[context.currentScope.length - 1]}`;
4095
+ }
4096
+ var javaParser = {
4097
+ name: "java",
4098
+ extensions: [".java", "pom.xml", "build.gradle", "build.gradle.kts"],
4099
+ parseFile: parseJavaFile
4100
+ };
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
+
3345
4930
  // src/parser/detect.ts
3346
4931
  var parsers = [
3347
4932
  typescriptParser,
@@ -3350,11 +4935,24 @@ var parsers = [
3350
4935
  goParser,
3351
4936
  rustParser,
3352
4937
  cParser,
3353
- csharpParser
4938
+ csharpParser,
4939
+ javaParser,
4940
+ cppParser
3354
4941
  ];
3355
- function getParserForFile(filePath) {
3356
- const ext = extname4(filePath).toLowerCase();
3357
- return parsers.find((p) => p.extensions.includes(ext)) || null;
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
+ }
4955
+ return parsers.find((p) => p.extensions.includes(ext) || p.extensions.includes(fileName)) || null;
3358
4956
  }
3359
4957
 
3360
4958
  // src/parser/index.ts
@@ -3362,7 +4960,7 @@ import { minimatch } from "minimatch";
3362
4960
  var MAX_FILE_SIZE = 1e6;
3363
4961
  function shouldParseFile(fullPath) {
3364
4962
  try {
3365
- const stats = statSync3(fullPath);
4963
+ const stats = statSync5(fullPath);
3366
4964
  if (stats.size > MAX_FILE_SIZE) {
3367
4965
  console.error(`[Parser] Skipping ${fullPath} \u2014 file too large (${(stats.size / 1024).toFixed(0)}KB)`);
3368
4966
  return false;
@@ -3380,8 +4978,8 @@ async function parseProject(projectRoot, options) {
3380
4978
  let errorFiles = 0;
3381
4979
  for (const file of files) {
3382
4980
  try {
3383
- const fullPath = join9(projectRoot, file);
3384
- if (!resolve4(fullPath).startsWith(resolve4(projectRoot))) {
4981
+ const fullPath = join11(projectRoot, file);
4982
+ if (!resolve5(fullPath).startsWith(resolve5(projectRoot))) {
3385
4983
  skippedFiles++;
3386
4984
  continue;
3387
4985
  }
@@ -3404,13 +5002,13 @@ async function parseProject(projectRoot, options) {
3404
5002
  if (options?.verbose) {
3405
5003
  console.error(`[Parser] Parsing: ${file}`);
3406
5004
  }
3407
- const parser = getParserForFile(file);
5005
+ const sourceCode = readFileSync8(fullPath, "utf-8");
5006
+ const parser = getParserForFile(file, sourceCode);
3408
5007
  if (!parser) {
3409
5008
  console.error(`No parser found for file: ${file}`);
3410
5009
  skippedFiles++;
3411
5010
  continue;
3412
5011
  }
3413
- const sourceCode = readFileSync6(fullPath, "utf-8");
3414
5012
  const parsed = parser.parseFile(file, sourceCode, projectRoot);
3415
5013
  parsedFiles.push(parsed);
3416
5014
  } catch (err) {
@@ -3433,14 +5031,16 @@ async function parseProject(projectRoot, options) {
3433
5031
  }
3434
5032
 
3435
5033
  // src/cross-language/detectors/rest-api.ts
3436
- import { readFileSync as readFileSync7 } from "fs";
3437
- import { join as join10, resolve as resolve5 } from "path";
5034
+ import { readFileSync as readFileSync9 } from "fs";
5035
+ import { join as join12, resolve as resolve6 } from "path";
3438
5036
  function getLanguage(filePath) {
3439
5037
  if (filePath.endsWith(".ts") || filePath.endsWith(".tsx")) return "typescript";
3440
5038
  if (filePath.endsWith(".js") || filePath.endsWith(".jsx") || filePath.endsWith(".mjs") || filePath.endsWith(".cjs")) return "javascript";
3441
5039
  if (filePath.endsWith(".py")) return "python";
3442
5040
  if (filePath.endsWith(".go")) return "go";
3443
5041
  if (filePath.endsWith(".cs") || filePath.endsWith(".csx")) return "csharp";
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";
3444
5044
  return "unknown";
3445
5045
  }
3446
5046
  function normalizePath(routePath) {
@@ -3620,9 +5220,159 @@ function extractRouteDefinitions(source, filePath) {
3620
5220
  }
3621
5221
  }
3622
5222
  }
5223
+ if (lang === "java") {
5224
+ const springMethodMatch = line.match(/@(Get|Post|Put|Delete|Patch)Mapping\s*\(\s*(?:value\s*=\s*)?["']([^"']+)["']/);
5225
+ if (springMethodMatch) {
5226
+ const method = springMethodMatch[1].toUpperCase();
5227
+ let path6 = springMethodMatch[2];
5228
+ const classPrefix = findClassLevelPrefix(source);
5229
+ if (classPrefix) path6 = classPrefix + path6;
5230
+ if (!path6.startsWith("/")) path6 = "/" + path6;
5231
+ routes.push({
5232
+ method,
5233
+ path: path6,
5234
+ normalizedPath: normalizePath(path6),
5235
+ file: filePath,
5236
+ line: i + 1
5237
+ });
5238
+ }
5239
+ if (!springMethodMatch) {
5240
+ const springNoPathMatch = line.match(/@(Get|Post|Put|Delete|Patch)Mapping\s*$/);
5241
+ if (springNoPathMatch) {
5242
+ const method = springNoPathMatch[1].toUpperCase();
5243
+ const classPrefix = findClassLevelPrefix(source);
5244
+ if (classPrefix) {
5245
+ routes.push({
5246
+ method,
5247
+ path: classPrefix,
5248
+ normalizedPath: normalizePath(classPrefix),
5249
+ file: filePath,
5250
+ line: i + 1
5251
+ });
5252
+ }
5253
+ }
5254
+ }
5255
+ const requestMappingMatch = line.match(/@RequestMapping\s*\(\s*(?:value\s*=\s*)?["']([^"']+)["']/);
5256
+ if (requestMappingMatch) {
5257
+ let path6 = requestMappingMatch[1];
5258
+ if (!path6.startsWith("/")) path6 = "/" + path6;
5259
+ const methodMatch = line.match(/method\s*=\s*RequestMethod\.(\w+)/);
5260
+ const method = methodMatch ? methodMatch[1].toUpperCase() : "ANY";
5261
+ routes.push({
5262
+ method,
5263
+ path: path6,
5264
+ normalizedPath: normalizePath(path6),
5265
+ file: filePath,
5266
+ line: i + 1
5267
+ });
5268
+ }
5269
+ const jaxPathMatch = line.match(/@Path\s*\(\s*["']([^"']+)["']\s*\)/);
5270
+ if (jaxPathMatch) {
5271
+ let path6 = jaxPathMatch[1];
5272
+ if (!path6.startsWith("/")) path6 = "/" + path6;
5273
+ const nextLine = i + 1 < lines.length ? lines[i + 1] : "";
5274
+ const prevLine = i > 0 ? lines[i - 1] : "";
5275
+ const jaxMethodMatch = (nextLine + prevLine).match(/@(GET|POST|PUT|DELETE|PATCH)/);
5276
+ const method = jaxMethodMatch ? jaxMethodMatch[1] : "ANY";
5277
+ routes.push({
5278
+ method,
5279
+ path: path6,
5280
+ normalizedPath: normalizePath(path6),
5281
+ file: filePath,
5282
+ line: i + 1
5283
+ });
5284
+ }
5285
+ const webFluxMatch = line.match(/(?:route|andRoute)\s*\(\s*(GET|POST|PUT|DELETE|PATCH)\s*\(\s*["']([^"']+)["']\s*\)/);
5286
+ if (webFluxMatch) {
5287
+ const path6 = webFluxMatch[2].startsWith("/") ? webFluxMatch[2] : "/" + webFluxMatch[2];
5288
+ routes.push({
5289
+ method: webFluxMatch[1].toUpperCase(),
5290
+ path: path6,
5291
+ normalizedPath: normalizePath(path6),
5292
+ file: filePath,
5293
+ line: i + 1
5294
+ });
5295
+ }
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
+ }
3623
5363
  }
3624
5364
  return routes;
3625
5365
  }
5366
+ function findClassLevelPrefix(source) {
5367
+ const match = source.match(/@RequestMapping\s*\(\s*(?:value\s*=\s*)?["']([^"']+)["']/);
5368
+ if (match) {
5369
+ let path6 = match[1];
5370
+ if (!path6.startsWith("/")) path6 = "/" + path6;
5371
+ if (path6.endsWith("/") && path6.length > 1) path6 = path6.slice(0, -1);
5372
+ return path6;
5373
+ }
5374
+ return null;
5375
+ }
3626
5376
  function matchPaths(callPath, routeNormalized) {
3627
5377
  const normalizedCall = normalizePath(stripTrailingSlash(callPath));
3628
5378
  const normalizedRoute = stripTrailingSlash(routeNormalized);
@@ -3658,11 +5408,11 @@ function detectRestApiEdges(files, projectRoot) {
3658
5408
  const allCalls = [];
3659
5409
  const allRoutes = [];
3660
5410
  for (const file of files) {
3661
- const fullPath = join10(projectRoot, file.filePath);
3662
- if (!resolve5(fullPath).startsWith(resolve5(projectRoot))) continue;
5411
+ const fullPath = join12(projectRoot, file.filePath);
5412
+ if (!resolve6(fullPath).startsWith(resolve6(projectRoot))) continue;
3663
5413
  let source;
3664
5414
  try {
3665
- source = readFileSync7(fullPath, "utf-8");
5415
+ source = readFileSync9(fullPath, "utf-8");
3666
5416
  } catch {
3667
5417
  continue;
3668
5418
  }
@@ -3698,8 +5448,8 @@ function detectRestApiEdges(files, projectRoot) {
3698
5448
  }
3699
5449
 
3700
5450
  // src/cross-language/detectors/subprocess.ts
3701
- import { readFileSync as readFileSync8 } from "fs";
3702
- import { join as join11, resolve as resolve6, basename as basename2 } from "path";
5451
+ import { readFileSync as readFileSync10 } from "fs";
5452
+ import { join as join13, resolve as resolve7, basename as basename5 } from "path";
3703
5453
  var SCRIPT_EXTENSIONS = [".py", ".js", ".ts", ".go", ".rs"];
3704
5454
  function getLanguage2(filePath) {
3705
5455
  if (filePath.endsWith(".ts") || filePath.endsWith(".tsx")) return "typescript";
@@ -3798,16 +5548,16 @@ function detectSubprocessEdges(files, projectRoot) {
3798
5548
  const knownFiles = new Set(files.map((f) => f.filePath));
3799
5549
  const basenameMap = /* @__PURE__ */ new Map();
3800
5550
  for (const f of files) {
3801
- const base = basename2(f.filePath);
5551
+ const base = basename5(f.filePath);
3802
5552
  if (!basenameMap.has(base)) basenameMap.set(base, []);
3803
5553
  basenameMap.get(base).push(f.filePath);
3804
5554
  }
3805
5555
  for (const file of files) {
3806
- const fullPath = join11(projectRoot, file.filePath);
3807
- if (!resolve6(fullPath).startsWith(resolve6(projectRoot))) continue;
5556
+ const fullPath = join13(projectRoot, file.filePath);
5557
+ if (!resolve7(fullPath).startsWith(resolve7(projectRoot))) continue;
3808
5558
  let source;
3809
5559
  try {
3810
- source = readFileSync8(fullPath, "utf-8");
5560
+ source = readFileSync10(fullPath, "utf-8");
3811
5561
  } catch {
3812
5562
  continue;
3813
5563
  }
@@ -3819,7 +5569,7 @@ function detectSubprocessEdges(files, projectRoot) {
3819
5569
  targetFile = call.calledFile;
3820
5570
  confidence = "high";
3821
5571
  } else {
3822
- const base = basename2(call.calledFile);
5572
+ const base = basename5(call.calledFile);
3823
5573
  const candidates = basenameMap.get(base);
3824
5574
  if (candidates && candidates.length > 0) {
3825
5575
  const exactCandidate = candidates.find((c) => c.endsWith(call.calledFile));
@@ -4198,7 +5948,7 @@ function getArchitectureSummary(graph) {
4198
5948
  }
4199
5949
 
4200
5950
  // src/health/metrics.ts
4201
- import { dirname as dirname8 } from "path";
5951
+ import { dirname as dirname10 } from "path";
4202
5952
  function scoreToGrade(score) {
4203
5953
  if (score >= 90) return "A";
4204
5954
  if (score >= 80) return "B";
@@ -4231,8 +5981,8 @@ function calculateCouplingScore(graph) {
4231
5981
  totalEdges++;
4232
5982
  fileConnections.set(sourceAttrs.filePath, (fileConnections.get(sourceAttrs.filePath) || 0) + 1);
4233
5983
  fileConnections.set(targetAttrs.filePath, (fileConnections.get(targetAttrs.filePath) || 0) + 1);
4234
- const sourceDir = dirname8(sourceAttrs.filePath).split("/")[0];
4235
- const targetDir = dirname8(targetAttrs.filePath).split("/")[0];
5984
+ const sourceDir = dirname10(sourceAttrs.filePath).split("/")[0];
5985
+ const targetDir = dirname10(targetAttrs.filePath).split("/")[0];
4236
5986
  if (sourceDir !== targetDir) {
4237
5987
  crossDirEdges++;
4238
5988
  }
@@ -4279,8 +6029,8 @@ function calculateCohesionScore(graph) {
4279
6029
  const sourceAttrs = graph.getNodeAttributes(source);
4280
6030
  const targetAttrs = graph.getNodeAttributes(target);
4281
6031
  if (sourceAttrs.filePath !== targetAttrs.filePath) {
4282
- const sourceDir = dirname8(sourceAttrs.filePath);
4283
- const targetDir = dirname8(targetAttrs.filePath);
6032
+ const sourceDir = dirname10(sourceAttrs.filePath);
6033
+ const targetDir = dirname10(targetAttrs.filePath);
4284
6034
  if (!dirEdges.has(sourceDir)) {
4285
6035
  dirEdges.set(sourceDir, { internal: 0, total: 0 });
4286
6036
  }
@@ -4562,8 +6312,8 @@ function calculateDepthScore(graph) {
4562
6312
  }
4563
6313
 
4564
6314
  // src/health/index.ts
4565
- import { readFileSync as readFileSync9, writeFileSync, existsSync as existsSync9, mkdirSync } from "fs";
4566
- import { dirname as dirname9, resolve as resolve7 } from "path";
6315
+ import { readFileSync as readFileSync11, writeFileSync, existsSync as existsSync11, mkdirSync } from "fs";
6316
+ import { dirname as dirname11, resolve as resolve8 } from "path";
4567
6317
  function calculateHealthScore(graph, projectRoot) {
4568
6318
  const coupling = calculateCouplingScore(graph);
4569
6319
  const cohesion = calculateCohesionScore(graph);
@@ -4662,8 +6412,8 @@ function getHealthTrend(projectRoot, currentScore) {
4662
6412
  }
4663
6413
  }
4664
6414
  function saveHealthHistory(projectRoot, report) {
4665
- const resolvedRoot = resolve7(projectRoot);
4666
- const historyFile = resolve7(resolvedRoot, ".depwire", "health-history.json");
6415
+ const resolvedRoot = resolve8(projectRoot);
6416
+ const historyFile = resolve8(resolvedRoot, ".depwire", "health-history.json");
4667
6417
  if (!historyFile.startsWith(resolvedRoot)) {
4668
6418
  return;
4669
6419
  }
@@ -4678,10 +6428,10 @@ function saveHealthHistory(projectRoot, report) {
4678
6428
  }))
4679
6429
  };
4680
6430
  let history = [];
4681
- if (existsSync9(historyFile)) {
6431
+ if (existsSync11(historyFile)) {
4682
6432
  try {
4683
6433
  if (!historyFile.startsWith(resolvedRoot)) return;
4684
- const content = readFileSync9(historyFile, "utf-8");
6434
+ const content = readFileSync11(historyFile, "utf-8");
4685
6435
  history = JSON.parse(content);
4686
6436
  } catch {
4687
6437
  }
@@ -4690,19 +6440,19 @@ function saveHealthHistory(projectRoot, report) {
4690
6440
  if (history.length > 50) {
4691
6441
  history = history.slice(-50);
4692
6442
  }
4693
- mkdirSync(dirname9(historyFile), { recursive: true });
6443
+ mkdirSync(dirname11(historyFile), { recursive: true });
4694
6444
  if (!historyFile.startsWith(resolvedRoot)) return;
4695
6445
  writeFileSync(historyFile, JSON.stringify(history, null, 2), "utf-8");
4696
6446
  }
4697
6447
  function loadHealthHistory(projectRoot) {
4698
- const resolvedRoot = resolve7(projectRoot);
4699
- const historyFile = resolve7(resolvedRoot, ".depwire", "health-history.json");
4700
- if (!historyFile.startsWith(resolvedRoot) || !existsSync9(historyFile)) {
6448
+ const resolvedRoot = resolve8(projectRoot);
6449
+ const historyFile = resolve8(resolvedRoot, ".depwire", "health-history.json");
6450
+ if (!historyFile.startsWith(resolvedRoot) || !existsSync11(historyFile)) {
4701
6451
  return [];
4702
6452
  }
4703
6453
  try {
4704
6454
  if (!historyFile.startsWith(resolvedRoot)) return [];
4705
- const content = readFileSync9(historyFile, "utf-8");
6455
+ const content = readFileSync11(historyFile, "utf-8");
4706
6456
  return JSON.parse(content);
4707
6457
  } catch {
4708
6458
  return [];
@@ -4711,7 +6461,7 @@ function loadHealthHistory(projectRoot) {
4711
6461
 
4712
6462
  // src/dead-code/detector.ts
4713
6463
  import path2 from "path";
4714
- import { readFileSync as readFileSync10, existsSync as existsSync10 } from "fs";
6464
+ import { readFileSync as readFileSync12, existsSync as existsSync12 } from "fs";
4715
6465
  function findDeadSymbols(graph, projectRoot, includeTests = false, debug = false) {
4716
6466
  const deadSymbols = [];
4717
6467
  const context = { graph, projectRoot };
@@ -4844,11 +6594,11 @@ function getPackageEntryPoints(projectRoot) {
4844
6594
  const entryPoints = /* @__PURE__ */ new Set();
4845
6595
  const resolvedRoot = path2.resolve(projectRoot);
4846
6596
  const packageJsonPath = path2.resolve(resolvedRoot, "package.json");
4847
- if (!packageJsonPath.startsWith(resolvedRoot) || !existsSync10(packageJsonPath)) {
6597
+ if (!packageJsonPath.startsWith(resolvedRoot) || !existsSync12(packageJsonPath)) {
4848
6598
  return entryPoints;
4849
6599
  }
4850
6600
  try {
4851
- const packageJson = JSON.parse(readFileSync10(packageJsonPath, "utf-8"));
6601
+ const packageJson = JSON.parse(readFileSync12(packageJsonPath, "utf-8"));
4852
6602
  if (packageJson.main) {
4853
6603
  entryPoints.add(path2.resolve(projectRoot, packageJson.main));
4854
6604
  }
@@ -4899,6 +6649,9 @@ function shouldExclude(attrs, context, includeTests, packageEntryPoints) {
4899
6649
  if (isFrameworkAutoLoadedFile(relativePath)) {
4900
6650
  return "framework";
4901
6651
  }
6652
+ if (isCppExcluded(attrs)) {
6653
+ return "framework";
6654
+ }
4902
6655
  return null;
4903
6656
  }
4904
6657
  function isRealPackageEntryPoint(filePath, packageEntryPoints) {
@@ -4921,7 +6674,21 @@ function isTypeDeclarationFile(filePath) {
4921
6674
  return filePath.endsWith(".d.ts");
4922
6675
  }
4923
6676
  function isFrameworkAutoLoadedFile(filePath) {
4924
- 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/");
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
6678
+ filePath.includes("/controller/") || filePath.includes("/controllers/") || filePath.includes("/service/") || filePath.includes("/repository/") || filePath.includes("/config/") || filePath.includes("/configuration/");
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;
4925
6692
  }
4926
6693
 
4927
6694
  // src/dead-code/classifier.ts
@@ -4989,8 +6756,8 @@ function generateReason(symbol, confidence) {
4989
6756
  return "Potentially unused";
4990
6757
  }
4991
6758
  function isBarrelFile(filePath) {
4992
- const basename6 = path3.basename(filePath);
4993
- return basename6 === "index.ts" || basename6 === "index.js";
6759
+ const basename9 = path3.basename(filePath);
6760
+ return basename9 === "index.ts" || basename9 === "index.js";
4994
6761
  }
4995
6762
  function isTestFile2(filePath) {
4996
6763
  return filePath.includes("__tests__/") || filePath.includes(".test.") || filePath.includes(".spec.") || filePath.includes("/test/") || filePath.includes("/tests/");
@@ -5169,11 +6936,11 @@ function filterByConfidence(symbols, minConfidence) {
5169
6936
  }
5170
6937
 
5171
6938
  // src/docs/generator.ts
5172
- import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, existsSync as existsSync13 } from "fs";
5173
- import { join as join15 } from "path";
6939
+ import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, existsSync as existsSync15 } from "fs";
6940
+ import { join as join17 } from "path";
5174
6941
 
5175
6942
  // src/docs/architecture.ts
5176
- import { dirname as dirname10 } from "path";
6943
+ import { dirname as dirname12 } from "path";
5177
6944
 
5178
6945
  // src/docs/templates.ts
5179
6946
  function header(text, level = 1) {
@@ -5324,7 +7091,7 @@ function generateModuleStructure(graph) {
5324
7091
  function getDirectoryStats(graph) {
5325
7092
  const dirMap = /* @__PURE__ */ new Map();
5326
7093
  graph.forEachNode((node, attrs) => {
5327
- const dir = dirname10(attrs.filePath);
7094
+ const dir = dirname12(attrs.filePath);
5328
7095
  if (dir === ".") return;
5329
7096
  if (!dirMap.has(dir)) {
5330
7097
  dirMap.set(dir, {
@@ -5349,7 +7116,7 @@ function getDirectoryStats(graph) {
5349
7116
  });
5350
7117
  const filesPerDir = /* @__PURE__ */ new Map();
5351
7118
  graph.forEachNode((node, attrs) => {
5352
- const dir = dirname10(attrs.filePath);
7119
+ const dir = dirname12(attrs.filePath);
5353
7120
  if (!filesPerDir.has(dir)) {
5354
7121
  filesPerDir.set(dir, /* @__PURE__ */ new Set());
5355
7122
  }
@@ -5364,8 +7131,8 @@ function getDirectoryStats(graph) {
5364
7131
  graph.forEachEdge((edge, attrs, source, target) => {
5365
7132
  const sourceAttrs = graph.getNodeAttributes(source);
5366
7133
  const targetAttrs = graph.getNodeAttributes(target);
5367
- const sourceDir = dirname10(sourceAttrs.filePath);
5368
- const targetDir = dirname10(targetAttrs.filePath);
7134
+ const sourceDir = dirname12(sourceAttrs.filePath);
7135
+ const targetDir = dirname12(targetAttrs.filePath);
5369
7136
  if (sourceDir !== targetDir) {
5370
7137
  if (!dirEdges.has(sourceDir)) {
5371
7138
  dirEdges.set(sourceDir, { in: 0, out: 0 });
@@ -5572,7 +7339,7 @@ function detectCycles(graph) {
5572
7339
  }
5573
7340
 
5574
7341
  // src/docs/conventions.ts
5575
- import { basename as basename3, extname as extname5 } from "path";
7342
+ import { basename as basename6, extname as extname7 } from "path";
5576
7343
  function generateConventions(graph, projectRoot, version) {
5577
7344
  let output = "";
5578
7345
  const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
@@ -5610,7 +7377,7 @@ function generateFileOrganization(graph) {
5610
7377
  graph.forEachNode((node, attrs) => {
5611
7378
  if (!files.has(attrs.filePath)) {
5612
7379
  files.add(attrs.filePath);
5613
- const fileName = basename3(attrs.filePath);
7380
+ const fileName = basename6(attrs.filePath);
5614
7381
  if (fileName === "index.ts" || fileName === "index.js" || fileName === "index.tsx" || fileName === "index.jsx") {
5615
7382
  barrelFileCount++;
5616
7383
  }
@@ -5669,7 +7436,7 @@ function generateNamingPatterns(graph) {
5669
7436
  graph.forEachNode((node, attrs) => {
5670
7437
  if (!files.has(attrs.filePath)) {
5671
7438
  files.add(attrs.filePath);
5672
- const fileName = basename3(attrs.filePath, extname5(attrs.filePath));
7439
+ const fileName = basename6(attrs.filePath, extname7(attrs.filePath));
5673
7440
  if (isCamelCase(fileName)) patterns.files.camelCase++;
5674
7441
  else if (isPascalCase(fileName)) patterns.files.PascalCase++;
5675
7442
  else if (isKebabCase(fileName)) patterns.files.kebabCase++;
@@ -6346,7 +8113,7 @@ function detectCyclesDetailed(graph) {
6346
8113
  }
6347
8114
 
6348
8115
  // src/docs/onboarding.ts
6349
- import { dirname as dirname11 } from "path";
8116
+ import { dirname as dirname13 } from "path";
6350
8117
  function generateOnboarding(graph, projectRoot, version) {
6351
8118
  let output = "";
6352
8119
  const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
@@ -6405,7 +8172,7 @@ function generateQuickOrientation(graph) {
6405
8172
  const primaryLang = Object.entries(languages2).sort((a, b) => b[1] - a[1])[0];
6406
8173
  const dirs = /* @__PURE__ */ new Set();
6407
8174
  graph.forEachNode((node, attrs) => {
6408
- const dir = dirname11(attrs.filePath);
8175
+ const dir = dirname13(attrs.filePath);
6409
8176
  if (dir !== ".") {
6410
8177
  const topLevel = dir.split("/")[0];
6411
8178
  dirs.add(topLevel);
@@ -6509,7 +8276,7 @@ function generateModuleMap(graph) {
6509
8276
  function getDirectoryStats2(graph) {
6510
8277
  const dirMap = /* @__PURE__ */ new Map();
6511
8278
  graph.forEachNode((node, attrs) => {
6512
- const dir = dirname11(attrs.filePath);
8279
+ const dir = dirname13(attrs.filePath);
6513
8280
  if (dir === ".") return;
6514
8281
  if (!dirMap.has(dir)) {
6515
8282
  dirMap.set(dir, {
@@ -6524,7 +8291,7 @@ function getDirectoryStats2(graph) {
6524
8291
  });
6525
8292
  const filesPerDir = /* @__PURE__ */ new Map();
6526
8293
  graph.forEachNode((node, attrs) => {
6527
- const dir = dirname11(attrs.filePath);
8294
+ const dir = dirname13(attrs.filePath);
6528
8295
  if (!filesPerDir.has(dir)) {
6529
8296
  filesPerDir.set(dir, /* @__PURE__ */ new Set());
6530
8297
  }
@@ -6539,8 +8306,8 @@ function getDirectoryStats2(graph) {
6539
8306
  graph.forEachEdge((edge, attrs, source, target) => {
6540
8307
  const sourceAttrs = graph.getNodeAttributes(source);
6541
8308
  const targetAttrs = graph.getNodeAttributes(target);
6542
- const sourceDir = dirname11(sourceAttrs.filePath);
6543
- const targetDir = dirname11(targetAttrs.filePath);
8309
+ const sourceDir = dirname13(sourceAttrs.filePath);
8310
+ const targetDir = dirname13(targetAttrs.filePath);
6544
8311
  if (sourceDir !== targetDir) {
6545
8312
  if (!dirEdges.has(sourceDir)) {
6546
8313
  dirEdges.set(sourceDir, { in: 0, out: 0 });
@@ -6621,7 +8388,7 @@ function detectClusters(graph) {
6621
8388
  const dirFiles = /* @__PURE__ */ new Map();
6622
8389
  const fileEdges = /* @__PURE__ */ new Map();
6623
8390
  graph.forEachNode((node, attrs) => {
6624
- const dir = dirname11(attrs.filePath);
8391
+ const dir = dirname13(attrs.filePath);
6625
8392
  if (!dirFiles.has(dir)) {
6626
8393
  dirFiles.set(dir, /* @__PURE__ */ new Set());
6627
8394
  }
@@ -6675,8 +8442,8 @@ function inferClusterName(files) {
6675
8442
  if (sortedWords.length > 0 && sortedWords[0][1] > 1) {
6676
8443
  return capitalizeFirst2(sortedWords[0][0]);
6677
8444
  }
6678
- const commonDir = dirname11(files[0]);
6679
- if (files.every((f) => dirname11(f) === commonDir)) {
8445
+ const commonDir = dirname13(files[0]);
8446
+ if (files.every((f) => dirname13(f) === commonDir)) {
6680
8447
  return capitalizeFirst2(commonDir.split("/").pop() || "Core");
6681
8448
  }
6682
8449
  return "Core";
@@ -6734,7 +8501,7 @@ function generateDepwireUsage(projectRoot) {
6734
8501
  }
6735
8502
 
6736
8503
  // src/docs/files.ts
6737
- import { dirname as dirname12, basename as basename4 } from "path";
8504
+ import { dirname as dirname14, basename as basename7 } from "path";
6738
8505
  function generateFiles(graph, projectRoot, version) {
6739
8506
  let output = "";
6740
8507
  const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
@@ -6838,7 +8605,7 @@ function generateDirectoryBreakdown(graph) {
6838
8605
  const fileStats = getFileStats2(graph);
6839
8606
  const dirMap = /* @__PURE__ */ new Map();
6840
8607
  for (const file of fileStats) {
6841
- const dir = dirname12(file.filePath);
8608
+ const dir = dirname14(file.filePath);
6842
8609
  const topDir = dir === "." ? "." : dir.split("/")[0];
6843
8610
  if (!dirMap.has(topDir)) {
6844
8611
  dirMap.set(topDir, {
@@ -6853,7 +8620,7 @@ function generateDirectoryBreakdown(graph) {
6853
8620
  dirStats.symbolCount += file.symbolCount;
6854
8621
  if (file.totalConnections > dirStats.maxConnections) {
6855
8622
  dirStats.maxConnections = file.totalConnections;
6856
- dirStats.mostConnectedFile = basename4(file.filePath);
8623
+ dirStats.mostConnectedFile = basename7(file.filePath);
6857
8624
  }
6858
8625
  }
6859
8626
  if (dirMap.size === 0) {
@@ -7481,7 +9248,7 @@ function generateRecommendations(graph) {
7481
9248
  }
7482
9249
 
7483
9250
  // src/docs/tests.ts
7484
- import { basename as basename5, dirname as dirname13 } from "path";
9251
+ import { basename as basename8, dirname as dirname15 } from "path";
7485
9252
  function generateTests(graph, projectRoot, version) {
7486
9253
  let output = "";
7487
9254
  const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
@@ -7509,8 +9276,8 @@ function getFileCount8(graph) {
7509
9276
  return files.size;
7510
9277
  }
7511
9278
  function isTestFile3(filePath) {
7512
- const fileName = basename5(filePath).toLowerCase();
7513
- const dirPath = dirname13(filePath).toLowerCase();
9279
+ const fileName = basename8(filePath).toLowerCase();
9280
+ const dirPath = dirname15(filePath).toLowerCase();
7514
9281
  if (dirPath.includes("test") || dirPath.includes("spec") || dirPath.includes("__tests__")) {
7515
9282
  return true;
7516
9283
  }
@@ -7568,13 +9335,13 @@ function generateTestFileInventory(graph) {
7568
9335
  return output;
7569
9336
  }
7570
9337
  function matchTestToSource(testFile) {
7571
- const testFileName = basename5(testFile);
7572
- const testDir = dirname13(testFile);
9338
+ const testFileName = basename8(testFile);
9339
+ const testDir = dirname15(testFile);
7573
9340
  let sourceFileName = testFileName.replace(/\.test\./g, ".").replace(/\.spec\./g, ".").replace(/_test\./g, ".").replace(/_spec\./g, ".");
7574
9341
  const possiblePaths = [];
7575
9342
  possiblePaths.push(testDir + "/" + sourceFileName);
7576
9343
  if (testDir.endsWith("/test") || testDir.endsWith("/tests") || testDir.endsWith("/__tests__")) {
7577
- const parentDir = dirname13(testDir);
9344
+ const parentDir = dirname15(testDir);
7578
9345
  possiblePaths.push(parentDir + "/" + sourceFileName);
7579
9346
  }
7580
9347
  if (testDir.includes("test")) {
@@ -7730,7 +9497,7 @@ function generateTestCoverageMap(graph) {
7730
9497
  const rows = mappings.slice(0, 30).map((m) => [
7731
9498
  `\`${m.sourceFile}\``,
7732
9499
  m.hasTest ? "\u2705" : "\u274C",
7733
- m.testFile ? `\`${basename5(m.testFile)}\`` : "-",
9500
+ m.testFile ? `\`${basename8(m.testFile)}\`` : "-",
7734
9501
  formatNumber(m.symbolCount)
7735
9502
  ]);
7736
9503
  let output = table(headers, rows);
@@ -7771,7 +9538,7 @@ function generateTestStatistics(graph) {
7771
9538
  `;
7772
9539
  const dirTestCoverage = /* @__PURE__ */ new Map();
7773
9540
  for (const sourceFile of sourceFiles) {
7774
- const dir = dirname13(sourceFile).split("/")[0];
9541
+ const dir = dirname15(sourceFile).split("/")[0];
7775
9542
  if (!dirTestCoverage.has(dir)) {
7776
9543
  dirTestCoverage.set(dir, { total: 0, tested: 0 });
7777
9544
  }
@@ -7794,7 +9561,7 @@ function generateTestStatistics(graph) {
7794
9561
  }
7795
9562
 
7796
9563
  // src/docs/history.ts
7797
- import { dirname as dirname14 } from "path";
9564
+ import { dirname as dirname16 } from "path";
7798
9565
  import { execSync } from "child_process";
7799
9566
  function generateHistory(graph, projectRoot, version) {
7800
9567
  let output = "";
@@ -8075,7 +9842,7 @@ function generateFeatureClusters(graph) {
8075
9842
  const dirFiles = /* @__PURE__ */ new Map();
8076
9843
  const fileEdges = /* @__PURE__ */ new Map();
8077
9844
  graph.forEachNode((node, attrs) => {
8078
- const dir = dirname14(attrs.filePath);
9845
+ const dir = dirname16(attrs.filePath);
8079
9846
  if (!dirFiles.has(dir)) {
8080
9847
  dirFiles.set(dir, /* @__PURE__ */ new Set());
8081
9848
  }
@@ -8157,7 +9924,7 @@ function capitalizeFirst3(str) {
8157
9924
  }
8158
9925
 
8159
9926
  // src/docs/current.ts
8160
- import { dirname as dirname15 } from "path";
9927
+ import { dirname as dirname17 } from "path";
8161
9928
  function generateCurrent(graph, projectRoot, version) {
8162
9929
  let output = "";
8163
9930
  const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
@@ -8295,7 +10062,7 @@ function generateCompleteFileIndex(graph) {
8295
10062
  fileInfos.sort((a, b) => a.filePath.localeCompare(b.filePath));
8296
10063
  const dirGroups = /* @__PURE__ */ new Map();
8297
10064
  for (const info of fileInfos) {
8298
- const dir = dirname15(info.filePath);
10065
+ const dir = dirname17(info.filePath);
8299
10066
  const topDir = dir === "." ? "root" : dir.split("/")[0];
8300
10067
  if (!dirGroups.has(topDir)) {
8301
10068
  dirGroups.set(topDir, []);
@@ -8506,8 +10273,8 @@ function getTopLevelDir2(filePath) {
8506
10273
  }
8507
10274
 
8508
10275
  // src/docs/status.ts
8509
- import { readFileSync as readFileSync11, existsSync as existsSync11 } from "fs";
8510
- import { resolve as resolve8 } from "path";
10276
+ import { readFileSync as readFileSync13, existsSync as existsSync13 } from "fs";
10277
+ import { resolve as resolve9 } from "path";
8511
10278
  function generateStatus(graph, projectRoot, version) {
8512
10279
  let output = "";
8513
10280
  const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
@@ -8540,16 +10307,16 @@ function getFileCount11(graph) {
8540
10307
  }
8541
10308
  function extractComments(projectRoot, filePath) {
8542
10309
  const comments = [];
8543
- const resolvedRoot = resolve8(projectRoot);
8544
- const fullPath = resolve8(resolvedRoot, filePath);
10310
+ const resolvedRoot = resolve9(projectRoot);
10311
+ const fullPath = resolve9(resolvedRoot, filePath);
8545
10312
  if (!fullPath.startsWith(resolvedRoot)) {
8546
10313
  return comments;
8547
10314
  }
8548
- if (!existsSync11(fullPath)) {
10315
+ if (!existsSync13(fullPath)) {
8549
10316
  return comments;
8550
10317
  }
8551
10318
  try {
8552
- const content = readFileSync11(fullPath, "utf-8");
10319
+ const content = readFileSync13(fullPath, "utf-8");
8553
10320
  const lines = content.split("\n");
8554
10321
  const patterns = [
8555
10322
  { type: "TODO", regex: /(?:\/\/|#|\/\*)\s*TODO:?\s*(.+)/i },
@@ -9128,16 +10895,16 @@ function generateConfidenceSection(title, description, symbols, projectRoot) {
9128
10895
  }
9129
10896
 
9130
10897
  // src/docs/metadata.ts
9131
- import { existsSync as existsSync12, readFileSync as readFileSync12, writeFileSync as writeFileSync2 } from "fs";
9132
- import { resolve as resolve9 } from "path";
10898
+ import { existsSync as existsSync14, readFileSync as readFileSync14, writeFileSync as writeFileSync2 } from "fs";
10899
+ import { resolve as resolve10 } from "path";
9133
10900
  function loadMetadata(outputDir) {
9134
- const resolvedDir = resolve9(outputDir);
9135
- const metadataPath = resolve9(resolvedDir, "metadata.json");
9136
- if (!metadataPath.startsWith(resolvedDir) || !existsSync12(metadataPath)) {
10901
+ const resolvedDir = resolve10(outputDir);
10902
+ const metadataPath = resolve10(resolvedDir, "metadata.json");
10903
+ if (!metadataPath.startsWith(resolvedDir) || !existsSync14(metadataPath)) {
9137
10904
  return null;
9138
10905
  }
9139
10906
  try {
9140
- const content = readFileSync12(metadataPath, "utf-8");
10907
+ const content = readFileSync14(metadataPath, "utf-8");
9141
10908
  return JSON.parse(content);
9142
10909
  } catch (err) {
9143
10910
  console.error("Failed to load metadata:", err);
@@ -9145,8 +10912,8 @@ function loadMetadata(outputDir) {
9145
10912
  }
9146
10913
  }
9147
10914
  function saveMetadata(outputDir, metadata) {
9148
- const resolvedDir = resolve9(outputDir);
9149
- const metadataPath = resolve9(resolvedDir, "metadata.json");
10915
+ const resolvedDir = resolve10(outputDir);
10916
+ const metadataPath = resolve10(resolvedDir, "metadata.json");
9150
10917
  if (!metadataPath.startsWith(resolvedDir)) {
9151
10918
  throw new Error(`Path traversal attempt blocked: ${metadataPath}`);
9152
10919
  }
@@ -9192,7 +10959,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
9192
10959
  const generated = [];
9193
10960
  const errors = [];
9194
10961
  try {
9195
- if (!existsSync13(options.outputDir)) {
10962
+ if (!existsSync15(options.outputDir)) {
9196
10963
  mkdirSync2(options.outputDir, { recursive: true });
9197
10964
  if (options.verbose) {
9198
10965
  console.log(`Created output directory: ${options.outputDir}`);
@@ -9231,7 +10998,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
9231
10998
  try {
9232
10999
  if (options.verbose) console.log("Generating ARCHITECTURE.md...");
9233
11000
  const content = generateArchitecture(graph, projectRoot, version, parseTime);
9234
- const filePath = join15(options.outputDir, "ARCHITECTURE.md");
11001
+ const filePath = join17(options.outputDir, "ARCHITECTURE.md");
9235
11002
  writeFileSync3(filePath, content, "utf-8");
9236
11003
  generated.push("ARCHITECTURE.md");
9237
11004
  } catch (err) {
@@ -9242,7 +11009,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
9242
11009
  try {
9243
11010
  if (options.verbose) console.log("Generating CONVENTIONS.md...");
9244
11011
  const content = generateConventions(graph, projectRoot, version);
9245
- const filePath = join15(options.outputDir, "CONVENTIONS.md");
11012
+ const filePath = join17(options.outputDir, "CONVENTIONS.md");
9246
11013
  writeFileSync3(filePath, content, "utf-8");
9247
11014
  generated.push("CONVENTIONS.md");
9248
11015
  } catch (err) {
@@ -9253,7 +11020,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
9253
11020
  try {
9254
11021
  if (options.verbose) console.log("Generating DEPENDENCIES.md...");
9255
11022
  const content = generateDependencies(graph, projectRoot, version);
9256
- const filePath = join15(options.outputDir, "DEPENDENCIES.md");
11023
+ const filePath = join17(options.outputDir, "DEPENDENCIES.md");
9257
11024
  writeFileSync3(filePath, content, "utf-8");
9258
11025
  generated.push("DEPENDENCIES.md");
9259
11026
  } catch (err) {
@@ -9264,7 +11031,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
9264
11031
  try {
9265
11032
  if (options.verbose) console.log("Generating ONBOARDING.md...");
9266
11033
  const content = generateOnboarding(graph, projectRoot, version);
9267
- const filePath = join15(options.outputDir, "ONBOARDING.md");
11034
+ const filePath = join17(options.outputDir, "ONBOARDING.md");
9268
11035
  writeFileSync3(filePath, content, "utf-8");
9269
11036
  generated.push("ONBOARDING.md");
9270
11037
  } catch (err) {
@@ -9275,7 +11042,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
9275
11042
  try {
9276
11043
  if (options.verbose) console.log("Generating FILES.md...");
9277
11044
  const content = generateFiles(graph, projectRoot, version);
9278
- const filePath = join15(options.outputDir, "FILES.md");
11045
+ const filePath = join17(options.outputDir, "FILES.md");
9279
11046
  writeFileSync3(filePath, content, "utf-8");
9280
11047
  generated.push("FILES.md");
9281
11048
  } catch (err) {
@@ -9286,7 +11053,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
9286
11053
  try {
9287
11054
  if (options.verbose) console.log("Generating API_SURFACE.md...");
9288
11055
  const content = generateApiSurface(graph, projectRoot, version);
9289
- const filePath = join15(options.outputDir, "API_SURFACE.md");
11056
+ const filePath = join17(options.outputDir, "API_SURFACE.md");
9290
11057
  writeFileSync3(filePath, content, "utf-8");
9291
11058
  generated.push("API_SURFACE.md");
9292
11059
  } catch (err) {
@@ -9297,7 +11064,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
9297
11064
  try {
9298
11065
  if (options.verbose) console.log("Generating ERRORS.md...");
9299
11066
  const content = generateErrors(graph, projectRoot, version);
9300
- const filePath = join15(options.outputDir, "ERRORS.md");
11067
+ const filePath = join17(options.outputDir, "ERRORS.md");
9301
11068
  writeFileSync3(filePath, content, "utf-8");
9302
11069
  generated.push("ERRORS.md");
9303
11070
  } catch (err) {
@@ -9308,7 +11075,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
9308
11075
  try {
9309
11076
  if (options.verbose) console.log("Generating TESTS.md...");
9310
11077
  const content = generateTests(graph, projectRoot, version);
9311
- const filePath = join15(options.outputDir, "TESTS.md");
11078
+ const filePath = join17(options.outputDir, "TESTS.md");
9312
11079
  writeFileSync3(filePath, content, "utf-8");
9313
11080
  generated.push("TESTS.md");
9314
11081
  } catch (err) {
@@ -9319,7 +11086,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
9319
11086
  try {
9320
11087
  if (options.verbose) console.log("Generating HISTORY.md...");
9321
11088
  const content = generateHistory(graph, projectRoot, version);
9322
- const filePath = join15(options.outputDir, "HISTORY.md");
11089
+ const filePath = join17(options.outputDir, "HISTORY.md");
9323
11090
  writeFileSync3(filePath, content, "utf-8");
9324
11091
  generated.push("HISTORY.md");
9325
11092
  } catch (err) {
@@ -9330,7 +11097,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
9330
11097
  try {
9331
11098
  if (options.verbose) console.log("Generating CURRENT.md...");
9332
11099
  const content = generateCurrent(graph, projectRoot, version);
9333
- const filePath = join15(options.outputDir, "CURRENT.md");
11100
+ const filePath = join17(options.outputDir, "CURRENT.md");
9334
11101
  writeFileSync3(filePath, content, "utf-8");
9335
11102
  generated.push("CURRENT.md");
9336
11103
  } catch (err) {
@@ -9341,7 +11108,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
9341
11108
  try {
9342
11109
  if (options.verbose) console.log("Generating STATUS.md...");
9343
11110
  const content = generateStatus(graph, projectRoot, version);
9344
- const filePath = join15(options.outputDir, "STATUS.md");
11111
+ const filePath = join17(options.outputDir, "STATUS.md");
9345
11112
  writeFileSync3(filePath, content, "utf-8");
9346
11113
  generated.push("STATUS.md");
9347
11114
  } catch (err) {
@@ -9352,7 +11119,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
9352
11119
  try {
9353
11120
  if (options.verbose) console.log("Generating HEALTH.md...");
9354
11121
  const content = generateHealth(graph, projectRoot, version);
9355
- const filePath = join15(options.outputDir, "HEALTH.md");
11122
+ const filePath = join17(options.outputDir, "HEALTH.md");
9356
11123
  writeFileSync3(filePath, content, "utf-8");
9357
11124
  generated.push("HEALTH.md");
9358
11125
  } catch (err) {
@@ -9363,7 +11130,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
9363
11130
  try {
9364
11131
  if (options.verbose) console.log("Generating DEAD_CODE.md...");
9365
11132
  const content = generateDeadCode(graph, projectRoot, version);
9366
- const filePath = join15(options.outputDir, "DEAD_CODE.md");
11133
+ const filePath = join17(options.outputDir, "DEAD_CODE.md");
9367
11134
  writeFileSync3(filePath, content, "utf-8");
9368
11135
  generated.push("DEAD_CODE.md");
9369
11136
  } catch (err) {
@@ -9407,7 +11174,7 @@ function getFileCount13(graph) {
9407
11174
  }
9408
11175
 
9409
11176
  // src/simulation/engine.ts
9410
- import { dirname as dirname16, join as join16 } from "path";
11177
+ import { dirname as dirname18, join as join18 } from "path";
9411
11178
  function normalizePath2(p) {
9412
11179
  return p.replace(/^\.\//, "").replace(/\/+$/, "");
9413
11180
  }
@@ -9538,7 +11305,7 @@ var SimulationEngine = class {
9538
11305
  }
9539
11306
  }
9540
11307
  applyRename(clone, target, newName, brokenImports) {
9541
- const destination = join16(dirname16(target), newName);
11308
+ const destination = join18(dirname18(target), newName);
9542
11309
  this.applyMove(clone, target, destination, brokenImports);
9543
11310
  }
9544
11311
  applySplit(clone, target, newFile, symbols, brokenImports) {
@@ -9738,13 +11505,13 @@ var SimulationEngine = class {
9738
11505
  };
9739
11506
 
9740
11507
  // src/security/scanner.ts
9741
- import { existsSync as existsSync15 } from "fs";
9742
- import { join as join26 } from "path";
11508
+ import { existsSync as existsSync17 } from "fs";
11509
+ import { join as join28 } from "path";
9743
11510
 
9744
11511
  // src/security/checks/dependencies.ts
9745
11512
  import { execSync as execSync2 } from "child_process";
9746
- import { existsSync as existsSync14, readFileSync as readFileSync13, readdirSync as readdirSync6 } from "fs";
9747
- import { join as join17 } from "path";
11513
+ import { existsSync as existsSync16, readFileSync as readFileSync15, readdirSync as readdirSync8 } from "fs";
11514
+ import { join as join19 } from "path";
9748
11515
  function cvssToSeverity(score) {
9749
11516
  if (score >= 9) return "critical";
9750
11517
  if (score >= 7) return "high";
@@ -9754,18 +11521,18 @@ function cvssToSeverity(score) {
9754
11521
  async function checkDependencies(_files, projectRoot) {
9755
11522
  const findings = [];
9756
11523
  try {
9757
- if (existsSync14(join17(projectRoot, "package.json"))) {
11524
+ if (existsSync16(join19(projectRoot, "package.json"))) {
9758
11525
  findings.push(...checkNpmAudit(projectRoot));
9759
11526
  findings.push(...checkPackageJsonPatterns(projectRoot));
9760
11527
  findings.push(...checkPostinstallScripts(projectRoot));
9761
11528
  }
9762
- if (existsSync14(join17(projectRoot, "requirements.txt")) || existsSync14(join17(projectRoot, "pyproject.toml"))) {
11529
+ if (existsSync16(join19(projectRoot, "requirements.txt")) || existsSync16(join19(projectRoot, "pyproject.toml"))) {
9763
11530
  findings.push(...checkPipAudit(projectRoot));
9764
11531
  }
9765
- if (existsSync14(join17(projectRoot, "Cargo.toml"))) {
11532
+ if (existsSync16(join19(projectRoot, "Cargo.toml"))) {
9766
11533
  findings.push(...checkCargoAudit(projectRoot));
9767
11534
  }
9768
- if (existsSync14(join17(projectRoot, "go.mod"))) {
11535
+ if (existsSync16(join19(projectRoot, "go.mod"))) {
9769
11536
  findings.push(...checkGoVerify(projectRoot));
9770
11537
  }
9771
11538
  } catch (err) {
@@ -9854,8 +11621,8 @@ function checkNpmAudit(projectRoot) {
9854
11621
  function checkPackageJsonPatterns(projectRoot) {
9855
11622
  const findings = [];
9856
11623
  try {
9857
- const pkgPath = join17(projectRoot, "package.json");
9858
- const pkg = JSON.parse(readFileSync13(pkgPath, "utf-8"));
11624
+ const pkgPath = join19(projectRoot, "package.json");
11625
+ const pkg = JSON.parse(readFileSync15(pkgPath, "utf-8"));
9859
11626
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
9860
11627
  for (const [name, version] of Object.entries(allDeps)) {
9861
11628
  if (version.startsWith("^") || version.startsWith("~")) {
@@ -9877,15 +11644,15 @@ function checkPackageJsonPatterns(projectRoot) {
9877
11644
  }
9878
11645
  function checkPostinstallScripts(projectRoot) {
9879
11646
  const findings = [];
9880
- const nodeModules = join17(projectRoot, "node_modules");
9881
- if (!existsSync14(nodeModules)) return findings;
11647
+ const nodeModules = join19(projectRoot, "node_modules");
11648
+ if (!existsSync16(nodeModules)) return findings;
9882
11649
  try {
9883
- const topLevelDeps = readdirSync6(nodeModules).filter((d) => !d.startsWith("."));
11650
+ const topLevelDeps = readdirSync8(nodeModules).filter((d) => !d.startsWith("."));
9884
11651
  for (const dep of topLevelDeps) {
9885
- const depPkgPath = join17(nodeModules, dep, "package.json");
9886
- if (!existsSync14(depPkgPath)) continue;
11652
+ const depPkgPath = join19(nodeModules, dep, "package.json");
11653
+ if (!existsSync16(depPkgPath)) continue;
9887
11654
  try {
9888
- const depPkg = JSON.parse(readFileSync13(depPkgPath, "utf-8"));
11655
+ const depPkg = JSON.parse(readFileSync15(depPkgPath, "utf-8"));
9889
11656
  const scripts = depPkg.scripts || {};
9890
11657
  if (scripts.postinstall || scripts.preinstall || scripts.install) {
9891
11658
  const scriptName = scripts.postinstall ? "postinstall" : scripts.preinstall ? "preinstall" : "install";
@@ -9923,7 +11690,7 @@ function checkPipAudit(projectRoot) {
9923
11690
  id: "",
9924
11691
  severity: cvssToSeverity(vuln.cvss?.score || 5),
9925
11692
  vulnerabilityClass: "dependency-cve",
9926
- file: existsSync14(join17(projectRoot, "requirements.txt")) ? "requirements.txt" : "pyproject.toml",
11693
+ file: existsSync16(join19(projectRoot, "requirements.txt")) ? "requirements.txt" : "pyproject.toml",
9927
11694
  title: `Vulnerable Python dependency: ${vuln.name}`,
9928
11695
  description: `${vuln.name}@${vuln.version} \u2014 ${vuln.id}: ${vuln.description || "Known vulnerability"}`,
9929
11696
  attackScenario: `An attacker could exploit the vulnerability in ${vuln.name}.`,
@@ -10020,8 +11787,8 @@ function checkGoVerify(projectRoot) {
10020
11787
  }
10021
11788
 
10022
11789
  // src/security/checks/injection.ts
10023
- import { readFileSync as readFileSync14 } from "fs";
10024
- import { join as join18 } from "path";
11790
+ import { readFileSync as readFileSync16 } from "fs";
11791
+ import { join as join20 } from "path";
10025
11792
  var SKIP_DIRS = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
10026
11793
  var TEST_PATTERNS = ["test", "spec", "fixture", "mock", "__tests__", "__mocks__"];
10027
11794
  var USER_INPUT_NAMES = /(?:input|user|name|path|query|branch|hash|cmd|command|req\.|params|body|args|url|dir|file|subdirectory)/i;
@@ -10106,6 +11873,107 @@ var PATTERNS = [
10106
11873
  description: "Database query built using fmt.Sprintf directly passed to db.Query.",
10107
11874
  attackScenario: "An attacker could inject SQL through interpolated values.",
10108
11875
  suggestedFix: 'Use parameterized queries: db.Query("SELECT ... WHERE id = ?", id)'
11876
+ },
11877
+ // Java-specific injection patterns
11878
+ {
11879
+ regex: /(?:executeQuery|executeUpdate|execute)\s*\(\s*["']?\s*(?:SELECT|INSERT|UPDATE|DELETE)\b[^"']*["']?\s*\+/i,
11880
+ title: "Java SQL injection via string concatenation",
11881
+ vulnClass: "code-injection",
11882
+ baseSeverity: "high",
11883
+ description: "SQL query built using string concatenation \u2014 vulnerable to SQL injection.",
11884
+ attackScenario: "An attacker could inject SQL through concatenated user input to read, modify, or delete database data.",
11885
+ suggestedFix: "Use PreparedStatement with parameterized queries: preparedStatement.setString(1, userInput)"
11886
+ },
11887
+ {
11888
+ regex: /Runtime\.getRuntime\(\)\.exec\s*\(/,
11889
+ title: "Java command injection via Runtime.exec",
11890
+ vulnClass: "shell-injection",
11891
+ baseSeverity: "high",
11892
+ description: "Runtime.exec() executes a system command \u2014 vulnerable if user input reaches the argument.",
11893
+ attackScenario: "An attacker could inject shell metacharacters to execute arbitrary commands on the server.",
11894
+ suggestedFix: "Use ProcessBuilder with an argument array. Validate all input against a strict allowlist."
11895
+ },
11896
+ {
11897
+ regex: /new\s+ProcessBuilder\s*\([^)]*(?:input|user|param|query|request|body|arg)/i,
11898
+ title: "Java command injection via ProcessBuilder with user input",
11899
+ vulnClass: "shell-injection",
11900
+ baseSeverity: "medium",
11901
+ description: "ProcessBuilder called with arguments that may originate from user input.",
11902
+ attackScenario: "An attacker could inject malicious arguments to the spawned process.",
11903
+ suggestedFix: "Validate all arguments against a strict allowlist before passing to ProcessBuilder."
11904
+ },
11905
+ {
11906
+ regex: /new\s+ObjectInputStream\s*\(/,
11907
+ title: "Java insecure deserialization via ObjectInputStream",
11908
+ vulnClass: "code-injection",
11909
+ baseSeverity: "high",
11910
+ description: "ObjectInputStream.readObject() deserializes arbitrary Java objects \u2014 potential RCE.",
11911
+ attackScenario: "An attacker could craft a malicious serialized object to achieve remote code execution.",
11912
+ suggestedFix: "Use a whitelist-based ObjectInputFilter, or switch to JSON/Protobuf for data exchange."
11913
+ },
11914
+ {
11915
+ regex: /DocumentBuilderFactory\.newInstance\(\)/,
11916
+ title: "Java XML External Entity (XXE) risk",
11917
+ vulnClass: "code-injection",
11918
+ baseSeverity: "medium",
11919
+ description: "DocumentBuilderFactory without FEATURE_SECURE_PROCESSING may allow XXE attacks.",
11920
+ attackScenario: "An attacker could inject external entity references in XML to read server files or perform SSRF.",
11921
+ suggestedFix: "Set FEATURE_SECURE_PROCESSING and disable external DTDs/entities: factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true)"
11922
+ },
11923
+ {
11924
+ regex: /\.csrf\(\)\s*\.\s*disable\(\)/,
11925
+ title: "Spring Security CSRF protection disabled",
11926
+ vulnClass: "code-injection",
11927
+ baseSeverity: "medium",
11928
+ description: "CSRF protection has been explicitly disabled in Spring Security configuration.",
11929
+ attackScenario: "An attacker could forge cross-site requests to perform actions on behalf of authenticated users.",
11930
+ suggestedFix: "Only disable CSRF for stateless APIs using JWT. Keep CSRF enabled for session-based authentication."
11931
+ },
11932
+ {
11933
+ regex: /\.permitAll\(\).*(?:admin|manage|delete|config|setting)/i,
11934
+ title: "Spring Security permitAll on sensitive path",
11935
+ vulnClass: "code-injection",
11936
+ baseSeverity: "high",
11937
+ description: "permitAll() applied to a path that appears security-sensitive.",
11938
+ attackScenario: "An attacker could access administrative or destructive endpoints without authentication.",
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."
10109
11977
  }
10110
11978
  ];
10111
11979
  function shouldSkip(filePath) {
@@ -10122,7 +11990,7 @@ async function checkInjection(files, projectRoot) {
10122
11990
  if (shouldSkip(file.filePath) || isTestFile4(file.filePath)) continue;
10123
11991
  let content;
10124
11992
  try {
10125
- content = readFileSync14(join18(projectRoot, file.filePath), "utf-8");
11993
+ content = readFileSync16(join20(projectRoot, file.filePath), "utf-8");
10126
11994
  } catch {
10127
11995
  continue;
10128
11996
  }
@@ -10160,8 +12028,8 @@ async function checkInjection(files, projectRoot) {
10160
12028
  }
10161
12029
 
10162
12030
  // src/security/checks/secrets.ts
10163
- import { readFileSync as readFileSync15 } from "fs";
10164
- import { join as join19 } from "path";
12031
+ import { readFileSync as readFileSync17 } from "fs";
12032
+ import { join as join21 } from "path";
10165
12033
  var SKIP_DIRS2 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
10166
12034
  var TEST_PATTERNS2 = ["test", "spec", "fixture", "mock", "__tests__", "__mocks__", ".example", ".sample"];
10167
12035
  var SECRET_PATTERNS = [
@@ -10194,7 +12062,7 @@ async function checkSecrets(files, projectRoot) {
10194
12062
  if (shouldSkip2(file.filePath) || isTestFile5(file.filePath)) continue;
10195
12063
  let content;
10196
12064
  try {
10197
- content = readFileSync15(join19(projectRoot, file.filePath), "utf-8");
12065
+ content = readFileSync17(join21(projectRoot, file.filePath), "utf-8");
10198
12066
  } catch {
10199
12067
  continue;
10200
12068
  }
@@ -10227,8 +12095,8 @@ async function checkSecrets(files, projectRoot) {
10227
12095
  }
10228
12096
 
10229
12097
  // src/security/checks/path-traversal.ts
10230
- import { readFileSync as readFileSync16 } from "fs";
10231
- import { join as join20 } from "path";
12098
+ import { readFileSync as readFileSync18 } from "fs";
12099
+ import { join as join22 } from "path";
10232
12100
  var SKIP_DIRS3 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
10233
12101
  var USER_INPUT_VARS = /(?:req\.|params|query|body|input|path|dir|subdirectory|file|userInput|fileName|filePath)/i;
10234
12102
  var PATTERNS2 = [
@@ -10275,7 +12143,7 @@ async function checkPathTraversal(files, projectRoot) {
10275
12143
  if (shouldSkip3(file.filePath)) continue;
10276
12144
  let content;
10277
12145
  try {
10278
- content = readFileSync16(join20(projectRoot, file.filePath), "utf-8");
12146
+ content = readFileSync18(join22(projectRoot, file.filePath), "utf-8");
10279
12147
  } catch {
10280
12148
  continue;
10281
12149
  }
@@ -10317,8 +12185,8 @@ async function checkPathTraversal(files, projectRoot) {
10317
12185
  }
10318
12186
 
10319
12187
  // src/security/checks/auth.ts
10320
- import { readFileSync as readFileSync17 } from "fs";
10321
- import { join as join21 } from "path";
12188
+ import { readFileSync as readFileSync19 } from "fs";
12189
+ import { join as join23 } from "path";
10322
12190
  var SKIP_DIRS4 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
10323
12191
  function shouldSkip4(filePath) {
10324
12192
  return SKIP_DIRS4.some((d) => filePath.includes(d));
@@ -10334,7 +12202,7 @@ async function checkAuth(files, projectRoot) {
10334
12202
  if (shouldSkip4(file.filePath)) continue;
10335
12203
  let content;
10336
12204
  try {
10337
- content = readFileSync17(join21(projectRoot, file.filePath), "utf-8");
12205
+ content = readFileSync19(join23(projectRoot, file.filePath), "utf-8");
10338
12206
  } catch {
10339
12207
  continue;
10340
12208
  }
@@ -10425,8 +12293,8 @@ async function checkAuth(files, projectRoot) {
10425
12293
  }
10426
12294
 
10427
12295
  // src/security/checks/input-validation.ts
10428
- import { readFileSync as readFileSync18 } from "fs";
10429
- import { join as join22 } from "path";
12296
+ import { readFileSync as readFileSync20 } from "fs";
12297
+ import { join as join24 } from "path";
10430
12298
  var SKIP_DIRS5 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
10431
12299
  function shouldSkip5(filePath) {
10432
12300
  return SKIP_DIRS5.some((d) => filePath.includes(d));
@@ -10438,7 +12306,7 @@ async function checkInputValidation(files, projectRoot) {
10438
12306
  if (shouldSkip5(file.filePath)) continue;
10439
12307
  let content;
10440
12308
  try {
10441
- content = readFileSync18(join22(projectRoot, file.filePath), "utf-8");
12309
+ content = readFileSync20(join24(projectRoot, file.filePath), "utf-8");
10442
12310
  } catch {
10443
12311
  continue;
10444
12312
  }
@@ -10515,8 +12383,8 @@ async function checkInputValidation(files, projectRoot) {
10515
12383
  }
10516
12384
 
10517
12385
  // src/security/checks/information-disclosure.ts
10518
- import { readFileSync as readFileSync19 } from "fs";
10519
- import { join as join23 } from "path";
12386
+ import { readFileSync as readFileSync21 } from "fs";
12387
+ import { join as join25 } from "path";
10520
12388
  var SKIP_DIRS6 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
10521
12389
  function shouldSkip6(filePath) {
10522
12390
  return SKIP_DIRS6.some((d) => filePath.includes(d));
@@ -10528,7 +12396,7 @@ async function checkInformationDisclosure(files, projectRoot) {
10528
12396
  if (shouldSkip6(file.filePath)) continue;
10529
12397
  let content;
10530
12398
  try {
10531
- content = readFileSync19(join23(projectRoot, file.filePath), "utf-8");
12399
+ content = readFileSync21(join25(projectRoot, file.filePath), "utf-8");
10532
12400
  } catch {
10533
12401
  continue;
10534
12402
  }
@@ -10598,9 +12466,10 @@ async function checkInformationDisclosure(files, projectRoot) {
10598
12466
  }
10599
12467
 
10600
12468
  // src/security/checks/cryptography.ts
10601
- import { readFileSync as readFileSync20 } from "fs";
10602
- import { join as join24 } from "path";
12469
+ import { readFileSync as readFileSync22 } from "fs";
12470
+ import { join as join26 } from "path";
10603
12471
  var SKIP_DIRS7 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
12472
+ var USER_INPUT_NAMES2 = /(?:input|user|name|path|query|param|request|body|args|url)/i;
10604
12473
  function shouldSkip7(filePath) {
10605
12474
  return SKIP_DIRS7.some((d) => filePath.includes(d));
10606
12475
  }
@@ -10615,7 +12484,7 @@ async function checkCryptography(files, projectRoot) {
10615
12484
  if (shouldSkip7(file.filePath)) continue;
10616
12485
  let content;
10617
12486
  try {
10618
- content = readFileSync20(join24(projectRoot, file.filePath), "utf-8");
12487
+ content = readFileSync22(join26(projectRoot, file.filePath), "utf-8");
10619
12488
  } catch {
10620
12489
  continue;
10621
12490
  }
@@ -10624,7 +12493,7 @@ async function checkCryptography(files, projectRoot) {
10624
12493
  for (let i = 0; i < lines.length; i++) {
10625
12494
  const line = lines[i];
10626
12495
  if (line.trimStart().startsWith("//") || line.trimStart().startsWith("#")) continue;
10627
- if (/createHash\s*\(\s*['"]md5['"]\s*\)/.test(line) || /hashlib\.md5\s*\(/.test(line)) {
12496
+ if (/createHash\s*\(\s*['"]md5['"]\s*\)/.test(line) || /hashlib\.md5\s*\(/.test(line) || /MessageDigest\.getInstance\s*\(\s*["']MD5["']\s*\)/.test(line)) {
10628
12497
  findings.push({
10629
12498
  id: "",
10630
12499
  severity: isCryptoFile ? "high" : "medium",
@@ -10637,7 +12506,7 @@ async function checkCryptography(files, projectRoot) {
10637
12506
  suggestedFix: "Use SHA-256 or SHA-3 for integrity checks. Use bcrypt, scrypt, or argon2 for password hashing."
10638
12507
  });
10639
12508
  }
10640
- if (/createHash\s*\(\s*['"]sha1['"]\s*\)/.test(line) || /hashlib\.sha1\s*\(/.test(line)) {
12509
+ if (/createHash\s*\(\s*['"]sha1['"]\s*\)/.test(line) || /hashlib\.sha1\s*\(/.test(line) || /MessageDigest\.getInstance\s*\(\s*["']SHA-?1["']\s*\)/.test(line)) {
10641
12510
  findings.push({
10642
12511
  id: "",
10643
12512
  severity: isCryptoFile ? "high" : "medium",
@@ -10650,6 +12519,34 @@ async function checkCryptography(files, projectRoot) {
10650
12519
  suggestedFix: "Use SHA-256 or SHA-3 for integrity checks. Use bcrypt, scrypt, or argon2 for password hashing."
10651
12520
  });
10652
12521
  }
12522
+ if (/Cipher\.getInstance\s*\(\s*["']DES/.test(line)) {
12523
+ findings.push({
12524
+ id: "",
12525
+ severity: "high",
12526
+ vulnerabilityClass: "cryptography",
12527
+ file: file.filePath,
12528
+ line: i + 1,
12529
+ title: "Weak cipher algorithm: DES",
12530
+ description: "DES uses a 56-bit key and can be brute-forced in hours.",
12531
+ attackScenario: "An attacker could brute-force DES-encrypted data to reveal plaintext.",
12532
+ suggestedFix: 'Use AES-256 with GCM mode: Cipher.getInstance("AES/GCM/NoPadding")'
12533
+ });
12534
+ }
12535
+ if (/(?:log|logger|LOG)\s*\.\s*(?:info|debug|warn|error|trace)\s*\([^)]*\+/.test(line)) {
12536
+ if (USER_INPUT_NAMES2.test(line)) {
12537
+ findings.push({
12538
+ id: "",
12539
+ severity: "medium",
12540
+ vulnerabilityClass: "cryptography",
12541
+ file: file.filePath,
12542
+ line: i + 1,
12543
+ title: "Potential log injection",
12544
+ description: "User-controlled input concatenated directly into log output.",
12545
+ attackScenario: "An attacker could inject newlines or control characters to forge log entries or hide malicious activity.",
12546
+ suggestedFix: 'Use parameterized logging: log.info("User: {}", userInput) instead of string concatenation.'
12547
+ });
12548
+ }
12549
+ }
10653
12550
  if (/Math\.random\(\)/.test(line) && isCryptoFile) {
10654
12551
  findings.push({
10655
12552
  id: "",
@@ -10689,6 +12586,32 @@ async function checkCryptography(files, projectRoot) {
10689
12586
  suggestedFix: "Generate a unique random salt per user using crypto.randomBytes(16)."
10690
12587
  });
10691
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
+ }
10692
12615
  }
10693
12616
  }
10694
12617
  } catch {
@@ -10697,8 +12620,8 @@ async function checkCryptography(files, projectRoot) {
10697
12620
  }
10698
12621
 
10699
12622
  // src/security/checks/frontend.ts
10700
- import { readFileSync as readFileSync21 } from "fs";
10701
- import { join as join25 } from "path";
12623
+ import { readFileSync as readFileSync23 } from "fs";
12624
+ import { join as join27 } from "path";
10702
12625
  var SKIP_DIRS8 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
10703
12626
  function shouldSkip8(filePath) {
10704
12627
  return SKIP_DIRS8.some((d) => filePath.includes(d));
@@ -10714,7 +12637,7 @@ async function checkFrontend(files, projectRoot) {
10714
12637
  if (!isFrontendFile(file.filePath)) continue;
10715
12638
  let content;
10716
12639
  try {
10717
- content = readFileSync21(join25(projectRoot, file.filePath), "utf-8");
12640
+ content = readFileSync23(join27(projectRoot, file.filePath), "utf-8");
10718
12641
  } catch {
10719
12642
  continue;
10720
12643
  }
@@ -11174,11 +13097,13 @@ async function scanSecurity(projectRoot, graph, options = {}) {
11174
13097
  };
11175
13098
  }
11176
13099
  function detectPackageManager(projectRoot) {
11177
- if (existsSync15(join26(projectRoot, "package.json"))) return "npm";
11178
- if (existsSync15(join26(projectRoot, "requirements.txt"))) return "pip";
11179
- if (existsSync15(join26(projectRoot, "pyproject.toml"))) return "pip";
11180
- if (existsSync15(join26(projectRoot, "Cargo.toml"))) return "cargo";
11181
- if (existsSync15(join26(projectRoot, "go.mod"))) return "go";
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";
11182
13107
  return "unknown";
11183
13108
  }
11184
13109