arcvision 0.1.10 → 0.1.13

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 CHANGED
@@ -56442,92 +56442,75 @@ var require_path_resolver = __commonJS({
56442
56442
  "src/core/path-resolver.js"(exports2, module2) {
56443
56443
  var fs2 = require("fs");
56444
56444
  var path2 = require("path");
56445
- function resolveImport(importPath, fromFile, projectRoot, tsconfig) {
56446
- if (importPath.startsWith("node_modules/") || importPath.includes("node_modules/") || importPath.startsWith("http") || importPath.startsWith("//")) {
56445
+ function resolveImport(importPath, importerPath, projectRoot, tsconfig) {
56446
+ if (importPath.startsWith("http://") || importPath.startsWith("https://") || importPath.startsWith("data:")) {
56447
56447
  return null;
56448
56448
  }
56449
- if (tsconfig && tsconfig.paths && importPath in tsconfig.paths) {
56450
- const pathMappings = tsconfig.paths[importPath];
56451
- if (Array.isArray(pathMappings) && pathMappings.length > 0) {
56452
- const mappedPath = pathMappings[0].replace("*", importPath.substring(0, importPath.lastIndexOf("/")));
56453
- const realPath = path2.resolve(projectRoot, tsconfig.baseUrl || ".", mappedPath);
56454
- return resolveFile(realPath);
56449
+ if (importPath.startsWith(".")) {
56450
+ let resolvedPath = path2.resolve(path2.dirname(importerPath), importPath);
56451
+ const extensions = [".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs"];
56452
+ for (const ext of extensions) {
56453
+ if (fs2.existsSync(resolvedPath + ext)) {
56454
+ return resolvedPath + ext;
56455
+ }
56456
+ }
56457
+ const indexFiles = ["index.js", "index.jsx", "index.ts", "index.tsx"];
56458
+ for (const idxFile of indexFiles) {
56459
+ const indexPath = path2.join(resolvedPath, idxFile);
56460
+ if (fs2.existsSync(indexPath)) {
56461
+ return indexPath;
56462
+ }
56463
+ }
56464
+ if (fs2.existsSync(resolvedPath)) {
56465
+ return resolvedPath;
56455
56466
  }
56467
+ return null;
56456
56468
  }
56457
56469
  if (tsconfig && tsconfig.paths) {
56458
- const pathKeys = Object.keys(tsconfig.paths);
56459
- for (const pathKey of pathKeys) {
56460
- if (pathKey.endsWith("*")) {
56461
- const prefix = pathKey.slice(0, -1);
56462
- if (importPath.startsWith(prefix)) {
56463
- const suffix = importPath.substring(prefix.length);
56464
- const pathMappings = tsconfig.paths[pathKey];
56465
- if (Array.isArray(pathMappings) && pathMappings.length > 0) {
56466
- const mappedPath = pathMappings[0].replace("*", suffix);
56467
- const realPath = path2.resolve(projectRoot, tsconfig.baseUrl || ".", mappedPath);
56468
- const resolved = resolveFile(realPath);
56469
- if (resolved)
56470
- return resolved;
56470
+ const paths = tsconfig.paths;
56471
+ for (const [aliasPattern, aliasTargets] of Object.entries(paths)) {
56472
+ const aliasBase = aliasPattern.replace(/\/\*$/, "");
56473
+ if (importPath.startsWith(aliasBase + "/")) {
56474
+ const relativePart = importPath.substring(aliasBase.length);
56475
+ for (const target of aliasTargets) {
56476
+ const targetPath = target.replace(/\/\*$/, "") + relativePart;
56477
+ let resolvedPath = path2.resolve(projectRoot, targetPath);
56478
+ const extensions = [".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs"];
56479
+ for (const ext of extensions) {
56480
+ if (fs2.existsSync(resolvedPath + ext)) {
56481
+ return resolvedPath + ext;
56482
+ }
56483
+ }
56484
+ const indexFiles = ["index.js", "index.jsx", "index.ts", "index.tsx"];
56485
+ for (const idxFile of indexFiles) {
56486
+ const indexPath = path2.join(resolvedPath, idxFile);
56487
+ if (fs2.existsSync(indexPath)) {
56488
+ return indexPath;
56489
+ }
56471
56490
  }
56472
56491
  }
56473
56492
  }
56474
56493
  }
56475
56494
  }
56476
56495
  if (tsconfig && tsconfig.baseUrl && !importPath.startsWith(".")) {
56477
- const baseUrlPath = path2.resolve(projectRoot, tsconfig.baseUrl, importPath);
56478
- const resolved = resolveFile(baseUrlPath);
56479
- if (resolved)
56480
- return resolved;
56481
- }
56482
- if (importPath.startsWith("@") && tsconfig && tsconfig.baseUrl) {
56483
- const relativePath = importPath.substring(1);
56484
- const realPath = path2.resolve(projectRoot, tsconfig.baseUrl, relativePath);
56485
- const resolved = resolveFile(realPath);
56486
- if (resolved)
56487
- return resolved;
56488
- const wildcardPath = importPath + "/*";
56489
- if (tsconfig.paths && tsconfig.paths[wildcardPath]) {
56490
- const pathMappings = tsconfig.paths[wildcardPath];
56491
- if (Array.isArray(pathMappings) && pathMappings.length > 0) {
56492
- const mappedPath = pathMappings[0].replace("*", "");
56493
- const realPath2 = path2.resolve(projectRoot, tsconfig.baseUrl || ".", mappedPath);
56494
- return resolveFile(realPath2);
56496
+ let resolvedPath = path2.resolve(projectRoot, tsconfig.baseUrl, importPath);
56497
+ const extensions = [".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs"];
56498
+ for (const ext of extensions) {
56499
+ if (fs2.existsSync(resolvedPath + ext)) {
56500
+ return resolvedPath + ext;
56495
56501
  }
56496
56502
  }
56497
- }
56498
- if (importPath.startsWith(".")) {
56499
- const realPath = path2.resolve(path2.dirname(fromFile), importPath);
56500
- return resolveFile(realPath);
56501
- }
56502
- if (!importPath.startsWith(".")) {
56503
- const realPath = path2.resolve(projectRoot, importPath);
56504
- return resolveFile(realPath);
56505
- }
56506
- return null;
56507
- }
56508
- function resolveFile(basePath) {
56509
- const extensions = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
56510
- const barrelFiles = ["index.ts", "index.tsx", "index.js", "index.jsx"];
56511
- if (fs2.existsSync(basePath) && fs2.statSync(basePath).isFile()) {
56512
- return basePath;
56513
- }
56514
- for (const ext of extensions) {
56515
- const pathWithExt = basePath + ext;
56516
- if (fs2.existsSync(pathWithExt) && fs2.statSync(pathWithExt).isFile()) {
56517
- return pathWithExt;
56518
- }
56519
- }
56520
- if (fs2.existsSync(basePath) && fs2.statSync(basePath).isDirectory()) {
56521
- for (const barrelFile of barrelFiles) {
56522
- const barrelPath = path2.join(basePath, barrelFile);
56523
- if (fs2.existsSync(barrelPath)) {
56524
- return barrelPath;
56503
+ const indexFiles = ["index.js", "index.jsx", "index.ts", "index.tsx"];
56504
+ for (const idxFile of indexFiles) {
56505
+ const indexPath = path2.join(resolvedPath, idxFile);
56506
+ if (fs2.existsSync(indexPath)) {
56507
+ return indexPath;
56525
56508
  }
56526
56509
  }
56527
56510
  }
56528
56511
  return null;
56529
56512
  }
56530
- module2.exports = { resolveImport, resolveFile };
56513
+ module2.exports = { resolveImport };
56531
56514
  }
56532
56515
  });
56533
56516
 
@@ -56541,6 +56524,7 @@ var require_scanner = __commonJS({
56541
56524
  var { loadTSConfig } = require_tsconfig_utils();
56542
56525
  var { resolveImport } = require_path_resolver();
56543
56526
  async function scan(directory) {
56527
+ const normalize = (p) => p.replace(/\\/g, "/");
56544
56528
  const options = {
56545
56529
  ignore: ["**/node_modules/**", "**/.git/**", "**/dist/**", "**/build/**"],
56546
56530
  cwd: directory,
@@ -56572,7 +56556,6 @@ var require_scanner = __commonJS({
56572
56556
  console.warn(`\u26A0\uFE0F Failed to parse ${file} \u2014 file skipped, you should check manually`);
56573
56557
  }
56574
56558
  }
56575
- const normalize = (p) => p.replace(/\\/g, "/");
56576
56559
  const tsconfig = loadTSConfig(directory);
56577
56560
  const normalizedFileMap = /* @__PURE__ */ new Map();
56578
56561
  architectureMap.nodes.forEach((n) => normalizedFileMap.set(normalize(n.id), n.id));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arcvision",
3
- "version": "0.1.10",
3
+ "version": "0.1.13",
4
4
  "description": "Architecture scanner for modern codebases",
5
5
  "bin": {
6
6
  "arcvision": "./dist/index.js"
@@ -2,126 +2,109 @@ const fs = require('fs');
2
2
  const path = require('path');
3
3
 
4
4
  /**
5
- * Resolve an import path to an actual file on disk
6
- * @param {string} importPath - The import string from the code (e.g., '@/components/Button', './utils')
7
- * @param {string} fromFile - The file that contains the import
5
+ * Resolve an import path to its actual file location
6
+ * Handles relative paths, path aliases, barrel files, and implicit extensions
7
+ * @param {string} importPath - The import path from the source code
8
+ * @param {string} importerPath - The path of the file doing the import
8
9
  * @param {string} projectRoot - The root directory of the project
9
- * @param {Object|null} tsconfig - The compilerOptions from tsconfig.json
10
+ * @param {Object|null} tsconfig - Loaded tsconfig with compilerOptions
10
11
  * @returns {string|null} The resolved absolute file path or null if not found
11
12
  */
12
- function resolveImport(importPath, fromFile, projectRoot, tsconfig) {
13
- // Skip external packages and node_modules
14
- if (importPath.startsWith('node_modules/') ||
15
- importPath.includes('node_modules/') ||
16
- importPath.startsWith('http') ||
17
- importPath.startsWith('//')) {
13
+ function resolveImport(importPath, importerPath, projectRoot, tsconfig) {
14
+ // If it's an absolute path or URL, skip resolution
15
+ if (importPath.startsWith('http://') || importPath.startsWith('https://') || importPath.startsWith('data:')) {
18
16
  return null;
19
17
  }
20
18
 
21
- // Handle path aliases (e.g., '@/components/Button', '@/lib/utils')
22
- if (tsconfig && tsconfig.paths && importPath in tsconfig.paths) {
23
- // Direct path mapping
24
- const pathMappings = tsconfig.paths[importPath];
25
- if (Array.isArray(pathMappings) && pathMappings.length > 0) {
26
- const mappedPath = pathMappings[0].replace('*', importPath.substring(0, importPath.lastIndexOf('/')));
27
- const realPath = path.resolve(projectRoot, tsconfig.baseUrl || '.', mappedPath);
28
- return resolveFile(realPath);
19
+ // Handle relative imports
20
+ if (importPath.startsWith('.')) {
21
+ // Resolve relative to importer
22
+ let resolvedPath = path.resolve(path.dirname(importerPath), importPath);
23
+
24
+ // Try with various extensions
25
+ const extensions = ['.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs'];
26
+ for (const ext of extensions) {
27
+ if (fs.existsSync(resolvedPath + ext)) {
28
+ return resolvedPath + ext;
29
+ }
29
30
  }
31
+
32
+ // Try as directory with index files
33
+ const indexFiles = ['index.js', 'index.jsx', 'index.ts', 'index.tsx'];
34
+ for (const idxFile of indexFiles) {
35
+ const indexPath = path.join(resolvedPath, idxFile);
36
+ if (fs.existsSync(indexPath)) {
37
+ return indexPath;
38
+ }
39
+ }
40
+
41
+ // If original path exists as-is
42
+ if (fs.existsSync(resolvedPath)) {
43
+ return resolvedPath;
44
+ }
45
+
46
+ return null;
30
47
  }
31
48
 
32
- // Handle wildcard path aliases (e.g., '@/components/*' -> './src/components/*')
49
+ // Handle path aliases (like @/components/, ~/utils/, etc.)
33
50
  if (tsconfig && tsconfig.paths) {
34
- const pathKeys = Object.keys(tsconfig.paths);
35
- for (const pathKey of pathKeys) {
36
- if (pathKey.endsWith('*')) {
37
- const prefix = pathKey.slice(0, -1); // Remove the '*'
38
- if (importPath.startsWith(prefix)) {
39
- const suffix = importPath.substring(prefix.length);
40
- const pathMappings = tsconfig.paths[pathKey];
41
- if (Array.isArray(pathMappings) && pathMappings.length > 0) {
42
- const mappedPath = pathMappings[0].replace('*', suffix);
43
- const realPath = path.resolve(projectRoot, tsconfig.baseUrl || '.', mappedPath);
44
- const resolved = resolveFile(realPath);
45
- if (resolved) return resolved;
51
+ const paths = tsconfig.paths;
52
+
53
+ // Find matching path alias
54
+ for (const [aliasPattern, aliasTargets] of Object.entries(paths)) {
55
+ // Remove trailing * from pattern
56
+ const aliasBase = aliasPattern.replace(/\/\*$/, '');
57
+
58
+ // If import starts with this alias
59
+ if (importPath.startsWith(aliasBase + '/')) {
60
+ // Get the part after the alias
61
+ const relativePart = importPath.substring(aliasBase.length);
62
+
63
+ // Use the first target path
64
+ for (const target of aliasTargets) {
65
+ // Replace * in target with relative part
66
+ const targetPath = target.replace(/\/\*$/, '') + relativePart;
67
+ let resolvedPath = path.resolve(projectRoot, targetPath);
68
+
69
+ // Try with extensions
70
+ const extensions = ['.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs'];
71
+ for (const ext of extensions) {
72
+ if (fs.existsSync(resolvedPath + ext)) {
73
+ return resolvedPath + ext;
74
+ }
75
+ }
76
+
77
+ // Try as directory with index files
78
+ const indexFiles = ['index.js', 'index.jsx', 'index.ts', 'index.tsx'];
79
+ for (const idxFile of indexFiles) {
80
+ const indexPath = path.join(resolvedPath, idxFile);
81
+ if (fs.existsSync(indexPath)) {
82
+ return indexPath;
83
+ }
46
84
  }
47
85
  }
48
86
  }
49
87
  }
50
88
  }
51
89
 
52
- // Handle baseUrl resolution (e.g., 'components/Button' -> './src/components/Button')
90
+ // Handle baseUrl if configured
53
91
  if (tsconfig && tsconfig.baseUrl && !importPath.startsWith('.')) {
54
- const baseUrlPath = path.resolve(projectRoot, tsconfig.baseUrl, importPath);
55
- const resolved = resolveFile(baseUrlPath);
56
- if (resolved) return resolved;
57
- }
58
-
59
- // Handle @ imports that don't match specific paths mappings
60
- if (importPath.startsWith('@') && tsconfig && tsconfig.baseUrl) {
61
- // Remove @ and resolve relative to baseUrl
62
- const relativePath = importPath.substring(1); // Remove @
63
- const realPath = path.resolve(projectRoot, tsconfig.baseUrl, relativePath);
64
- const resolved = resolveFile(realPath);
65
- if (resolved) return resolved;
92
+ let resolvedPath = path.resolve(projectRoot, tsconfig.baseUrl, importPath);
66
93
 
67
- // Also try adding '/*' to see if it matches a path mapping pattern
68
- // e.g., '@/utils' might match '@/utils/*' -> './src/utils/*'
69
- const wildcardPath = importPath + '/*';
70
- if (tsconfig.paths && tsconfig.paths[wildcardPath]) {
71
- const pathMappings = tsconfig.paths[wildcardPath];
72
- if (Array.isArray(pathMappings) && pathMappings.length > 0) {
73
- const mappedPath = pathMappings[0].replace('*', '');
74
- const realPath = path.resolve(projectRoot, tsconfig.baseUrl || '.', mappedPath);
75
- return resolveFile(realPath);
94
+ // Try with extensions
95
+ const extensions = ['.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs'];
96
+ for (const ext of extensions) {
97
+ if (fs.existsSync(resolvedPath + ext)) {
98
+ return resolvedPath + ext;
76
99
  }
77
100
  }
78
- }
79
-
80
- // Handle relative paths (e.g., './utils', '../components')
81
- if (importPath.startsWith('.')) {
82
- const realPath = path.resolve(path.dirname(fromFile), importPath);
83
- return resolveFile(realPath);
84
- }
85
-
86
- // For absolute paths within the project that don't match tsconfig paths
87
- if (!importPath.startsWith('.')) {
88
- // Try resolving relative to project root
89
- const realPath = path.resolve(projectRoot, importPath);
90
- return resolveFile(realPath);
91
- }
92
-
93
- return null;
94
- }
95
-
96
- /**
97
- * Resolve a potential file path to an actual existing file
98
- * Handles implicit extensions and barrel files (index files)
99
- * @param {string} basePath - The base path to resolve
100
- * @returns {string|null} The resolved file path or null if no file exists
101
- */
102
- function resolveFile(basePath) {
103
- const extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'];
104
- const barrelFiles = ['index.ts', 'index.tsx', 'index.js', 'index.jsx'];
105
-
106
- // First, try the exact path
107
- if (fs.existsSync(basePath) && fs.statSync(basePath).isFile()) {
108
- return basePath;
109
- }
110
-
111
- // Try with extensions
112
- for (const ext of extensions) {
113
- const pathWithExt = basePath + ext;
114
- if (fs.existsSync(pathWithExt) && fs.statSync(pathWithExt).isFile()) {
115
- return pathWithExt;
116
- }
117
- }
118
-
119
- // Try as a directory with barrel files
120
- if (fs.existsSync(basePath) && fs.statSync(basePath).isDirectory()) {
121
- for (const barrelFile of barrelFiles) {
122
- const barrelPath = path.join(basePath, barrelFile);
123
- if (fs.existsSync(barrelPath)) {
124
- return barrelPath;
101
+
102
+ // Try as directory with index files
103
+ const indexFiles = ['index.js', 'index.jsx', 'index.ts', 'index.tsx'];
104
+ for (const idxFile of indexFiles) {
105
+ const indexPath = path.join(resolvedPath, idxFile);
106
+ if (fs.existsSync(indexPath)) {
107
+ return indexPath;
125
108
  }
126
109
  }
127
110
  }
@@ -129,4 +112,4 @@ function resolveFile(basePath) {
129
112
  return null;
130
113
  }
131
114
 
132
- module.exports = { resolveImport, resolveFile };
115
+ module.exports = { resolveImport };
@@ -6,6 +6,9 @@ const { loadTSConfig } = require('./tsconfig-utils');
6
6
  const { resolveImport } = require('./path-resolver');
7
7
 
8
8
  async function scan(directory) {
9
+ // Normalize helper
10
+ const normalize = p => p.replace(/\\/g, '/');
11
+
9
12
  const options = {
10
13
  ignore: ['**/node_modules/**', '**/.git/**', '**/dist/**', '**/build/**'],
11
14
  cwd: directory,
@@ -50,10 +53,7 @@ async function scan(directory) {
50
53
  console.warn(`⚠️ Failed to parse ${file} — file skipped, you should check manually`);
51
54
  }
52
55
  }
53
-
54
- // Normalize helper
55
- const normalize = p => p.replace(/\\/g, '/');
56
-
56
+
57
57
  // Load tsconfig for path resolution
58
58
  const tsconfig = loadTSConfig(directory);
59
59