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/src/core/parser.js
DELETED
|
@@ -1,343 +0,0 @@
|
|
|
1
|
-
const parser = require('@babel/parser');
|
|
2
|
-
const traverse = require('@babel/traverse').default;
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
|
|
6
|
-
function parseFile(filePath) {
|
|
7
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
8
|
-
let ast;
|
|
9
|
-
|
|
10
|
-
// Enhanced parser options with more comprehensive plugin support
|
|
11
|
-
const parserOptions = {
|
|
12
|
-
sourceType: 'unambiguous', // Auto-detect between script and module
|
|
13
|
-
allowImportExportEverywhere: true,
|
|
14
|
-
allowReturnOutsideFunction: true,
|
|
15
|
-
allowSuperOutsideMethod: true,
|
|
16
|
-
plugins: [
|
|
17
|
-
'jsx',
|
|
18
|
-
'typescript',
|
|
19
|
-
'decorators-legacy',
|
|
20
|
-
'classProperties',
|
|
21
|
-
'exportDefaultFrom',
|
|
22
|
-
'exportNamespaceFrom',
|
|
23
|
-
'dynamicImport',
|
|
24
|
-
'functionBind',
|
|
25
|
-
'nullishCoalescingOperator',
|
|
26
|
-
'optionalChaining',
|
|
27
|
-
'numericSeparator',
|
|
28
|
-
'bigInt',
|
|
29
|
-
'importMeta',
|
|
30
|
-
'asyncGenerators',
|
|
31
|
-
'optionalCatchBinding',
|
|
32
|
-
'throwExpressions',
|
|
33
|
-
'logicalAssignment',
|
|
34
|
-
'nullishCoalescingOperator',
|
|
35
|
-
'doExpressions',
|
|
36
|
-
'pipeOperator',
|
|
37
|
-
'recordAndTuple',
|
|
38
|
-
'moduleBlocks',
|
|
39
|
-
'topLevelAwait',
|
|
40
|
-
'v8intrinsic',
|
|
41
|
-
'partialApplication',
|
|
42
|
-
'regexpUnicodeSets',
|
|
43
|
-
'destructuringPrivate',
|
|
44
|
-
'decoratorAutoAccessors'
|
|
45
|
-
]
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
try {
|
|
49
|
-
ast = parser.parse(content, parserOptions);
|
|
50
|
-
} catch (error) {
|
|
51
|
-
// Log the parsing error but don't throw - let the scanner continue
|
|
52
|
-
console.warn(`⚠️ Failed to parse ${filePath}: ${error.message}`);
|
|
53
|
-
// Return minimal metadata for files that can't be parsed
|
|
54
|
-
return {
|
|
55
|
-
id: filePath,
|
|
56
|
-
imports: [],
|
|
57
|
-
exports: [],
|
|
58
|
-
functions: [],
|
|
59
|
-
apiCalls: []
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const metadata = {
|
|
64
|
-
id: filePath,
|
|
65
|
-
imports: [],
|
|
66
|
-
exports: [],
|
|
67
|
-
functions: [],
|
|
68
|
-
apiCalls: [],
|
|
69
|
-
classes: [],
|
|
70
|
-
variables: [],
|
|
71
|
-
dependencies: []
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
traverse(ast, {
|
|
75
|
-
ImportDeclaration({ node }) {
|
|
76
|
-
const importSource = node.source.value;
|
|
77
|
-
const specifiers = [];
|
|
78
|
-
|
|
79
|
-
node.specifiers.forEach(spec => {
|
|
80
|
-
if (spec.imported && spec.local) {
|
|
81
|
-
// Named import: import { name as alias } from 'source'
|
|
82
|
-
specifiers.push({
|
|
83
|
-
imported: spec.imported.name || spec.imported.value,
|
|
84
|
-
local: spec.local.name
|
|
85
|
-
});
|
|
86
|
-
} else if (spec.local) {
|
|
87
|
-
// Default import: import name from 'source'
|
|
88
|
-
specifiers.push({
|
|
89
|
-
imported: 'default',
|
|
90
|
-
local: spec.local.name
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
metadata.imports.push({
|
|
96
|
-
source: importSource,
|
|
97
|
-
specifiers: specifiers
|
|
98
|
-
});
|
|
99
|
-
},
|
|
100
|
-
ImportExpression({ node }) {
|
|
101
|
-
// Handle dynamic imports: import('module')
|
|
102
|
-
if (node.source && node.source.type === 'StringLiteral') {
|
|
103
|
-
metadata.imports.push({
|
|
104
|
-
source: node.source.value,
|
|
105
|
-
specifiers: [],
|
|
106
|
-
dynamic: true
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
},
|
|
110
|
-
ExportNamedDeclaration({ node }) {
|
|
111
|
-
// Handle export { X, Y, Z } from './file' statements
|
|
112
|
-
if (node.source) {
|
|
113
|
-
const specifiers = [];
|
|
114
|
-
if (node.specifiers) {
|
|
115
|
-
node.specifiers.forEach(spec => {
|
|
116
|
-
specifiers.push({
|
|
117
|
-
exported: spec.exported.name || spec.exported.value || spec.exported.value,
|
|
118
|
-
local: spec.local ? spec.local.name : spec.exported.name || spec.exported.value
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
metadata.imports.push({
|
|
124
|
-
source: node.source.value,
|
|
125
|
-
specifiers: specifiers,
|
|
126
|
-
type: 'export-from'
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
// Handle export declarations without source (local exports)
|
|
130
|
-
if (node.declaration) {
|
|
131
|
-
if (node.declaration.type === 'FunctionDeclaration' && node.declaration.id) {
|
|
132
|
-
metadata.exports.push({
|
|
133
|
-
name: node.declaration.id.name,
|
|
134
|
-
type: 'function',
|
|
135
|
-
loc: node.declaration.loc
|
|
136
|
-
});
|
|
137
|
-
} else if (node.declaration.type === 'ClassDeclaration' && node.declaration.id) {
|
|
138
|
-
metadata.exports.push({
|
|
139
|
-
name: node.declaration.id.name,
|
|
140
|
-
type: 'class',
|
|
141
|
-
loc: node.declaration.loc
|
|
142
|
-
});
|
|
143
|
-
} else if (node.declaration.type === 'VariableDeclaration') {
|
|
144
|
-
node.declaration.declarations.forEach(decl => {
|
|
145
|
-
if (decl.id.name) {
|
|
146
|
-
metadata.exports.push({
|
|
147
|
-
name: decl.id.name,
|
|
148
|
-
type: 'variable',
|
|
149
|
-
loc: decl.loc
|
|
150
|
-
});
|
|
151
|
-
} else if (decl.id.type === 'ObjectPattern') {
|
|
152
|
-
// Handle destructuring exports: export const { a, b } = obj
|
|
153
|
-
decl.id.properties.forEach(prop => {
|
|
154
|
-
if (prop.key.name) {
|
|
155
|
-
metadata.exports.push({
|
|
156
|
-
name: prop.key.name,
|
|
157
|
-
type: 'variable',
|
|
158
|
-
loc: prop.loc
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
} else if (decl.id.type === 'ArrayPattern') {
|
|
163
|
-
// Handle array destructuring exports: export const [a, b] = arr
|
|
164
|
-
decl.id.elements.forEach(element => {
|
|
165
|
-
if (element && element.name) {
|
|
166
|
-
metadata.exports.push({
|
|
167
|
-
name: element.name,
|
|
168
|
-
type: 'variable',
|
|
169
|
-
loc: element.loc
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
},
|
|
178
|
-
ExportAllDeclaration({ node }) {
|
|
179
|
-
// Handle export * from './file' statements
|
|
180
|
-
metadata.imports.push({
|
|
181
|
-
source: node.source.value,
|
|
182
|
-
specifiers: ['*'],
|
|
183
|
-
type: 'export-all'
|
|
184
|
-
});
|
|
185
|
-
},
|
|
186
|
-
ExportDefaultDeclaration({ node }) {
|
|
187
|
-
let exportName = 'default';
|
|
188
|
-
|
|
189
|
-
if (node.declaration) {
|
|
190
|
-
if (node.declaration.type === 'FunctionDeclaration' && node.declaration.id) {
|
|
191
|
-
exportName = node.declaration.id.name || 'default';
|
|
192
|
-
} else if (node.declaration.type === 'ClassDeclaration' && node.declaration.id) {
|
|
193
|
-
exportName = node.declaration.id.name || 'default';
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
metadata.exports.push({
|
|
198
|
-
name: exportName,
|
|
199
|
-
type: 'default',
|
|
200
|
-
loc: node.loc
|
|
201
|
-
});
|
|
202
|
-
},
|
|
203
|
-
FunctionDeclaration({ node }) {
|
|
204
|
-
if (node.id && node.id.name) {
|
|
205
|
-
metadata.functions.push({
|
|
206
|
-
name: node.id.name,
|
|
207
|
-
params: node.params.map(p => {
|
|
208
|
-
if (p.type === 'Identifier') {
|
|
209
|
-
return p.name;
|
|
210
|
-
} else if (p.type === 'ObjectPattern') {
|
|
211
|
-
return 'ObjectPattern';
|
|
212
|
-
} else if (p.type === 'ArrayPattern') {
|
|
213
|
-
return 'ArrayPattern';
|
|
214
|
-
} else {
|
|
215
|
-
return '?';
|
|
216
|
-
}
|
|
217
|
-
}),
|
|
218
|
-
loc: node.loc
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
},
|
|
222
|
-
FunctionExpression({ node }) {
|
|
223
|
-
// Capture anonymous function assignments
|
|
224
|
-
if (node.id && node.id.name) {
|
|
225
|
-
metadata.functions.push({
|
|
226
|
-
name: node.id.name,
|
|
227
|
-
params: node.params.map(p => p.name || '?'),
|
|
228
|
-
loc: node.loc
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
},
|
|
232
|
-
ArrowFunctionExpression({ node }) {
|
|
233
|
-
// Capture arrow functions if they're part of variable declarations
|
|
234
|
-
// This helps identify function definitions in modern JS
|
|
235
|
-
},
|
|
236
|
-
ClassDeclaration({ node }) {
|
|
237
|
-
if (node.id && node.id.name) {
|
|
238
|
-
metadata.classes.push({
|
|
239
|
-
name: node.id.name,
|
|
240
|
-
superClass: node.superClass ? node.superClass.name : null,
|
|
241
|
-
loc: node.loc
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
},
|
|
245
|
-
VariableDeclaration({ node }) {
|
|
246
|
-
node.declarations.forEach(decl => {
|
|
247
|
-
if (decl.id.name) {
|
|
248
|
-
metadata.variables.push({
|
|
249
|
-
name: decl.id.name,
|
|
250
|
-
type: 'variable',
|
|
251
|
-
loc: decl.loc
|
|
252
|
-
});
|
|
253
|
-
} else if (decl.id.type === 'ObjectPattern') {
|
|
254
|
-
// Handle destructuring: const { a, b } = obj
|
|
255
|
-
decl.id.properties.forEach(prop => {
|
|
256
|
-
if (prop.key && prop.key.name) {
|
|
257
|
-
metadata.variables.push({
|
|
258
|
-
name: prop.key.name,
|
|
259
|
-
type: 'destructured',
|
|
260
|
-
loc: prop.loc
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
});
|
|
264
|
-
} else if (decl.id.type === 'ArrayPattern') {
|
|
265
|
-
// Handle array destructuring: const [a, b] = arr
|
|
266
|
-
decl.id.elements.forEach((element, index) => {
|
|
267
|
-
if (element && element.name) {
|
|
268
|
-
metadata.variables.push({
|
|
269
|
-
name: element.name,
|
|
270
|
-
type: 'destructured',
|
|
271
|
-
loc: element.loc
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
});
|
|
275
|
-
}
|
|
276
|
-
});
|
|
277
|
-
},
|
|
278
|
-
CallExpression({ node }) {
|
|
279
|
-
if (node.callee.name === 'fetch') {
|
|
280
|
-
const arg = node.arguments[0];
|
|
281
|
-
metadata.apiCalls.push({
|
|
282
|
-
type: 'fetch',
|
|
283
|
-
url: arg && arg.type === 'StringLiteral' ? arg.value : 'dynamic',
|
|
284
|
-
loc: node.loc
|
|
285
|
-
});
|
|
286
|
-
}
|
|
287
|
-
if (node.callee.name === 'require' && node.arguments.length > 0) {
|
|
288
|
-
const sourceArg = node.arguments[0];
|
|
289
|
-
if (sourceArg && sourceArg.type === 'StringLiteral') {
|
|
290
|
-
metadata.imports.push({
|
|
291
|
-
source: sourceArg.value,
|
|
292
|
-
specifiers: [],
|
|
293
|
-
type: 'require'
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
// Handle other common API calls
|
|
298
|
-
if (node.callee.type === 'MemberExpression' &&
|
|
299
|
-
node.callee.object &&
|
|
300
|
-
node.callee.object.name === 'axios') {
|
|
301
|
-
metadata.apiCalls.push({
|
|
302
|
-
type: 'axios',
|
|
303
|
-
method: node.callee.property.name,
|
|
304
|
-
loc: node.loc
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// Handle other common import patterns like import() in function calls
|
|
309
|
-
if (node.callee.type === 'Import' && node.arguments.length > 0) {
|
|
310
|
-
const sourceArg = node.arguments[0];
|
|
311
|
-
if (sourceArg && sourceArg.type === 'StringLiteral') {
|
|
312
|
-
metadata.imports.push({
|
|
313
|
-
source: sourceArg.value,
|
|
314
|
-
specifiers: [],
|
|
315
|
-
type: 'dynamic-import'
|
|
316
|
-
});
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
},
|
|
320
|
-
|
|
321
|
-
VariableDeclarator({ node }) {
|
|
322
|
-
// Handle import assignments like: const { something } = require('module')
|
|
323
|
-
if (node.init && node.init.type === 'CallExpression' &&
|
|
324
|
-
node.init.callee.name === 'require' &&
|
|
325
|
-
node.init.arguments.length > 0 &&
|
|
326
|
-
node.init.arguments[0].type === 'StringLiteral') {
|
|
327
|
-
metadata.imports.push({
|
|
328
|
-
source: node.init.arguments[0].value,
|
|
329
|
-
specifiers: [],
|
|
330
|
-
type: 'require-assignment'
|
|
331
|
-
});
|
|
332
|
-
}
|
|
333
|
-
},
|
|
334
|
-
|
|
335
|
-
MemberExpression({ node }) {
|
|
336
|
-
// Additional member expression handling for complex import patterns
|
|
337
|
-
}
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
return metadata;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
module.exports = { parseFile };
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
|
|
4
|
-
/**
|
|
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
|
|
9
|
-
* @param {string} projectRoot - The root directory of the project
|
|
10
|
-
* @param {Object|null} tsconfig - Loaded tsconfig with compilerOptions
|
|
11
|
-
* @returns {string|null} The resolved absolute file path or null if not found
|
|
12
|
-
*/
|
|
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://') ||
|
|
16
|
-
importPath.startsWith('data:') || importPath.startsWith('file:')) {
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// Handle relative imports
|
|
21
|
-
if (importPath.startsWith('.')) {
|
|
22
|
-
// Resolve relative to importer
|
|
23
|
-
let resolvedPath = path.resolve(path.dirname(importerPath), importPath);
|
|
24
|
-
|
|
25
|
-
// Try with various extensions in order of preference
|
|
26
|
-
const extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.json'];
|
|
27
|
-
for (const ext of extensions) {
|
|
28
|
-
if (fs.existsSync(resolvedPath + ext)) {
|
|
29
|
-
return resolvedPath + ext;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Try as directory with index files
|
|
34
|
-
const indexFiles = ['index.ts', 'index.tsx', 'index.js', 'index.jsx', 'index.json'];
|
|
35
|
-
for (const idxFile of indexFiles) {
|
|
36
|
-
const indexPath = path.join(resolvedPath, idxFile);
|
|
37
|
-
if (fs.existsSync(indexPath)) {
|
|
38
|
-
return indexPath;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// If original path exists as-is
|
|
43
|
-
if (fs.existsSync(resolvedPath)) {
|
|
44
|
-
return resolvedPath;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return null;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Handle path aliases (like @/components/, ~/utils/, etc.)
|
|
51
|
-
if (tsconfig && tsconfig.paths) {
|
|
52
|
-
const paths = tsconfig.paths;
|
|
53
|
-
|
|
54
|
-
// Sort aliases by length (descending) to match longer patterns first
|
|
55
|
-
const sortedAliases = Object.keys(paths).sort((a, b) => b.length - a.length);
|
|
56
|
-
|
|
57
|
-
for (const aliasPattern of sortedAliases) {
|
|
58
|
-
const aliasTargets = paths[aliasPattern];
|
|
59
|
-
|
|
60
|
-
// Handle pattern like "@/*" -> ["./src/*"]
|
|
61
|
-
if (aliasPattern.includes('*')) {
|
|
62
|
-
const patternBase = aliasPattern.replace(/\*.*$/, '');
|
|
63
|
-
|
|
64
|
-
if (importPath.startsWith(patternBase)) {
|
|
65
|
-
const suffix = importPath.substring(patternBase.length);
|
|
66
|
-
|
|
67
|
-
for (const target of aliasTargets) {
|
|
68
|
-
const targetBase = target.replace(/\*.*$/, '');
|
|
69
|
-
const targetPath = path.resolve(projectRoot, path.join(targetBase, suffix));
|
|
70
|
-
|
|
71
|
-
// Try with extensions
|
|
72
|
-
const extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.json'];
|
|
73
|
-
for (const ext of extensions) {
|
|
74
|
-
if (fs.existsSync(targetPath + ext)) {
|
|
75
|
-
return targetPath + ext;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Try as directory with index files
|
|
80
|
-
const indexFiles = ['index.ts', 'index.tsx', 'index.js', 'index.jsx', 'index.json'];
|
|
81
|
-
for (const idxFile of indexFiles) {
|
|
82
|
-
const indexPath = path.join(targetPath, idxFile);
|
|
83
|
-
if (fs.existsSync(indexPath)) {
|
|
84
|
-
return indexPath;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Try exact path
|
|
89
|
-
if (fs.existsSync(targetPath)) {
|
|
90
|
-
return targetPath;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
} else {
|
|
95
|
-
// Handle exact match patterns
|
|
96
|
-
if (importPath === aliasPattern || importPath.startsWith(aliasPattern + '/')) {
|
|
97
|
-
for (const target of aliasTargets) {
|
|
98
|
-
let targetPath = path.resolve(projectRoot, target);
|
|
99
|
-
|
|
100
|
-
// If importPath is longer than the alias pattern, add the remaining part
|
|
101
|
-
if (importPath.length > aliasPattern.length) {
|
|
102
|
-
const remainingPath = importPath.substring(aliasPattern.length);
|
|
103
|
-
targetPath = path.join(targetPath, remainingPath);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Try with extensions
|
|
107
|
-
const extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.json'];
|
|
108
|
-
for (const ext of extensions) {
|
|
109
|
-
if (fs.existsSync(targetPath + ext)) {
|
|
110
|
-
return targetPath + ext;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Try as directory with index files
|
|
115
|
-
const indexFiles = ['index.ts', 'index.tsx', 'index.js', 'index.jsx', 'index.json'];
|
|
116
|
-
for (const idxFile of indexFiles) {
|
|
117
|
-
const indexPath = path.join(targetPath, idxFile);
|
|
118
|
-
if (fs.existsSync(indexPath)) {
|
|
119
|
-
return indexPath;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Try exact path
|
|
124
|
-
if (fs.existsSync(targetPath)) {
|
|
125
|
-
return targetPath;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// Handle baseUrl if configured
|
|
134
|
-
if (tsconfig && tsconfig.baseUrl && !importPath.startsWith('.')) {
|
|
135
|
-
let resolvedPath = path.resolve(projectRoot, tsconfig.baseUrl, importPath);
|
|
136
|
-
|
|
137
|
-
// Try with extensions
|
|
138
|
-
const extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.json'];
|
|
139
|
-
for (const ext of extensions) {
|
|
140
|
-
if (fs.existsSync(resolvedPath + ext)) {
|
|
141
|
-
return resolvedPath + ext;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Try as directory with index files
|
|
146
|
-
const indexFiles = ['index.ts', 'index.tsx', 'index.js', 'index.jsx', 'index.json'];
|
|
147
|
-
for (const idxFile of indexFiles) {
|
|
148
|
-
const indexPath = path.join(resolvedPath, idxFile);
|
|
149
|
-
if (fs.existsSync(indexPath)) {
|
|
150
|
-
return indexPath;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// Try exact path
|
|
155
|
-
if (fs.existsSync(resolvedPath)) {
|
|
156
|
-
return resolvedPath;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Handle node_modules resolution
|
|
161
|
-
if (!importPath.startsWith('.')) {
|
|
162
|
-
// Check if it's a node module
|
|
163
|
-
try {
|
|
164
|
-
const resolved = require.resolve(importPath, { paths: [path.dirname(importerPath)] });
|
|
165
|
-
return resolved;
|
|
166
|
-
} catch (e) {
|
|
167
|
-
// If require.resolve fails, it's not a node module
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
return null;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
module.exports = { resolveImport };
|