@@ -58,6 +58,7 @@ const enableSourceMaps = getOptionValue('--enable-source-maps');
5858const preserveSymlinks = getOptionValue ( '--preserve-symlinks' ) ;
5959const preserveSymlinksMain = getOptionValue ( '--preserve-symlinks-main' ) ;
6060const experimentalModules = getOptionValue ( '--experimental-modules' ) ;
61+ const experimentalSelf = getOptionValue ( '--experimental-resolve-self' ) ;
6162const manifest = getOptionValue ( '--experimental-policy' ) ?
6263 require ( 'internal/process/policy' ) . manifest :
6364 null ;
@@ -241,6 +242,7 @@ function readPackage(requestPath) {
241242 try {
242243 const parsed = JSON . parse ( json ) ;
243244 const filtered = {
245+ name : parsed . name ,
244246 main : parsed . main ,
245247 exports : parsed . exports ,
246248 type : parsed . type
@@ -370,6 +372,125 @@ function findLongestRegisteredExtension(filename) {
370372 return '.js' ;
371373}
372374
375+ function resolveBasePath ( basePath , exts , isMain , trailingSlash , request ) {
376+ let filename ;
377+
378+ const rc = stat ( basePath ) ;
379+ if ( ! trailingSlash ) {
380+ if ( rc === 0 ) { // File.
381+ if ( ! isMain ) {
382+ if ( preserveSymlinks ) {
383+ filename = path . resolve ( basePath ) ;
384+ } else {
385+ filename = toRealPath ( basePath ) ;
386+ }
387+ } else if ( preserveSymlinksMain ) {
388+ // For the main module, we use the preserveSymlinksMain flag instead
389+ // mainly for backward compatibility, as the preserveSymlinks flag
390+ // historically has not applied to the main module. Most likely this
391+ // was intended to keep .bin/ binaries working, as following those
392+ // symlinks is usually required for the imports in the corresponding
393+ // files to resolve; that said, in some use cases following symlinks
394+ // causes bigger problems which is why the preserveSymlinksMain option
395+ // is needed.
396+ filename = path . resolve ( basePath ) ;
397+ } else {
398+ filename = toRealPath ( basePath ) ;
399+ }
400+ }
401+
402+ if ( ! filename ) {
403+ // Try it with each of the extensions
404+ if ( exts === undefined )
405+ exts = Object . keys ( Module . _extensions ) ;
406+ filename = tryExtensions ( basePath , exts , isMain ) ;
407+ }
408+ }
409+
410+ if ( ! filename && rc === 1 ) { // Directory.
411+ // try it with each of the extensions at "index"
412+ if ( exts === undefined )
413+ exts = Object . keys ( Module . _extensions ) ;
414+ filename = tryPackage ( basePath , exts , isMain , request ) ;
415+ }
416+
417+ return filename ;
418+ }
419+
420+ function trySelf ( paths , exts , isMain , trailingSlash , request ) {
421+ if ( ! experimentalSelf ) {
422+ return false ;
423+ }
424+
425+ const { data : pkg , path : basePath } = readPackageScope ( paths [ 0 ] ) ;
426+ if ( ! pkg ) return false ;
427+ if ( typeof pkg . name !== 'string' ) return false ;
428+
429+ let expansion ;
430+ if ( request === pkg . name ) {
431+ expansion = '' ;
432+ } else if ( StringPrototype . startsWith ( request , `${ pkg . name } /` ) ) {
433+ expansion = StringPrototype . slice ( request , pkg . name . length ) ;
434+ } else {
435+ return false ;
436+ }
437+
438+ if ( exts === undefined )
439+ exts = Object . keys ( Module . _extensions ) ;
440+
441+ if ( expansion ) {
442+ // Use exports
443+ const fromExports = applyExports ( basePath , expansion ) ;
444+ if ( ! fromExports ) return false ;
445+ return resolveBasePath ( fromExports , exts , isMain , trailingSlash , request ) ;
446+ } else {
447+ // Use main field
448+ return tryPackage ( basePath , exts , isMain , request ) ;
449+ }
450+ }
451+
452+ function applyExports ( basePath , expansion ) {
453+ const pkgExports = readPackageExports ( basePath ) ;
454+ const mappingKey = `.${ expansion } ` ;
455+
456+ if ( typeof pkgExports === 'object' && pkgExports !== null ) {
457+ if ( ObjectPrototype . hasOwnProperty ( pkgExports , mappingKey ) ) {
458+ const mapping = pkgExports [ mappingKey ] ;
459+ return resolveExportsTarget ( pathToFileURL ( basePath + '/' ) , mapping , '' ,
460+ basePath , mappingKey ) ;
461+ }
462+
463+ let dirMatch = '' ;
464+ for ( const candidateKey of Object . keys ( pkgExports ) ) {
465+ if ( candidateKey [ candidateKey . length - 1 ] !== '/' ) continue ;
466+ if ( candidateKey . length > dirMatch . length &&
467+ StringPrototype . startsWith ( mappingKey , candidateKey ) ) {
468+ dirMatch = candidateKey ;
469+ }
470+ }
471+
472+ if ( dirMatch !== '' ) {
473+ const mapping = pkgExports [ dirMatch ] ;
474+ const subpath = StringPrototype . slice ( mappingKey , dirMatch . length ) ;
475+ return resolveExportsTarget ( pathToFileURL ( basePath + '/' ) , mapping ,
476+ subpath , basePath , mappingKey ) ;
477+ }
478+ }
479+ if ( mappingKey === '.' && typeof pkgExports === 'string' ) {
480+ return resolveExportsTarget ( pathToFileURL ( basePath + '/' ) , pkgExports ,
481+ '' , basePath , mappingKey ) ;
482+ }
483+ if ( pkgExports != null ) {
484+ // eslint-disable-next-line no-restricted-syntax
485+ const e = new Error ( `Package exports for '${ basePath } ' do not define ` +
486+ `a '${ mappingKey } ' subpath` ) ;
487+ e . code = 'MODULE_NOT_FOUND' ;
488+ throw e ;
489+ }
490+
491+ return path . resolve ( basePath , mappingKey ) ;
492+ }
493+
373494// This only applies to requests of a specific form:
374495// 1. name/.*
375496// 2. @scope/name/.*
@@ -384,43 +505,7 @@ function resolveExports(nmPath, request, absoluteRequest) {
384505 }
385506
386507 const basePath = path . resolve ( nmPath , name ) ;
387- const pkgExports = readPackageExports ( basePath ) ;
388- const mappingKey = `.${ expansion } ` ;
389-
390- if ( typeof pkgExports === 'object' && pkgExports !== null ) {
391- if ( ObjectPrototype . hasOwnProperty ( pkgExports , mappingKey ) ) {
392- const mapping = pkgExports [ mappingKey ] ;
393- return resolveExportsTarget ( pathToFileURL ( basePath + '/' ) , mapping , '' ,
394- basePath , mappingKey ) ;
395- }
396-
397- let dirMatch = '' ;
398- for ( const candidateKey of Object . keys ( pkgExports ) ) {
399- if ( candidateKey [ candidateKey . length - 1 ] !== '/' ) continue ;
400- if ( candidateKey . length > dirMatch . length &&
401- StringPrototype . startsWith ( mappingKey , candidateKey ) ) {
402- dirMatch = candidateKey ;
403- }
404- }
405-
406- if ( dirMatch !== '' ) {
407- const mapping = pkgExports [ dirMatch ] ;
408- const subpath = StringPrototype . slice ( mappingKey , dirMatch . length ) ;
409- return resolveExportsTarget ( pathToFileURL ( basePath + '/' ) , mapping ,
410- subpath , basePath , mappingKey ) ;
411- }
412- }
413- if ( mappingKey === '.' && typeof pkgExports === 'string' ) {
414- return resolveExportsTarget ( pathToFileURL ( basePath + '/' ) , pkgExports ,
415- '' , basePath , mappingKey ) ;
416- }
417- if ( pkgExports != null ) {
418- // eslint-disable-next-line no-restricted-syntax
419- const e = new Error ( `Package exports for '${ basePath } ' do not define ` +
420- `a '${ mappingKey } ' subpath` ) ;
421- e . code = 'MODULE_NOT_FOUND' ;
422- throw e ;
423- }
508+ return applyExports ( basePath , expansion ) ;
424509 }
425510
426511 return path . resolve ( nmPath , request ) ;
@@ -536,6 +621,13 @@ Module._findPath = function(request, paths, isMain) {
536621 return filename ;
537622 }
538623 }
624+
625+ const selfFilename = trySelf ( paths , exts , isMain , trailingSlash , request ) ;
626+ if ( selfFilename ) {
627+ Module . _pathCache [ cacheKey ] = selfFilename ;
628+ return selfFilename ;
629+ }
630+
539631 return false ;
540632} ;
541633
0 commit comments