@@ -34,6 +34,7 @@ const {
3434 ObjectKeys,
3535 ObjectPrototypeHasOwnProperty,
3636 ReflectSet,
37+ RegExpPrototypeTest,
3738 SafeMap,
3839 String,
3940 StringPrototypeIndexOf,
@@ -121,7 +122,7 @@ function enrichCJSError(err) {
121122 after a comment block and/or after a variable definition.
122123 */
123124 if ( err . message . startsWith ( 'Unexpected token \'export\'' ) ||
124- ( / ^ \s * i m p o r t (? = [ { ' " * ] ) \s * (? ! [ ( ] ) / ) . test ( lineWithErr ) ) {
125+ ( RegExpPrototypeTest ( / ^ \s * i m p o r t (? = [ { ' " * ] ) \s * (? ! [ ( ] ) / , lineWithErr ) ) ) {
125126 process . emitWarning (
126127 'To load an ES module, set "type": "module" in the package.json or use ' +
127128 'the .mjs extension.' ,
@@ -348,10 +349,11 @@ const realpathCache = new Map();
348349// absolute realpath.
349350function tryFile ( requestPath , isMain ) {
350351 const rc = stat ( requestPath ) ;
352+ if ( rc !== 0 ) return ;
351353 if ( preserveSymlinks && ! isMain ) {
352- return rc === 0 && path . resolve ( requestPath ) ;
354+ return path . resolve ( requestPath ) ;
353355 }
354- return rc === 0 && toRealPath ( requestPath ) ;
356+ return toRealPath ( requestPath ) ;
355357}
356358
357359function toRealPath ( requestPath ) {
@@ -388,52 +390,7 @@ function findLongestRegisteredExtension(filename) {
388390 return '.js' ;
389391}
390392
391- function resolveBasePath ( basePath , exts , isMain , trailingSlash , request ) {
392- let filename ;
393-
394- const rc = stat ( basePath ) ;
395- if ( ! trailingSlash ) {
396- if ( rc === 0 ) { // File.
397- if ( ! isMain ) {
398- if ( preserveSymlinks ) {
399- filename = path . resolve ( basePath ) ;
400- } else {
401- filename = toRealPath ( basePath ) ;
402- }
403- } else if ( preserveSymlinksMain ) {
404- // For the main module, we use the preserveSymlinksMain flag instead
405- // mainly for backward compatibility, as the preserveSymlinks flag
406- // historically has not applied to the main module. Most likely this
407- // was intended to keep .bin/ binaries working, as following those
408- // symlinks is usually required for the imports in the corresponding
409- // files to resolve; that said, in some use cases following symlinks
410- // causes bigger problems which is why the preserveSymlinksMain option
411- // is needed.
412- filename = path . resolve ( basePath ) ;
413- } else {
414- filename = toRealPath ( basePath ) ;
415- }
416- }
417-
418- if ( ! filename ) {
419- // Try it with each of the extensions
420- if ( exts === undefined )
421- exts = ObjectKeys ( Module . _extensions ) ;
422- filename = tryExtensions ( basePath , exts , isMain ) ;
423- }
424- }
425-
426- if ( ! filename && rc === 1 ) { // Directory.
427- // try it with each of the extensions at "index"
428- if ( exts === undefined )
429- exts = ObjectKeys ( Module . _extensions ) ;
430- filename = tryPackage ( basePath , exts , isMain , request ) ;
431- }
432-
433- return filename ;
434- }
435-
436- function trySelf ( parentPath , isMain , request ) {
393+ function trySelf ( parentPath , request ) {
437394 const { data : pkg , path : basePath } = readPackageScope ( parentPath ) || { } ;
438395 if ( ! pkg || pkg . exports === undefined ) return false ;
439396 if ( typeof pkg . name !== 'string' ) return false ;
@@ -447,20 +404,11 @@ function trySelf(parentPath, isMain, request) {
447404 return false ;
448405 }
449406
450- const exts = ObjectKeys ( Module . _extensions ) ;
451407 const fromExports = applyExports ( basePath , expansion ) ;
452- // Use exports
453408 if ( fromExports ) {
454- let trailingSlash = request . length > 0 &&
455- request . charCodeAt ( request . length - 1 ) === CHAR_FORWARD_SLASH ;
456- if ( ! trailingSlash ) {
457- trailingSlash = / (?: ^ | \/ ) \. ? \. $ / . test ( request ) ;
458- }
459- return resolveBasePath ( fromExports , exts , isMain , trailingSlash , request ) ;
460- } else {
461- // Use main field
462- return tryPackage ( basePath , exts , isMain , request ) ;
409+ return tryFile ( fromExports , false ) ;
463410 }
411+ assert ( fromExports !== false ) ;
464412}
465413
466414function isConditionalDotExportSugar ( exports , basePath ) {
@@ -492,7 +440,7 @@ function applyExports(basePath, expansion) {
492440
493441 let pkgExports = readPackageExports ( basePath ) ;
494442 if ( pkgExports === undefined || pkgExports === null )
495- return path . resolve ( basePath , mappingKey ) ;
443+ return false ;
496444
497445 if ( isConditionalDotExportSugar ( pkgExports , basePath ) )
498446 pkgExports = { '.' : pkgExports } ;
@@ -516,8 +464,24 @@ function applyExports(basePath, expansion) {
516464 if ( dirMatch !== '' ) {
517465 const mapping = pkgExports [ dirMatch ] ;
518466 const subpath = StringPrototypeSlice ( mappingKey , dirMatch . length ) ;
519- return resolveExportsTarget ( pathToFileURL ( basePath + '/' ) , mapping ,
520- subpath , mappingKey ) ;
467+ const resolved = resolveExportsTarget ( pathToFileURL ( basePath + '/' ) ,
468+ mapping , subpath , mappingKey ) ;
469+ // Extension searching for folder exports only
470+ const rc = stat ( resolved ) ;
471+ if ( rc === 0 ) return resolved ;
472+ if ( ! ( RegExpPrototypeTest ( trailingSlashRegex , resolved ) ) ) {
473+ const exts = ObjectKeys ( Module . _extensions ) ;
474+ const filename = tryExtensions ( resolved , exts , false ) ;
475+ if ( filename ) return filename ;
476+ }
477+ if ( rc === 1 ) {
478+ const exts = ObjectKeys ( Module . _extensions ) ;
479+ const filename = tryPackage ( resolved , exts , false ,
480+ basePath + expansion ) ;
481+ if ( filename ) return filename ;
482+ }
483+ // Undefined means not found
484+ return ;
521485 }
522486 }
523487
@@ -528,20 +492,20 @@ function applyExports(basePath, expansion) {
528492// 1. name/.*
529493// 2. @scope/name/.*
530494const EXPORTS_PATTERN = / ^ ( (?: @ [ ^ / \\ % ] + \/ ) ? [ ^ . / \\ % ] [ ^ / \\ % ] * ) ( \/ .* ) ? $ / ;
531- function resolveExports ( nmPath , request , absoluteRequest ) {
495+ function resolveExports ( nmPath , request ) {
532496 // The implementation's behavior is meant to mirror resolution in ESM.
533- if ( ! absoluteRequest ) {
534- const [ , name , expansion = '' ] =
535- StringPrototypeMatch ( request , EXPORTS_PATTERN ) || [ ] ;
536- if ( ! name ) {
537- return path . resolve ( nmPath , request ) ;
538- }
539-
540- const basePath = path . resolve ( nmPath , name ) ;
541- return applyExports ( basePath , expansion ) ;
497+ const [ , name , expansion = '' ] =
498+ StringPrototypeMatch ( request , EXPORTS_PATTERN ) || [ ] ;
499+ if ( ! name ) {
500+ return false ;
542501 }
543502
544- return path . resolve ( nmPath , request ) ;
503+ const basePath = path . resolve ( nmPath , name ) ;
504+ const fromExports = applyExports ( basePath , expansion ) ;
505+ if ( fromExports ) {
506+ return tryFile ( fromExports , false ) ;
507+ }
508+ return fromExports ;
545509}
546510
547511function isArrayIndex ( p ) {
@@ -632,6 +596,7 @@ function resolveExportsTarget(baseUrl, target, subpath, mappingKey) {
632596 StringPrototypeSlice ( baseUrl . pathname , 0 , - 1 ) , mappingKey , subpath , target ) ;
633597}
634598
599+ const trailingSlashRegex = / (?: ^ | \/ ) \. ? \. $ / ;
635600Module . _findPath = function ( request , paths , isMain ) {
636601 const absoluteRequest = path . isAbsolute ( request ) ;
637602 if ( absoluteRequest ) {
@@ -650,15 +615,26 @@ Module._findPath = function(request, paths, isMain) {
650615 let trailingSlash = request . length > 0 &&
651616 request . charCodeAt ( request . length - 1 ) === CHAR_FORWARD_SLASH ;
652617 if ( ! trailingSlash ) {
653- trailingSlash = / (?: ^ | \/ ) \. ? \. $ / . test ( request ) ;
618+ trailingSlash = RegExpPrototypeTest ( trailingSlashRegex , request ) ;
654619 }
655620
656621 // For each path
657622 for ( let i = 0 ; i < paths . length ; i ++ ) {
658623 // Don't search further if path doesn't exist
659624 const curPath = paths [ i ] ;
660625 if ( curPath && stat ( curPath ) < 1 ) continue ;
661- const basePath = resolveExports ( curPath , request , absoluteRequest ) ;
626+
627+ if ( ! absoluteRequest ) {
628+ const exportsResolved = resolveExports ( curPath , request ) ;
629+ // Undefined means not found, false means no exports
630+ if ( exportsResolved === undefined )
631+ break ;
632+ if ( exportsResolved ) {
633+ return exportsResolved ;
634+ }
635+ }
636+
637+ const basePath = path . resolve ( curPath , request ) ;
662638 let filename ;
663639
664640 const rc = stat ( basePath ) ;
@@ -950,7 +926,7 @@ Module._resolveFilename = function(request, parent, isMain, options) {
950926 }
951927
952928 if ( parent && parent . filename ) {
953- const filename = trySelf ( parent . filename , isMain , request ) ;
929+ const filename = trySelf ( parent . filename , request ) ;
954930 if ( filename ) {
955931 const cacheKey = request + '\x00' +
956932 ( paths . length === 1 ? paths [ 0 ] : paths . join ( '\x00' ) ) ;
0 commit comments