arcvision 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1690 -439
- package/package.json +12 -2
- package/arcvision.context.json +0 -7870
- package/docs/blast-radius-implementation.md +0 -76
- package/docs/blast-radius.md +0 -44
- package/output1.json +0 -281
- package/output2.json +0 -281
- package/scan_output.txt +0 -0
- package/schema/arcvision_context_schema_v1.json +0 -84
- package/src/core/blastRadius.js +0 -249
- package/src/core/parser.js +0 -343
- package/src/core/path-resolver.js +0 -174
- package/src/core/scanner.js +0 -492
- package/src/core/tsconfig-utils.js +0 -35
- package/src/core/watcher.js +0 -18
- package/src/engine/context_builder.js +0 -130
- package/src/engine/context_sorter.js +0 -41
- package/src/engine/context_validator.js +0 -75
- package/src/engine/id-generator.js +0 -16
- package/src/index.js +0 -325
- package/src/plugins/express-plugin.js +0 -48
- package/src/plugins/plugin-manager.js +0 -58
- package/src/plugins/react-plugin.js +0 -54
- package/test/determinism-test.js +0 -65
package/dist/index.js
CHANGED
|
@@ -4582,6 +4582,124 @@ var require_source = __commonJS({
|
|
|
4582
4582
|
}
|
|
4583
4583
|
});
|
|
4584
4584
|
|
|
4585
|
+
// src/core/tsconfig-utils.js
|
|
4586
|
+
var require_tsconfig_utils = __commonJS({
|
|
4587
|
+
"src/core/tsconfig-utils.js"(exports2, module2) {
|
|
4588
|
+
var fs2 = require("fs");
|
|
4589
|
+
var path2 = require("path");
|
|
4590
|
+
function loadTSConfig(startDir) {
|
|
4591
|
+
let currentDir = startDir;
|
|
4592
|
+
const root = path2.parse(currentDir).root;
|
|
4593
|
+
while (currentDir) {
|
|
4594
|
+
const tsconfigPaths = [
|
|
4595
|
+
path2.join(currentDir, "tsconfig.json"),
|
|
4596
|
+
path2.join(currentDir, "jsconfig.json")
|
|
4597
|
+
];
|
|
4598
|
+
for (const tsconfigPath of tsconfigPaths) {
|
|
4599
|
+
if (fs2.existsSync(tsconfigPath)) {
|
|
4600
|
+
try {
|
|
4601
|
+
let content = fs2.readFileSync(tsconfigPath, "utf-8");
|
|
4602
|
+
if (content.charCodeAt(0) === 65279)
|
|
4603
|
+
content = content.slice(1);
|
|
4604
|
+
let parsed = null;
|
|
4605
|
+
try {
|
|
4606
|
+
parsed = JSON.parse(content);
|
|
4607
|
+
} catch (e) {
|
|
4608
|
+
const stripped = content.replace(/\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*$/gm, "$1").replace(/,\s*([\]}])/g, "$1");
|
|
4609
|
+
parsed = JSON.parse(stripped);
|
|
4610
|
+
}
|
|
4611
|
+
if (parsed) {
|
|
4612
|
+
return {
|
|
4613
|
+
options: parsed.compilerOptions || {},
|
|
4614
|
+
configDir: currentDir
|
|
4615
|
+
};
|
|
4616
|
+
}
|
|
4617
|
+
} catch (error) {
|
|
4618
|
+
console.warn(`Warning: Could not parse ${tsconfigPath}:`, error.message);
|
|
4619
|
+
}
|
|
4620
|
+
}
|
|
4621
|
+
}
|
|
4622
|
+
if (currentDir === root)
|
|
4623
|
+
break;
|
|
4624
|
+
currentDir = path2.dirname(currentDir);
|
|
4625
|
+
}
|
|
4626
|
+
return { options: null, configDir: startDir };
|
|
4627
|
+
}
|
|
4628
|
+
module2.exports = { loadTSConfig };
|
|
4629
|
+
}
|
|
4630
|
+
});
|
|
4631
|
+
|
|
4632
|
+
// src/core/workspace-scanner.js
|
|
4633
|
+
var require_workspace_scanner = __commonJS({
|
|
4634
|
+
"src/core/workspace-scanner.js"(exports2, module2) {
|
|
4635
|
+
var fs2 = require("fs");
|
|
4636
|
+
var path2 = require("path");
|
|
4637
|
+
var { loadTSConfig } = require_tsconfig_utils();
|
|
4638
|
+
var WorkspaceScanner = class {
|
|
4639
|
+
constructor(rootPath) {
|
|
4640
|
+
this.rootPath = path2.resolve(rootPath);
|
|
4641
|
+
this.workspaceMap = /* @__PURE__ */ new Map();
|
|
4642
|
+
this.tsconfigMap = /* @__PURE__ */ new Map();
|
|
4643
|
+
}
|
|
4644
|
+
/**
|
|
4645
|
+
* Performs the scan and returns the context.
|
|
4646
|
+
* @returns {Object} { workspaceMap, tsconfigMap }
|
|
4647
|
+
*/
|
|
4648
|
+
scan() {
|
|
4649
|
+
console.log(`Starting workspace scan at ${this.rootPath}`);
|
|
4650
|
+
this._scanRecursively(this.rootPath);
|
|
4651
|
+
const sortedWorkspaceMap = new Map([...this.workspaceMap.entries()].sort());
|
|
4652
|
+
const sortedTsconfigMap = new Map([...this.tsconfigMap.entries()].sort());
|
|
4653
|
+
console.log(`Workspace scan complete. Found ${sortedWorkspaceMap.size} packages.`);
|
|
4654
|
+
return {
|
|
4655
|
+
workspaceMap: sortedWorkspaceMap,
|
|
4656
|
+
tsconfigMap: sortedTsconfigMap
|
|
4657
|
+
};
|
|
4658
|
+
}
|
|
4659
|
+
_scanRecursively(currentPath) {
|
|
4660
|
+
let entries;
|
|
4661
|
+
try {
|
|
4662
|
+
entries = fs2.readdirSync(currentPath, { withFileTypes: true });
|
|
4663
|
+
} catch (e) {
|
|
4664
|
+
console.error(`Failed to read directory ${currentPath}: ${e.message}`);
|
|
4665
|
+
return;
|
|
4666
|
+
}
|
|
4667
|
+
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
4668
|
+
const tsConfig = loadTSConfig(currentPath);
|
|
4669
|
+
if (tsConfig) {
|
|
4670
|
+
this.tsconfigMap.set(currentPath, tsConfig);
|
|
4671
|
+
}
|
|
4672
|
+
for (const entry of entries) {
|
|
4673
|
+
const fullPath = path2.join(currentPath, entry.name);
|
|
4674
|
+
if (entry.isDirectory()) {
|
|
4675
|
+
if (entry.name === "node_modules" || entry.name.startsWith(".")) {
|
|
4676
|
+
continue;
|
|
4677
|
+
}
|
|
4678
|
+
this._scanRecursively(fullPath);
|
|
4679
|
+
} else if (entry.name === "package.json") {
|
|
4680
|
+
this._processPackageJson(fullPath);
|
|
4681
|
+
}
|
|
4682
|
+
}
|
|
4683
|
+
}
|
|
4684
|
+
_processPackageJson(packageJsonPath) {
|
|
4685
|
+
try {
|
|
4686
|
+
const content = fs2.readFileSync(packageJsonPath, "utf-8");
|
|
4687
|
+
const pkg = JSON.parse(content);
|
|
4688
|
+
if (pkg.name) {
|
|
4689
|
+
if (this.workspaceMap.has(pkg.name)) {
|
|
4690
|
+
} else {
|
|
4691
|
+
this.workspaceMap.set(pkg.name, path2.dirname(packageJsonPath));
|
|
4692
|
+
}
|
|
4693
|
+
}
|
|
4694
|
+
} catch (e) {
|
|
4695
|
+
console.warn(`Failed to parse package.json at ${packageJsonPath}: ${e.message}`);
|
|
4696
|
+
}
|
|
4697
|
+
}
|
|
4698
|
+
};
|
|
4699
|
+
module2.exports = { WorkspaceScanner };
|
|
4700
|
+
}
|
|
4701
|
+
});
|
|
4702
|
+
|
|
4585
4703
|
// node_modules/balanced-match/index.js
|
|
4586
4704
|
var require_balanced_match = __commonJS({
|
|
4587
4705
|
"node_modules/balanced-match/index.js"(exports2, module2) {
|
|
@@ -56320,12 +56438,15 @@ var require_parser = __commonJS({
|
|
|
56320
56438
|
}
|
|
56321
56439
|
const metadata = {
|
|
56322
56440
|
id: filePath,
|
|
56441
|
+
ast,
|
|
56442
|
+
// Include AST for enhanced analyzers
|
|
56323
56443
|
imports: [],
|
|
56324
56444
|
exports: [],
|
|
56325
56445
|
functions: [],
|
|
56326
56446
|
apiCalls: [],
|
|
56327
56447
|
classes: [],
|
|
56328
56448
|
variables: [],
|
|
56449
|
+
types: [],
|
|
56329
56450
|
dependencies: []
|
|
56330
56451
|
};
|
|
56331
56452
|
traverse(ast, {
|
|
@@ -56419,6 +56540,18 @@ var require_parser = __commonJS({
|
|
|
56419
56540
|
});
|
|
56420
56541
|
}
|
|
56421
56542
|
});
|
|
56543
|
+
} else if (node.declaration.type === "TSInterfaceDeclaration" && node.declaration.id) {
|
|
56544
|
+
metadata.exports.push({
|
|
56545
|
+
name: node.declaration.id.name,
|
|
56546
|
+
type: "interface",
|
|
56547
|
+
loc: node.declaration.loc
|
|
56548
|
+
});
|
|
56549
|
+
} else if (node.declaration.type === "TSTypeAliasDeclaration" && node.declaration.id) {
|
|
56550
|
+
metadata.exports.push({
|
|
56551
|
+
name: node.declaration.id.name,
|
|
56552
|
+
type: "type",
|
|
56553
|
+
loc: node.declaration.loc
|
|
56554
|
+
});
|
|
56422
56555
|
}
|
|
56423
56556
|
}
|
|
56424
56557
|
},
|
|
@@ -56472,13 +56605,30 @@ var require_parser = __commonJS({
|
|
|
56472
56605
|
});
|
|
56473
56606
|
}
|
|
56474
56607
|
},
|
|
56475
|
-
ArrowFunctionExpression(
|
|
56608
|
+
ArrowFunctionExpression(path3) {
|
|
56609
|
+
const parent = path3.parent;
|
|
56610
|
+
if (parent.type === "VariableDeclarator" && parent.id.type === "Identifier") {
|
|
56611
|
+
metadata.functions.push({
|
|
56612
|
+
name: parent.id.name,
|
|
56613
|
+
params: path3.node.params.map((p) => p.name || "?"),
|
|
56614
|
+
loc: parent.loc
|
|
56615
|
+
});
|
|
56616
|
+
}
|
|
56617
|
+
},
|
|
56618
|
+
TSInterfaceDeclaration({ node }) {
|
|
56619
|
+
if (node.id && node.id.name) {
|
|
56620
|
+
metadata.types.push({
|
|
56621
|
+
name: node.id.name,
|
|
56622
|
+
kind: "interface",
|
|
56623
|
+
loc: node.loc
|
|
56624
|
+
});
|
|
56625
|
+
}
|
|
56476
56626
|
},
|
|
56477
|
-
|
|
56627
|
+
TSTypeAliasDeclaration({ node }) {
|
|
56478
56628
|
if (node.id && node.id.name) {
|
|
56479
|
-
metadata.
|
|
56629
|
+
metadata.types.push({
|
|
56480
56630
|
name: node.id.name,
|
|
56481
|
-
|
|
56631
|
+
kind: "type",
|
|
56482
56632
|
loc: node.loc
|
|
56483
56633
|
});
|
|
56484
56634
|
}
|
|
@@ -56486,11 +56636,23 @@ var require_parser = __commonJS({
|
|
|
56486
56636
|
VariableDeclaration({ node }) {
|
|
56487
56637
|
node.declarations.forEach((decl) => {
|
|
56488
56638
|
if (decl.id.name) {
|
|
56489
|
-
|
|
56639
|
+
const variableData = {
|
|
56490
56640
|
name: decl.id.name,
|
|
56491
56641
|
type: "variable",
|
|
56492
56642
|
loc: decl.loc
|
|
56493
|
-
}
|
|
56643
|
+
};
|
|
56644
|
+
if (decl.init && decl.init.type === "ObjectExpression") {
|
|
56645
|
+
variableData.properties = decl.init.properties.map((p) => {
|
|
56646
|
+
if (p.key && (p.key.name || p.key.value)) {
|
|
56647
|
+
return {
|
|
56648
|
+
name: p.key.name || p.key.value,
|
|
56649
|
+
loc: p.loc
|
|
56650
|
+
};
|
|
56651
|
+
}
|
|
56652
|
+
return null;
|
|
56653
|
+
}).filter(Boolean);
|
|
56654
|
+
}
|
|
56655
|
+
metadata.variables.push(variableData);
|
|
56494
56656
|
} else if (decl.id.type === "ObjectPattern") {
|
|
56495
56657
|
decl.id.properties.forEach((prop) => {
|
|
56496
56658
|
if (prop.key && prop.key.name) {
|
|
@@ -56553,9 +56715,27 @@ var require_parser = __commonJS({
|
|
|
56553
56715
|
},
|
|
56554
56716
|
VariableDeclarator({ node }) {
|
|
56555
56717
|
if (node.init && node.init.type === "CallExpression" && node.init.callee.name === "require" && node.init.arguments.length > 0 && node.init.arguments[0].type === "StringLiteral") {
|
|
56718
|
+
const specifiers = [];
|
|
56719
|
+
if (node.id.type === "ObjectPattern") {
|
|
56720
|
+
node.id.properties.forEach((prop) => {
|
|
56721
|
+
const importedName = prop.key && (prop.key.name || prop.key.value) || null;
|
|
56722
|
+
const localName = prop.value && prop.value.name || importedName;
|
|
56723
|
+
if (importedName) {
|
|
56724
|
+
specifiers.push({
|
|
56725
|
+
imported: importedName,
|
|
56726
|
+
local: localName
|
|
56727
|
+
});
|
|
56728
|
+
}
|
|
56729
|
+
});
|
|
56730
|
+
} else if (node.id.type === "Identifier") {
|
|
56731
|
+
specifiers.push({
|
|
56732
|
+
imported: "default",
|
|
56733
|
+
local: node.id.name
|
|
56734
|
+
});
|
|
56735
|
+
}
|
|
56556
56736
|
metadata.imports.push({
|
|
56557
56737
|
source: node.init.arguments[0].value,
|
|
56558
|
-
specifiers
|
|
56738
|
+
specifiers,
|
|
56559
56739
|
type: "require-assignment"
|
|
56560
56740
|
});
|
|
56561
56741
|
}
|
|
@@ -56569,6 +56749,688 @@ var require_parser = __commonJS({
|
|
|
56569
56749
|
}
|
|
56570
56750
|
});
|
|
56571
56751
|
|
|
56752
|
+
// src/core/di-detector.js
|
|
56753
|
+
var require_di_detector = __commonJS({
|
|
56754
|
+
"src/core/di-detector.js"(exports2, module2) {
|
|
56755
|
+
var traverse = require_lib8().default;
|
|
56756
|
+
function detectConstructorInjection(ast) {
|
|
56757
|
+
const injections = [];
|
|
56758
|
+
traverse(ast, {
|
|
56759
|
+
ClassDeclaration(path2) {
|
|
56760
|
+
const className = path2.node.id ? path2.node.id.name : "Anonymous";
|
|
56761
|
+
const constructor = path2.node.body.body.find(
|
|
56762
|
+
(member) => member.kind === "constructor"
|
|
56763
|
+
);
|
|
56764
|
+
if (constructor && constructor.params) {
|
|
56765
|
+
constructor.params.forEach((param) => {
|
|
56766
|
+
let paramName = null;
|
|
56767
|
+
let paramType = null;
|
|
56768
|
+
if (param.type === "TSParameterProperty") {
|
|
56769
|
+
if (param.parameter.type === "Identifier") {
|
|
56770
|
+
paramName = param.parameter.name;
|
|
56771
|
+
if (param.parameter.typeAnnotation) {
|
|
56772
|
+
paramType = extractTypeName(param.parameter.typeAnnotation);
|
|
56773
|
+
}
|
|
56774
|
+
}
|
|
56775
|
+
} else if (param.type === "Identifier") {
|
|
56776
|
+
paramName = param.name;
|
|
56777
|
+
if (param.typeAnnotation) {
|
|
56778
|
+
paramType = extractTypeName(param.typeAnnotation);
|
|
56779
|
+
}
|
|
56780
|
+
}
|
|
56781
|
+
if (paramName) {
|
|
56782
|
+
injections.push({
|
|
56783
|
+
className,
|
|
56784
|
+
paramName,
|
|
56785
|
+
paramType,
|
|
56786
|
+
pattern: "constructor_injection",
|
|
56787
|
+
loc: constructor.loc
|
|
56788
|
+
});
|
|
56789
|
+
}
|
|
56790
|
+
});
|
|
56791
|
+
}
|
|
56792
|
+
}
|
|
56793
|
+
});
|
|
56794
|
+
return injections;
|
|
56795
|
+
}
|
|
56796
|
+
function detectReactContextUsage(ast) {
|
|
56797
|
+
const contextUsages = [];
|
|
56798
|
+
traverse(ast, {
|
|
56799
|
+
// Detect useContext hook calls
|
|
56800
|
+
CallExpression(path2) {
|
|
56801
|
+
if (path2.node.callee.name === "useContext" && path2.node.arguments.length > 0) {
|
|
56802
|
+
const contextArg = path2.node.arguments[0];
|
|
56803
|
+
let contextName = null;
|
|
56804
|
+
if (contextArg.type === "Identifier") {
|
|
56805
|
+
contextName = contextArg.name;
|
|
56806
|
+
} else if (contextArg.type === "MemberExpression") {
|
|
56807
|
+
contextName = extractMemberExpressionName(contextArg);
|
|
56808
|
+
}
|
|
56809
|
+
if (contextName) {
|
|
56810
|
+
contextUsages.push({
|
|
56811
|
+
type: "useContext",
|
|
56812
|
+
contextName,
|
|
56813
|
+
pattern: "context_consumer",
|
|
56814
|
+
loc: path2.node.loc
|
|
56815
|
+
});
|
|
56816
|
+
}
|
|
56817
|
+
}
|
|
56818
|
+
},
|
|
56819
|
+
// Detect Context.Provider usage in JSX
|
|
56820
|
+
JSXElement(path2) {
|
|
56821
|
+
const openingElement = path2.node.openingElement;
|
|
56822
|
+
if (openingElement.name.type === "JSXMemberExpression") {
|
|
56823
|
+
const objectName = openingElement.name.object.name;
|
|
56824
|
+
const propertyName = openingElement.name.property.name;
|
|
56825
|
+
if (propertyName === "Provider" || propertyName === "Consumer") {
|
|
56826
|
+
contextUsages.push({
|
|
56827
|
+
type: "JSXProvider",
|
|
56828
|
+
contextName: objectName,
|
|
56829
|
+
pattern: propertyName === "Provider" ? "context_provider" : "context_consumer",
|
|
56830
|
+
loc: path2.node.loc
|
|
56831
|
+
});
|
|
56832
|
+
}
|
|
56833
|
+
}
|
|
56834
|
+
}
|
|
56835
|
+
});
|
|
56836
|
+
return contextUsages;
|
|
56837
|
+
}
|
|
56838
|
+
function detectHookDependencies(ast) {
|
|
56839
|
+
const hookDeps = [];
|
|
56840
|
+
traverse(ast, {
|
|
56841
|
+
CallExpression(path2) {
|
|
56842
|
+
const calleeName = path2.node.callee.name;
|
|
56843
|
+
if (calleeName && calleeName.startsWith("use") && calleeName !== "useContext") {
|
|
56844
|
+
hookDeps.push({
|
|
56845
|
+
hookName: calleeName,
|
|
56846
|
+
pattern: "custom_hook",
|
|
56847
|
+
loc: path2.node.loc
|
|
56848
|
+
});
|
|
56849
|
+
}
|
|
56850
|
+
}
|
|
56851
|
+
});
|
|
56852
|
+
return hookDeps;
|
|
56853
|
+
}
|
|
56854
|
+
function detectDependencyInjection(ast) {
|
|
56855
|
+
if (!ast) {
|
|
56856
|
+
return {
|
|
56857
|
+
constructorInjections: [],
|
|
56858
|
+
contextUsages: [],
|
|
56859
|
+
hookDependencies: []
|
|
56860
|
+
};
|
|
56861
|
+
}
|
|
56862
|
+
return {
|
|
56863
|
+
constructorInjections: detectConstructorInjection(ast),
|
|
56864
|
+
contextUsages: detectReactContextUsage(ast),
|
|
56865
|
+
hookDependencies: detectHookDependencies(ast)
|
|
56866
|
+
};
|
|
56867
|
+
}
|
|
56868
|
+
function extractTypeName(typeAnnotation) {
|
|
56869
|
+
if (!typeAnnotation)
|
|
56870
|
+
return null;
|
|
56871
|
+
const annotation = typeAnnotation.typeAnnotation || typeAnnotation;
|
|
56872
|
+
if (annotation.type === "TSTypeReference" && annotation.typeName) {
|
|
56873
|
+
if (annotation.typeName.type === "Identifier") {
|
|
56874
|
+
return annotation.typeName.name;
|
|
56875
|
+
}
|
|
56876
|
+
}
|
|
56877
|
+
return null;
|
|
56878
|
+
}
|
|
56879
|
+
function extractMemberExpressionName(node) {
|
|
56880
|
+
if (node.type === "MemberExpression") {
|
|
56881
|
+
const object = node.object.name || "";
|
|
56882
|
+
const property = node.property.name || "";
|
|
56883
|
+
return object + "." + property;
|
|
56884
|
+
}
|
|
56885
|
+
return null;
|
|
56886
|
+
}
|
|
56887
|
+
module2.exports = {
|
|
56888
|
+
detectConstructorInjection,
|
|
56889
|
+
detectReactContextUsage,
|
|
56890
|
+
detectHookDependencies,
|
|
56891
|
+
detectDependencyInjection
|
|
56892
|
+
};
|
|
56893
|
+
}
|
|
56894
|
+
});
|
|
56895
|
+
|
|
56896
|
+
// src/core/method-tracker.js
|
|
56897
|
+
var require_method_tracker = __commonJS({
|
|
56898
|
+
"src/core/method-tracker.js"(exports2, module2) {
|
|
56899
|
+
var traverse = require_lib8().default;
|
|
56900
|
+
function trackMethodCalls(ast, imports = []) {
|
|
56901
|
+
const functionCalls = [];
|
|
56902
|
+
const methodCalls = [];
|
|
56903
|
+
const constructorCalls = [];
|
|
56904
|
+
if (!ast) {
|
|
56905
|
+
return { functionCalls, methodCalls, constructorCalls };
|
|
56906
|
+
}
|
|
56907
|
+
const importedSymbols = /* @__PURE__ */ new Set();
|
|
56908
|
+
imports.forEach((imp) => {
|
|
56909
|
+
if (imp.specifiers && Array.isArray(imp.specifiers)) {
|
|
56910
|
+
imp.specifiers.forEach((spec) => {
|
|
56911
|
+
const localName = spec.local || spec.imported || spec;
|
|
56912
|
+
if (typeof localName === "string") {
|
|
56913
|
+
importedSymbols.add(localName);
|
|
56914
|
+
}
|
|
56915
|
+
});
|
|
56916
|
+
}
|
|
56917
|
+
});
|
|
56918
|
+
traverse(ast, {
|
|
56919
|
+
CallExpression(path2) {
|
|
56920
|
+
const callee = path2.node.callee;
|
|
56921
|
+
if (callee.type === "Identifier") {
|
|
56922
|
+
const functionName = callee.name;
|
|
56923
|
+
functionCalls.push({
|
|
56924
|
+
name: functionName,
|
|
56925
|
+
type: "function_call",
|
|
56926
|
+
loc: path2.node.loc
|
|
56927
|
+
});
|
|
56928
|
+
} else if (callee.type === "MemberExpression") {
|
|
56929
|
+
const objectName = extractObjectName(callee.object);
|
|
56930
|
+
const methodName = callee.property.name || callee.property.value;
|
|
56931
|
+
if (objectName && methodName) {
|
|
56932
|
+
methodCalls.push({
|
|
56933
|
+
object: objectName,
|
|
56934
|
+
method: methodName,
|
|
56935
|
+
type: "method_call",
|
|
56936
|
+
loc: path2.node.loc
|
|
56937
|
+
});
|
|
56938
|
+
}
|
|
56939
|
+
}
|
|
56940
|
+
},
|
|
56941
|
+
// Track constructor calls: new ClassName()
|
|
56942
|
+
NewExpression(path2) {
|
|
56943
|
+
const callee = path2.node.callee;
|
|
56944
|
+
if (callee.type === "Identifier") {
|
|
56945
|
+
const className = callee.name;
|
|
56946
|
+
constructorCalls.push({
|
|
56947
|
+
className,
|
|
56948
|
+
type: "constructor_call",
|
|
56949
|
+
loc: path2.node.loc
|
|
56950
|
+
});
|
|
56951
|
+
}
|
|
56952
|
+
}
|
|
56953
|
+
});
|
|
56954
|
+
return {
|
|
56955
|
+
functionCalls,
|
|
56956
|
+
methodCalls,
|
|
56957
|
+
constructorCalls
|
|
56958
|
+
};
|
|
56959
|
+
}
|
|
56960
|
+
function buildCallGraph(nodes) {
|
|
56961
|
+
const callEdges = [];
|
|
56962
|
+
nodes.forEach((node) => {
|
|
56963
|
+
const filePath = node.id;
|
|
56964
|
+
const metadata = node.metadata;
|
|
56965
|
+
if (!metadata)
|
|
56966
|
+
return;
|
|
56967
|
+
if (metadata.functionCalls && Array.isArray(metadata.functionCalls)) {
|
|
56968
|
+
metadata.functionCalls.forEach((call) => {
|
|
56969
|
+
callEdges.push({
|
|
56970
|
+
source: filePath,
|
|
56971
|
+
callType: "function",
|
|
56972
|
+
calledSymbol: call.name,
|
|
56973
|
+
loc: call.loc
|
|
56974
|
+
});
|
|
56975
|
+
});
|
|
56976
|
+
}
|
|
56977
|
+
if (metadata.constructorCalls && Array.isArray(metadata.constructorCalls)) {
|
|
56978
|
+
metadata.constructorCalls.forEach((call) => {
|
|
56979
|
+
callEdges.push({
|
|
56980
|
+
source: filePath,
|
|
56981
|
+
callType: "constructor",
|
|
56982
|
+
calledSymbol: call.className,
|
|
56983
|
+
loc: call.loc
|
|
56984
|
+
});
|
|
56985
|
+
});
|
|
56986
|
+
}
|
|
56987
|
+
if (metadata.methodCalls && Array.isArray(metadata.methodCalls)) {
|
|
56988
|
+
metadata.methodCalls.forEach((call) => {
|
|
56989
|
+
callEdges.push({
|
|
56990
|
+
source: filePath,
|
|
56991
|
+
callType: "method",
|
|
56992
|
+
calledSymbol: `${call.object}.${call.method}`,
|
|
56993
|
+
loc: call.loc
|
|
56994
|
+
});
|
|
56995
|
+
});
|
|
56996
|
+
}
|
|
56997
|
+
});
|
|
56998
|
+
return callEdges;
|
|
56999
|
+
}
|
|
57000
|
+
function extractObjectName(node) {
|
|
57001
|
+
if (node.type === "Identifier") {
|
|
57002
|
+
return node.name;
|
|
57003
|
+
} else if (node.type === "ThisExpression") {
|
|
57004
|
+
return "this";
|
|
57005
|
+
} else if (node.type === "MemberExpression") {
|
|
57006
|
+
const object = extractObjectName(node.object);
|
|
57007
|
+
const property = node.property.name || node.property.value;
|
|
57008
|
+
return object && property ? `${object}.${property}` : object;
|
|
57009
|
+
}
|
|
57010
|
+
return null;
|
|
57011
|
+
}
|
|
57012
|
+
module2.exports = {
|
|
57013
|
+
trackMethodCalls,
|
|
57014
|
+
buildCallGraph
|
|
57015
|
+
};
|
|
57016
|
+
}
|
|
57017
|
+
});
|
|
57018
|
+
|
|
57019
|
+
// src/core/type-analyzer.js
|
|
57020
|
+
var require_type_analyzer = __commonJS({
|
|
57021
|
+
"src/core/type-analyzer.js"(exports2, module2) {
|
|
57022
|
+
var traverse = require_lib8().default;
|
|
57023
|
+
function extractTypeImports(ast) {
|
|
57024
|
+
const typeImports = [];
|
|
57025
|
+
if (!ast)
|
|
57026
|
+
return typeImports;
|
|
57027
|
+
traverse(ast, {
|
|
57028
|
+
ImportDeclaration(path2) {
|
|
57029
|
+
const node = path2.node;
|
|
57030
|
+
if (node.importKind === "type") {
|
|
57031
|
+
const specifiers = [];
|
|
57032
|
+
node.specifiers.forEach((spec) => {
|
|
57033
|
+
if (spec.imported) {
|
|
57034
|
+
specifiers.push({
|
|
57035
|
+
imported: spec.imported.name || spec.imported.value,
|
|
57036
|
+
local: spec.local.name
|
|
57037
|
+
});
|
|
57038
|
+
}
|
|
57039
|
+
});
|
|
57040
|
+
typeImports.push({
|
|
57041
|
+
source: node.source.value,
|
|
57042
|
+
specifiers,
|
|
57043
|
+
importKind: "type",
|
|
57044
|
+
loc: node.loc
|
|
57045
|
+
});
|
|
57046
|
+
} else {
|
|
57047
|
+
const typeSpecifiers = [];
|
|
57048
|
+
node.specifiers.forEach((spec) => {
|
|
57049
|
+
if (spec.importKind === "type" && spec.imported) {
|
|
57050
|
+
typeSpecifiers.push({
|
|
57051
|
+
imported: spec.imported.name || spec.imported.value,
|
|
57052
|
+
local: spec.local.name
|
|
57053
|
+
});
|
|
57054
|
+
}
|
|
57055
|
+
});
|
|
57056
|
+
if (typeSpecifiers.length > 0) {
|
|
57057
|
+
typeImports.push({
|
|
57058
|
+
source: node.source.value,
|
|
57059
|
+
specifiers: typeSpecifiers,
|
|
57060
|
+
importKind: "mixed",
|
|
57061
|
+
loc: node.loc
|
|
57062
|
+
});
|
|
57063
|
+
}
|
|
57064
|
+
}
|
|
57065
|
+
}
|
|
57066
|
+
});
|
|
57067
|
+
return typeImports;
|
|
57068
|
+
}
|
|
57069
|
+
function extractInterfaceDependencies(ast) {
|
|
57070
|
+
const interfaceDeps = [];
|
|
57071
|
+
if (!ast)
|
|
57072
|
+
return interfaceDeps;
|
|
57073
|
+
traverse(ast, {
|
|
57074
|
+
// Interface extends
|
|
57075
|
+
TSInterfaceDeclaration(path2) {
|
|
57076
|
+
const node = path2.node;
|
|
57077
|
+
const interfaceName = node.id.name;
|
|
57078
|
+
if (node.extends && node.extends.length > 0) {
|
|
57079
|
+
node.extends.forEach((ext) => {
|
|
57080
|
+
const extendedInterface = extractTypeName(ext.expression);
|
|
57081
|
+
if (extendedInterface) {
|
|
57082
|
+
interfaceDeps.push({
|
|
57083
|
+
interface: interfaceName,
|
|
57084
|
+
extends: extendedInterface,
|
|
57085
|
+
type: "interface_extends",
|
|
57086
|
+
loc: node.loc
|
|
57087
|
+
});
|
|
57088
|
+
}
|
|
57089
|
+
});
|
|
57090
|
+
}
|
|
57091
|
+
},
|
|
57092
|
+
// Class implements
|
|
57093
|
+
ClassDeclaration(path2) {
|
|
57094
|
+
const node = path2.node;
|
|
57095
|
+
const className = node.id ? node.id.name : "Anonymous";
|
|
57096
|
+
if (node.implements && node.implements.length > 0) {
|
|
57097
|
+
node.implements.forEach((impl) => {
|
|
57098
|
+
const implementedInterface = extractTypeName(impl.expression);
|
|
57099
|
+
if (implementedInterface) {
|
|
57100
|
+
interfaceDeps.push({
|
|
57101
|
+
class: className,
|
|
57102
|
+
implements: implementedInterface,
|
|
57103
|
+
type: "class_implements",
|
|
57104
|
+
loc: node.loc
|
|
57105
|
+
});
|
|
57106
|
+
}
|
|
57107
|
+
});
|
|
57108
|
+
}
|
|
57109
|
+
}
|
|
57110
|
+
});
|
|
57111
|
+
return interfaceDeps;
|
|
57112
|
+
}
|
|
57113
|
+
function extractGenericDependencies(ast) {
|
|
57114
|
+
const genericDeps = [];
|
|
57115
|
+
if (!ast)
|
|
57116
|
+
return genericDeps;
|
|
57117
|
+
traverse(ast, {
|
|
57118
|
+
// Function return types
|
|
57119
|
+
FunctionDeclaration(path2) {
|
|
57120
|
+
const node = path2.node;
|
|
57121
|
+
const functionName = node.id ? node.id.name : "anonymous";
|
|
57122
|
+
if (node.returnType) {
|
|
57123
|
+
const returnTypeName = extractComplexTypeName(node.returnType.typeAnnotation);
|
|
57124
|
+
if (returnTypeName) {
|
|
57125
|
+
genericDeps.push({
|
|
57126
|
+
function: functionName,
|
|
57127
|
+
returnType: returnTypeName,
|
|
57128
|
+
type: "return_type",
|
|
57129
|
+
loc: node.loc
|
|
57130
|
+
});
|
|
57131
|
+
}
|
|
57132
|
+
}
|
|
57133
|
+
},
|
|
57134
|
+
// Arrow function return types
|
|
57135
|
+
ArrowFunctionExpression(path2) {
|
|
57136
|
+
const node = path2.node;
|
|
57137
|
+
if (node.returnType) {
|
|
57138
|
+
const returnTypeName = extractComplexTypeName(node.returnType.typeAnnotation);
|
|
57139
|
+
if (returnTypeName) {
|
|
57140
|
+
genericDeps.push({
|
|
57141
|
+
function: "arrow_function",
|
|
57142
|
+
returnType: returnTypeName,
|
|
57143
|
+
type: "return_type",
|
|
57144
|
+
loc: node.loc
|
|
57145
|
+
});
|
|
57146
|
+
}
|
|
57147
|
+
}
|
|
57148
|
+
},
|
|
57149
|
+
// Variable type annotations
|
|
57150
|
+
VariableDeclarator(path2) {
|
|
57151
|
+
const node = path2.node;
|
|
57152
|
+
const varName = node.id.name;
|
|
57153
|
+
if (node.id.typeAnnotation) {
|
|
57154
|
+
const typeName = extractComplexTypeName(node.id.typeAnnotation.typeAnnotation);
|
|
57155
|
+
if (typeName) {
|
|
57156
|
+
genericDeps.push({
|
|
57157
|
+
variable: varName,
|
|
57158
|
+
type: typeName,
|
|
57159
|
+
kind: "variable_type",
|
|
57160
|
+
loc: node.loc
|
|
57161
|
+
});
|
|
57162
|
+
}
|
|
57163
|
+
}
|
|
57164
|
+
}
|
|
57165
|
+
});
|
|
57166
|
+
return genericDeps;
|
|
57167
|
+
}
|
|
57168
|
+
function analyzeTypeDependencies(ast) {
|
|
57169
|
+
if (!ast) {
|
|
57170
|
+
return {
|
|
57171
|
+
typeImports: [],
|
|
57172
|
+
interfaceDependencies: [],
|
|
57173
|
+
genericDependencies: []
|
|
57174
|
+
};
|
|
57175
|
+
}
|
|
57176
|
+
return {
|
|
57177
|
+
typeImports: extractTypeImports(ast),
|
|
57178
|
+
interfaceDependencies: extractInterfaceDependencies(ast),
|
|
57179
|
+
genericDependencies: extractGenericDependencies(ast)
|
|
57180
|
+
};
|
|
57181
|
+
}
|
|
57182
|
+
function extractTypeName(node) {
|
|
57183
|
+
if (!node)
|
|
57184
|
+
return null;
|
|
57185
|
+
if (node.type === "Identifier") {
|
|
57186
|
+
return node.name;
|
|
57187
|
+
} else if (node.type === "TSTypeReference" && node.typeName) {
|
|
57188
|
+
if (node.typeName.type === "Identifier") {
|
|
57189
|
+
return node.typeName.name;
|
|
57190
|
+
}
|
|
57191
|
+
}
|
|
57192
|
+
return null;
|
|
57193
|
+
}
|
|
57194
|
+
function extractComplexTypeName(node) {
|
|
57195
|
+
if (!node)
|
|
57196
|
+
return null;
|
|
57197
|
+
if (node.type === "TSTypeReference" && node.typeName) {
|
|
57198
|
+
let baseName = extractTypeName(node);
|
|
57199
|
+
if (node.typeParameters && node.typeParameters.params) {
|
|
57200
|
+
const params = node.typeParameters.params.map((p) => extractComplexTypeName(p)).filter(Boolean).join(", ");
|
|
57201
|
+
if (params) {
|
|
57202
|
+
baseName += `<${params}>`;
|
|
57203
|
+
}
|
|
57204
|
+
}
|
|
57205
|
+
return baseName;
|
|
57206
|
+
} else if (node.type === "Identifier") {
|
|
57207
|
+
return node.name;
|
|
57208
|
+
} else if (node.type === "TSArrayType") {
|
|
57209
|
+
const elementType = extractComplexTypeName(node.elementType);
|
|
57210
|
+
return elementType ? `${elementType}[]` : null;
|
|
57211
|
+
}
|
|
57212
|
+
return null;
|
|
57213
|
+
}
|
|
57214
|
+
module2.exports = {
|
|
57215
|
+
extractTypeImports,
|
|
57216
|
+
extractInterfaceDependencies,
|
|
57217
|
+
extractGenericDependencies,
|
|
57218
|
+
analyzeTypeDependencies
|
|
57219
|
+
};
|
|
57220
|
+
}
|
|
57221
|
+
});
|
|
57222
|
+
|
|
57223
|
+
// src/core/react-nextjs-detector.js
|
|
57224
|
+
var require_react_nextjs_detector = __commonJS({
|
|
57225
|
+
"src/core/react-nextjs-detector.js"(exports2, module2) {
|
|
57226
|
+
var traverse = require_lib8().default;
|
|
57227
|
+
function detectComponentUsage(ast) {
|
|
57228
|
+
const componentUsages = [];
|
|
57229
|
+
if (!ast)
|
|
57230
|
+
return componentUsages;
|
|
57231
|
+
traverse(ast, {
|
|
57232
|
+
JSXElement(path2) {
|
|
57233
|
+
const openingElement = path2.node.openingElement;
|
|
57234
|
+
let componentName = null;
|
|
57235
|
+
if (openingElement.name.type === "JSXIdentifier") {
|
|
57236
|
+
componentName = openingElement.name.name;
|
|
57237
|
+
if (/^[A-Z]/.test(componentName)) {
|
|
57238
|
+
componentUsages.push({
|
|
57239
|
+
component: componentName,
|
|
57240
|
+
type: "jsx_component",
|
|
57241
|
+
loc: path2.node.loc
|
|
57242
|
+
});
|
|
57243
|
+
}
|
|
57244
|
+
} else if (openingElement.name.type === "JSXMemberExpression") {
|
|
57245
|
+
const object = openingElement.name.object.name;
|
|
57246
|
+
const property = openingElement.name.property.name;
|
|
57247
|
+
componentName = `${object}.${property}`;
|
|
57248
|
+
componentUsages.push({
|
|
57249
|
+
component: componentName,
|
|
57250
|
+
type: "jsx_member_component",
|
|
57251
|
+
loc: path2.node.loc
|
|
57252
|
+
});
|
|
57253
|
+
}
|
|
57254
|
+
}
|
|
57255
|
+
});
|
|
57256
|
+
return componentUsages;
|
|
57257
|
+
}
|
|
57258
|
+
function detectServerClientBoundaries(content) {
|
|
57259
|
+
const boundaries = {
|
|
57260
|
+
isClientComponent: false,
|
|
57261
|
+
isServerComponent: false,
|
|
57262
|
+
isServerAction: false
|
|
57263
|
+
};
|
|
57264
|
+
if (!content)
|
|
57265
|
+
return boundaries;
|
|
57266
|
+
if (/['"]use client['"]/.test(content)) {
|
|
57267
|
+
boundaries.isClientComponent = true;
|
|
57268
|
+
}
|
|
57269
|
+
if (/['"]use server['"]/.test(content)) {
|
|
57270
|
+
boundaries.isServerAction = true;
|
|
57271
|
+
}
|
|
57272
|
+
if (!boundaries.isClientComponent && !boundaries.isServerAction) {
|
|
57273
|
+
boundaries.isServerComponent = true;
|
|
57274
|
+
}
|
|
57275
|
+
return boundaries;
|
|
57276
|
+
}
|
|
57277
|
+
function detectAPIRouteDependencies(ast) {
|
|
57278
|
+
const apiDeps = [];
|
|
57279
|
+
if (!ast)
|
|
57280
|
+
return apiDeps;
|
|
57281
|
+
traverse(ast, {
|
|
57282
|
+
// Detect Next.js API route handlers: export async function GET/POST/etc
|
|
57283
|
+
ExportNamedDeclaration(path2) {
|
|
57284
|
+
const node = path2.node;
|
|
57285
|
+
if (node.declaration && node.declaration.type === "FunctionDeclaration") {
|
|
57286
|
+
const funcName = node.declaration.id ? node.declaration.id.name : null;
|
|
57287
|
+
if (["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"].includes(funcName)) {
|
|
57288
|
+
apiDeps.push({
|
|
57289
|
+
handler: funcName,
|
|
57290
|
+
type: "api_route_handler",
|
|
57291
|
+
loc: node.loc
|
|
57292
|
+
});
|
|
57293
|
+
}
|
|
57294
|
+
}
|
|
57295
|
+
},
|
|
57296
|
+
// Detect fetch calls and database queries within API routes
|
|
57297
|
+
CallExpression(path2) {
|
|
57298
|
+
const callee = path2.node.callee;
|
|
57299
|
+
if (callee.type === "MemberExpression") {
|
|
57300
|
+
const objectName = callee.object.name;
|
|
57301
|
+
const methodName = callee.property.name || callee.property.value;
|
|
57302
|
+
if (objectName === "supabase" || /supabase/i.test(objectName)) {
|
|
57303
|
+
apiDeps.push({
|
|
57304
|
+
service: "supabase",
|
|
57305
|
+
method: methodName,
|
|
57306
|
+
type: "database_query",
|
|
57307
|
+
loc: path2.node.loc
|
|
57308
|
+
});
|
|
57309
|
+
}
|
|
57310
|
+
if (objectName === "prisma" || /prisma/i.test(objectName)) {
|
|
57311
|
+
apiDeps.push({
|
|
57312
|
+
service: "prisma",
|
|
57313
|
+
method: methodName,
|
|
57314
|
+
type: "database_query",
|
|
57315
|
+
loc: path2.node.loc
|
|
57316
|
+
});
|
|
57317
|
+
}
|
|
57318
|
+
}
|
|
57319
|
+
}
|
|
57320
|
+
});
|
|
57321
|
+
return apiDeps;
|
|
57322
|
+
}
|
|
57323
|
+
function detectMiddlewareDependencies(ast, filePath = "") {
|
|
57324
|
+
const middlewareDeps = [];
|
|
57325
|
+
const isMiddleware = /middleware\.(ts|js)$/.test(filePath);
|
|
57326
|
+
if (!isMiddleware || !ast)
|
|
57327
|
+
return middlewareDeps;
|
|
57328
|
+
traverse(ast, {
|
|
57329
|
+
// Detect middleware function export
|
|
57330
|
+
ExportNamedDeclaration(path2) {
|
|
57331
|
+
const node = path2.node;
|
|
57332
|
+
if (node.declaration && node.declaration.type === "FunctionDeclaration") {
|
|
57333
|
+
const funcName = node.declaration.id ? node.declaration.id.name : null;
|
|
57334
|
+
if (funcName === "middleware") {
|
|
57335
|
+
middlewareDeps.push({
|
|
57336
|
+
function: funcName,
|
|
57337
|
+
type: "middleware_function",
|
|
57338
|
+
loc: node.loc
|
|
57339
|
+
});
|
|
57340
|
+
}
|
|
57341
|
+
}
|
|
57342
|
+
},
|
|
57343
|
+
// Detect auth checks and redirects
|
|
57344
|
+
CallExpression(path2) {
|
|
57345
|
+
const callee = path2.node.callee;
|
|
57346
|
+
if (callee.type === "MemberExpression") {
|
|
57347
|
+
const methodName = callee.property.name || callee.property.value;
|
|
57348
|
+
if (methodName === "getUser" || methodName === "getSession") {
|
|
57349
|
+
middlewareDeps.push({
|
|
57350
|
+
service: "auth",
|
|
57351
|
+
method: methodName,
|
|
57352
|
+
type: "auth_check",
|
|
57353
|
+
loc: path2.node.loc
|
|
57354
|
+
});
|
|
57355
|
+
}
|
|
57356
|
+
if (methodName === "redirect" || methodName === "rewrite") {
|
|
57357
|
+
middlewareDeps.push({
|
|
57358
|
+
service: "next",
|
|
57359
|
+
method: methodName,
|
|
57360
|
+
type: "middleware_action",
|
|
57361
|
+
loc: path2.node.loc
|
|
57362
|
+
});
|
|
57363
|
+
}
|
|
57364
|
+
}
|
|
57365
|
+
}
|
|
57366
|
+
});
|
|
57367
|
+
return middlewareDeps;
|
|
57368
|
+
}
|
|
57369
|
+
function detectReactNextJSPatterns(ast, content = "", filePath = "") {
|
|
57370
|
+
return {
|
|
57371
|
+
componentUsages: detectComponentUsage(ast),
|
|
57372
|
+
boundaries: detectServerClientBoundaries(content),
|
|
57373
|
+
apiDependencies: detectAPIRouteDependencies(ast),
|
|
57374
|
+
middlewareDependencies: detectMiddlewareDependencies(ast, filePath)
|
|
57375
|
+
};
|
|
57376
|
+
}
|
|
57377
|
+
module2.exports = {
|
|
57378
|
+
detectComponentUsage,
|
|
57379
|
+
detectServerClientBoundaries,
|
|
57380
|
+
detectAPIRouteDependencies,
|
|
57381
|
+
detectMiddlewareDependencies,
|
|
57382
|
+
detectReactNextJSPatterns
|
|
57383
|
+
};
|
|
57384
|
+
}
|
|
57385
|
+
});
|
|
57386
|
+
|
|
57387
|
+
// src/core/parser-enhanced.js
|
|
57388
|
+
var require_parser_enhanced = __commonJS({
|
|
57389
|
+
"src/core/parser-enhanced.js"(exports2, module2) {
|
|
57390
|
+
var { parseFile: originalParseFile } = require_parser();
|
|
57391
|
+
var { detectDependencyInjection } = require_di_detector();
|
|
57392
|
+
var { trackMethodCalls } = require_method_tracker();
|
|
57393
|
+
var { analyzeTypeDependencies } = require_type_analyzer();
|
|
57394
|
+
var { detectReactNextJSPatterns } = require_react_nextjs_detector();
|
|
57395
|
+
var fs2 = require("fs");
|
|
57396
|
+
function parseFileEnhanced(filePath) {
|
|
57397
|
+
const metadata = originalParseFile(filePath);
|
|
57398
|
+
if (!metadata.ast) {
|
|
57399
|
+
return metadata;
|
|
57400
|
+
}
|
|
57401
|
+
const ast = metadata.ast;
|
|
57402
|
+
const fileContent = fs2.readFileSync(filePath, "utf-8");
|
|
57403
|
+
try {
|
|
57404
|
+
const diPatterns = detectDependencyInjection(ast);
|
|
57405
|
+
metadata.constructorInjections = diPatterns.constructorInjections || [];
|
|
57406
|
+
metadata.contextUsages = diPatterns.contextUsages || [];
|
|
57407
|
+
metadata.hookDependencies = diPatterns.hookDependencies || [];
|
|
57408
|
+
const callTracking = trackMethodCalls(ast, metadata.imports);
|
|
57409
|
+
metadata.functionCalls = callTracking.functionCalls || [];
|
|
57410
|
+
metadata.constructorCalls = callTracking.constructorCalls || [];
|
|
57411
|
+
metadata.methodCalls = callTracking.methodCalls || [];
|
|
57412
|
+
const typeDeps = analyzeTypeDependencies(ast);
|
|
57413
|
+
metadata.typeImports = typeDeps.typeImports || [];
|
|
57414
|
+
metadata.interfaceDependencies = typeDeps.interfaceDependencies || [];
|
|
57415
|
+
metadata.genericDependencies = typeDeps.genericDependencies || [];
|
|
57416
|
+
const reactPatterns = detectReactNextJSPatterns(ast, fileContent, filePath);
|
|
57417
|
+
metadata.componentUsage = reactPatterns.componentUsages || [];
|
|
57418
|
+
metadata.serverClientBoundaries = reactPatterns.boundaries || {};
|
|
57419
|
+
metadata.apiDependencies = reactPatterns.apiDependencies || [];
|
|
57420
|
+
metadata.middlewareDependencies = reactPatterns.middlewareDependencies || [];
|
|
57421
|
+
} catch (error) {
|
|
57422
|
+
console.warn(`\u26A0\uFE0F Enhanced analysis failed for ${filePath}: ${error.message}`);
|
|
57423
|
+
}
|
|
57424
|
+
delete metadata.ast;
|
|
57425
|
+
return metadata;
|
|
57426
|
+
}
|
|
57427
|
+
module2.exports = {
|
|
57428
|
+
parseFile: parseFileEnhanced,
|
|
57429
|
+
parseFileBasic: originalParseFile
|
|
57430
|
+
};
|
|
57431
|
+
}
|
|
57432
|
+
});
|
|
57433
|
+
|
|
56572
57434
|
// src/plugins/plugin-manager.js
|
|
56573
57435
|
var require_plugin_manager = __commonJS({
|
|
56574
57436
|
"src/plugins/plugin-manager.js"(exports2, module2) {
|
|
@@ -56624,34 +57486,96 @@ var require_plugin_manager = __commonJS({
|
|
|
56624
57486
|
}
|
|
56625
57487
|
});
|
|
56626
57488
|
|
|
56627
|
-
// src/
|
|
56628
|
-
var
|
|
56629
|
-
"src/
|
|
56630
|
-
var
|
|
57489
|
+
// src/engine/pass1_facts.js
|
|
57490
|
+
var require_pass1_facts = __commonJS({
|
|
57491
|
+
"src/engine/pass1_facts.js"(exports2, module2) {
|
|
57492
|
+
var { glob } = require_commonjs5();
|
|
56631
57493
|
var path2 = require("path");
|
|
56632
|
-
|
|
56633
|
-
|
|
56634
|
-
|
|
56635
|
-
|
|
56636
|
-
|
|
56637
|
-
|
|
56638
|
-
|
|
56639
|
-
|
|
56640
|
-
|
|
56641
|
-
|
|
56642
|
-
|
|
57494
|
+
var fs2 = require("fs");
|
|
57495
|
+
var parser = require_parser_enhanced();
|
|
57496
|
+
var pluginManager = require_plugin_manager();
|
|
57497
|
+
async function executePass1(directory, options = {}) {
|
|
57498
|
+
console.log("\u{1F9F1} PASS 1: Syntactic Fact Extraction...");
|
|
57499
|
+
const normalize = (p) => p.replace(/\\/g, "/");
|
|
57500
|
+
const scanOptions = {
|
|
57501
|
+
ignore: ["**/node_modules/**", "**/.git/**", "**/dist/**", "**/build/**", ...options.ignore || []],
|
|
57502
|
+
cwd: directory,
|
|
57503
|
+
absolute: true
|
|
57504
|
+
};
|
|
57505
|
+
const pluginDir = path2.join(__dirname, "../plugins");
|
|
57506
|
+
if (fs2.existsSync(pluginDir)) {
|
|
57507
|
+
pluginManager.loadPluginsFromDirectory(pluginDir);
|
|
57508
|
+
}
|
|
57509
|
+
const files = await glob("**/*.{js,jsx,ts,tsx,json}", {
|
|
57510
|
+
...scanOptions,
|
|
57511
|
+
ignore: [...scanOptions.ignore, "**/*.d.ts", "**/.next/**", "**/coverage/**", "**/arcvision.context.json"]
|
|
57512
|
+
});
|
|
57513
|
+
const rawNodes = [];
|
|
57514
|
+
let totalFacts = 0;
|
|
57515
|
+
for (const file of files) {
|
|
57516
|
+
try {
|
|
57517
|
+
const relativePath = path2.relative(directory, file);
|
|
57518
|
+
const normalizedRelativePath = normalize(relativePath);
|
|
57519
|
+
let metadata = {};
|
|
57520
|
+
if (file.endsWith(".json")) {
|
|
57521
|
+
try {
|
|
57522
|
+
const content = fs2.readFileSync(file, "utf-8");
|
|
57523
|
+
JSON.parse(content);
|
|
57524
|
+
metadata = {
|
|
57525
|
+
id: file,
|
|
57526
|
+
isJson: true,
|
|
57527
|
+
// JSONs might have "imports" in semantic sense (like package.json), but raw syntax is just data
|
|
57528
|
+
raw: content
|
|
57529
|
+
};
|
|
57530
|
+
} catch (e) {
|
|
57531
|
+
console.warn(`\u26A0\uFE0F Invalid JSON in ${normalizedRelativePath}: ${e.message}`);
|
|
57532
|
+
continue;
|
|
56643
57533
|
}
|
|
56644
|
-
|
|
56645
|
-
|
|
56646
|
-
}
|
|
56647
|
-
|
|
56648
|
-
|
|
56649
|
-
|
|
57534
|
+
} else {
|
|
57535
|
+
metadata = parser.parseFile(file);
|
|
57536
|
+
}
|
|
57537
|
+
metadata = await pluginManager.processFile(file, metadata);
|
|
57538
|
+
const node = {
|
|
57539
|
+
id: normalizedRelativePath,
|
|
57540
|
+
// Unique ID for this pass
|
|
57541
|
+
filePath: file,
|
|
57542
|
+
type: "file",
|
|
57543
|
+
// The "facts" are the metadata properties
|
|
57544
|
+
facts: {
|
|
57545
|
+
imports: metadata.imports || [],
|
|
57546
|
+
exports: metadata.exports || [],
|
|
57547
|
+
functions: metadata.functions || [],
|
|
57548
|
+
classes: metadata.classes || [],
|
|
57549
|
+
types: metadata.types || [],
|
|
57550
|
+
calls: {
|
|
57551
|
+
functions: metadata.functionCalls || [],
|
|
57552
|
+
methods: metadata.methodCalls || [],
|
|
57553
|
+
constructors: metadata.constructorCalls || []
|
|
57554
|
+
},
|
|
57555
|
+
typeAnalysis: {
|
|
57556
|
+
typeImports: metadata.typeImports || [],
|
|
57557
|
+
interfaceDeps: metadata.interfaceDependencies || [],
|
|
57558
|
+
genericDeps: metadata.genericDependencies || []
|
|
57559
|
+
},
|
|
57560
|
+
di: {
|
|
57561
|
+
injections: metadata.constructorInjections || [],
|
|
57562
|
+
hooks: metadata.hookDependencies || [],
|
|
57563
|
+
context: metadata.contextUsages || []
|
|
57564
|
+
},
|
|
57565
|
+
react: metadata.componentUsage || []
|
|
57566
|
+
}
|
|
57567
|
+
};
|
|
57568
|
+
totalFacts += (metadata.imports?.length || 0) + (metadata.functionCalls?.length || 0);
|
|
57569
|
+
rawNodes.push(node);
|
|
57570
|
+
} catch (e) {
|
|
57571
|
+
console.warn(`\u26A0\uFE0F Pass 1 failed for ${file}: ${e.message}`);
|
|
56650
57572
|
}
|
|
56651
57573
|
}
|
|
56652
|
-
|
|
57574
|
+
console.log(` \u2713 Scanned ${rawNodes.length} files`);
|
|
57575
|
+
console.log(` \u2713 Extracted ${totalFacts} raw syntactic facts`);
|
|
57576
|
+
return rawNodes;
|
|
56653
57577
|
}
|
|
56654
|
-
module2.exports = {
|
|
57578
|
+
module2.exports = { executePass1 };
|
|
56655
57579
|
}
|
|
56656
57580
|
});
|
|
56657
57581
|
|
|
@@ -56660,7 +57584,7 @@ var require_path_resolver = __commonJS({
|
|
|
56660
57584
|
"src/core/path-resolver.js"(exports2, module2) {
|
|
56661
57585
|
var fs2 = require("fs");
|
|
56662
57586
|
var path2 = require("path");
|
|
56663
|
-
function resolveImport(importPath, importerPath, projectRoot, tsconfig) {
|
|
57587
|
+
function resolveImport(importPath, importerPath, projectRoot, tsconfig, workspaceMap) {
|
|
56664
57588
|
if (importPath.startsWith("http://") || importPath.startsWith("https://") || importPath.startsWith("data:") || importPath.startsWith("file:")) {
|
|
56665
57589
|
return null;
|
|
56666
57590
|
}
|
|
@@ -56691,8 +57615,8 @@ var require_path_resolver = __commonJS({
|
|
|
56691
57615
|
const aliasTargets = paths[aliasPattern];
|
|
56692
57616
|
if (aliasPattern.includes("*")) {
|
|
56693
57617
|
const patternBase = aliasPattern.replace(/\*.*$/, "");
|
|
56694
|
-
if (importPath.startsWith(patternBase)) {
|
|
56695
|
-
const suffix = importPath.substring(patternBase.length);
|
|
57618
|
+
if (importPath === patternBase.slice(0, -1) || importPath.startsWith(patternBase)) {
|
|
57619
|
+
const suffix = importPath.length >= patternBase.length ? importPath.substring(patternBase.length) : "";
|
|
56696
57620
|
for (const target of aliasTargets) {
|
|
56697
57621
|
const targetBase = target.replace(/\*.*$/, "");
|
|
56698
57622
|
const targetPath = path2.resolve(projectRoot, path2.join(targetBase, suffix));
|
|
@@ -56762,6 +57686,51 @@ var require_path_resolver = __commonJS({
|
|
|
56762
57686
|
return resolvedPath;
|
|
56763
57687
|
}
|
|
56764
57688
|
}
|
|
57689
|
+
if (workspaceMap && workspaceMap.has(importPath)) {
|
|
57690
|
+
const packageRoot = workspaceMap.get(importPath);
|
|
57691
|
+
try {
|
|
57692
|
+
const pkgPath = path2.join(packageRoot, "package.json");
|
|
57693
|
+
if (fs2.existsSync(pkgPath)) {
|
|
57694
|
+
const pkg = JSON.parse(fs2.readFileSync(pkgPath, "utf-8"));
|
|
57695
|
+
const mainFile = pkg.main || pkg.module || "index.js";
|
|
57696
|
+
const searchPath = path2.join(packageRoot, mainFile);
|
|
57697
|
+
const extensions = ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".json"];
|
|
57698
|
+
for (const ext of extensions) {
|
|
57699
|
+
const p = searchPath + ext;
|
|
57700
|
+
if (fs2.existsSync(p))
|
|
57701
|
+
return p;
|
|
57702
|
+
}
|
|
57703
|
+
}
|
|
57704
|
+
const indexFiles = ["index.ts", "index.tsx", "index.js", "index.jsx"];
|
|
57705
|
+
for (const idx of indexFiles) {
|
|
57706
|
+
const p = path2.join(packageRoot, idx);
|
|
57707
|
+
if (fs2.existsSync(p))
|
|
57708
|
+
return p;
|
|
57709
|
+
}
|
|
57710
|
+
} catch (e) {
|
|
57711
|
+
}
|
|
57712
|
+
return packageRoot;
|
|
57713
|
+
}
|
|
57714
|
+
if (workspaceMap) {
|
|
57715
|
+
for (const [pkgName, pkgRoot] of workspaceMap.entries()) {
|
|
57716
|
+
if (importPath.startsWith(pkgName + "/")) {
|
|
57717
|
+
const suffix = importPath.substring(pkgName.length + 1);
|
|
57718
|
+
const targetPath = path2.join(pkgRoot, suffix);
|
|
57719
|
+
const extensions = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".json", ""];
|
|
57720
|
+
for (const ext of extensions) {
|
|
57721
|
+
if (fs2.existsSync(targetPath + ext)) {
|
|
57722
|
+
return targetPath + ext;
|
|
57723
|
+
}
|
|
57724
|
+
}
|
|
57725
|
+
const indexFiles = ["index.ts", "index.tsx", "index.js", "index.jsx"];
|
|
57726
|
+
for (const idx of indexFiles) {
|
|
57727
|
+
const p = path2.join(targetPath, idx);
|
|
57728
|
+
if (fs2.existsSync(p))
|
|
57729
|
+
return p;
|
|
57730
|
+
}
|
|
57731
|
+
}
|
|
57732
|
+
}
|
|
57733
|
+
}
|
|
56765
57734
|
if (!importPath.startsWith(".")) {
|
|
56766
57735
|
try {
|
|
56767
57736
|
const resolved = require.resolve(importPath, { paths: [path2.dirname(importerPath)] });
|
|
@@ -56775,6 +57744,509 @@ var require_path_resolver = __commonJS({
|
|
|
56775
57744
|
}
|
|
56776
57745
|
});
|
|
56777
57746
|
|
|
57747
|
+
// src/core/symbol-indexer.js
|
|
57748
|
+
var require_symbol_indexer = __commonJS({
|
|
57749
|
+
"src/core/symbol-indexer.js"(exports2, module2) {
|
|
57750
|
+
var crypto = require("crypto");
|
|
57751
|
+
var SymbolIndexer = class {
|
|
57752
|
+
constructor() {
|
|
57753
|
+
this.symbols = /* @__PURE__ */ new Map();
|
|
57754
|
+
this.fileToSymbols = /* @__PURE__ */ new Map();
|
|
57755
|
+
}
|
|
57756
|
+
/**
|
|
57757
|
+
* Build symbol index from raw files
|
|
57758
|
+
* @param {Array<Object>} rawFiles - List of files with metadata from parser
|
|
57759
|
+
* @returns {Object} { symbols, fileToSymbols }
|
|
57760
|
+
*/
|
|
57761
|
+
index(rawFiles) {
|
|
57762
|
+
console.log(`Indexing symbols for ${rawFiles.length} files...`);
|
|
57763
|
+
this.reExports = /* @__PURE__ */ new Map();
|
|
57764
|
+
const sortedFiles = [...rawFiles].sort((a, b) => a.id.localeCompare(b.id));
|
|
57765
|
+
for (const file of sortedFiles) {
|
|
57766
|
+
if (!file.metadata)
|
|
57767
|
+
continue;
|
|
57768
|
+
this._indexFile(file);
|
|
57769
|
+
}
|
|
57770
|
+
this._propagateReExports();
|
|
57771
|
+
console.log(`Indexed ${this.symbols.size} symbols.`);
|
|
57772
|
+
return {
|
|
57773
|
+
symbols: this.symbols,
|
|
57774
|
+
fileToSymbols: this.fileToSymbols
|
|
57775
|
+
};
|
|
57776
|
+
}
|
|
57777
|
+
_indexFile(file) {
|
|
57778
|
+
const fileId = file.id;
|
|
57779
|
+
const metadata = file.metadata;
|
|
57780
|
+
const addSymbol = (name, kind, exported = false, loc = null) => {
|
|
57781
|
+
const id = `${fileId}::${name}`;
|
|
57782
|
+
const symbol = { id, name, kind, fileId, exported, loc };
|
|
57783
|
+
this.symbols.set(id, symbol);
|
|
57784
|
+
if (!this.fileToSymbols.has(fileId)) {
|
|
57785
|
+
this.fileToSymbols.set(fileId, /* @__PURE__ */ new Set());
|
|
57786
|
+
}
|
|
57787
|
+
this.fileToSymbols.get(fileId).add(id);
|
|
57788
|
+
return symbol;
|
|
57789
|
+
};
|
|
57790
|
+
if (metadata.exports) {
|
|
57791
|
+
metadata.exports.forEach((exp) => {
|
|
57792
|
+
addSymbol(exp.name, exp.type || "variable", true, exp.loc);
|
|
57793
|
+
if (exp.type === "default" && exp.name !== "default") {
|
|
57794
|
+
addSymbol("default", "default", true, exp.loc);
|
|
57795
|
+
}
|
|
57796
|
+
});
|
|
57797
|
+
}
|
|
57798
|
+
if (metadata.functions) {
|
|
57799
|
+
metadata.functions.forEach((func) => {
|
|
57800
|
+
const id = `${fileId}::${func.name}`;
|
|
57801
|
+
if (!this.symbols.has(id)) {
|
|
57802
|
+
addSymbol(func.name, "function", false, func.loc);
|
|
57803
|
+
} else {
|
|
57804
|
+
const sym = this.symbols.get(id);
|
|
57805
|
+
if (sym.kind === "variable")
|
|
57806
|
+
sym.kind = "function";
|
|
57807
|
+
}
|
|
57808
|
+
});
|
|
57809
|
+
}
|
|
57810
|
+
if (metadata.imports) {
|
|
57811
|
+
metadata.imports.forEach((imp) => {
|
|
57812
|
+
if (imp.type === "export-all" && imp.resolvedPath) {
|
|
57813
|
+
if (!this.reExports.has(fileId))
|
|
57814
|
+
this.reExports.set(fileId, /* @__PURE__ */ new Set());
|
|
57815
|
+
this.reExports.get(fileId).add(imp.resolvedPath);
|
|
57816
|
+
}
|
|
57817
|
+
});
|
|
57818
|
+
}
|
|
57819
|
+
if (metadata.classes) {
|
|
57820
|
+
metadata.classes.forEach((c) => {
|
|
57821
|
+
const id = `${fileId}::${c.name}`;
|
|
57822
|
+
if (this.symbols.has(id)) {
|
|
57823
|
+
this.symbols.get(id).kind = "class";
|
|
57824
|
+
} else {
|
|
57825
|
+
addSymbol(c.name, "class", false, c.loc);
|
|
57826
|
+
}
|
|
57827
|
+
});
|
|
57828
|
+
}
|
|
57829
|
+
if (metadata.types) {
|
|
57830
|
+
metadata.types.forEach((t) => {
|
|
57831
|
+
const id = `${fileId}::${t.name}`;
|
|
57832
|
+
if (this.symbols.has(id)) {
|
|
57833
|
+
this.symbols.get(id).kind = t.kind;
|
|
57834
|
+
} else {
|
|
57835
|
+
addSymbol(t.name, t.kind, false, t.loc);
|
|
57836
|
+
}
|
|
57837
|
+
});
|
|
57838
|
+
}
|
|
57839
|
+
if (metadata.variables) {
|
|
57840
|
+
metadata.variables.forEach((v) => {
|
|
57841
|
+
addSymbol(v.name, "variable", false, v.loc);
|
|
57842
|
+
if (v.properties && v.properties.length > 0) {
|
|
57843
|
+
v.properties.forEach((prop) => {
|
|
57844
|
+
addSymbol(`${v.name}.${prop.name}`, "method", false, prop.loc);
|
|
57845
|
+
});
|
|
57846
|
+
}
|
|
57847
|
+
});
|
|
57848
|
+
}
|
|
57849
|
+
}
|
|
57850
|
+
_propagateReExports() {
|
|
57851
|
+
const visited = /* @__PURE__ */ new Set();
|
|
57852
|
+
const propagate = (fileId) => {
|
|
57853
|
+
if (visited.has(fileId))
|
|
57854
|
+
return;
|
|
57855
|
+
visited.add(fileId);
|
|
57856
|
+
const targets = this.reExports.get(fileId);
|
|
57857
|
+
if (!targets)
|
|
57858
|
+
return;
|
|
57859
|
+
for (const targetPath of targets) {
|
|
57860
|
+
propagate(targetPath);
|
|
57861
|
+
const targetSymbolIds = this.fileToSymbols.get(targetPath);
|
|
57862
|
+
if (targetSymbolIds) {
|
|
57863
|
+
for (const symId of targetSymbolIds) {
|
|
57864
|
+
const originalSym = this.symbols.get(symId);
|
|
57865
|
+
if (originalSym && originalSym.exported) {
|
|
57866
|
+
const localId = `${fileId}::${originalSym.name}`;
|
|
57867
|
+
if (!this.symbols.has(localId)) {
|
|
57868
|
+
const newSym = { ...originalSym, id: localId, fileId };
|
|
57869
|
+
this.symbols.set(localId, newSym);
|
|
57870
|
+
if (!this.fileToSymbols.has(fileId))
|
|
57871
|
+
this.fileToSymbols.set(fileId, /* @__PURE__ */ new Set());
|
|
57872
|
+
this.fileToSymbols.get(fileId).add(localId);
|
|
57873
|
+
}
|
|
57874
|
+
}
|
|
57875
|
+
}
|
|
57876
|
+
}
|
|
57877
|
+
}
|
|
57878
|
+
};
|
|
57879
|
+
for (const fileId of this.reExports.keys()) {
|
|
57880
|
+
propagate(fileId);
|
|
57881
|
+
}
|
|
57882
|
+
}
|
|
57883
|
+
};
|
|
57884
|
+
module2.exports = { SymbolIndexer };
|
|
57885
|
+
}
|
|
57886
|
+
});
|
|
57887
|
+
|
|
57888
|
+
// src/core/call-resolver.js
|
|
57889
|
+
var require_call_resolver = __commonJS({
|
|
57890
|
+
"src/core/call-resolver.js"(exports2, module2) {
|
|
57891
|
+
var CallResolver = class {
|
|
57892
|
+
constructor(symbolIndex, fileMap) {
|
|
57893
|
+
this.symbolIndex = symbolIndex;
|
|
57894
|
+
this.fileMap = fileMap;
|
|
57895
|
+
}
|
|
57896
|
+
/**
|
|
57897
|
+
* Resolve calls in all files
|
|
57898
|
+
* @returns {Array<Object>} List of edges
|
|
57899
|
+
*/
|
|
57900
|
+
resolve(rawFiles) {
|
|
57901
|
+
const edges = [];
|
|
57902
|
+
console.log(`Resolving calls for ${rawFiles.length} files...`);
|
|
57903
|
+
for (const file of rawFiles) {
|
|
57904
|
+
const fileEdges = this._resolveFile(file);
|
|
57905
|
+
edges.push(...fileEdges);
|
|
57906
|
+
}
|
|
57907
|
+
console.log(`Resolved ${edges.length} call/instantiate edges.`);
|
|
57908
|
+
return edges;
|
|
57909
|
+
}
|
|
57910
|
+
_resolveFile(file) {
|
|
57911
|
+
const edges = [];
|
|
57912
|
+
if (!file.methodCalls)
|
|
57913
|
+
return edges;
|
|
57914
|
+
const fileId = file.id;
|
|
57915
|
+
const { functionCalls, constructorCalls, methodCalls } = file.methodCalls;
|
|
57916
|
+
const imports = file.metadata.imports || [];
|
|
57917
|
+
const resolveImportedSymbol = (symbolName) => {
|
|
57918
|
+
for (const imp of imports) {
|
|
57919
|
+
if (imp.specifiers) {
|
|
57920
|
+
const spec = imp.specifiers.find((s) => s.local === symbolName);
|
|
57921
|
+
if (spec) {
|
|
57922
|
+
if (imp.resolvedPath) {
|
|
57923
|
+
const targetFileId = imp.resolvedPath;
|
|
57924
|
+
const targetSymbolName = spec.imported === "default" ? "default" : spec.imported;
|
|
57925
|
+
let candidateId = `${targetFileId}::${targetSymbolName}`;
|
|
57926
|
+
if (this.symbolIndex.has(candidateId))
|
|
57927
|
+
return candidateId;
|
|
57928
|
+
if (spec.imported === "default") {
|
|
57929
|
+
candidateId = `${targetFileId}::default`;
|
|
57930
|
+
if (this.symbolIndex.has(candidateId))
|
|
57931
|
+
return candidateId;
|
|
57932
|
+
}
|
|
57933
|
+
}
|
|
57934
|
+
}
|
|
57935
|
+
}
|
|
57936
|
+
}
|
|
57937
|
+
const localId = `${fileId}::${symbolName}`;
|
|
57938
|
+
if (this.symbolIndex.has(localId)) {
|
|
57939
|
+
return localId;
|
|
57940
|
+
}
|
|
57941
|
+
return null;
|
|
57942
|
+
};
|
|
57943
|
+
if (functionCalls) {
|
|
57944
|
+
for (const call of functionCalls) {
|
|
57945
|
+
const targetSymbolId = resolveImportedSymbol(call.name);
|
|
57946
|
+
if (targetSymbolId) {
|
|
57947
|
+
edges.push({
|
|
57948
|
+
sourceFileId: fileId,
|
|
57949
|
+
targetSymbolId,
|
|
57950
|
+
type: "CALLS",
|
|
57951
|
+
line: call.loc ? call.loc.start.line : 0,
|
|
57952
|
+
confidence: 1
|
|
57953
|
+
});
|
|
57954
|
+
}
|
|
57955
|
+
}
|
|
57956
|
+
}
|
|
57957
|
+
if (constructorCalls) {
|
|
57958
|
+
for (const call of constructorCalls) {
|
|
57959
|
+
const targetSymbolId = resolveImportedSymbol(call.className);
|
|
57960
|
+
if (targetSymbolId) {
|
|
57961
|
+
edges.push({
|
|
57962
|
+
sourceFileId: fileId,
|
|
57963
|
+
targetSymbolId,
|
|
57964
|
+
type: "INSTANTIATES",
|
|
57965
|
+
line: call.loc ? call.loc.start.line : 0,
|
|
57966
|
+
confidence: 1
|
|
57967
|
+
});
|
|
57968
|
+
}
|
|
57969
|
+
}
|
|
57970
|
+
}
|
|
57971
|
+
if (methodCalls) {
|
|
57972
|
+
for (const call of methodCalls) {
|
|
57973
|
+
const imp = imports.find((i) => i.specifiers?.some((s) => s.local === call.object));
|
|
57974
|
+
if (imp && imp.resolvedPath) {
|
|
57975
|
+
const targetFileId = imp.resolvedPath;
|
|
57976
|
+
const spec = imp.specifiers.find((s) => s.local === call.object);
|
|
57977
|
+
const importedAs = spec ? spec.imported : null;
|
|
57978
|
+
let candidateId = `${targetFileId}::${call.method}`;
|
|
57979
|
+
if (this.symbolIndex.has(candidateId)) {
|
|
57980
|
+
edges.push({
|
|
57981
|
+
sourceFileId: fileId,
|
|
57982
|
+
targetSymbolId: candidateId,
|
|
57983
|
+
type: "CALLS",
|
|
57984
|
+
line: call.loc ? call.loc.start.line : 0,
|
|
57985
|
+
confidence: 1
|
|
57986
|
+
});
|
|
57987
|
+
continue;
|
|
57988
|
+
}
|
|
57989
|
+
if (importedAs) {
|
|
57990
|
+
const targetSymbolName = importedAs === "default" ? "default" : importedAs;
|
|
57991
|
+
candidateId = `${targetFileId}::${targetSymbolName}.${call.method}`;
|
|
57992
|
+
if (this.symbolIndex.has(candidateId)) {
|
|
57993
|
+
edges.push({
|
|
57994
|
+
sourceFileId: fileId,
|
|
57995
|
+
targetSymbolId: candidateId,
|
|
57996
|
+
type: "CALLS",
|
|
57997
|
+
line: call.loc ? call.loc.start.line : 0,
|
|
57998
|
+
confidence: 1
|
|
57999
|
+
});
|
|
58000
|
+
continue;
|
|
58001
|
+
}
|
|
58002
|
+
}
|
|
58003
|
+
}
|
|
58004
|
+
const localObjectId = `${fileId}::${call.object}.${call.method}`;
|
|
58005
|
+
if (this.symbolIndex.has(localObjectId)) {
|
|
58006
|
+
edges.push({
|
|
58007
|
+
sourceFileId: fileId,
|
|
58008
|
+
targetSymbolId: localObjectId,
|
|
58009
|
+
type: "CALLS",
|
|
58010
|
+
line: call.loc ? call.loc.start.line : 0,
|
|
58011
|
+
confidence: 1
|
|
58012
|
+
});
|
|
58013
|
+
}
|
|
58014
|
+
}
|
|
58015
|
+
}
|
|
58016
|
+
return edges;
|
|
58017
|
+
}
|
|
58018
|
+
};
|
|
58019
|
+
module2.exports = { CallResolver };
|
|
58020
|
+
}
|
|
58021
|
+
});
|
|
58022
|
+
|
|
58023
|
+
// src/engine/pass2_semantics.js
|
|
58024
|
+
var require_pass2_semantics = __commonJS({
|
|
58025
|
+
"src/engine/pass2_semantics.js"(exports2, module2) {
|
|
58026
|
+
var path2 = require("path");
|
|
58027
|
+
var { loadTSConfig } = require_tsconfig_utils();
|
|
58028
|
+
var { resolveImport } = require_path_resolver();
|
|
58029
|
+
var { SymbolIndexer } = require_symbol_indexer();
|
|
58030
|
+
var { CallResolver } = require_call_resolver();
|
|
58031
|
+
async function executePass2(rawNodes, rootDir, workspaceContext) {
|
|
58032
|
+
console.log("\u{1F9E0} PASS 2: Semantic Resolution...");
|
|
58033
|
+
const config = loadTSConfig(rootDir);
|
|
58034
|
+
const tsconfig = config.options;
|
|
58035
|
+
const configRoot = config.configDir;
|
|
58036
|
+
const normalize = (p) => p.replace(/\\/g, "/");
|
|
58037
|
+
const workspaceMap = workspaceContext ? workspaceContext.workspaceMap : null;
|
|
58038
|
+
const fileSet = new Set(rawNodes.map((n) => n.id));
|
|
58039
|
+
const edges = [];
|
|
58040
|
+
const addEdge = (source, target, type, confidence = 1, metadata = {}) => {
|
|
58041
|
+
if (!source || !target)
|
|
58042
|
+
return;
|
|
58043
|
+
if (source === target)
|
|
58044
|
+
return;
|
|
58045
|
+
edges.push({
|
|
58046
|
+
source,
|
|
58047
|
+
target,
|
|
58048
|
+
type,
|
|
58049
|
+
confidence,
|
|
58050
|
+
metadata
|
|
58051
|
+
});
|
|
58052
|
+
};
|
|
58053
|
+
let resolvedImports = 0;
|
|
58054
|
+
for (const node of rawNodes) {
|
|
58055
|
+
if (!node.facts.imports)
|
|
58056
|
+
continue;
|
|
58057
|
+
for (const imp of node.facts.imports) {
|
|
58058
|
+
const importString = imp.source;
|
|
58059
|
+
let targetId = null;
|
|
58060
|
+
let resolvedPath = null;
|
|
58061
|
+
const resolvedAbs = resolveImport(importString, node.filePath, configRoot, tsconfig, workspaceMap);
|
|
58062
|
+
if (resolvedAbs) {
|
|
58063
|
+
targetId = normalize(path2.relative(rootDir, resolvedAbs));
|
|
58064
|
+
resolvedPath = targetId;
|
|
58065
|
+
imp.resolvedPath = targetId;
|
|
58066
|
+
} else {
|
|
58067
|
+
if (importString.startsWith(".")) {
|
|
58068
|
+
try {
|
|
58069
|
+
const nodeDir = path2.dirname(node.filePath);
|
|
58070
|
+
const simpleAbs = path2.resolve(nodeDir, importString);
|
|
58071
|
+
const exts = [".ts", ".tsx", ".js", ".jsx", ".json", "/index.ts", "/index.js"];
|
|
58072
|
+
for (const ext of [""].concat(exts)) {
|
|
58073
|
+
const candidate = normalize(path2.relative(rootDir, simpleAbs + ext));
|
|
58074
|
+
if (fileSet.has(candidate)) {
|
|
58075
|
+
targetId = candidate;
|
|
58076
|
+
imp.resolvedPath = candidate;
|
|
58077
|
+
break;
|
|
58078
|
+
}
|
|
58079
|
+
}
|
|
58080
|
+
} catch (e) {
|
|
58081
|
+
}
|
|
58082
|
+
}
|
|
58083
|
+
}
|
|
58084
|
+
if (targetId && fileSet.has(targetId)) {
|
|
58085
|
+
let type = "imports";
|
|
58086
|
+
if (workspaceContext && workspaceContext.workspaceMap) {
|
|
58087
|
+
}
|
|
58088
|
+
addEdge(node.id, targetId, type, 1, { specifiers: imp.specifiers });
|
|
58089
|
+
resolvedImports++;
|
|
58090
|
+
}
|
|
58091
|
+
}
|
|
58092
|
+
}
|
|
58093
|
+
console.log(` \u2713 Resolved ${resolvedImports} import dependencies`);
|
|
58094
|
+
const symbolIndexer = new SymbolIndexer();
|
|
58095
|
+
const nodesForIndexing = rawNodes.map((n) => ({
|
|
58096
|
+
id: n.id,
|
|
58097
|
+
metadata: n.facts
|
|
58098
|
+
// Indexer expects metadata.exports, etc. (Pass 1 facts structure matches enough)
|
|
58099
|
+
}));
|
|
58100
|
+
const { symbols, fileToSymbols } = symbolIndexer.index(nodesForIndexing);
|
|
58101
|
+
const callResolver = new CallResolver(symbols, null);
|
|
58102
|
+
const nodesForResolution = rawNodes.map((n) => {
|
|
58103
|
+
const combinedFunctions = [
|
|
58104
|
+
...n.facts.calls.functions || [],
|
|
58105
|
+
...(n.facts.react || []).map((r) => ({
|
|
58106
|
+
name: r.component,
|
|
58107
|
+
type: "jsx_component",
|
|
58108
|
+
loc: r.loc
|
|
58109
|
+
}))
|
|
58110
|
+
];
|
|
58111
|
+
return {
|
|
58112
|
+
id: n.id,
|
|
58113
|
+
metadata: n.facts,
|
|
58114
|
+
methodCalls: {
|
|
58115
|
+
functionCalls: combinedFunctions,
|
|
58116
|
+
methodCalls: n.facts.calls.methods,
|
|
58117
|
+
constructorCalls: n.facts.calls.constructors
|
|
58118
|
+
}
|
|
58119
|
+
};
|
|
58120
|
+
});
|
|
58121
|
+
const callEdges = callResolver.resolve(nodesForResolution);
|
|
58122
|
+
let resolvedCalls = 0;
|
|
58123
|
+
for (const edge of callEdges) {
|
|
58124
|
+
const symbol = symbols.get(edge.targetSymbolId);
|
|
58125
|
+
if (symbol) {
|
|
58126
|
+
const targetFileId = symbol.fileId;
|
|
58127
|
+
if (fileSet.has(targetFileId)) {
|
|
58128
|
+
addEdge(edge.sourceFileId, targetFileId, edge.type, edge.confidence, {
|
|
58129
|
+
symbol: symbol.name,
|
|
58130
|
+
symbolId: edge.targetSymbolId,
|
|
58131
|
+
line: edge.line
|
|
58132
|
+
});
|
|
58133
|
+
resolvedCalls++;
|
|
58134
|
+
}
|
|
58135
|
+
}
|
|
58136
|
+
}
|
|
58137
|
+
console.log(` \u2713 Resolved ${resolvedCalls} semantic call edges`);
|
|
58138
|
+
let typeEdgesCount = 0;
|
|
58139
|
+
for (const node of rawNodes) {
|
|
58140
|
+
if (!node.facts.typeAnalysis)
|
|
58141
|
+
continue;
|
|
58142
|
+
const { typeImports, interfaceDeps, genericDeps } = node.facts.typeAnalysis;
|
|
58143
|
+
for (const imp of typeImports) {
|
|
58144
|
+
const resolvedAbs = resolveImport(imp.source, node.filePath, rootDir, tsconfig, workspaceMap);
|
|
58145
|
+
if (resolvedAbs) {
|
|
58146
|
+
const targetId = normalize(path2.relative(rootDir, resolvedAbs));
|
|
58147
|
+
if (fileSet.has(targetId)) {
|
|
58148
|
+
addEdge(node.id, targetId, "depends_on", 0.9, { type: "type_import" });
|
|
58149
|
+
typeEdgesCount++;
|
|
58150
|
+
}
|
|
58151
|
+
}
|
|
58152
|
+
}
|
|
58153
|
+
const allTypeDeps = [...interfaceDeps, ...genericDeps];
|
|
58154
|
+
for (const dep of allTypeDeps) {
|
|
58155
|
+
const typeName = dep.extends || dep.implements || dep.returnType || dep.type;
|
|
58156
|
+
if (!typeName)
|
|
58157
|
+
continue;
|
|
58158
|
+
for (const imp of node.facts.imports || []) {
|
|
58159
|
+
if (imp.resolvedPath) {
|
|
58160
|
+
const targetFileId = imp.resolvedPath;
|
|
58161
|
+
const candidateId = `${targetFileId}::${typeName}`;
|
|
58162
|
+
if (symbols.has(candidateId)) {
|
|
58163
|
+
addEdge(node.id, targetFileId, "depends_on", 1, { type: "type_reference", symbol: typeName });
|
|
58164
|
+
typeEdgesCount++;
|
|
58165
|
+
break;
|
|
58166
|
+
}
|
|
58167
|
+
}
|
|
58168
|
+
}
|
|
58169
|
+
}
|
|
58170
|
+
}
|
|
58171
|
+
console.log(` \u2713 Resolved ${typeEdgesCount} TypeScript type connections`);
|
|
58172
|
+
return {
|
|
58173
|
+
nodes: rawNodes,
|
|
58174
|
+
edges,
|
|
58175
|
+
symbols: Array.from(symbols.values())
|
|
58176
|
+
// Return symbols list for ContextBuilder
|
|
58177
|
+
};
|
|
58178
|
+
}
|
|
58179
|
+
module2.exports = { executePass2 };
|
|
58180
|
+
}
|
|
58181
|
+
});
|
|
58182
|
+
|
|
58183
|
+
// src/engine/pass3_lifter.js
|
|
58184
|
+
var require_pass3_lifter = __commonJS({
|
|
58185
|
+
"src/engine/pass3_lifter.js"(exports2, module2) {
|
|
58186
|
+
async function executePass3(semanticData) {
|
|
58187
|
+
console.log("\u{1F9EC} PASS 3: Structural Lifting...");
|
|
58188
|
+
const { nodes, edges } = semanticData;
|
|
58189
|
+
const liftedNodes = [];
|
|
58190
|
+
let rolesFound = {};
|
|
58191
|
+
for (const node of nodes) {
|
|
58192
|
+
let role = "module";
|
|
58193
|
+
let layer = "generic";
|
|
58194
|
+
const pathLower = node.id.toLowerCase();
|
|
58195
|
+
const filename = node.id.split("/").pop();
|
|
58196
|
+
if (pathLower.includes("service") || filename.endsWith(".service.ts")) {
|
|
58197
|
+
role = "service";
|
|
58198
|
+
layer = "logic";
|
|
58199
|
+
} else if (pathLower.includes("controller") || filename.endsWith(".controller.ts")) {
|
|
58200
|
+
role = "controller";
|
|
58201
|
+
layer = "api";
|
|
58202
|
+
} else if (pathLower.includes("component") || pathLower.includes(".tsx") || pathLower.includes(".jsx")) {
|
|
58203
|
+
role = "component";
|
|
58204
|
+
layer = "ui";
|
|
58205
|
+
} else if (pathLower.includes("store") || pathLower.includes("redux") || pathLower.includes("context")) {
|
|
58206
|
+
role = "store";
|
|
58207
|
+
layer = "state";
|
|
58208
|
+
} else if (pathLower.includes("util") || pathLower.includes("helper")) {
|
|
58209
|
+
role = "utility";
|
|
58210
|
+
layer = "shared";
|
|
58211
|
+
} else if (pathLower.includes("model") || pathLower.includes("entity") || pathLower.includes("dto")) {
|
|
58212
|
+
role = "model";
|
|
58213
|
+
layer = "data";
|
|
58214
|
+
} else if (pathLower.includes("config") || pathLower.includes("env")) {
|
|
58215
|
+
role = "config";
|
|
58216
|
+
} else if (pathLower.includes("hook") || filename.startsWith("use")) {
|
|
58217
|
+
role = "hook";
|
|
58218
|
+
layer = "ui-logic";
|
|
58219
|
+
}
|
|
58220
|
+
if (node.facts.di && (node.facts.di.injections.length > 0 || node.facts.di.context.length > 0)) {
|
|
58221
|
+
if (role === "module")
|
|
58222
|
+
role = "consumer";
|
|
58223
|
+
}
|
|
58224
|
+
if (node.facts.exports.some((e) => e.type === "class")) {
|
|
58225
|
+
if (role === "module")
|
|
58226
|
+
role = "class_def";
|
|
58227
|
+
}
|
|
58228
|
+
rolesFound[role] = (rolesFound[role] || 0) + 1;
|
|
58229
|
+
liftedNodes.push({
|
|
58230
|
+
...node,
|
|
58231
|
+
structure: {
|
|
58232
|
+
role,
|
|
58233
|
+
layer
|
|
58234
|
+
}
|
|
58235
|
+
});
|
|
58236
|
+
}
|
|
58237
|
+
console.log(` \u2713 Inferred structural roles: ${JSON.stringify(rolesFound)}`);
|
|
58238
|
+
return {
|
|
58239
|
+
nodes: liftedNodes,
|
|
58240
|
+
edges,
|
|
58241
|
+
// Edges passed through
|
|
58242
|
+
symbols: semanticData.symbols
|
|
58243
|
+
// Propagate symbols
|
|
58244
|
+
};
|
|
58245
|
+
}
|
|
58246
|
+
module2.exports = { executePass3 };
|
|
58247
|
+
}
|
|
58248
|
+
});
|
|
58249
|
+
|
|
56778
58250
|
// src/core/blastRadius.js
|
|
56779
58251
|
var require_blastRadius = __commonJS({
|
|
56780
58252
|
"src/core/blastRadius.js"(exports2, module2) {
|
|
@@ -56896,7 +58368,12 @@ var require_blastRadius = __commonJS({
|
|
|
56896
58368
|
// Consider files with blast radius > 5 as hubs
|
|
56897
58369
|
});
|
|
56898
58370
|
}
|
|
56899
|
-
return criticalityAnalysis.sort((a, b) =>
|
|
58371
|
+
return criticalityAnalysis.sort((a, b) => {
|
|
58372
|
+
if (b.criticalityScore !== a.criticalityScore) {
|
|
58373
|
+
return b.criticalityScore - a.criticalityScore;
|
|
58374
|
+
}
|
|
58375
|
+
return a.file.localeCompare(b.file);
|
|
58376
|
+
});
|
|
56900
58377
|
}
|
|
56901
58378
|
function calculateDependencyStrength(reverseGraph, file) {
|
|
56902
58379
|
if (!reverseGraph[file] || !Array.isArray(reverseGraph[file])) {
|
|
@@ -56922,6 +58399,76 @@ var require_blastRadius = __commonJS({
|
|
|
56922
58399
|
}
|
|
56923
58400
|
});
|
|
56924
58401
|
|
|
58402
|
+
// src/engine/pass4_signals.js
|
|
58403
|
+
var require_pass4_signals = __commonJS({
|
|
58404
|
+
"src/engine/pass4_signals.js"(exports2, module2) {
|
|
58405
|
+
var { buildReverseDependencyGraph, computeBlastRadius, analyzeCriticality } = require_blastRadius();
|
|
58406
|
+
async function executePass4(liftedData) {
|
|
58407
|
+
console.log("\u{1F9E0} PASS 4: Signal Extraction & Metrics...");
|
|
58408
|
+
const { nodes, edges } = liftedData;
|
|
58409
|
+
const architectureMap = { nodes, edges };
|
|
58410
|
+
const reverseGraph = buildReverseDependencyGraph(architectureMap);
|
|
58411
|
+
const blastRadiusMap = computeBlastRadius(reverseGraph);
|
|
58412
|
+
nodes.forEach((n) => {
|
|
58413
|
+
n.metadata = n.facts;
|
|
58414
|
+
n.metadata.blast_radius = blastRadiusMap[n.id] || 0;
|
|
58415
|
+
});
|
|
58416
|
+
const criticalityList = analyzeCriticality(blastRadiusMap, reverseGraph, nodes);
|
|
58417
|
+
const criticalityMap = new Map(criticalityList.map((c) => [c.file, c]));
|
|
58418
|
+
const finalNodes = nodes.map((node) => {
|
|
58419
|
+
const signals = {
|
|
58420
|
+
blast_radius: blastRadiusMap[node.id] || 0,
|
|
58421
|
+
criticality: criticalityMap.get(node.id)?.criticalityScore || 0,
|
|
58422
|
+
is_hub: criticalityMap.get(node.id)?.isHub || false,
|
|
58423
|
+
// Calculate instability: closer to 1 means "depends on many things" (outgoing edges)
|
|
58424
|
+
// (coupling)
|
|
58425
|
+
outgoing_deps: edges.filter((e) => e.source === node.id).length,
|
|
58426
|
+
incoming_deps: edges.filter((e) => e.target === node.id).length
|
|
58427
|
+
};
|
|
58428
|
+
return {
|
|
58429
|
+
id: node.id,
|
|
58430
|
+
type: node.type,
|
|
58431
|
+
filePath: node.filePath,
|
|
58432
|
+
// Internal absolute path
|
|
58433
|
+
// The 3 Pillars of Arcvision
|
|
58434
|
+
role: node.structure.role,
|
|
58435
|
+
// From Pass 3
|
|
58436
|
+
layer: node.structure.layer,
|
|
58437
|
+
// From Pass 3
|
|
58438
|
+
signals,
|
|
58439
|
+
// From Pass 4
|
|
58440
|
+
// Deep Code Intelligence (from Pass 1 & 2)
|
|
58441
|
+
intelligence: {
|
|
58442
|
+
...node.facts,
|
|
58443
|
+
// Add resolved outbound connections for easy traversal
|
|
58444
|
+
connections: edges.filter((e) => e.source === node.id).map((e) => ({
|
|
58445
|
+
target: e.target,
|
|
58446
|
+
type: e.type,
|
|
58447
|
+
confidence: e.confidence
|
|
58448
|
+
}))
|
|
58449
|
+
}
|
|
58450
|
+
};
|
|
58451
|
+
});
|
|
58452
|
+
const totalFiles = finalNodes.length;
|
|
58453
|
+
const maxBlast = Math.max(...finalNodes.map((n) => n.signals.blast_radius));
|
|
58454
|
+
console.log(` \u2713 Signals computed. Max Blast Radius: ${maxBlast}`);
|
|
58455
|
+
const contextSurface = criticalityList.slice(0, 5).map((c) => ({
|
|
58456
|
+
file: c.file,
|
|
58457
|
+
score: c.criticalityScore,
|
|
58458
|
+
reason: `Blast: ${c.blastRadius}, Deps: ${c.dependencies}`
|
|
58459
|
+
}));
|
|
58460
|
+
return {
|
|
58461
|
+
nodes: finalNodes,
|
|
58462
|
+
edges,
|
|
58463
|
+
symbols: liftedData.symbols,
|
|
58464
|
+
// Propagate symbols
|
|
58465
|
+
contextSurface
|
|
58466
|
+
};
|
|
58467
|
+
}
|
|
58468
|
+
module2.exports = { executePass4 };
|
|
58469
|
+
}
|
|
58470
|
+
});
|
|
58471
|
+
|
|
56925
58472
|
// src/engine/id-generator.js
|
|
56926
58473
|
var require_id_generator = __commonJS({
|
|
56927
58474
|
"src/engine/id-generator.js"(exports2, module2) {
|
|
@@ -56934,81 +58481,109 @@ var require_id_generator = __commonJS({
|
|
|
56934
58481
|
}
|
|
56935
58482
|
});
|
|
56936
58483
|
|
|
56937
|
-
// src/
|
|
58484
|
+
// src/core/context_builder.js
|
|
56938
58485
|
var require_context_builder = __commonJS({
|
|
56939
|
-
"src/
|
|
58486
|
+
"src/core/context_builder.js"(exports2, module2) {
|
|
56940
58487
|
var path2 = require("path");
|
|
56941
58488
|
var { stableId } = require_id_generator();
|
|
56942
|
-
function buildContext(
|
|
58489
|
+
function buildContext(fileNodes, edges, symbols, options = {}) {
|
|
56943
58490
|
const {
|
|
56944
58491
|
directory = ".",
|
|
56945
58492
|
projectName = "arcvision",
|
|
56946
58493
|
language = "javascript"
|
|
56947
58494
|
} = options;
|
|
56948
|
-
const nodes =
|
|
56949
|
-
const
|
|
56950
|
-
const
|
|
56951
|
-
const hasClasses = file.metadata.classes && file.metadata.classes.length > 0;
|
|
56952
|
-
const hasExports = file.metadata.exports && file.metadata.exports.length > 0;
|
|
56953
|
-
const hasApiCalls = file.metadata.apiCalls && file.metadata.apiCalls.length > 0;
|
|
56954
|
-
let role = "Structure";
|
|
56955
|
-
if (hasFunctions || hasClasses || hasApiCalls) {
|
|
56956
|
-
role = "Implementation";
|
|
56957
|
-
} else if (hasExports) {
|
|
56958
|
-
role = "Interface";
|
|
56959
|
-
}
|
|
58495
|
+
const nodes = fileNodes.map((file) => {
|
|
58496
|
+
const role = file.role || "Structure";
|
|
58497
|
+
const layer = file.layer || "generic";
|
|
56960
58498
|
const dependencies = [];
|
|
56961
58499
|
const uniqueDeps = /* @__PURE__ */ new Set();
|
|
56962
|
-
|
|
56963
|
-
|
|
56964
|
-
|
|
56965
|
-
|
|
56966
|
-
|
|
56967
|
-
|
|
56968
|
-
|
|
56969
|
-
|
|
56970
|
-
|
|
58500
|
+
const addDep = (target) => {
|
|
58501
|
+
if (target && !uniqueDeps.has(target)) {
|
|
58502
|
+
uniqueDeps.add(target);
|
|
58503
|
+
dependencies.push(target);
|
|
58504
|
+
}
|
|
58505
|
+
};
|
|
58506
|
+
if (file.intelligence && file.intelligence.connections) {
|
|
58507
|
+
file.intelligence.connections.forEach((c) => addDep(c.target));
|
|
58508
|
+
} else {
|
|
58509
|
+
edges.filter((e) => e.source === file.id).forEach((e) => addDep(e.target));
|
|
56971
58510
|
}
|
|
56972
|
-
|
|
56973
|
-
id: stableId(
|
|
58511
|
+
const nodeObj = {
|
|
58512
|
+
id: stableId(file.id),
|
|
56974
58513
|
type: "file",
|
|
56975
|
-
path:
|
|
58514
|
+
path: file.id,
|
|
56976
58515
|
role,
|
|
56977
58516
|
dependencies,
|
|
56978
|
-
blast_radius: file.
|
|
58517
|
+
blast_radius: file.signals && file.signals.blast_radius || 0,
|
|
58518
|
+
// New Schema Extensions (if supported by backend, otherwise ignored)
|
|
58519
|
+
layer,
|
|
58520
|
+
criticality: file.signals ? file.signals.criticality : 0
|
|
56979
58521
|
};
|
|
58522
|
+
return nodeObj;
|
|
56980
58523
|
});
|
|
56981
|
-
const
|
|
58524
|
+
const nodeMap = new Map(nodes.map((n) => [n.path, n]));
|
|
58525
|
+
const edgeKeyMap = /* @__PURE__ */ new Map();
|
|
56982
58526
|
for (const edge of edges) {
|
|
56983
|
-
const sourceNode =
|
|
56984
|
-
const targetNode =
|
|
56985
|
-
if (sourceNode) {
|
|
58527
|
+
const sourceNode = nodeMap.get(edge.source);
|
|
58528
|
+
const targetNode = nodeMap.get(edge.target);
|
|
58529
|
+
if (sourceNode && targetNode) {
|
|
56986
58530
|
let relationType = "imports";
|
|
56987
|
-
|
|
56988
|
-
|
|
56989
|
-
|
|
56990
|
-
|
|
56991
|
-
|
|
56992
|
-
|
|
56993
|
-
|
|
56994
|
-
|
|
56995
|
-
|
|
56996
|
-
|
|
56997
|
-
|
|
58531
|
+
switch (edge.type) {
|
|
58532
|
+
case "function_call":
|
|
58533
|
+
case "method_call":
|
|
58534
|
+
case "constructor_call":
|
|
58535
|
+
case "calls":
|
|
58536
|
+
case "CALLS":
|
|
58537
|
+
case "instantiates":
|
|
58538
|
+
case "INSTANTIATES":
|
|
58539
|
+
case "jsx_component":
|
|
58540
|
+
relationType = "calls";
|
|
58541
|
+
break;
|
|
58542
|
+
case "injects":
|
|
58543
|
+
case "depends_on":
|
|
58544
|
+
relationType = "depends_on";
|
|
58545
|
+
break;
|
|
58546
|
+
case "owns":
|
|
58547
|
+
relationType = "owns";
|
|
58548
|
+
break;
|
|
58549
|
+
case "imports":
|
|
58550
|
+
case "require":
|
|
58551
|
+
default:
|
|
58552
|
+
relationType = "imports";
|
|
58553
|
+
break;
|
|
58554
|
+
}
|
|
58555
|
+
const key = `${sourceNode.id}::${targetNode.id}::${relationType}`;
|
|
58556
|
+
if (edgeKeyMap.has(key)) {
|
|
58557
|
+
edgeKeyMap.get(key).weight = (edgeKeyMap.get(key).weight || 1) + 1;
|
|
58558
|
+
} else {
|
|
58559
|
+
edgeKeyMap.set(key, {
|
|
56998
58560
|
from: sourceNode.id,
|
|
56999
58561
|
to: targetNode.id,
|
|
57000
|
-
relation: relationType
|
|
58562
|
+
relation: relationType,
|
|
58563
|
+
weight: 1
|
|
57001
58564
|
});
|
|
57002
|
-
} else {
|
|
57003
58565
|
}
|
|
57004
58566
|
}
|
|
57005
58567
|
}
|
|
58568
|
+
const schemaEdges = Array.from(edgeKeyMap.values()).sort((a, b) => {
|
|
58569
|
+
if (a.from !== b.from)
|
|
58570
|
+
return a.from.localeCompare(b.from);
|
|
58571
|
+
if (a.to !== b.to)
|
|
58572
|
+
return a.to.localeCompare(b.to);
|
|
58573
|
+
return a.relation.localeCompare(b.relation);
|
|
58574
|
+
});
|
|
57006
58575
|
const metrics = {
|
|
57007
58576
|
total_files: nodes.length,
|
|
57008
58577
|
total_nodes: nodes.length,
|
|
57009
58578
|
total_edges: schemaEdges.length,
|
|
57010
|
-
total_imports: schemaEdges.
|
|
57011
|
-
|
|
58579
|
+
total_imports: schemaEdges.filter((edge) => edge.relation === "imports").reduce((sum, e) => sum + (e.weight || 1), 0),
|
|
58580
|
+
total_calls: schemaEdges.filter((edge) => edge.relation === "calls").reduce((sum, e) => sum + (e.weight || 1), 0),
|
|
58581
|
+
total_owns: schemaEdges.filter((edge) => edge.relation === "owns").reduce((sum, e) => sum + (e.weight || 1), 0),
|
|
58582
|
+
total_depends_on: schemaEdges.filter((edge) => edge.relation === "depends_on").reduce((sum, e) => sum + (e.weight || 1), 0),
|
|
58583
|
+
files_with_functions: fileNodes.filter((n) => n.intelligence && n.intelligence.functions && n.intelligence.functions.length > 0).length,
|
|
58584
|
+
// New metrics
|
|
58585
|
+
total_dependencies: schemaEdges.length,
|
|
58586
|
+
files_with_high_blast_radius: nodes.filter((n) => n.blast_radius > 5).length
|
|
57012
58587
|
};
|
|
57013
58588
|
const context = {
|
|
57014
58589
|
schema_version: "1.0.0",
|
|
@@ -57020,12 +58595,10 @@ var require_context_builder = __commonJS({
|
|
|
57020
58595
|
},
|
|
57021
58596
|
nodes,
|
|
57022
58597
|
edges: schemaEdges,
|
|
58598
|
+
symbols: symbols || [],
|
|
57023
58599
|
metrics,
|
|
57024
|
-
contextSurface: options.contextSurface ||
|
|
58600
|
+
contextSurface: options.contextSurface || []
|
|
57025
58601
|
};
|
|
57026
|
-
context.metrics.files_with_functions = nodes.filter((n) => n.role === "Implementation").length;
|
|
57027
|
-
context.metrics.files_with_high_blast_radius = nodes.filter((n) => n.blast_radius > 5).length;
|
|
57028
|
-
context.metrics.total_dependencies = schemaEdges.length;
|
|
57029
58602
|
return context;
|
|
57030
58603
|
}
|
|
57031
58604
|
module2.exports = { buildContext };
|
|
@@ -63583,374 +65156,53 @@ var require_context_sorter = __commonJS({
|
|
|
63583
65156
|
// src/core/scanner.js
|
|
63584
65157
|
var require_scanner = __commonJS({
|
|
63585
65158
|
"src/core/scanner.js"(exports2, module2) {
|
|
63586
|
-
var { glob } = require_commonjs5();
|
|
63587
65159
|
var path2 = require("path");
|
|
63588
|
-
var fs2 = require("fs");
|
|
63589
|
-
var parser = require_parser();
|
|
63590
|
-
var pluginManager = require_plugin_manager();
|
|
63591
65160
|
var { loadTSConfig } = require_tsconfig_utils();
|
|
63592
|
-
var {
|
|
63593
|
-
var {
|
|
65161
|
+
var { WorkspaceScanner } = require_workspace_scanner();
|
|
65162
|
+
var { executePass1 } = require_pass1_facts();
|
|
65163
|
+
var { executePass2 } = require_pass2_semantics();
|
|
65164
|
+
var { executePass3 } = require_pass3_lifter();
|
|
65165
|
+
var { executePass4 } = require_pass4_signals();
|
|
63594
65166
|
var { buildContext } = require_context_builder();
|
|
63595
65167
|
var { validateContext } = require_context_validator();
|
|
63596
65168
|
var { sortContext } = require_context_sorter();
|
|
63597
65169
|
async function scan(directory) {
|
|
63598
|
-
|
|
63599
|
-
|
|
63600
|
-
|
|
63601
|
-
|
|
63602
|
-
absolute: true
|
|
63603
|
-
};
|
|
65170
|
+
console.log(`
|
|
65171
|
+
\u{1F680} ARCVISION STRUCTURAL ENGINE (4-PASS)`);
|
|
65172
|
+
console.log(` Target: ${directory}
|
|
65173
|
+
`);
|
|
63604
65174
|
try {
|
|
63605
|
-
const
|
|
63606
|
-
|
|
63607
|
-
const
|
|
63608
|
-
const
|
|
63609
|
-
|
|
63610
|
-
|
|
63611
|
-
|
|
63612
|
-
const
|
|
63613
|
-
|
|
63614
|
-
|
|
63615
|
-
|
|
63616
|
-
|
|
63617
|
-
|
|
63618
|
-
|
|
63619
|
-
if (file.endsWith(".json")) {
|
|
63620
|
-
try {
|
|
63621
|
-
const content = fs2.readFileSync(file, "utf-8");
|
|
63622
|
-
JSON.parse(content);
|
|
63623
|
-
metadata = {
|
|
63624
|
-
id: file,
|
|
63625
|
-
imports: [],
|
|
63626
|
-
exports: [],
|
|
63627
|
-
functions: [],
|
|
63628
|
-
apiCalls: [],
|
|
63629
|
-
isJson: true
|
|
63630
|
-
};
|
|
63631
|
-
} catch (jsonError) {
|
|
63632
|
-
console.warn(`\u26A0\uFE0F Invalid JSON in ${file} \u2014 file skipped`);
|
|
63633
|
-
continue;
|
|
63634
|
-
}
|
|
63635
|
-
} else {
|
|
63636
|
-
metadata = parser.parseFile(file);
|
|
63637
|
-
}
|
|
63638
|
-
metadata = await pluginManager.processFile(file, metadata);
|
|
63639
|
-
if (metadata.imports && Array.isArray(metadata.imports)) {
|
|
63640
|
-
totalImportsFound += metadata.imports.length;
|
|
63641
|
-
}
|
|
63642
|
-
const node = {
|
|
63643
|
-
id: normalizedRelativePath,
|
|
63644
|
-
type: "file",
|
|
63645
|
-
metadata
|
|
63646
|
-
};
|
|
63647
|
-
architectureMap.nodes.push(node);
|
|
63648
|
-
fileMap.set(normalizedRelativePath, metadata);
|
|
63649
|
-
} catch (e) {
|
|
63650
|
-
console.warn(`\u26A0\uFE0F Failed to process ${file} \u2014 file skipped, you should check manually (${e.message})`);
|
|
63651
|
-
}
|
|
63652
|
-
}
|
|
63653
|
-
const tsconfig = loadTSConfig(directory);
|
|
63654
|
-
const allPossiblePaths = /* @__PURE__ */ new Set();
|
|
63655
|
-
const pathToNodeIdMap = /* @__PURE__ */ new Map();
|
|
63656
|
-
architectureMap.nodes.forEach((node) => {
|
|
63657
|
-
const normalizedPath = normalize(node.id);
|
|
63658
|
-
allPossiblePaths.add(normalizedPath);
|
|
63659
|
-
pathToNodeIdMap.set(normalizedPath, node.id);
|
|
63660
|
-
});
|
|
63661
|
-
let unresolvedImports = 0;
|
|
63662
|
-
let resolvedImports = 0;
|
|
63663
|
-
architectureMap.nodes.forEach((node) => {
|
|
63664
|
-
if (node.metadata.imports && Array.isArray(node.metadata.imports)) {
|
|
63665
|
-
node.metadata.imports.forEach((imp) => {
|
|
63666
|
-
if (imp.source && typeof imp.source === "string") {
|
|
63667
|
-
let targetFound = false;
|
|
63668
|
-
try {
|
|
63669
|
-
if (allPossiblePaths.has(imp.source)) {
|
|
63670
|
-
architectureMap.edges.push({
|
|
63671
|
-
source: normalize(node.id),
|
|
63672
|
-
target: imp.source,
|
|
63673
|
-
type: imp.type || "import"
|
|
63674
|
-
});
|
|
63675
|
-
resolvedImports++;
|
|
63676
|
-
targetFound = true;
|
|
63677
|
-
}
|
|
63678
|
-
if (!targetFound) {
|
|
63679
|
-
const resolvedPath = resolveImport(
|
|
63680
|
-
imp.source,
|
|
63681
|
-
path2.join(directory, node.id),
|
|
63682
|
-
directory,
|
|
63683
|
-
tsconfig
|
|
63684
|
-
);
|
|
63685
|
-
if (resolvedPath) {
|
|
63686
|
-
const relativeResolvedPath = path2.relative(directory, resolvedPath);
|
|
63687
|
-
const normalizedResolvedPath = normalize(relativeResolvedPath);
|
|
63688
|
-
if (allPossiblePaths.has(normalizedResolvedPath)) {
|
|
63689
|
-
architectureMap.edges.push({
|
|
63690
|
-
source: normalize(node.id),
|
|
63691
|
-
target: normalizedResolvedPath,
|
|
63692
|
-
type: imp.type || "import"
|
|
63693
|
-
});
|
|
63694
|
-
resolvedImports++;
|
|
63695
|
-
targetFound = true;
|
|
63696
|
-
}
|
|
63697
|
-
}
|
|
63698
|
-
}
|
|
63699
|
-
if (!targetFound) {
|
|
63700
|
-
try {
|
|
63701
|
-
const baseDir = path2.dirname(path2.join(directory, node.id));
|
|
63702
|
-
const calculatedAbsolutePath = path2.resolve(baseDir, imp.source);
|
|
63703
|
-
const calculatedRelativePath = path2.relative(directory, calculatedAbsolutePath);
|
|
63704
|
-
const calculatedNormalizedPath = normalize(calculatedRelativePath);
|
|
63705
|
-
if (allPossiblePaths.has(calculatedNormalizedPath)) {
|
|
63706
|
-
architectureMap.edges.push({
|
|
63707
|
-
source: normalize(node.id),
|
|
63708
|
-
target: calculatedNormalizedPath,
|
|
63709
|
-
type: imp.type || "import"
|
|
63710
|
-
});
|
|
63711
|
-
resolvedImports++;
|
|
63712
|
-
targetFound = true;
|
|
63713
|
-
}
|
|
63714
|
-
} catch (e) {
|
|
63715
|
-
console.warn(`\u26A0\uFE0F Path calculation failed for import '${imp.source}' in file '${node.id}': ${e.message}`);
|
|
63716
|
-
}
|
|
63717
|
-
}
|
|
63718
|
-
if (!targetFound) {
|
|
63719
|
-
if (imp.source.startsWith("./") || imp.source.startsWith("../")) {
|
|
63720
|
-
const extensions = ["", ".js", ".ts", ".jsx", ".tsx", ".mjs", ".cjs"];
|
|
63721
|
-
for (const ext of extensions) {
|
|
63722
|
-
let testPath = imp.source;
|
|
63723
|
-
if (!imp.source.endsWith(ext)) {
|
|
63724
|
-
testPath = imp.source + ext;
|
|
63725
|
-
}
|
|
63726
|
-
try {
|
|
63727
|
-
const baseDir = path2.dirname(path2.join(directory, node.id));
|
|
63728
|
-
const calculatedAbsolutePath = path2.resolve(baseDir, testPath);
|
|
63729
|
-
const calculatedRelativePath = path2.relative(directory, calculatedAbsolutePath);
|
|
63730
|
-
const calculatedNormalizedPath = normalize(calculatedRelativePath);
|
|
63731
|
-
if (allPossiblePaths.has(calculatedNormalizedPath)) {
|
|
63732
|
-
architectureMap.edges.push({
|
|
63733
|
-
source: normalize(node.id),
|
|
63734
|
-
target: calculatedNormalizedPath,
|
|
63735
|
-
type: imp.type || "import"
|
|
63736
|
-
});
|
|
63737
|
-
resolvedImports++;
|
|
63738
|
-
targetFound = true;
|
|
63739
|
-
break;
|
|
63740
|
-
}
|
|
63741
|
-
} catch (e) {
|
|
63742
|
-
console.warn(`\u26A0\uFE0F Extension path calculation failed for import '${imp.source}' with extension '${ext}' in file '${node.id}': ${e.message}`);
|
|
63743
|
-
}
|
|
63744
|
-
}
|
|
63745
|
-
}
|
|
63746
|
-
}
|
|
63747
|
-
if (!targetFound) {
|
|
63748
|
-
if (imp.source.startsWith("./") || imp.source.startsWith("../")) {
|
|
63749
|
-
try {
|
|
63750
|
-
const baseDir = path2.dirname(path2.join(directory, node.id));
|
|
63751
|
-
const calculatedAbsolutePath = path2.resolve(baseDir, imp.source);
|
|
63752
|
-
const directoryPath = calculatedAbsolutePath;
|
|
63753
|
-
const indexFiles = ["index.js", "index.ts", "index.jsx", "index.tsx", "index.mjs", "index.cjs"];
|
|
63754
|
-
for (const indexFile of indexFiles) {
|
|
63755
|
-
const indexPath = path2.join(directoryPath, indexFile);
|
|
63756
|
-
const indexRelativePath = path2.relative(directory, indexPath);
|
|
63757
|
-
const indexNormalizedPath = normalize(indexRelativePath);
|
|
63758
|
-
if (allPossiblePaths.has(indexNormalizedPath)) {
|
|
63759
|
-
architectureMap.edges.push({
|
|
63760
|
-
source: normalize(node.id),
|
|
63761
|
-
target: indexNormalizedPath,
|
|
63762
|
-
type: imp.type || "import"
|
|
63763
|
-
});
|
|
63764
|
-
resolvedImports++;
|
|
63765
|
-
targetFound = true;
|
|
63766
|
-
break;
|
|
63767
|
-
}
|
|
63768
|
-
}
|
|
63769
|
-
} catch (e) {
|
|
63770
|
-
console.warn(`\u26A0\uFE0F Index file check failed for import '${imp.source}' in file '${node.id}': ${e.message}`);
|
|
63771
|
-
}
|
|
63772
|
-
}
|
|
63773
|
-
}
|
|
63774
|
-
if (!targetFound) {
|
|
63775
|
-
if (imp.source.startsWith("@") || imp.source.startsWith("/") || !imp.source.startsWith(".")) {
|
|
63776
|
-
const commonSourceDirs = ["src", "app", "lib", "components", "utils", "services", "assets"];
|
|
63777
|
-
for (const srcDir of commonSourceDirs) {
|
|
63778
|
-
const potentialPath = path2.join(srcDir, imp.source);
|
|
63779
|
-
const potentialRelativePath = path2.relative(directory, path2.resolve(directory, potentialPath));
|
|
63780
|
-
const potentialNormalizedPath = normalize(potentialRelativePath);
|
|
63781
|
-
if (allPossiblePaths.has(potentialNormalizedPath)) {
|
|
63782
|
-
architectureMap.edges.push({
|
|
63783
|
-
source: normalize(node.id),
|
|
63784
|
-
target: potentialNormalizedPath,
|
|
63785
|
-
type: imp.type || "import"
|
|
63786
|
-
});
|
|
63787
|
-
resolvedImports++;
|
|
63788
|
-
targetFound = true;
|
|
63789
|
-
break;
|
|
63790
|
-
}
|
|
63791
|
-
const extensions = [
|
|
63792
|
-
".js",
|
|
63793
|
-
".ts",
|
|
63794
|
-
".jsx",
|
|
63795
|
-
".tsx",
|
|
63796
|
-
".mjs",
|
|
63797
|
-
".cjs",
|
|
63798
|
-
"index.js",
|
|
63799
|
-
"index.ts",
|
|
63800
|
-
"index.jsx",
|
|
63801
|
-
"index.tsx",
|
|
63802
|
-
"index.mjs",
|
|
63803
|
-
"index.cjs"
|
|
63804
|
-
];
|
|
63805
|
-
for (const ext of extensions) {
|
|
63806
|
-
let testPath;
|
|
63807
|
-
if (ext.startsWith("index")) {
|
|
63808
|
-
testPath = path2.join(srcDir, imp.source, ext);
|
|
63809
|
-
} else {
|
|
63810
|
-
testPath = path2.join(srcDir, imp.source + ext);
|
|
63811
|
-
}
|
|
63812
|
-
const testRelativePath = path2.relative(directory, path2.resolve(directory, testPath));
|
|
63813
|
-
const testNormalizedPath = normalize(testRelativePath);
|
|
63814
|
-
if (allPossiblePaths.has(testNormalizedPath)) {
|
|
63815
|
-
architectureMap.edges.push({
|
|
63816
|
-
source: normalize(node.id),
|
|
63817
|
-
target: testNormalizedPath,
|
|
63818
|
-
type: imp.type || "import"
|
|
63819
|
-
});
|
|
63820
|
-
resolvedImports++;
|
|
63821
|
-
targetFound = true;
|
|
63822
|
-
break;
|
|
63823
|
-
}
|
|
63824
|
-
}
|
|
63825
|
-
if (targetFound)
|
|
63826
|
-
break;
|
|
63827
|
-
}
|
|
63828
|
-
}
|
|
63829
|
-
}
|
|
63830
|
-
if (!targetFound) {
|
|
63831
|
-
if (imp.source.startsWith("@") || imp.source.startsWith("/")) {
|
|
63832
|
-
try {
|
|
63833
|
-
const parts = imp.source.split("/");
|
|
63834
|
-
if (parts.length > 1) {
|
|
63835
|
-
const dirParts = parts.slice(0, -1);
|
|
63836
|
-
const fileName = parts[parts.length - 1];
|
|
63837
|
-
const dirPath = dirParts.join("/") + "/index";
|
|
63838
|
-
const indexFiles = ["index.js", "index.ts", "index.jsx", "index.tsx", "index.mjs", "index.cjs"];
|
|
63839
|
-
for (const indexFile of indexFiles) {
|
|
63840
|
-
const indexPath = path2.join(dirParts.join("/"), indexFile);
|
|
63841
|
-
const indexRelativePath = path2.relative(directory, path2.resolve(directory, indexPath));
|
|
63842
|
-
const indexNormalizedPath = normalize(indexRelativePath);
|
|
63843
|
-
if (allPossiblePaths.has(indexNormalizedPath)) {
|
|
63844
|
-
architectureMap.edges.push({
|
|
63845
|
-
source: normalize(node.id),
|
|
63846
|
-
target: indexNormalizedPath,
|
|
63847
|
-
type: imp.type || "import"
|
|
63848
|
-
});
|
|
63849
|
-
resolvedImports++;
|
|
63850
|
-
targetFound = true;
|
|
63851
|
-
break;
|
|
63852
|
-
}
|
|
63853
|
-
}
|
|
63854
|
-
}
|
|
63855
|
-
} catch (e) {
|
|
63856
|
-
console.warn(`\u26A0\uFE0F Barrel file check failed for import '${imp.source}' in file '${node.id}': ${e.message}`);
|
|
63857
|
-
}
|
|
63858
|
-
}
|
|
63859
|
-
}
|
|
63860
|
-
if (!targetFound) {
|
|
63861
|
-
for (const possiblePath of allPossiblePaths) {
|
|
63862
|
-
if (possiblePath.toLowerCase() === imp.source.toLowerCase()) {
|
|
63863
|
-
architectureMap.edges.push({
|
|
63864
|
-
source: normalize(node.id),
|
|
63865
|
-
target: possiblePath,
|
|
63866
|
-
type: imp.type || "import"
|
|
63867
|
-
});
|
|
63868
|
-
resolvedImports++;
|
|
63869
|
-
targetFound = true;
|
|
63870
|
-
break;
|
|
63871
|
-
}
|
|
63872
|
-
}
|
|
63873
|
-
}
|
|
63874
|
-
} catch (e) {
|
|
63875
|
-
console.error(`\u274C Critical error processing import '${imp.source}' in file '${node.id}': ${e.message}`);
|
|
63876
|
-
console.error(e.stack);
|
|
63877
|
-
unresolvedImports++;
|
|
63878
|
-
}
|
|
63879
|
-
if (!targetFound) {
|
|
63880
|
-
unresolvedImports++;
|
|
63881
|
-
}
|
|
63882
|
-
}
|
|
63883
|
-
});
|
|
63884
|
-
}
|
|
63885
|
-
});
|
|
63886
|
-
console.log("RESOLVED IMPORTS:", resolvedImports);
|
|
63887
|
-
console.log("UNRESOLVED IMPORTS:", unresolvedImports);
|
|
63888
|
-
console.log("EDGES CREATED:", architectureMap.edges.length);
|
|
63889
|
-
const reverseGraph = buildReverseDependencyGraph(architectureMap);
|
|
63890
|
-
const blastRadiusMap = computeBlastRadius(reverseGraph);
|
|
63891
|
-
architectureMap.nodes.forEach((node) => {
|
|
63892
|
-
node.metadata.blast_radius = blastRadiusMap[node.id] || 0;
|
|
63893
|
-
});
|
|
63894
|
-
console.log("BEFORE DEDUPLICATION EDGES:", architectureMap.edges.length);
|
|
63895
|
-
const validEdges = [];
|
|
63896
|
-
const edgeSet = /* @__PURE__ */ new Set();
|
|
63897
|
-
architectureMap.edges.forEach((edge) => {
|
|
63898
|
-
const normalizedSource = normalize(edge.source);
|
|
63899
|
-
const normalizedTarget = normalize(edge.target);
|
|
63900
|
-
const edgeKey = `${normalizedSource}\u2192${normalizedTarget}`;
|
|
63901
|
-
const sourceNodeExists = architectureMap.nodes.some((node) => node.id === normalizedSource);
|
|
63902
|
-
const targetNodeExists = architectureMap.nodes.some((node) => node.id === normalizedTarget);
|
|
63903
|
-
if (sourceNodeExists && targetNodeExists && !edgeSet.has(edgeKey)) {
|
|
63904
|
-
edgeSet.add(edgeKey);
|
|
63905
|
-
validEdges.push({
|
|
63906
|
-
source: normalizedSource,
|
|
63907
|
-
target: normalizedTarget,
|
|
63908
|
-
type: edge.type
|
|
63909
|
-
});
|
|
63910
|
-
}
|
|
63911
|
-
});
|
|
63912
|
-
console.log("AFTER DEDUPLICATION EDGES:", validEdges.length);
|
|
63913
|
-
architectureMap.edges = validEdges;
|
|
63914
|
-
const totalFiles = architectureMap.nodes.length;
|
|
63915
|
-
const { computeBlastRadiusWithPercentage: computeBlastRadiusWithPercentage2, analyzeCriticality } = require_blastRadius();
|
|
63916
|
-
const allFilesWithPercentage = computeBlastRadiusWithPercentage2(blastRadiusMap, totalFiles);
|
|
63917
|
-
const criticalityAnalysis = analyzeCriticality(blastRadiusMap, reverseGraph, architectureMap.nodes);
|
|
63918
|
-
const topFiles = allFilesWithPercentage.slice(0, 3);
|
|
63919
|
-
architectureMap.contextSurface = {
|
|
63920
|
-
topBlastRadiusFiles: topFiles,
|
|
63921
|
-
criticalityAnalysis: criticalityAnalysis.slice(0, 5)
|
|
63922
|
-
// Top 5 most critical files
|
|
63923
|
-
};
|
|
63924
|
-
let context = buildContext(architectureMap.nodes, architectureMap.edges, {
|
|
65175
|
+
const start = Date.now();
|
|
65176
|
+
const workspaceScanner = new WorkspaceScanner(directory);
|
|
65177
|
+
const workspaceContext = workspaceScanner.scan();
|
|
65178
|
+
const rawNodes = await executePass1(directory);
|
|
65179
|
+
const semanticData = await executePass2(rawNodes, directory, workspaceContext);
|
|
65180
|
+
const liftedData = await executePass3(semanticData);
|
|
65181
|
+
const structuralContext = await executePass4(liftedData);
|
|
65182
|
+
const { nodes, edges, contextSurface, symbols } = structuralContext;
|
|
65183
|
+
console.log(`
|
|
65184
|
+
\u{1F50D} Analysis Complete (${Date.now() - start}ms)`);
|
|
65185
|
+
console.log(` Nodes: ${nodes.length}`);
|
|
65186
|
+
console.log(` Edges: ${edges.length}`);
|
|
65187
|
+
console.log(` Symbols: ${symbols ? symbols.length : 0}`);
|
|
65188
|
+
const contextOptions = {
|
|
63925
65189
|
directory,
|
|
63926
65190
|
projectName: path2.basename(directory),
|
|
63927
|
-
|
|
63928
|
-
|
|
63929
|
-
|
|
63930
|
-
console.log("Validating structural context...");
|
|
65191
|
+
contextSurface
|
|
65192
|
+
};
|
|
65193
|
+
let context = buildContext(nodes, edges, symbols, contextOptions);
|
|
65194
|
+
console.log(" Validating structural context...");
|
|
63931
65195
|
let validation = validateContext(context);
|
|
63932
65196
|
if (!validation.valid) {
|
|
63933
|
-
console.error("
|
|
63934
|
-
validation.errors.forEach((e) => console.error("
|
|
63935
|
-
|
|
63936
|
-
context = buildContext(architectureMap.nodes, architectureMap.edges, {
|
|
63937
|
-
directory,
|
|
63938
|
-
projectName: path2.basename(directory),
|
|
63939
|
-
language: "javascript",
|
|
63940
|
-
contextSurface: architectureMap.contextSurface
|
|
63941
|
-
});
|
|
63942
|
-
validation = validateContext(context);
|
|
63943
|
-
if (!validation.valid) {
|
|
63944
|
-
console.error("VALIDATION FAILED (Attempt 2)");
|
|
63945
|
-
validation.errors.forEach((e) => console.error(" -", e));
|
|
63946
|
-
console.error("ABORTING. JSON NOT SAVED.");
|
|
63947
|
-
process.exit(1);
|
|
63948
|
-
}
|
|
65197
|
+
console.error(" \u274C Validation Failed");
|
|
65198
|
+
validation.errors.forEach((e) => console.error(" -", e));
|
|
65199
|
+
throw new Error("Context validation failed");
|
|
63949
65200
|
}
|
|
63950
65201
|
const sortedContext = sortContext(context);
|
|
63951
|
-
console.log("
|
|
65202
|
+
console.log(" \u2705 Context Verified & Ready");
|
|
63952
65203
|
return sortedContext;
|
|
63953
65204
|
} catch (err) {
|
|
65205
|
+
console.error("\u274C Scanner Failed:", err);
|
|
63954
65206
|
throw err;
|
|
63955
65207
|
}
|
|
63956
65208
|
}
|
|
@@ -64180,7 +65432,6 @@ program.command("scan").description("Scan the current directory and generate arc
|
|
|
64180
65432
|
const outputFileName = "arcvision.context.json";
|
|
64181
65433
|
fs2.writeFileSync(outputFileName, JSON.stringify(map, null, 2));
|
|
64182
65434
|
console.log(chalk.green(`\u2705 Structural context saved to ${outputFileName}`));
|
|
64183
|
-
console.log(JSON.stringify(map, null, 2));
|
|
64184
65435
|
console.log(chalk.dim("\nUse --upload to send to dashboard."));
|
|
64185
65436
|
}
|
|
64186
65437
|
} catch (error) {
|