@@ -625,9 +625,10 @@ function trySelfParentPath(parent) {
625625 * @param {string } parentPath The path of the parent module
626626 * @param {string } request The module request to resolve
627627 * @param {unknown } conditions
628+ * @param {Module } [parent] The module that issued the require() call
628629 * @returns {false|string }
629630 */
630- function trySelf ( parentPath , request , conditions ) {
631+ function trySelf ( parentPath , request , conditions , parent ) {
631632 if ( ! parentPath ) { return false ; }
632633
633634 const pkg = packageJsonReader . getNearestParentPackageJSON ( parentPath ) ;
@@ -648,10 +649,10 @@ function trySelf(parentPath, request, conditions) {
648649 const { packageExportsResolve } = require ( 'internal/modules/esm/resolve' ) ;
649650 return finalizeEsmResolution ( packageExportsResolve (
650651 pathToFileURL ( pkg . path ) , expansion , pkg . data ,
651- pathToFileURL ( parentPath ) , conditions ) , parentPath , pkg . path ) ;
652+ pathToFileURL ( parentPath ) , conditions ) , parentPath , pkg . path , parent ) ;
652653 } catch ( e ) {
653654 if ( e . code === 'ERR_MODULE_NOT_FOUND' ) {
654- throw createEsmNotFoundErr ( request , pkg . path ) ;
655+ throw createEsmNotFoundErr ( request , pkg . path , parent ) ;
655656 }
656657 throw e ;
657658 }
@@ -671,7 +672,7 @@ const EXPORTS_PATTERN = /^((?:@[^/\\%]+\/)?[^./\\%][^/\\%]*)(\/.*)?$/;
671672 * @param {Set<string> } conditions The conditions to use for resolution.
672673 * @returns {undefined|string }
673674 */
674- function resolveExports ( nmPath , request , conditions ) {
675+ function resolveExports ( nmPath , request , conditions , parent ) {
675676 // The implementation's behavior is meant to mirror resolution in ESM.
676677 const { 1 : name , 2 : expansion = '' } =
677678 RegExpPrototypeExec ( EXPORTS_PATTERN , request ) || kEmptyObject ;
@@ -683,10 +684,10 @@ function resolveExports(nmPath, request, conditions) {
683684 const { packageExportsResolve } = require ( 'internal/modules/esm/resolve' ) ;
684685 return finalizeEsmResolution ( packageExportsResolve (
685686 pathToFileURL ( pkgPath + '/package.json' ) , '.' + expansion , pkg , null ,
686- conditions ) , null , pkgPath ) ;
687+ conditions ) , null , pkgPath , parent ) ;
687688 } catch ( e ) {
688689 if ( e . code === 'ERR_MODULE_NOT_FOUND' ) {
689- throw createEsmNotFoundErr ( request , pkgPath + '/package.json' ) ;
690+ throw createEsmNotFoundErr ( request , pkgPath + '/package.json' , parent ) ;
690691 }
691692 throw e ;
692693 }
@@ -698,9 +699,11 @@ function resolveExports(nmPath, request, conditions) {
698699 * @param {string } request Relative or absolute file path
699700 * @param {Array<string> } paths Folders to search as file paths
700701 * @param {boolean } isMain Whether the request is the main app entry point
702+ * @param {Set<string> } [conditions] The conditions to use for resolution
703+ * @param {Module } [parent] The module that issued the require() call
701704 * @returns {string | false }
702705 */
703- Module . _findPath = function ( request , paths , isMain , conditions = getCjsConditions ( ) ) {
706+ Module . _findPath = function ( request , paths , isMain , conditions = getCjsConditions ( ) , parent ) {
704707 const absoluteRequest = path . isAbsolute ( request ) ;
705708 if ( absoluteRequest ) {
706709 paths = [ '' ] ;
@@ -748,7 +751,7 @@ Module._findPath = function(request, paths, isMain, conditions = getCjsCondition
748751 }
749752
750753 if ( ! absoluteRequest ) {
751- const exportsResolved = resolveExports ( curPath , request , conditions ) ;
754+ const exportsResolved = resolveExports ( curPath , request , conditions , parent ) ;
752755 if ( exportsResolved ) {
753756 return exportsResolved ;
754757 }
@@ -1436,10 +1439,11 @@ Module._resolveFilename = function(request, parent, isMain, options) {
14361439 packageImportsResolve ( request , pathToFileURL ( parentPath ) , conditions ) ,
14371440 parentPath ,
14381441 pkg . path ,
1442+ parent ,
14391443 ) ;
14401444 } catch ( e ) {
14411445 if ( e . code === 'ERR_MODULE_NOT_FOUND' ) {
1442- throw createEsmNotFoundErr ( request ) ;
1446+ throw createEsmNotFoundErr ( request , undefined , parent ) ;
14431447 }
14441448 throw e ;
14451449 }
@@ -1448,7 +1452,7 @@ Module._resolveFilename = function(request, parent, isMain, options) {
14481452
14491453 // Try module self resolution first
14501454 const parentPath = trySelfParentPath ( parent ) ;
1451- const selfResolved = trySelf ( parentPath , request , conditions ) ;
1455+ const selfResolved = trySelf ( parentPath , request , conditions , parent ) ;
14521456 if ( selfResolved ) {
14531457 const cacheKey = request + '\x00' +
14541458 ( paths . length === 1 ? paths [ 0 ] : ArrayPrototypeJoin ( paths , '\x00' ) ) ;
@@ -1457,7 +1461,7 @@ Module._resolveFilename = function(request, parent, isMain, options) {
14571461 }
14581462
14591463 // Look up the filename first, since that's the cache key.
1460- const filename = Module . _findPath ( request , paths , isMain , conditions ) ;
1464+ const filename = Module . _findPath ( request , paths , isMain , conditions , parent ) ;
14611465 if ( filename ) { return filename ; }
14621466 const requireStack = [ ] ;
14631467 for ( let cursor = parent ;
@@ -1483,11 +1487,12 @@ Module._resolveFilename = function(request, parent, isMain, options) {
14831487 * @param {string } resolved The resolved module specifier
14841488 * @param {string } parentPath The path of the parent module
14851489 * @param {string } pkgPath The path of the package.json file
1490+ * @param {Module } [parent] The module that issued the require() call
14861491 * @throws {ERR_INVALID_MODULE_SPECIFIER } If the resolved module specifier contains encoded `/` or `\\` characters
14871492 * @throws {Error } If the module cannot be found
14881493 * @returns {void|string|undefined }
14891494 */
1490- function finalizeEsmResolution ( resolved , parentPath , pkgPath ) {
1495+ function finalizeEsmResolution ( resolved , parentPath , pkgPath , parent ) {
14911496 const { encodedSepRegEx } = require ( 'internal/modules/esm/resolve' ) ;
14921497 if ( RegExpPrototypeExec ( encodedSepRegEx , resolved ) !== null ) {
14931498 throw new ERR_INVALID_MODULE_SPECIFIER (
@@ -1498,23 +1503,37 @@ function finalizeEsmResolution(resolved, parentPath, pkgPath) {
14981503 if ( actual ) {
14991504 return actual ;
15001505 }
1501- throw createEsmNotFoundErr ( filename , pkgPath ) ;
1506+ throw createEsmNotFoundErr ( filename , pkgPath , parent ) ;
15021507}
15031508
15041509/**
15051510 * Creates an error object for when a requested ES module cannot be found.
15061511 * @param {string } request The name of the requested module
15071512 * @param {string } [path] The path to the requested module
1513+ * @param {Module } [parent] The module that issued the require() call
15081514 * @returns {Error }
15091515 */
1510- function createEsmNotFoundErr ( request , path ) {
1516+ function createEsmNotFoundErr ( request , path , parent ) {
1517+ const requireStack = [ ] ;
1518+ for ( let cursor = parent ;
1519+ cursor ;
1520+ cursor = cursor [ kLastModuleParent ] ) {
1521+ ArrayPrototypePush ( requireStack , cursor . filename || cursor . id ) ;
1522+ }
1523+ let message = `Cannot find module '${ request } '` ;
1524+ if ( requireStack . length > 0 ) {
1525+ message = message + '\nRequire stack:\n- ' +
1526+ ArrayPrototypeJoin ( requireStack , '\n- ' ) ;
1527+ }
15111528 // eslint-disable-next-line no-restricted-syntax
1512- const err = new Error ( `Cannot find module ' ${ request } '` ) ;
1529+ const err = new Error ( message ) ;
15131530 err . code = 'MODULE_NOT_FOUND' ;
15141531 if ( path ) {
15151532 err . path = path ;
15161533 }
1517- // TODO(BridgeAR): Add the requireStack as well.
1534+ if ( requireStack . length > 0 ) {
1535+ err . requireStack = requireStack ;
1536+ }
15181537 return err ;
15191538}
15201539
0 commit comments