ts-morph icon indicating copy to clipboard operation
ts-morph copied to clipboard

Ability to resolve import path to SourceFile

Open jahudka opened this issue 4 years ago • 8 comments

Hi, I'd like to ask if there's an easy way to resolve an arbitrary string coming from outside a project's source code as if it were an import source specifier within the project. Specifically, let's say I have a project with the following structure:

src/
  index.ts
  foo.ts
  bar/
    baz.ts
node_modules/
  @types/
    express/
      index.d.ts
tsconfig.json

Also let's say that the tsconfig.json file contains moduleResolution: "node" in the compilerOptions. The TypeScript compiler is then able to resolve, for example, import { Baz } from './bar/baz'; in the index.ts file to the full path to the src/bar/baz.ts file; similarly it is able to resolve import { Application } from 'express'; to the full path to node_modules/@types/express/index.d.ts.

What I'd like to do is create a new Project({ tsConfigFilePath: '/path/to/tsconfig.json' }) and then resolve an arbitrary module to an actual SourceFile so that I can get declarations of a specific export within that file - so I want to be able to do something like project.resolve('./bar/baz').getExportedDeclarations().get('Baz'), or project.resolve('express').getExportedDeclarations().get('Application'). I know module resolution needs to know where the module is being resolved from in order to resolve relative paths, so maybe it would have to be project.resolve('./bar/baz', '.'), but I can't find anything even remotely resembling this. The best I got was project.getModuleResolutionHost().realpath(), but that might just be a helper to get the filesystem real path for a symlink and it relies on the current working directory for relative paths anyway, which just doesn't seem like it's the thing I'm looking for..

Is there anything like that?

Thanks for the amazing library by the way @dsherret, you rock!

jahudka avatar Feb 02 '21 01:02 jahudka

Hey @jahudka, sorry for my delay. I've wanted to do this too, but I don't think there is an easy way at the moment.

I believe the closest thing to this is ambient modules https://ts-morph.com/navigation/ambient-modules for stuff like "express", then for other kinds of module specifiers it gets tricky as you've pointed out. I think some people have hacked around it by inserting an import declaration into a dummy file then calling getModuleSpecifierSourceFile() on it. I don't believe there is a nice way to do this with the compiler API that ts-morph could take advantage of, but maybe I'm missing something.

Also, thanks and I'm glad you like the library 🙂

Edit: I think this is something that should be added to the library.

dsherret avatar Feb 06 '21 23:02 dsherret

Hey @dsherret, thanks for the reply, I think I've arrived at the same conclusion - the only universal way to get type declarations for a [<module>, <export>] pair that I found is to create a temporary source file in the project containing something like export { <export> as knownName } from '<module>'; and then .getExportedDeclarations() from that file & remove it again. I'm not yet sure how my usecase will turn out - it's possible that I'll be able to do this in a batch, so the overhead of creating and parsing a (virtual) source file will probably be negligible. Still.. would be nice if TypeScript had a handy little method for that which your library could just neatly wrap without resorting to "hacks".. Anyway, thanks again! Should we leave this issue open, or close it as there's no (pretty) solution for now?

jahudka avatar Feb 08 '21 18:02 jahudka

@jahudka let's leave it open and use it as the tracking issue. I've renamed the title. I think it should be possible to come up with some nice api for doing this.

dsherret avatar Feb 08 '21 21:02 dsherret

Hey @dsherret, is there any update on this issue?

I'm working on something that needs to resolve file system paths of imports in a TypeScript file. Would be really handy to have an API that does this.

haroldadmin avatar Jul 24 '22 07:07 haroldadmin

Hey @dsherret, is there any update on this issue?

I'm working on something that needs to resolve file system paths of imports in a TypeScript file. Would be really handy to have an API that does this.

Following up on this, I have a project with a similar need. Any news on this?

marioparaschiv avatar Apr 14 '23 23:04 marioparaschiv

similarly it is able to resolve import { Application } from 'express'; to the full path to node_modules/@types/express/index.d.ts.

this should already be possible given an ImportDeclaration like 'express' to call .getDefinitionNodes()[0].getSourceFile() and get the node_modules path

noqcks avatar Apr 24 '24 14:04 noqcks