@@ -78,6 +78,9 @@ export interface TsResolverOptions
7878
7979const fileSystem = fs as FileSystem
8080
81+ const JS_EXT_PATTERN = / \. (?: [ c m ] j s | j s x ? ) $ /
82+ const RELATIVE_PATH_PATTERN = / ^ \. { 1 , 2 } (?: \/ .* ) ? $ /
83+
8184let mappersBuildForOptions : TsResolverOptions
8285let mappers : Array < ( ( specifier : string ) => string [ ] ) | null > | undefined
8386let resolver : Resolver
@@ -95,7 +98,14 @@ export function resolve(
9598 found : boolean
9699 path ?: string | null
97100} {
98- const opts : ResolveOptions & TsResolverOptions = {
101+ const opts : Required <
102+ Pick <
103+ ResolveOptions ,
104+ 'conditionNames' | 'extensions' | 'mainFields' | 'useSyncFileSystemCalls'
105+ >
106+ > &
107+ ResolveOptions &
108+ TsResolverOptions = {
99109 ...options ,
100110 extensions : options ?. extensions ?? defaultExtensions ,
101111 mainFields : options ?. mainFields ?? defaultMainFields ,
@@ -122,7 +132,7 @@ export function resolve(
122132
123133 initMappers ( opts )
124134
125- const mappedPath = getMappedPath ( source , file , true )
135+ const mappedPath = getMappedPath ( source , file , opts . extensions , true )
126136 if ( mappedPath ) {
127137 log ( 'matched ts path:' , mappedPath )
128138 }
@@ -140,7 +150,7 @@ export function resolve(
140150 // naive attempt at @types /* resolution,
141151 // if path is neither absolute nor relative
142152 if (
143- ( / \. j s x ? $ / . test ( foundNodePath ! ) ||
153+ ( JS_EXT_PATTERN . test ( foundNodePath ! ) ||
144154 ( opts . alwaysTryTypes && ! foundNodePath ) ) &&
145155 ! / ^ @ t y p e s [ / \\ ] / . test ( source ) &&
146156 ! path . isAbsolute ( source ) &&
@@ -179,17 +189,17 @@ function resolveExtension(id: string) {
179189 return
180190 }
181191
182- if ( id . endsWith ( '.mjs ' ) ) {
192+ if ( id . endsWith ( '.cjs ' ) ) {
183193 return {
184194 path : idWithoutJsExt ,
185- extensions : [ '.mts ' , '.d.mts ' ] ,
195+ extensions : [ '.cts ' , '.d.cts ' ] ,
186196 }
187197 }
188198
189- if ( id . endsWith ( '.cjs ' ) ) {
199+ if ( id . endsWith ( '.mjs ' ) ) {
190200 return {
191201 path : idWithoutJsExt ,
192- extensions : [ '.cts ' , '.d.cts ' ] ,
202+ extensions : [ '.mts ' , '.d.mts ' ] ,
193203 }
194204 }
195205
@@ -200,7 +210,7 @@ function resolveExtension(id: string) {
200210
201211/**
202212 * Like `sync` from `resolve` package, but considers that the module id
203- * could have a .js or .jsx extension.
213+ * could have a .cjs, .mjs, . js or .jsx extension.
204214 */
205215function tsResolve (
206216 source : string ,
@@ -231,10 +241,7 @@ function removeQuerystring(id: string) {
231241 return id
232242}
233243
234- const JS_EXT_PATTERN = / \. (?: [ c m ] j s | j s x ? ) $ /
235- const RELATIVE_PATH_PATTERN = / ^ \. { 1 , 2 } (?: \/ .* ) ? $ /
236-
237- /** Remove .js or .jsx extension from module id. */
244+ /** Remove .cjs, .mjs, .js or .jsx extension from module id. */
238245function removeJsExtension ( id : string ) {
239246 return id . replace ( JS_EXT_PATTERN , '' )
240247}
@@ -250,14 +257,19 @@ const isFile = (path?: string | undefined): path is string => {
250257/**
251258 * @param {string } source the module to resolve; i.e './some-module'
252259 * @param {string } file the importing file's full path; i.e. '/usr/local/bin/file.js'
260+ * @param {string[] } extensions the extensions to try
261+ * @param {boolean } retry should retry on failed to resolve
253262 * @returns The mapped path of the module or undefined
254263 */
255264// eslint-disable-next-line sonarjs/cognitive-complexity
256265function getMappedPath (
257266 source : string ,
258267 file : string ,
268+ extensions = defaultExtensions ,
259269 retry ?: boolean ,
260270) : string | undefined {
271+ extensions = [ '' , ...extensions ]
272+
261273 let paths : string [ ] | undefined = [ ]
262274
263275 if ( RELATIVE_PATH_PATTERN . test ( source ) ) {
@@ -268,43 +280,40 @@ function getMappedPath(
268280 } else {
269281 paths = mappers !
270282 . map ( mapper =>
271- mapper ?.( source ) . map ( item =>
272- path . extname ( item )
273- ? item
274- : [ 'ts' , 'tsx' , '.d.ts' , 'js' ] . map ( ext => `${ item } .${ ext } ` ) ,
275- ) ,
283+ mapper ?.( source ) . map ( item => extensions . map ( ext => `${ item } ${ ext } ` ) ) ,
276284 )
277285 . flat ( 2 )
278286 . filter ( isFile )
279287 }
280288
281289 if ( retry && paths . length === 0 ) {
282- if ( JS_EXT_PATTERN . test ( source ) ) {
290+ const isJs = JS_EXT_PATTERN . test ( source )
291+ if ( isJs ) {
283292 const jsExt = path . extname ( source )
284293 const tsExt = jsExt . replace ( 'js' , 'ts' )
285294 const basename = source . replace ( JS_EXT_PATTERN , '' )
286- return (
295+
296+ const resolved =
287297 getMappedPath ( basename + tsExt , file ) ||
288- getMappedPath ( source + '/index.ts' , file ) ||
289- getMappedPath ( source + '/index.tsx' , file ) ||
290- getMappedPath ( source + '/index.d.ts' , file ) ||
291298 getMappedPath (
292299 basename + '.d' + ( tsExt === '.tsx' ? '.ts' : tsExt ) ,
293300 file ,
294- ) ||
295- getMappedPath ( source + '/index.js' , file )
296- )
301+ )
302+
303+ if ( resolved ) {
304+ return resolved
305+ }
306+ }
307+
308+ for ( const ext of extensions ) {
309+ const resolved =
310+ ( isJs ? null : getMappedPath ( source + ext , file ) ) ||
311+ getMappedPath ( source + `/index${ ext } ` , file )
312+
313+ if ( resolved ) {
314+ return resolved
315+ }
297316 }
298- return (
299- getMappedPath ( source + '.ts' , file ) ||
300- getMappedPath ( source + '.tsx' , file ) ||
301- getMappedPath ( source + '.js' , file ) ||
302- getMappedPath ( source + '.d.ts' , file ) ||
303- getMappedPath ( source + '/index.ts' , file ) ||
304- getMappedPath ( source + '/index.tsx' , file ) ||
305- getMappedPath ( source + '/index.d.ts' , file ) ||
306- getMappedPath ( source + '/index.js' , file )
307- )
308317 }
309318
310319 if ( paths . length > 1 ) {
0 commit comments