@@ -59,6 +59,7 @@ const enableSourceMaps = getOptionValue('--enable-source-maps');
5959const preserveSymlinks = getOptionValue ( '--preserve-symlinks' ) ;
6060const preserveSymlinksMain = getOptionValue ( '--preserve-symlinks-main' ) ;
6161const experimentalModules = getOptionValue ( '--experimental-modules' ) ;
62+ const experimentalSelf = getOptionValue ( '--experimental-resolve-self' ) ;
6263const manifest = getOptionValue ( '--experimental-policy' ) ?
6364 require ( 'internal/process/policy' ) . manifest :
6465 null ;
@@ -237,6 +238,7 @@ function readPackage(requestPath) {
237238 try {
238239 const parsed = JSON . parse ( json ) ;
239240 const filtered = {
241+ name : parsed . name ,
240242 main : parsed . main ,
241243 exports : parsed . exports ,
242244 type : parsed . type
@@ -366,6 +368,125 @@ function findLongestRegisteredExtension(filename) {
366368 return '.js' ;
367369}
368370
371+ function resolveBasePath ( basePath , exts , isMain , trailingSlash , request ) {
372+ let filename ;
373+
374+ const rc = stat ( basePath ) ;
375+ if ( ! trailingSlash ) {
376+ if ( rc === 0 ) { // File.
377+ if ( ! isMain ) {
378+ if ( preserveSymlinks ) {
379+ filename = path . resolve ( basePath ) ;
380+ } else {
381+ filename = toRealPath ( basePath ) ;
382+ }
383+ } else if ( preserveSymlinksMain ) {
384+ // For the main module, we use the preserveSymlinksMain flag instead
385+ // mainly for backward compatibility, as the preserveSymlinks flag
386+ // historically has not applied to the main module. Most likely this
387+ // was intended to keep .bin/ binaries working, as following those
388+ // symlinks is usually required for the imports in the corresponding
389+ // files to resolve; that said, in some use cases following symlinks
390+ // causes bigger problems which is why the preserveSymlinksMain option
391+ // is needed.
392+ filename = path . resolve ( basePath ) ;
393+ } else {
394+ filename = toRealPath ( basePath ) ;
395+ }
396+ }
397+
398+ if ( ! filename ) {
399+ // Try it with each of the extensions
400+ if ( exts === undefined )
401+ exts = Object . keys ( Module . _extensions ) ;
402+ filename = tryExtensions ( basePath , exts , isMain ) ;
403+ }
404+ }
405+
406+ if ( ! filename && rc === 1 ) { // Directory.
407+ // try it with each of the extensions at "index"
408+ if ( exts === undefined )
409+ exts = Object . keys ( Module . _extensions ) ;
410+ filename = tryPackage ( basePath , exts , isMain , request ) ;
411+ }
412+
413+ return filename ;
414+ }
415+
416+ function trySelf ( paths , exts , isMain , trailingSlash , request ) {
417+ if ( ! experimentalSelf ) {
418+ return false ;
419+ }
420+
421+ const { data : pkg , path : basePath } = readPackageScope ( paths [ 0 ] ) ;
422+ if ( ! pkg ) return false ;
423+ if ( typeof pkg . name !== 'string' ) return false ;
424+
425+ let expansion ;
426+ if ( request === pkg . name ) {
427+ expansion = '' ;
428+ } else if ( StringPrototype . startsWith ( request , `${ pkg . name } /` ) ) {
429+ expansion = StringPrototype . slice ( request , pkg . name . length ) ;
430+ } else {
431+ return false ;
432+ }
433+
434+ if ( exts === undefined )
435+ exts = Object . keys ( Module . _extensions ) ;
436+
437+ if ( expansion ) {
438+ // Use exports
439+ const fromExports = applyExports ( basePath , expansion ) ;
440+ if ( ! fromExports ) return false ;
441+ return resolveBasePath ( fromExports , exts , isMain , trailingSlash , request ) ;
442+ } else {
443+ // Use main field
444+ return tryPackage ( basePath , exts , isMain , request ) ;
445+ }
446+ }
447+
448+ function applyExports ( basePath , expansion ) {
449+ const pkgExports = readPackageExports ( basePath ) ;
450+ const mappingKey = `.${ expansion } ` ;
451+
452+ if ( typeof pkgExports === 'object' && pkgExports !== null ) {
453+ if ( ObjectPrototype . hasOwnProperty ( pkgExports , mappingKey ) ) {
454+ const mapping = pkgExports [ mappingKey ] ;
455+ return resolveExportsTarget ( pathToFileURL ( basePath + '/' ) , mapping , '' ,
456+ basePath , mappingKey ) ;
457+ }
458+
459+ let dirMatch = '' ;
460+ for ( const candidateKey of Object . keys ( pkgExports ) ) {
461+ if ( candidateKey [ candidateKey . length - 1 ] !== '/' ) continue ;
462+ if ( candidateKey . length > dirMatch . length &&
463+ StringPrototype . startsWith ( mappingKey , candidateKey ) ) {
464+ dirMatch = candidateKey ;
465+ }
466+ }
467+
468+ if ( dirMatch !== '' ) {
469+ const mapping = pkgExports [ dirMatch ] ;
470+ const subpath = StringPrototype . slice ( mappingKey , dirMatch . length ) ;
471+ return resolveExportsTarget ( pathToFileURL ( basePath + '/' ) , mapping ,
472+ subpath , basePath , mappingKey ) ;
473+ }
474+ }
475+ if ( mappingKey === '.' && typeof pkgExports === 'string' ) {
476+ return resolveExportsTarget ( pathToFileURL ( basePath + '/' ) , pkgExports ,
477+ '' , basePath , mappingKey ) ;
478+ }
479+ if ( pkgExports != null ) {
480+ // eslint-disable-next-line no-restricted-syntax
481+ const e = new Error ( `Package exports for '${ basePath } ' do not define ` +
482+ `a '${ mappingKey } ' subpath` ) ;
483+ e . code = 'MODULE_NOT_FOUND' ;
484+ throw e ;
485+ }
486+
487+ return path . resolve ( basePath , mappingKey ) ;
488+ }
489+
369490// This only applies to requests of a specific form:
370491// 1. name/.*
371492// 2. @scope/name/.*
@@ -380,43 +501,7 @@ function resolveExports(nmPath, request, absoluteRequest) {
380501 }
381502
382503 const basePath = path . resolve ( nmPath , name ) ;
383- const pkgExports = readPackageExports ( basePath ) ;
384- const mappingKey = `.${ expansion } ` ;
385-
386- if ( typeof pkgExports === 'object' && pkgExports !== null ) {
387- if ( ObjectPrototype . hasOwnProperty ( pkgExports , mappingKey ) ) {
388- const mapping = pkgExports [ mappingKey ] ;
389- return resolveExportsTarget ( pathToFileURL ( basePath + '/' ) , mapping , '' ,
390- basePath , mappingKey ) ;
391- }
392-
393- let dirMatch = '' ;
394- for ( const candidateKey of Object . keys ( pkgExports ) ) {
395- if ( candidateKey [ candidateKey . length - 1 ] !== '/' ) continue ;
396- if ( candidateKey . length > dirMatch . length &&
397- StringPrototype . startsWith ( mappingKey , candidateKey ) ) {
398- dirMatch = candidateKey ;
399- }
400- }
401-
402- if ( dirMatch !== '' ) {
403- const mapping = pkgExports [ dirMatch ] ;
404- const subpath = StringPrototype . slice ( mappingKey , dirMatch . length ) ;
405- return resolveExportsTarget ( pathToFileURL ( basePath + '/' ) , mapping ,
406- subpath , basePath , mappingKey ) ;
407- }
408- }
409- if ( mappingKey === '.' && typeof pkgExports === 'string' ) {
410- return resolveExportsTarget ( pathToFileURL ( basePath + '/' ) , pkgExports ,
411- '' , basePath , mappingKey ) ;
412- }
413- if ( pkgExports != null ) {
414- // eslint-disable-next-line no-restricted-syntax
415- const e = new Error ( `Package exports for '${ basePath } ' do not define ` +
416- `a '${ mappingKey } ' subpath` ) ;
417- e . code = 'MODULE_NOT_FOUND' ;
418- throw e ;
419- }
504+ return applyExports ( basePath , expansion ) ;
420505 }
421506
422507 return path . resolve ( nmPath , request ) ;
@@ -532,6 +617,13 @@ Module._findPath = function(request, paths, isMain) {
532617 return filename ;
533618 }
534619 }
620+
621+ const selfFilename = trySelf ( paths , exts , isMain , trailingSlash , request ) ;
622+ if ( selfFilename ) {
623+ Module . _pathCache [ cacheKey ] = selfFilename ;
624+ return selfFilename ;
625+ }
626+
535627 return false ;
536628} ;
537629
0 commit comments