MCPcopy Create free account
hub / github.com/colbymchenry/codegraph / resolveRelativeImport

Function resolveRelativeImport

src/resolution/import-resolver.ts:382–427  ·  view source on GitHub ↗

* Resolve a relative import

(
  importPath: string,
  fromDir: string,
  language: Language,
  context: ResolutionContext
)

Source from the content-addressed store, hash-verified

380 * Resolve a relative import
381 */
382function resolveRelativeImport(
383 importPath: string,
384 fromDir: string,
385 language: Language,
386 context: ResolutionContext
387): string | null {
388 const projectRoot = context.getProjectRoot();
389 const extensions = EXTENSION_RESOLUTION[language] || [];
390
391 // Python dotted-relative imports (`from .certs import x`, `from ..pkg.mod
392 // import y`): leading dots are PACKAGE levels (1 = current package), and the
393 // remainder is a dotted submodule path. `path.resolve(dir, '.certs')` would
394 // treat `.certs` as a literal hidden filename, so translate the Python form
395 // to a real filesystem-relative path before resolving.
396 if (language === 'python' && importPath.startsWith('.')) {
397 const dots = importPath.length - importPath.replace(/^\.+/, '').length;
398 const up = '../'.repeat(Math.max(0, dots - 1)); // 1 dot = current dir
399 const rest = importPath.slice(dots).replace(/\./g, '/'); // 'sub.mod' -> 'sub/mod'
400 const pyBase = path.resolve(fromDir, up + rest);
401 const pyRel = path.relative(projectRoot, pyBase).replace(/\\/g, '/');
402 for (const ext of extensions) {
403 if (context.fileExists(pyRel + ext)) return pyRel + ext;
404 }
405 if (pyRel && context.fileExists(pyRel)) return pyRel;
406 return null;
407 }
408
409 // Try the path as-is first
410 const basePath = path.resolve(fromDir, importPath);
411 const relativePath = path.relative(projectRoot, basePath).replace(/\\/g, '/');
412
413 // Try each extension
414 for (const ext of extensions) {
415 const candidatePath = relativePath + ext;
416 if (context.fileExists(candidatePath)) {
417 return candidatePath;
418 }
419 }
420
421 // Try without extension (might already have one)
422 if (context.fileExists(relativePath)) {
423 return relativePath;
424 }
425
426 return null;
427}
428
429/**
430 * Resolve an aliased/absolute import.

Callers 1

Calls 3

resolveMethod · 0.80
fileExistsMethod · 0.80
getProjectRootMethod · 0.65

Tested by

no test coverage detected