arcvision 0.2.3 → 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 +1017 -636
- package/package.json +12 -2
- package/arcvision.context.json +0 -533
- 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/di-detector.js +0 -202
- package/src/core/method-tracker.js +0 -174
- package/src/core/parser-enhanced.js +0 -73
- package/src/core/parser.js +0 -343
- package/src/core/path-resolver.js +0 -174
- package/src/core/react-nextjs-detector.js +0 -245
- package/src/core/scanner.js +0 -518
- package/src/core/semantic-analyzer.js +0 -204
- package/src/core/tsconfig-utils.js +0 -35
- package/src/core/type-analyzer.js +0 -272
- package/src/core/watcher.js +0 -18
- package/src/engine/context_builder.js +0 -153
- 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
|
}
|
|
@@ -56740,13 +56920,11 @@ var require_method_tracker = __commonJS({
|
|
|
56740
56920
|
const callee = path2.node.callee;
|
|
56741
56921
|
if (callee.type === "Identifier") {
|
|
56742
56922
|
const functionName = callee.name;
|
|
56743
|
-
|
|
56744
|
-
|
|
56745
|
-
|
|
56746
|
-
|
|
56747
|
-
|
|
56748
|
-
});
|
|
56749
|
-
}
|
|
56923
|
+
functionCalls.push({
|
|
56924
|
+
name: functionName,
|
|
56925
|
+
type: "function_call",
|
|
56926
|
+
loc: path2.node.loc
|
|
56927
|
+
});
|
|
56750
56928
|
} else if (callee.type === "MemberExpression") {
|
|
56751
56929
|
const objectName = extractObjectName(callee.object);
|
|
56752
56930
|
const methodName = callee.property.name || callee.property.value;
|
|
@@ -56765,13 +56943,11 @@ var require_method_tracker = __commonJS({
|
|
|
56765
56943
|
const callee = path2.node.callee;
|
|
56766
56944
|
if (callee.type === "Identifier") {
|
|
56767
56945
|
const className = callee.name;
|
|
56768
|
-
|
|
56769
|
-
|
|
56770
|
-
|
|
56771
|
-
|
|
56772
|
-
|
|
56773
|
-
});
|
|
56774
|
-
}
|
|
56946
|
+
constructorCalls.push({
|
|
56947
|
+
className,
|
|
56948
|
+
type: "constructor_call",
|
|
56949
|
+
loc: path2.node.loc
|
|
56950
|
+
});
|
|
56775
56951
|
}
|
|
56776
56952
|
}
|
|
56777
56953
|
});
|
|
@@ -57310,34 +57486,96 @@ var require_plugin_manager = __commonJS({
|
|
|
57310
57486
|
}
|
|
57311
57487
|
});
|
|
57312
57488
|
|
|
57313
|
-
// src/
|
|
57314
|
-
var
|
|
57315
|
-
"src/
|
|
57316
|
-
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();
|
|
57317
57493
|
var path2 = require("path");
|
|
57318
|
-
|
|
57319
|
-
|
|
57320
|
-
|
|
57321
|
-
|
|
57322
|
-
|
|
57323
|
-
|
|
57324
|
-
|
|
57325
|
-
|
|
57326
|
-
|
|
57327
|
-
|
|
57328
|
-
|
|
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;
|
|
57329
57533
|
}
|
|
57330
|
-
|
|
57331
|
-
|
|
57332
|
-
}
|
|
57333
|
-
|
|
57334
|
-
|
|
57335
|
-
|
|
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}`);
|
|
57336
57572
|
}
|
|
57337
57573
|
}
|
|
57338
|
-
|
|
57574
|
+
console.log(` \u2713 Scanned ${rawNodes.length} files`);
|
|
57575
|
+
console.log(` \u2713 Extracted ${totalFacts} raw syntactic facts`);
|
|
57576
|
+
return rawNodes;
|
|
57339
57577
|
}
|
|
57340
|
-
module2.exports = {
|
|
57578
|
+
module2.exports = { executePass1 };
|
|
57341
57579
|
}
|
|
57342
57580
|
});
|
|
57343
57581
|
|
|
@@ -57346,7 +57584,7 @@ var require_path_resolver = __commonJS({
|
|
|
57346
57584
|
"src/core/path-resolver.js"(exports2, module2) {
|
|
57347
57585
|
var fs2 = require("fs");
|
|
57348
57586
|
var path2 = require("path");
|
|
57349
|
-
function resolveImport(importPath, importerPath, projectRoot, tsconfig) {
|
|
57587
|
+
function resolveImport(importPath, importerPath, projectRoot, tsconfig, workspaceMap) {
|
|
57350
57588
|
if (importPath.startsWith("http://") || importPath.startsWith("https://") || importPath.startsWith("data:") || importPath.startsWith("file:")) {
|
|
57351
57589
|
return null;
|
|
57352
57590
|
}
|
|
@@ -57377,8 +57615,8 @@ var require_path_resolver = __commonJS({
|
|
|
57377
57615
|
const aliasTargets = paths[aliasPattern];
|
|
57378
57616
|
if (aliasPattern.includes("*")) {
|
|
57379
57617
|
const patternBase = aliasPattern.replace(/\*.*$/, "");
|
|
57380
|
-
if (importPath.startsWith(patternBase)) {
|
|
57381
|
-
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) : "";
|
|
57382
57620
|
for (const target of aliasTargets) {
|
|
57383
57621
|
const targetBase = target.replace(/\*.*$/, "");
|
|
57384
57622
|
const targetPath = path2.resolve(projectRoot, path2.join(targetBase, suffix));
|
|
@@ -57448,6 +57686,51 @@ var require_path_resolver = __commonJS({
|
|
|
57448
57686
|
return resolvedPath;
|
|
57449
57687
|
}
|
|
57450
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
|
+
}
|
|
57451
57734
|
if (!importPath.startsWith(".")) {
|
|
57452
57735
|
try {
|
|
57453
57736
|
const resolved = require.resolve(importPath, { paths: [path2.dirname(importerPath)] });
|
|
@@ -57461,6 +57744,509 @@ var require_path_resolver = __commonJS({
|
|
|
57461
57744
|
}
|
|
57462
57745
|
});
|
|
57463
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
|
+
|
|
57464
58250
|
// src/core/blastRadius.js
|
|
57465
58251
|
var require_blastRadius = __commonJS({
|
|
57466
58252
|
"src/core/blastRadius.js"(exports2, module2) {
|
|
@@ -57582,7 +58368,12 @@ var require_blastRadius = __commonJS({
|
|
|
57582
58368
|
// Consider files with blast radius > 5 as hubs
|
|
57583
58369
|
});
|
|
57584
58370
|
}
|
|
57585
|
-
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
|
+
});
|
|
57586
58377
|
}
|
|
57587
58378
|
function calculateDependencyStrength(reverseGraph, file) {
|
|
57588
58379
|
if (!reverseGraph[file] || !Array.isArray(reverseGraph[file])) {
|
|
@@ -57608,6 +58399,76 @@ var require_blastRadius = __commonJS({
|
|
|
57608
58399
|
}
|
|
57609
58400
|
});
|
|
57610
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
|
+
|
|
57611
58472
|
// src/engine/id-generator.js
|
|
57612
58473
|
var require_id_generator = __commonJS({
|
|
57613
58474
|
"src/engine/id-generator.js"(exports2, module2) {
|
|
@@ -57620,92 +58481,109 @@ var require_id_generator = __commonJS({
|
|
|
57620
58481
|
}
|
|
57621
58482
|
});
|
|
57622
58483
|
|
|
57623
|
-
// src/
|
|
58484
|
+
// src/core/context_builder.js
|
|
57624
58485
|
var require_context_builder = __commonJS({
|
|
57625
|
-
"src/
|
|
58486
|
+
"src/core/context_builder.js"(exports2, module2) {
|
|
57626
58487
|
var path2 = require("path");
|
|
57627
58488
|
var { stableId } = require_id_generator();
|
|
57628
|
-
function buildContext(
|
|
58489
|
+
function buildContext(fileNodes, edges, symbols, options = {}) {
|
|
57629
58490
|
const {
|
|
57630
58491
|
directory = ".",
|
|
57631
58492
|
projectName = "arcvision",
|
|
57632
58493
|
language = "javascript"
|
|
57633
58494
|
} = options;
|
|
57634
|
-
const nodes =
|
|
57635
|
-
const
|
|
57636
|
-
const
|
|
57637
|
-
const hasClasses = file.metadata.classes && file.metadata.classes.length > 0;
|
|
57638
|
-
const hasExports = file.metadata.exports && file.metadata.exports.length > 0;
|
|
57639
|
-
const hasApiCalls = file.metadata.apiCalls && file.metadata.apiCalls.length > 0;
|
|
57640
|
-
let role = "Structure";
|
|
57641
|
-
if (hasFunctions || hasClasses || hasApiCalls) {
|
|
57642
|
-
role = "Implementation";
|
|
57643
|
-
} else if (hasExports) {
|
|
57644
|
-
role = "Interface";
|
|
57645
|
-
}
|
|
58495
|
+
const nodes = fileNodes.map((file) => {
|
|
58496
|
+
const role = file.role || "Structure";
|
|
58497
|
+
const layer = file.layer || "generic";
|
|
57646
58498
|
const dependencies = [];
|
|
57647
58499
|
const uniqueDeps = /* @__PURE__ */ new Set();
|
|
57648
|
-
|
|
57649
|
-
|
|
57650
|
-
|
|
57651
|
-
|
|
57652
|
-
|
|
57653
|
-
|
|
57654
|
-
|
|
57655
|
-
|
|
57656
|
-
|
|
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));
|
|
57657
58510
|
}
|
|
57658
|
-
|
|
57659
|
-
id: stableId(
|
|
58511
|
+
const nodeObj = {
|
|
58512
|
+
id: stableId(file.id),
|
|
57660
58513
|
type: "file",
|
|
57661
|
-
path:
|
|
58514
|
+
path: file.id,
|
|
57662
58515
|
role,
|
|
57663
58516
|
dependencies,
|
|
57664
|
-
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
|
|
57665
58521
|
};
|
|
58522
|
+
return nodeObj;
|
|
57666
58523
|
});
|
|
57667
|
-
const
|
|
58524
|
+
const nodeMap = new Map(nodes.map((n) => [n.path, n]));
|
|
58525
|
+
const edgeKeyMap = /* @__PURE__ */ new Map();
|
|
57668
58526
|
for (const edge of edges) {
|
|
57669
|
-
const sourceNode =
|
|
57670
|
-
const targetNode =
|
|
57671
|
-
if (sourceNode) {
|
|
58527
|
+
const sourceNode = nodeMap.get(edge.source);
|
|
58528
|
+
const targetNode = nodeMap.get(edge.target);
|
|
58529
|
+
if (sourceNode && targetNode) {
|
|
57672
58530
|
let relationType = "imports";
|
|
57673
|
-
|
|
57674
|
-
|
|
57675
|
-
|
|
57676
|
-
|
|
57677
|
-
|
|
57678
|
-
|
|
57679
|
-
|
|
57680
|
-
|
|
57681
|
-
|
|
57682
|
-
|
|
57683
|
-
|
|
57684
|
-
|
|
57685
|
-
|
|
57686
|
-
|
|
57687
|
-
|
|
57688
|
-
|
|
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;
|
|
57689
58554
|
}
|
|
57690
|
-
|
|
57691
|
-
|
|
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, {
|
|
57692
58560
|
from: sourceNode.id,
|
|
57693
58561
|
to: targetNode.id,
|
|
57694
|
-
relation: relationType
|
|
58562
|
+
relation: relationType,
|
|
58563
|
+
weight: 1
|
|
57695
58564
|
});
|
|
57696
|
-
} else {
|
|
57697
58565
|
}
|
|
57698
58566
|
}
|
|
57699
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
|
+
});
|
|
57700
58575
|
const metrics = {
|
|
57701
58576
|
total_files: nodes.length,
|
|
57702
58577
|
total_nodes: nodes.length,
|
|
57703
58578
|
total_edges: schemaEdges.length,
|
|
57704
|
-
total_imports: schemaEdges.filter((edge) => edge.relation === "imports").
|
|
57705
|
-
total_calls: schemaEdges.filter((edge) => edge.relation === "calls").
|
|
57706
|
-
total_owns: schemaEdges.filter((edge) => edge.relation === "owns").
|
|
57707
|
-
total_depends_on: schemaEdges.filter((edge) => edge.relation === "depends_on").
|
|
57708
|
-
files_with_functions:
|
|
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
|
|
57709
58587
|
};
|
|
57710
58588
|
const context = {
|
|
57711
58589
|
schema_version: "1.0.0",
|
|
@@ -57717,12 +58595,10 @@ var require_context_builder = __commonJS({
|
|
|
57717
58595
|
},
|
|
57718
58596
|
nodes,
|
|
57719
58597
|
edges: schemaEdges,
|
|
58598
|
+
symbols: symbols || [],
|
|
57720
58599
|
metrics,
|
|
57721
|
-
contextSurface: options.contextSurface ||
|
|
58600
|
+
contextSurface: options.contextSurface || []
|
|
57722
58601
|
};
|
|
57723
|
-
context.metrics.files_with_functions = nodes.filter((n) => n.role === "Implementation").length;
|
|
57724
|
-
context.metrics.files_with_high_blast_radius = nodes.filter((n) => n.blast_radius > 5).length;
|
|
57725
|
-
context.metrics.total_dependencies = schemaEdges.length;
|
|
57726
58602
|
return context;
|
|
57727
58603
|
}
|
|
57728
58604
|
module2.exports = { buildContext };
|
|
@@ -64277,550 +65153,56 @@ var require_context_sorter = __commonJS({
|
|
|
64277
65153
|
}
|
|
64278
65154
|
});
|
|
64279
65155
|
|
|
64280
|
-
// src/core/semantic-analyzer.js
|
|
64281
|
-
var require_semantic_analyzer = __commonJS({
|
|
64282
|
-
"src/core/semantic-analyzer.js"(exports2, module2) {
|
|
64283
|
-
function buildSymbolTable(nodes) {
|
|
64284
|
-
const symbolTable = /* @__PURE__ */ new Map();
|
|
64285
|
-
nodes.forEach((node) => {
|
|
64286
|
-
const filePath = node.id;
|
|
64287
|
-
const metadata = node.metadata;
|
|
64288
|
-
if (!metadata)
|
|
64289
|
-
return;
|
|
64290
|
-
if (metadata.exports && Array.isArray(metadata.exports)) {
|
|
64291
|
-
metadata.exports.forEach((exp) => {
|
|
64292
|
-
const symbolName = exp.name;
|
|
64293
|
-
if (!symbolTable.has(symbolName)) {
|
|
64294
|
-
symbolTable.set(symbolName, []);
|
|
64295
|
-
}
|
|
64296
|
-
symbolTable.get(symbolName).push({
|
|
64297
|
-
file: filePath,
|
|
64298
|
-
type: exp.type,
|
|
64299
|
-
loc: exp.loc
|
|
64300
|
-
});
|
|
64301
|
-
});
|
|
64302
|
-
}
|
|
64303
|
-
if (metadata.functions && Array.isArray(metadata.functions)) {
|
|
64304
|
-
metadata.functions.forEach((func) => {
|
|
64305
|
-
const symbolName = func.name;
|
|
64306
|
-
if (!symbolTable.has(symbolName)) {
|
|
64307
|
-
symbolTable.set(symbolName, []);
|
|
64308
|
-
}
|
|
64309
|
-
symbolTable.get(symbolName).push({
|
|
64310
|
-
file: filePath,
|
|
64311
|
-
type: "function",
|
|
64312
|
-
loc: func.loc
|
|
64313
|
-
});
|
|
64314
|
-
});
|
|
64315
|
-
}
|
|
64316
|
-
if (metadata.classes && Array.isArray(metadata.classes)) {
|
|
64317
|
-
metadata.classes.forEach((cls) => {
|
|
64318
|
-
const symbolName = cls.name;
|
|
64319
|
-
if (!symbolTable.has(symbolName)) {
|
|
64320
|
-
symbolTable.set(symbolName, []);
|
|
64321
|
-
}
|
|
64322
|
-
symbolTable.get(symbolName).push({
|
|
64323
|
-
file: filePath,
|
|
64324
|
-
type: "class",
|
|
64325
|
-
loc: cls.loc
|
|
64326
|
-
});
|
|
64327
|
-
});
|
|
64328
|
-
}
|
|
64329
|
-
});
|
|
64330
|
-
return symbolTable;
|
|
64331
|
-
}
|
|
64332
|
-
function resolveSymbolUsage(node, symbolTable) {
|
|
64333
|
-
const resolvedUsages = [];
|
|
64334
|
-
const metadata = node.metadata;
|
|
64335
|
-
if (!metadata)
|
|
64336
|
-
return resolvedUsages;
|
|
64337
|
-
const importedSymbols = /* @__PURE__ */ new Map();
|
|
64338
|
-
if (metadata.imports && Array.isArray(metadata.imports)) {
|
|
64339
|
-
metadata.imports.forEach((imp) => {
|
|
64340
|
-
if (imp.specifiers && Array.isArray(imp.specifiers)) {
|
|
64341
|
-
imp.specifiers.forEach((spec) => {
|
|
64342
|
-
const localName = spec.local || spec.imported || spec;
|
|
64343
|
-
const importedName = spec.imported || spec.local || spec;
|
|
64344
|
-
importedSymbols.set(localName, {
|
|
64345
|
-
source: imp.source,
|
|
64346
|
-
originalName: importedName
|
|
64347
|
-
});
|
|
64348
|
-
});
|
|
64349
|
-
}
|
|
64350
|
-
});
|
|
64351
|
-
}
|
|
64352
|
-
if (metadata.functionCalls && Array.isArray(metadata.functionCalls)) {
|
|
64353
|
-
metadata.functionCalls.forEach((call) => {
|
|
64354
|
-
const callName = call.name;
|
|
64355
|
-
if (importedSymbols.has(callName)) {
|
|
64356
|
-
const importInfo = importedSymbols.get(callName);
|
|
64357
|
-
resolvedUsages.push({
|
|
64358
|
-
type: "function_call",
|
|
64359
|
-
symbol: callName,
|
|
64360
|
-
source: importInfo.source,
|
|
64361
|
-
loc: call.loc
|
|
64362
|
-
});
|
|
64363
|
-
}
|
|
64364
|
-
});
|
|
64365
|
-
}
|
|
64366
|
-
if (metadata.constructorCalls && Array.isArray(metadata.constructorCalls)) {
|
|
64367
|
-
metadata.constructorCalls.forEach((call) => {
|
|
64368
|
-
const className = call.className;
|
|
64369
|
-
if (importedSymbols.has(className)) {
|
|
64370
|
-
const importInfo = importedSymbols.get(className);
|
|
64371
|
-
resolvedUsages.push({
|
|
64372
|
-
type: "constructor_call",
|
|
64373
|
-
symbol: className,
|
|
64374
|
-
source: importInfo.source,
|
|
64375
|
-
loc: call.loc
|
|
64376
|
-
});
|
|
64377
|
-
}
|
|
64378
|
-
});
|
|
64379
|
-
}
|
|
64380
|
-
if (metadata.componentUsage && Array.isArray(metadata.componentUsage)) {
|
|
64381
|
-
metadata.componentUsage.forEach((comp) => {
|
|
64382
|
-
const componentName = comp.component;
|
|
64383
|
-
if (importedSymbols.has(componentName)) {
|
|
64384
|
-
const importInfo = importedSymbols.get(componentName);
|
|
64385
|
-
resolvedUsages.push({
|
|
64386
|
-
type: "component_usage",
|
|
64387
|
-
symbol: componentName,
|
|
64388
|
-
source: importInfo.source,
|
|
64389
|
-
loc: comp.loc
|
|
64390
|
-
});
|
|
64391
|
-
}
|
|
64392
|
-
});
|
|
64393
|
-
}
|
|
64394
|
-
return resolvedUsages;
|
|
64395
|
-
}
|
|
64396
|
-
function trackCrossFileReferences(nodes, symbolTable) {
|
|
64397
|
-
const usageEdges = [];
|
|
64398
|
-
nodes.forEach((node) => {
|
|
64399
|
-
const filePath = node.id;
|
|
64400
|
-
const resolvedUsages = resolveSymbolUsage(node, symbolTable);
|
|
64401
|
-
resolvedUsages.forEach((usage) => {
|
|
64402
|
-
usageEdges.push({
|
|
64403
|
-
source: filePath,
|
|
64404
|
-
target: usage.source,
|
|
64405
|
-
type: usage.type,
|
|
64406
|
-
symbol: usage.symbol,
|
|
64407
|
-
loc: usage.loc
|
|
64408
|
-
});
|
|
64409
|
-
});
|
|
64410
|
-
});
|
|
64411
|
-
return usageEdges;
|
|
64412
|
-
}
|
|
64413
|
-
function analyzeSemantics(nodes) {
|
|
64414
|
-
const symbolTable = buildSymbolTable(nodes);
|
|
64415
|
-
const usageEdges = trackCrossFileReferences(nodes, symbolTable);
|
|
64416
|
-
return {
|
|
64417
|
-
symbolTable,
|
|
64418
|
-
usageEdges,
|
|
64419
|
-
stats: {
|
|
64420
|
-
totalSymbols: symbolTable.size,
|
|
64421
|
-
totalUsages: usageEdges.length
|
|
64422
|
-
}
|
|
64423
|
-
};
|
|
64424
|
-
}
|
|
64425
|
-
module2.exports = {
|
|
64426
|
-
buildSymbolTable,
|
|
64427
|
-
resolveSymbolUsage,
|
|
64428
|
-
trackCrossFileReferences,
|
|
64429
|
-
analyzeSemantics
|
|
64430
|
-
};
|
|
64431
|
-
}
|
|
64432
|
-
});
|
|
64433
|
-
|
|
64434
65156
|
// src/core/scanner.js
|
|
64435
65157
|
var require_scanner = __commonJS({
|
|
64436
65158
|
"src/core/scanner.js"(exports2, module2) {
|
|
64437
|
-
var { glob } = require_commonjs5();
|
|
64438
65159
|
var path2 = require("path");
|
|
64439
|
-
var fs2 = require("fs");
|
|
64440
|
-
var parser = require_parser_enhanced();
|
|
64441
|
-
var pluginManager = require_plugin_manager();
|
|
64442
65160
|
var { loadTSConfig } = require_tsconfig_utils();
|
|
64443
|
-
var {
|
|
64444
|
-
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();
|
|
64445
65166
|
var { buildContext } = require_context_builder();
|
|
64446
65167
|
var { validateContext } = require_context_validator();
|
|
64447
65168
|
var { sortContext } = require_context_sorter();
|
|
64448
|
-
var { analyzeSemantics } = require_semantic_analyzer();
|
|
64449
65169
|
async function scan(directory) {
|
|
64450
|
-
|
|
64451
|
-
|
|
64452
|
-
|
|
64453
|
-
|
|
64454
|
-
absolute: true
|
|
64455
|
-
};
|
|
65170
|
+
console.log(`
|
|
65171
|
+
\u{1F680} ARCVISION STRUCTURAL ENGINE (4-PASS)`);
|
|
65172
|
+
console.log(` Target: ${directory}
|
|
65173
|
+
`);
|
|
64456
65174
|
try {
|
|
64457
|
-
const
|
|
64458
|
-
|
|
64459
|
-
const
|
|
64460
|
-
const
|
|
64461
|
-
|
|
64462
|
-
|
|
64463
|
-
|
|
64464
|
-
const
|
|
64465
|
-
|
|
64466
|
-
|
|
64467
|
-
|
|
64468
|
-
|
|
64469
|
-
|
|
64470
|
-
|
|
64471
|
-
if (file.endsWith(".json")) {
|
|
64472
|
-
try {
|
|
64473
|
-
const content = fs2.readFileSync(file, "utf-8");
|
|
64474
|
-
JSON.parse(content);
|
|
64475
|
-
metadata = {
|
|
64476
|
-
id: file,
|
|
64477
|
-
imports: [],
|
|
64478
|
-
exports: [],
|
|
64479
|
-
functions: [],
|
|
64480
|
-
apiCalls: [],
|
|
64481
|
-
isJson: true
|
|
64482
|
-
};
|
|
64483
|
-
} catch (jsonError) {
|
|
64484
|
-
console.warn(`\u26A0\uFE0F Invalid JSON in ${file} \u2014 file skipped`);
|
|
64485
|
-
continue;
|
|
64486
|
-
}
|
|
64487
|
-
} else {
|
|
64488
|
-
metadata = parser.parseFile(file);
|
|
64489
|
-
}
|
|
64490
|
-
metadata = await pluginManager.processFile(file, metadata);
|
|
64491
|
-
if (metadata.imports && Array.isArray(metadata.imports)) {
|
|
64492
|
-
totalImportsFound += metadata.imports.length;
|
|
64493
|
-
}
|
|
64494
|
-
const node = {
|
|
64495
|
-
id: normalizedRelativePath,
|
|
64496
|
-
type: "file",
|
|
64497
|
-
metadata
|
|
64498
|
-
};
|
|
64499
|
-
architectureMap.nodes.push(node);
|
|
64500
|
-
fileMap.set(normalizedRelativePath, metadata);
|
|
64501
|
-
} catch (e) {
|
|
64502
|
-
console.warn(`\u26A0\uFE0F Failed to process ${file} \u2014 file skipped, you should check manually (${e.message})`);
|
|
64503
|
-
}
|
|
64504
|
-
}
|
|
64505
|
-
console.log("Performing semantic analysis...");
|
|
64506
|
-
const semanticResults = analyzeSemantics(architectureMap.nodes);
|
|
64507
|
-
console.log(`Semantic analysis complete: ${semanticResults.stats.totalSymbols} symbols, ${semanticResults.stats.totalUsages} usage edges`);
|
|
64508
|
-
const tsconfig = loadTSConfig(directory);
|
|
64509
|
-
const allPossiblePaths = /* @__PURE__ */ new Set();
|
|
64510
|
-
const pathToNodeIdMap = /* @__PURE__ */ new Map();
|
|
64511
|
-
architectureMap.nodes.forEach((node) => {
|
|
64512
|
-
const normalizedPath = normalize(node.id);
|
|
64513
|
-
allPossiblePaths.add(normalizedPath);
|
|
64514
|
-
pathToNodeIdMap.set(normalizedPath, node.id);
|
|
64515
|
-
});
|
|
64516
|
-
let unresolvedImports = 0;
|
|
64517
|
-
let resolvedImports = 0;
|
|
64518
|
-
architectureMap.nodes.forEach((node) => {
|
|
64519
|
-
if (node.metadata.imports && Array.isArray(node.metadata.imports)) {
|
|
64520
|
-
node.metadata.imports.forEach((imp) => {
|
|
64521
|
-
if (imp.source && typeof imp.source === "string") {
|
|
64522
|
-
let targetFound = false;
|
|
64523
|
-
try {
|
|
64524
|
-
if (allPossiblePaths.has(imp.source)) {
|
|
64525
|
-
architectureMap.edges.push({
|
|
64526
|
-
source: normalize(node.id),
|
|
64527
|
-
target: imp.source,
|
|
64528
|
-
type: imp.type || "import"
|
|
64529
|
-
});
|
|
64530
|
-
resolvedImports++;
|
|
64531
|
-
targetFound = true;
|
|
64532
|
-
}
|
|
64533
|
-
if (!targetFound) {
|
|
64534
|
-
const resolvedPath = resolveImport(
|
|
64535
|
-
imp.source,
|
|
64536
|
-
path2.join(directory, node.id),
|
|
64537
|
-
directory,
|
|
64538
|
-
tsconfig
|
|
64539
|
-
);
|
|
64540
|
-
if (resolvedPath) {
|
|
64541
|
-
const relativeResolvedPath = path2.relative(directory, resolvedPath);
|
|
64542
|
-
const normalizedResolvedPath = normalize(relativeResolvedPath);
|
|
64543
|
-
if (allPossiblePaths.has(normalizedResolvedPath)) {
|
|
64544
|
-
architectureMap.edges.push({
|
|
64545
|
-
source: normalize(node.id),
|
|
64546
|
-
target: normalizedResolvedPath,
|
|
64547
|
-
type: imp.type || "import"
|
|
64548
|
-
});
|
|
64549
|
-
resolvedImports++;
|
|
64550
|
-
targetFound = true;
|
|
64551
|
-
}
|
|
64552
|
-
}
|
|
64553
|
-
}
|
|
64554
|
-
if (!targetFound) {
|
|
64555
|
-
try {
|
|
64556
|
-
const baseDir = path2.dirname(path2.join(directory, node.id));
|
|
64557
|
-
const calculatedAbsolutePath = path2.resolve(baseDir, imp.source);
|
|
64558
|
-
const calculatedRelativePath = path2.relative(directory, calculatedAbsolutePath);
|
|
64559
|
-
const calculatedNormalizedPath = normalize(calculatedRelativePath);
|
|
64560
|
-
if (allPossiblePaths.has(calculatedNormalizedPath)) {
|
|
64561
|
-
architectureMap.edges.push({
|
|
64562
|
-
source: normalize(node.id),
|
|
64563
|
-
target: calculatedNormalizedPath,
|
|
64564
|
-
type: imp.type || "import"
|
|
64565
|
-
});
|
|
64566
|
-
resolvedImports++;
|
|
64567
|
-
targetFound = true;
|
|
64568
|
-
}
|
|
64569
|
-
} catch (e) {
|
|
64570
|
-
console.warn(`\u26A0\uFE0F Path calculation failed for import '${imp.source}' in file '${node.id}': ${e.message}`);
|
|
64571
|
-
}
|
|
64572
|
-
}
|
|
64573
|
-
if (!targetFound) {
|
|
64574
|
-
if (imp.source.startsWith("./") || imp.source.startsWith("../")) {
|
|
64575
|
-
const extensions = ["", ".js", ".ts", ".jsx", ".tsx", ".mjs", ".cjs"];
|
|
64576
|
-
for (const ext of extensions) {
|
|
64577
|
-
let testPath = imp.source;
|
|
64578
|
-
if (!imp.source.endsWith(ext)) {
|
|
64579
|
-
testPath = imp.source + ext;
|
|
64580
|
-
}
|
|
64581
|
-
try {
|
|
64582
|
-
const baseDir = path2.dirname(path2.join(directory, node.id));
|
|
64583
|
-
const calculatedAbsolutePath = path2.resolve(baseDir, testPath);
|
|
64584
|
-
const calculatedRelativePath = path2.relative(directory, calculatedAbsolutePath);
|
|
64585
|
-
const calculatedNormalizedPath = normalize(calculatedRelativePath);
|
|
64586
|
-
if (allPossiblePaths.has(calculatedNormalizedPath)) {
|
|
64587
|
-
architectureMap.edges.push({
|
|
64588
|
-
source: normalize(node.id),
|
|
64589
|
-
target: calculatedNormalizedPath,
|
|
64590
|
-
type: imp.type || "import"
|
|
64591
|
-
});
|
|
64592
|
-
resolvedImports++;
|
|
64593
|
-
targetFound = true;
|
|
64594
|
-
break;
|
|
64595
|
-
}
|
|
64596
|
-
} catch (e) {
|
|
64597
|
-
console.warn(`\u26A0\uFE0F Extension path calculation failed for import '${imp.source}' with extension '${ext}' in file '${node.id}': ${e.message}`);
|
|
64598
|
-
}
|
|
64599
|
-
}
|
|
64600
|
-
}
|
|
64601
|
-
}
|
|
64602
|
-
if (!targetFound) {
|
|
64603
|
-
if (imp.source.startsWith("./") || imp.source.startsWith("../")) {
|
|
64604
|
-
try {
|
|
64605
|
-
const baseDir = path2.dirname(path2.join(directory, node.id));
|
|
64606
|
-
const calculatedAbsolutePath = path2.resolve(baseDir, imp.source);
|
|
64607
|
-
const directoryPath = calculatedAbsolutePath;
|
|
64608
|
-
const indexFiles = ["index.js", "index.ts", "index.jsx", "index.tsx", "index.mjs", "index.cjs"];
|
|
64609
|
-
for (const indexFile of indexFiles) {
|
|
64610
|
-
const indexPath = path2.join(directoryPath, indexFile);
|
|
64611
|
-
const indexRelativePath = path2.relative(directory, indexPath);
|
|
64612
|
-
const indexNormalizedPath = normalize(indexRelativePath);
|
|
64613
|
-
if (allPossiblePaths.has(indexNormalizedPath)) {
|
|
64614
|
-
architectureMap.edges.push({
|
|
64615
|
-
source: normalize(node.id),
|
|
64616
|
-
target: indexNormalizedPath,
|
|
64617
|
-
type: imp.type || "import"
|
|
64618
|
-
});
|
|
64619
|
-
resolvedImports++;
|
|
64620
|
-
targetFound = true;
|
|
64621
|
-
break;
|
|
64622
|
-
}
|
|
64623
|
-
}
|
|
64624
|
-
} catch (e) {
|
|
64625
|
-
console.warn(`\u26A0\uFE0F Index file check failed for import '${imp.source}' in file '${node.id}': ${e.message}`);
|
|
64626
|
-
}
|
|
64627
|
-
}
|
|
64628
|
-
}
|
|
64629
|
-
if (!targetFound) {
|
|
64630
|
-
if (imp.source.startsWith("@") || imp.source.startsWith("/") || !imp.source.startsWith(".")) {
|
|
64631
|
-
const commonSourceDirs = ["src", "app", "lib", "components", "utils", "services", "assets"];
|
|
64632
|
-
for (const srcDir of commonSourceDirs) {
|
|
64633
|
-
const potentialPath = path2.join(srcDir, imp.source);
|
|
64634
|
-
const potentialRelativePath = path2.relative(directory, path2.resolve(directory, potentialPath));
|
|
64635
|
-
const potentialNormalizedPath = normalize(potentialRelativePath);
|
|
64636
|
-
if (allPossiblePaths.has(potentialNormalizedPath)) {
|
|
64637
|
-
architectureMap.edges.push({
|
|
64638
|
-
source: normalize(node.id),
|
|
64639
|
-
target: potentialNormalizedPath,
|
|
64640
|
-
type: imp.type || "import"
|
|
64641
|
-
});
|
|
64642
|
-
resolvedImports++;
|
|
64643
|
-
targetFound = true;
|
|
64644
|
-
break;
|
|
64645
|
-
}
|
|
64646
|
-
const extensions = [
|
|
64647
|
-
".js",
|
|
64648
|
-
".ts",
|
|
64649
|
-
".jsx",
|
|
64650
|
-
".tsx",
|
|
64651
|
-
".mjs",
|
|
64652
|
-
".cjs",
|
|
64653
|
-
"index.js",
|
|
64654
|
-
"index.ts",
|
|
64655
|
-
"index.jsx",
|
|
64656
|
-
"index.tsx",
|
|
64657
|
-
"index.mjs",
|
|
64658
|
-
"index.cjs"
|
|
64659
|
-
];
|
|
64660
|
-
for (const ext of extensions) {
|
|
64661
|
-
let testPath;
|
|
64662
|
-
if (ext.startsWith("index")) {
|
|
64663
|
-
testPath = path2.join(srcDir, imp.source, ext);
|
|
64664
|
-
} else {
|
|
64665
|
-
testPath = path2.join(srcDir, imp.source + ext);
|
|
64666
|
-
}
|
|
64667
|
-
const testRelativePath = path2.relative(directory, path2.resolve(directory, testPath));
|
|
64668
|
-
const testNormalizedPath = normalize(testRelativePath);
|
|
64669
|
-
if (allPossiblePaths.has(testNormalizedPath)) {
|
|
64670
|
-
architectureMap.edges.push({
|
|
64671
|
-
source: normalize(node.id),
|
|
64672
|
-
target: testNormalizedPath,
|
|
64673
|
-
type: imp.type || "import"
|
|
64674
|
-
});
|
|
64675
|
-
resolvedImports++;
|
|
64676
|
-
targetFound = true;
|
|
64677
|
-
break;
|
|
64678
|
-
}
|
|
64679
|
-
}
|
|
64680
|
-
if (targetFound)
|
|
64681
|
-
break;
|
|
64682
|
-
}
|
|
64683
|
-
}
|
|
64684
|
-
}
|
|
64685
|
-
if (!targetFound) {
|
|
64686
|
-
if (imp.source.startsWith("@") || imp.source.startsWith("/")) {
|
|
64687
|
-
try {
|
|
64688
|
-
const parts = imp.source.split("/");
|
|
64689
|
-
if (parts.length > 1) {
|
|
64690
|
-
const dirParts = parts.slice(0, -1);
|
|
64691
|
-
const fileName = parts[parts.length - 1];
|
|
64692
|
-
const dirPath = dirParts.join("/") + "/index";
|
|
64693
|
-
const indexFiles = ["index.js", "index.ts", "index.jsx", "index.tsx", "index.mjs", "index.cjs"];
|
|
64694
|
-
for (const indexFile of indexFiles) {
|
|
64695
|
-
const indexPath = path2.join(dirParts.join("/"), indexFile);
|
|
64696
|
-
const indexRelativePath = path2.relative(directory, path2.resolve(directory, indexPath));
|
|
64697
|
-
const indexNormalizedPath = normalize(indexRelativePath);
|
|
64698
|
-
if (allPossiblePaths.has(indexNormalizedPath)) {
|
|
64699
|
-
architectureMap.edges.push({
|
|
64700
|
-
source: normalize(node.id),
|
|
64701
|
-
target: indexNormalizedPath,
|
|
64702
|
-
type: imp.type || "import"
|
|
64703
|
-
});
|
|
64704
|
-
resolvedImports++;
|
|
64705
|
-
targetFound = true;
|
|
64706
|
-
break;
|
|
64707
|
-
}
|
|
64708
|
-
}
|
|
64709
|
-
}
|
|
64710
|
-
} catch (e) {
|
|
64711
|
-
console.warn(`\u26A0\uFE0F Barrel file check failed for import '${imp.source}' in file '${node.id}': ${e.message}`);
|
|
64712
|
-
}
|
|
64713
|
-
}
|
|
64714
|
-
}
|
|
64715
|
-
if (!targetFound) {
|
|
64716
|
-
for (const possiblePath of allPossiblePaths) {
|
|
64717
|
-
if (possiblePath.toLowerCase() === imp.source.toLowerCase()) {
|
|
64718
|
-
architectureMap.edges.push({
|
|
64719
|
-
source: normalize(node.id),
|
|
64720
|
-
target: possiblePath,
|
|
64721
|
-
type: imp.type || "import"
|
|
64722
|
-
});
|
|
64723
|
-
resolvedImports++;
|
|
64724
|
-
targetFound = true;
|
|
64725
|
-
break;
|
|
64726
|
-
}
|
|
64727
|
-
}
|
|
64728
|
-
}
|
|
64729
|
-
} catch (e) {
|
|
64730
|
-
console.error(`\u274C Critical error processing import '${imp.source}' in file '${node.id}': ${e.message}`);
|
|
64731
|
-
console.error(e.stack);
|
|
64732
|
-
unresolvedImports++;
|
|
64733
|
-
}
|
|
64734
|
-
if (!targetFound) {
|
|
64735
|
-
unresolvedImports++;
|
|
64736
|
-
}
|
|
64737
|
-
}
|
|
64738
|
-
});
|
|
64739
|
-
}
|
|
64740
|
-
});
|
|
64741
|
-
console.log("RESOLVED IMPORTS:", resolvedImports);
|
|
64742
|
-
console.log("UNRESOLVED IMPORTS:", unresolvedImports);
|
|
64743
|
-
console.log("IMPORT EDGES CREATED:", architectureMap.edges.length);
|
|
64744
|
-
if (semanticResults && semanticResults.usageEdges) {
|
|
64745
|
-
semanticResults.usageEdges.forEach((usageEdge) => {
|
|
64746
|
-
const sourceExists = architectureMap.nodes.some((n) => n.id === usageEdge.source);
|
|
64747
|
-
const targetExists = architectureMap.nodes.some((n) => n.id === usageEdge.target);
|
|
64748
|
-
if (sourceExists && targetExists) {
|
|
64749
|
-
architectureMap.edges.push({
|
|
64750
|
-
source: normalize(usageEdge.source),
|
|
64751
|
-
target: normalize(usageEdge.target),
|
|
64752
|
-
type: usageEdge.type
|
|
64753
|
-
// 'function_call', 'constructor_call', 'component_usage'
|
|
64754
|
-
});
|
|
64755
|
-
}
|
|
64756
|
-
});
|
|
64757
|
-
}
|
|
64758
|
-
console.log("TOTAL EDGES (with usage):", architectureMap.edges.length);
|
|
64759
|
-
const reverseGraph = buildReverseDependencyGraph(architectureMap);
|
|
64760
|
-
const blastRadiusMap = computeBlastRadius(reverseGraph);
|
|
64761
|
-
architectureMap.nodes.forEach((node) => {
|
|
64762
|
-
node.metadata.blast_radius = blastRadiusMap[node.id] || 0;
|
|
64763
|
-
});
|
|
64764
|
-
console.log("BEFORE DEDUPLICATION EDGES:", architectureMap.edges.length);
|
|
64765
|
-
const validEdges = [];
|
|
64766
|
-
const edgeSet = /* @__PURE__ */ new Set();
|
|
64767
|
-
architectureMap.edges.forEach((edge) => {
|
|
64768
|
-
const normalizedSource = normalize(edge.source);
|
|
64769
|
-
const normalizedTarget = normalize(edge.target);
|
|
64770
|
-
const edgeKey = `${normalizedSource}\u2192${normalizedTarget}`;
|
|
64771
|
-
const sourceNodeExists = architectureMap.nodes.some((node) => node.id === normalizedSource);
|
|
64772
|
-
const targetNodeExists = architectureMap.nodes.some((node) => node.id === normalizedTarget);
|
|
64773
|
-
if (sourceNodeExists && targetNodeExists && !edgeSet.has(edgeKey)) {
|
|
64774
|
-
edgeSet.add(edgeKey);
|
|
64775
|
-
validEdges.push({
|
|
64776
|
-
source: normalizedSource,
|
|
64777
|
-
target: normalizedTarget,
|
|
64778
|
-
type: edge.type
|
|
64779
|
-
});
|
|
64780
|
-
}
|
|
64781
|
-
});
|
|
64782
|
-
console.log("AFTER DEDUPLICATION EDGES:", validEdges.length);
|
|
64783
|
-
architectureMap.edges = validEdges;
|
|
64784
|
-
const totalFiles = architectureMap.nodes.length;
|
|
64785
|
-
const { computeBlastRadiusWithPercentage: computeBlastRadiusWithPercentage2, analyzeCriticality } = require_blastRadius();
|
|
64786
|
-
const allFilesWithPercentage = computeBlastRadiusWithPercentage2(blastRadiusMap, totalFiles);
|
|
64787
|
-
const criticalityAnalysis = analyzeCriticality(blastRadiusMap, reverseGraph, architectureMap.nodes);
|
|
64788
|
-
const topFiles = allFilesWithPercentage.slice(0, 3);
|
|
64789
|
-
architectureMap.contextSurface = {
|
|
64790
|
-
topBlastRadiusFiles: topFiles,
|
|
64791
|
-
criticalityAnalysis: criticalityAnalysis.slice(0, 5)
|
|
64792
|
-
// Top 5 most critical files
|
|
64793
|
-
};
|
|
64794
|
-
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 = {
|
|
64795
65189
|
directory,
|
|
64796
65190
|
projectName: path2.basename(directory),
|
|
64797
|
-
|
|
64798
|
-
|
|
64799
|
-
|
|
64800
|
-
console.log("Validating structural context...");
|
|
65191
|
+
contextSurface
|
|
65192
|
+
};
|
|
65193
|
+
let context = buildContext(nodes, edges, symbols, contextOptions);
|
|
65194
|
+
console.log(" Validating structural context...");
|
|
64801
65195
|
let validation = validateContext(context);
|
|
64802
65196
|
if (!validation.valid) {
|
|
64803
|
-
console.error("
|
|
64804
|
-
validation.errors.forEach((e) => console.error("
|
|
64805
|
-
|
|
64806
|
-
context = buildContext(architectureMap.nodes, architectureMap.edges, {
|
|
64807
|
-
directory,
|
|
64808
|
-
projectName: path2.basename(directory),
|
|
64809
|
-
language: "javascript",
|
|
64810
|
-
contextSurface: architectureMap.contextSurface
|
|
64811
|
-
});
|
|
64812
|
-
validation = validateContext(context);
|
|
64813
|
-
if (!validation.valid) {
|
|
64814
|
-
console.error("VALIDATION FAILED (Attempt 2)");
|
|
64815
|
-
validation.errors.forEach((e) => console.error(" -", e));
|
|
64816
|
-
console.error("ABORTING. JSON NOT SAVED.");
|
|
64817
|
-
process.exit(1);
|
|
64818
|
-
}
|
|
65197
|
+
console.error(" \u274C Validation Failed");
|
|
65198
|
+
validation.errors.forEach((e) => console.error(" -", e));
|
|
65199
|
+
throw new Error("Context validation failed");
|
|
64819
65200
|
}
|
|
64820
65201
|
const sortedContext = sortContext(context);
|
|
64821
|
-
console.log("
|
|
65202
|
+
console.log(" \u2705 Context Verified & Ready");
|
|
64822
65203
|
return sortedContext;
|
|
64823
65204
|
} catch (err) {
|
|
65205
|
+
console.error("\u274C Scanner Failed:", err);
|
|
64824
65206
|
throw err;
|
|
64825
65207
|
}
|
|
64826
65208
|
}
|
|
@@ -65050,7 +65432,6 @@ program.command("scan").description("Scan the current directory and generate arc
|
|
|
65050
65432
|
const outputFileName = "arcvision.context.json";
|
|
65051
65433
|
fs2.writeFileSync(outputFileName, JSON.stringify(map, null, 2));
|
|
65052
65434
|
console.log(chalk.green(`\u2705 Structural context saved to ${outputFileName}`));
|
|
65053
|
-
console.log(JSON.stringify(map, null, 2));
|
|
65054
65435
|
console.log(chalk.dim("\nUse --upload to send to dashboard."));
|
|
65055
65436
|
}
|
|
65056
65437
|
} catch (error) {
|