@@ -34,6 +34,7 @@ const {
3434 ObjectKeys,
3535 ObjectPrototypeHasOwnProperty,
3636 ReflectSet,
37+ RegExpPrototypeTest,
3738 SafeMap,
3839 String,
3940 StringPrototypeIndexOf,
@@ -122,7 +123,10 @@ function enrichCJSError(err) {
122123 after a comment block and/or after a variable definition.
123124 */
124125 if ( err . message . startsWith ( 'Unexpected token \'export\'' ) ||
125- ( / ^ \s * i m p o r t (? = [ { ' " * ] ) \s * (? ! [ ( ] ) / ) . test ( lineWithErr ) ) {
126+ ( RegExpPrototypeTest ( / ^ \s * i m p o r t (? = [ { ' " * ] ) \s * (? ! [ ( ] ) / , lineWithErr ) ) ) {
127+ // Emit the warning synchronously because we are in the middle of handling
128+ // a SyntaxError that will throw and likely terminate the process before an
129+ // asynchronous warning would be emitted.
126130 process . emitWarning (
127131 'To load an ES module, set "type": "module" in the package.json or use ' +
128132 'the .mjs extension.' ,
@@ -349,10 +353,11 @@ const realpathCache = new Map();
349353// absolute realpath.
350354function tryFile ( requestPath , isMain ) {
351355 const rc = stat ( requestPath ) ;
356+ if ( rc !== 0 ) return ;
352357 if ( preserveSymlinks && ! isMain ) {
353- return rc === 0 && path . resolve ( requestPath ) ;
358+ return path . resolve ( requestPath ) ;
354359 }
355- return rc === 0 && toRealPath ( requestPath ) ;
360+ return toRealPath ( requestPath ) ;
356361}
357362
358363function toRealPath ( requestPath ) {
@@ -389,52 +394,7 @@ function findLongestRegisteredExtension(filename) {
389394 return '.js' ;
390395}
391396
392- function resolveBasePath ( basePath , exts , isMain , trailingSlash , request ) {
393- let filename ;
394-
395- const rc = stat ( basePath ) ;
396- if ( ! trailingSlash ) {
397- if ( rc === 0 ) { // File.
398- if ( ! isMain ) {
399- if ( preserveSymlinks ) {
400- filename = path . resolve ( basePath ) ;
401- } else {
402- filename = toRealPath ( basePath ) ;
403- }
404- } else if ( preserveSymlinksMain ) {
405- // For the main module, we use the preserveSymlinksMain flag instead
406- // mainly for backward compatibility, as the preserveSymlinks flag
407- // historically has not applied to the main module. Most likely this
408- // was intended to keep .bin/ binaries working, as following those
409- // symlinks is usually required for the imports in the corresponding
410- // files to resolve; that said, in some use cases following symlinks
411- // causes bigger problems which is why the preserveSymlinksMain option
412- // is needed.
413- filename = path . resolve ( basePath ) ;
414- } else {
415- filename = toRealPath ( basePath ) ;
416- }
417- }
418-
419- if ( ! filename ) {
420- // Try it with each of the extensions
421- if ( exts === undefined )
422- exts = ObjectKeys ( Module . _extensions ) ;
423- filename = tryExtensions ( basePath , exts , isMain ) ;
424- }
425- }
426-
427- if ( ! filename && rc === 1 ) { // Directory.
428- // try it with each of the extensions at "index"
429- if ( exts === undefined )
430- exts = ObjectKeys ( Module . _extensions ) ;
431- filename = tryPackage ( basePath , exts , isMain , request ) ;
432- }
433-
434- return filename ;
435- }
436-
437- function trySelf ( parentPath , isMain , request ) {
397+ function trySelf ( parentPath , request ) {
438398 if ( ! experimentalModules ) return false ;
439399 const { data : pkg , path : basePath } = readPackageScope ( parentPath ) || { } ;
440400 if ( ! pkg || pkg . exports === undefined ) return false ;
@@ -449,20 +409,11 @@ function trySelf(parentPath, isMain, request) {
449409 return false ;
450410 }
451411
452- const exts = ObjectKeys ( Module . _extensions ) ;
453412 const fromExports = applyExports ( basePath , expansion ) ;
454- // Use exports
455413 if ( fromExports ) {
456- let trailingSlash = request . length > 0 &&
457- request . charCodeAt ( request . length - 1 ) === CHAR_FORWARD_SLASH ;
458- if ( ! trailingSlash ) {
459- trailingSlash = / (?: ^ | \/ ) \. ? \. $ / . test ( request ) ;
460- }
461- return resolveBasePath ( fromExports , exts , isMain , trailingSlash , request ) ;
462- } else {
463- // Use main field
464- return tryPackage ( basePath , exts , isMain , request ) ;
414+ return tryFile ( fromExports , false ) ;
465415 }
416+ assert ( fromExports !== false ) ;
466417}
467418
468419function isConditionalDotExportSugar ( exports , basePath ) {
@@ -494,7 +445,7 @@ function applyExports(basePath, expansion) {
494445
495446 let pkgExports = readPackageExports ( basePath ) ;
496447 if ( pkgExports === undefined || pkgExports === null || ! experimentalModules )
497- return path . resolve ( basePath , mappingKey ) ;
448+ return false ;
498449
499450 if ( isConditionalDotExportSugar ( pkgExports , basePath ) )
500451 pkgExports = { '.' : pkgExports } ;
@@ -518,8 +469,24 @@ function applyExports(basePath, expansion) {
518469 if ( dirMatch !== '' ) {
519470 const mapping = pkgExports [ dirMatch ] ;
520471 const subpath = StringPrototypeSlice ( mappingKey , dirMatch . length ) ;
521- return resolveExportsTarget ( pathToFileURL ( basePath + '/' ) , mapping ,
522- subpath , mappingKey ) ;
472+ const resolved = resolveExportsTarget ( pathToFileURL ( basePath + '/' ) ,
473+ mapping , subpath , mappingKey ) ;
474+ // Extension searching for folder exports only
475+ const rc = stat ( resolved ) ;
476+ if ( rc === 0 ) return resolved ;
477+ if ( ! ( RegExpPrototypeTest ( trailingSlashRegex , resolved ) ) ) {
478+ const exts = ObjectKeys ( Module . _extensions ) ;
479+ const filename = tryExtensions ( resolved , exts , false ) ;
480+ if ( filename ) return filename ;
481+ }
482+ if ( rc === 1 ) {
483+ const exts = ObjectKeys ( Module . _extensions ) ;
484+ const filename = tryPackage ( resolved , exts , false ,
485+ basePath + expansion ) ;
486+ if ( filename ) return filename ;
487+ }
488+ // Undefined means not found
489+ return ;
523490 }
524491 }
525492
@@ -530,20 +497,20 @@ function applyExports(basePath, expansion) {
530497// 1. name/.*
531498// 2. @scope/name/.*
532499const EXPORTS_PATTERN = / ^ ( (?: @ [ ^ / \\ % ] + \/ ) ? [ ^ . / \\ % ] [ ^ / \\ % ] * ) ( \/ .* ) ? $ / ;
533- function resolveExports ( nmPath , request , absoluteRequest ) {
500+ function resolveExports ( nmPath , request ) {
534501 // The implementation's behavior is meant to mirror resolution in ESM.
535- if ( ! absoluteRequest ) {
536- const [ , name , expansion = '' ] =
537- StringPrototypeMatch ( request , EXPORTS_PATTERN ) || [ ] ;
538- if ( ! name ) {
539- return path . resolve ( nmPath , request ) ;
540- }
541-
542- const basePath = path . resolve ( nmPath , name ) ;
543- return applyExports ( basePath , expansion ) ;
502+ const [ , name , expansion = '' ] =
503+ StringPrototypeMatch ( request , EXPORTS_PATTERN ) || [ ] ;
504+ if ( ! name ) {
505+ return false ;
544506 }
545507
546- return path . resolve ( nmPath , request ) ;
508+ const basePath = path . resolve ( nmPath , name ) ;
509+ const fromExports = applyExports ( basePath , expansion ) ;
510+ if ( fromExports ) {
511+ return tryFile ( fromExports , false ) ;
512+ }
513+ return fromExports ;
547514}
548515
549516function isArrayIndex ( p ) {
@@ -635,6 +602,7 @@ function resolveExportsTarget(baseUrl, target, subpath, mappingKey) {
635602 StringPrototypeSlice ( baseUrl . pathname , 0 , - 1 ) , mappingKey , subpath , target ) ;
636603}
637604
605+ const trailingSlashRegex = / (?: ^ | \/ ) \. ? \. $ / ;
638606Module . _findPath = function ( request , paths , isMain ) {
639607 const absoluteRequest = path . isAbsolute ( request ) ;
640608 if ( absoluteRequest ) {
@@ -653,15 +621,26 @@ Module._findPath = function(request, paths, isMain) {
653621 let trailingSlash = request . length > 0 &&
654622 request . charCodeAt ( request . length - 1 ) === CHAR_FORWARD_SLASH ;
655623 if ( ! trailingSlash ) {
656- trailingSlash = / (?: ^ | \/ ) \. ? \. $ / . test ( request ) ;
624+ trailingSlash = RegExpPrototypeTest ( trailingSlashRegex , request ) ;
657625 }
658626
659627 // For each path
660628 for ( let i = 0 ; i < paths . length ; i ++ ) {
661629 // Don't search further if path doesn't exist
662630 const curPath = paths [ i ] ;
663631 if ( curPath && stat ( curPath ) < 1 ) continue ;
664- const basePath = resolveExports ( curPath , request , absoluteRequest ) ;
632+
633+ if ( ! absoluteRequest ) {
634+ const exportsResolved = resolveExports ( curPath , request ) ;
635+ // Undefined means not found, false means no exports
636+ if ( exportsResolved === undefined )
637+ break ;
638+ if ( exportsResolved ) {
639+ return exportsResolved ;
640+ }
641+ }
642+
643+ const basePath = path . resolve ( curPath , request ) ;
665644 let filename ;
666645
667646 const rc = stat ( basePath ) ;
@@ -953,7 +932,7 @@ Module._resolveFilename = function(request, parent, isMain, options) {
953932 }
954933
955934 if ( parent && parent . filename ) {
956- const filename = trySelf ( parent . filename , isMain , request ) ;
935+ const filename = trySelf ( parent . filename , request ) ;
957936 if ( filename ) {
958937 emitExperimentalWarning ( 'Package name self resolution' ) ;
959938 const cacheKey = request + '\x00' +
0 commit comments