77 FileSystem ,
88} from 'enhanced-resolve'
99import { loadPnPApi , type PnpApi } from './pnp'
10+ import { loadTsConfig , type TSConfigApi } from './tsconfig'
1011
1112export interface ResolverOptions {
1213 /**
@@ -23,6 +24,15 @@ export interface ResolverOptions {
2324 */
2425 pnp ?: boolean | PnpApi
2526
27+ /**
28+ * Whether or not the resolver should load tsconfig path mappings.
29+ *
30+ * If `true`, the resolver will look for all `tsconfig` files in the project
31+ * and use them to resolve module paths where possible. However, if an API is
32+ * provided, the resolver will use that API to resolve module paths.
33+ */
34+ tsconfig ?: boolean | TSConfigApi
35+
2636 /**
2737 * A filesystem to use for resolution. If not provided, the resolver will
2838 * create one and use it internally for itself and any child resolvers that
@@ -61,6 +71,23 @@ export interface Resolver {
6171 */
6272 resolveCssId ( id : string , base : string ) : Promise < string >
6373
74+ /**
75+ * Resolves a module to a possible file or directory path.
76+ *
77+ * This provides reasonable results when TypeScript config files are in use.
78+ * This file may not exist but is the likely path that would be used to load
79+ * the module if it were to exist.
80+ *
81+ * @param id The module, file, or directory to resolve
82+ * @param base The base directory to resolve the module from
83+ */
84+ substituteId ( id : string , base : string ) : Promise < string >
85+
86+ /**
87+ * Return a list of path resolution aliases for the given base directory
88+ */
89+ aliases ( base : string ) : Promise < Record < string , string [ ] > >
90+
6491 /**
6592 * Create a child resolver with the given options.
6693 *
@@ -83,6 +110,22 @@ export async function createResolver(opts: ResolverOptions): Promise<Resolver> {
83110 pnpApi = await loadPnPApi ( opts . root )
84111 }
85112
113+ let tsconfig : TSConfigApi | null = null
114+
115+ // Load TSConfig path mappings
116+ if ( typeof opts . tsconfig === 'object' ) {
117+ tsconfig = opts . tsconfig
118+ } else if ( opts . tsconfig ) {
119+ try {
120+ tsconfig = await loadTsConfig ( opts . root )
121+ } catch ( err ) {
122+ // We don't want to hard crash in case of an error handling tsconfigs
123+ // It does affect what projects we can resolve or how we load files
124+ // but the LSP shouldn't become unusable because of it.
125+ console . error ( 'Failed to load tsconfig' , err )
126+ }
127+ }
128+
86129 let esmResolver = ResolverFactory . createResolver ( {
87130 fileSystem,
88131 extensions : [ '.mjs' , '.js' ] ,
@@ -128,6 +171,11 @@ export async function createResolver(opts: ResolverOptions): Promise<Resolver> {
128171 if ( base . startsWith ( '//' ) ) base = `\\\\${ base . slice ( 2 ) } `
129172 }
130173
174+ if ( tsconfig ) {
175+ let match = await tsconfig . resolveId ( id , base )
176+ if ( match ) id = match
177+ }
178+
131179 return new Promise ( ( resolve , reject ) => {
132180 resolver . resolve ( { } , base , id , { } , ( err , res ) => {
133181 if ( err ) {
@@ -151,14 +199,29 @@ export async function createResolver(opts: ResolverOptions): Promise<Resolver> {
151199 return ( await resolveId ( cssResolver , id , base ) ) || id
152200 }
153201
202+ // Takes a path which may or may not be complete and returns the aliased path
203+ // if possible
204+ async function substituteId ( id : string , base : string ) : Promise < string > {
205+ return ( await tsconfig ?. substituteId ( id , base ) ) ?? id
206+ }
207+
154208 async function setupPnP ( ) {
155209 pnpApi ?. setup ( )
156210 }
157211
212+ async function aliases ( base : string ) {
213+ if ( ! tsconfig ) return { }
214+
215+ return await tsconfig . paths ( base )
216+ }
217+
158218 return {
159219 setupPnP,
160220 resolveJsId,
161221 resolveCssId,
222+ substituteId,
223+
224+ aliases,
162225
163226 child ( childOpts : Partial < ResolverOptions > ) {
164227 return createResolver ( {
@@ -167,6 +230,7 @@ export async function createResolver(opts: ResolverOptions): Promise<Resolver> {
167230
168231 // Inherit defaults from parent
169232 pnp : childOpts . pnp ?? pnpApi ,
233+ tsconfig : childOpts . tsconfig ?? tsconfig ,
170234 fileSystem : childOpts . fileSystem ?? fileSystem ,
171235 } )
172236 } ,
0 commit comments