@@ -100,6 +100,9 @@ const kIsMainSymbol = Symbol('kIsMainSymbol');
100
100
const kIsCachedByESMLoader = Symbol ( 'kIsCachedByESMLoader' ) ;
101
101
const kRequiredModuleSymbol = Symbol ( 'kRequiredModuleSymbol' ) ;
102
102
const kIsExecuting = Symbol ( 'kIsExecuting' ) ;
103
+
104
+ const kFormat = Symbol ( 'kFormat' ) ;
105
+
103
106
// Set first due to cycle with ESM loader functions.
104
107
module . exports = {
105
108
kModuleSource,
@@ -433,10 +436,6 @@ function initializeCJS() {
433
436
// TODO(joyeecheung): deprecate this in favor of a proper hook?
434
437
Module . runMain =
435
438
require ( 'internal/modules/run_main' ) . executeUserEntryPoint ;
436
-
437
- if ( getOptionValue ( '--experimental-require-module' ) ) {
438
- Module . _extensions [ '.mjs' ] = loadESMFromCJS ;
439
- }
440
439
}
441
440
442
441
// Given a module name, and a list of paths to test, returns the first
@@ -646,14 +645,7 @@ function resolveExports(nmPath, request) {
646
645
// We don't cache this in case user extends the extensions.
647
646
function getDefaultExtensions ( ) {
648
647
const extensions = ObjectKeys ( Module . _extensions ) ;
649
- if ( ! getOptionValue ( '--experimental-require-module' ) ) {
650
- return extensions ;
651
- }
652
- // If the .mjs extension is added by --experimental-require-module,
653
- // remove it from the supported default extensions to maintain
654
- // compatibility.
655
- // TODO(joyeecheung): allow both .mjs and .cjs?
656
- return ArrayPrototypeFilter ( extensions , ( ext ) => ext !== '.mjs' || Module . _extensions [ '.mjs' ] !== loadESMFromCJS ) ;
648
+ return extensions ;
657
649
}
658
650
659
651
/**
@@ -1280,10 +1272,6 @@ Module.prototype.load = function(filename) {
1280
1272
this . paths = Module . _nodeModulePaths ( path . dirname ( filename ) ) ;
1281
1273
1282
1274
const extension = findLongestRegisteredExtension ( filename ) ;
1283
- // allow .mjs to be overridden
1284
- if ( StringPrototypeEndsWith ( filename , '.mjs' ) && ! Module . _extensions [ '.mjs' ] ) {
1285
- throw new ERR_REQUIRE_ESM ( filename , true ) ;
1286
- }
1287
1275
1288
1276
Module . _extensions [ extension ] ( this , filename ) ;
1289
1277
this . loaded = true ;
@@ -1327,9 +1315,10 @@ let hasPausedEntry = false;
1327
1315
* Resolve and evaluate it synchronously as ESM if it's ESM.
1328
1316
* @param {Module } mod CJS module instance
1329
1317
* @param {string } filename Absolute path of the file.
1318
+ * @param {string } format Format of the module. If it had types, this would be what it is after type-stripping.
1319
+ * @param {string } source Source the module. If it had types, this would have the type stripped.
1330
1320
*/
1331
- function loadESMFromCJS ( mod , filename ) {
1332
- const source = getMaybeCachedSource ( mod , filename ) ;
1321
+ function loadESMFromCJS ( mod , filename , format , source ) {
1333
1322
const cascadedLoader = require ( 'internal/modules/esm/loader' ) . getOrInitializeCascadedLoader ( ) ;
1334
1323
const isMain = mod [ kIsMainSymbol ] ;
1335
1324
if ( isMain ) {
@@ -1483,7 +1472,9 @@ function wrapSafe(filename, content, cjsModuleInstance, format) {
1483
1472
* `exports`) to the file. Returns exception, if any.
1484
1473
* @param {string } content The source code of the module
1485
1474
* @param {string } filename The file path of the module
1486
- * @param {'module'|'commonjs'|undefined } format Intended format of the module.
1475
+ * @param {
1476
+ * 'module'|'commonjs'|'commonjs-typescript'|'module-typescript'
1477
+ * } format Intended format of the module.
1487
1478
*/
1488
1479
Module . prototype . _compile = function ( content , filename , format ) {
1489
1480
let moduleURL ;
@@ -1505,9 +1496,7 @@ Module.prototype._compile = function(content, filename, format) {
1505
1496
}
1506
1497
1507
1498
if ( format === 'module' ) {
1508
- // Pass the source into the .mjs extension handler indirectly through the cache.
1509
- this [ kModuleSource ] = content ;
1510
- loadESMFromCJS ( this , filename ) ;
1499
+ loadESMFromCJS ( this , filename , format , content ) ;
1511
1500
return ;
1512
1501
}
1513
1502
@@ -1560,22 +1549,72 @@ Module.prototype._compile = function(content, filename, format) {
1560
1549
1561
1550
/**
1562
1551
* Get the source code of a module, using cached ones if it's cached.
1552
+ * After this returns, mod[kFormat], mod[kModuleSource] and mod[kURL] will be set.
1563
1553
* @param {Module } mod Module instance whose source is potentially already cached.
1564
1554
* @param {string } filename Absolute path to the file of the module.
1565
- * @returns {string }
1555
+ * @returns {{source: string, format?: string} }
1566
1556
*/
1567
- function getMaybeCachedSource ( mod , filename ) {
1568
- // If already analyzed the source, then it will be cached.
1569
- let content ;
1570
- if ( mod [ kModuleSource ] !== undefined ) {
1571
- content = mod [ kModuleSource ] ;
1557
+ function loadSource ( mod , filename , formatFromNode ) {
1558
+ if ( formatFromNode !== undefined ) {
1559
+ mod [ kFormat ] = formatFromNode ;
1560
+ }
1561
+ const format = mod [ kFormat ] ;
1562
+
1563
+ let source = mod [ kModuleSource ] ;
1564
+ if ( source !== undefined ) {
1572
1565
mod [ kModuleSource ] = undefined ;
1573
1566
} else {
1574
1567
// TODO(joyeecheung): we can read a buffer instead to speed up
1575
1568
// compilation.
1576
- content = fs . readFileSync ( filename , 'utf8' ) ;
1569
+ source = fs . readFileSync ( filename , 'utf8' ) ;
1570
+ }
1571
+ return { source, format } ;
1572
+ }
1573
+
1574
+ function reconstructErrorStack ( err , parentPath , parentSource ) {
1575
+ const errLine = StringPrototypeSplit (
1576
+ StringPrototypeSlice ( err . stack , StringPrototypeIndexOf (
1577
+ err . stack , ' at ' ) ) , '\n' , 1 ) [ 0 ] ;
1578
+ const { 1 : line , 2 : col } =
1579
+ RegExpPrototypeExec ( / ( \d + ) : ( \d + ) \) / , errLine ) || [ ] ;
1580
+ if ( line && col ) {
1581
+ const srcLine = StringPrototypeSplit ( parentSource , '\n' ) [ line - 1 ] ;
1582
+ const frame = `${ parentPath } :${ line } \n${ srcLine } \n${ StringPrototypeRepeat ( ' ' , col - 1 ) } ^\n` ;
1583
+ setArrowMessage ( err , frame ) ;
1584
+ }
1585
+ }
1586
+
1587
+ /**
1588
+ * Generate the legacy ERR_REQUIRE_ESM for the cases where require(esm) is disabled.
1589
+ * @param {Module } mod The module being required.
1590
+ * @param {undefined|object } pkg Data of the nearest package.json of the module.
1591
+ * @param {string } content Source code of the module.
1592
+ * @param {string } filename Filename of the module
1593
+ * @returns {Error }
1594
+ */
1595
+ function getRequireESMError ( mod , pkg , content , filename ) {
1596
+ // This is an error path because `require` of a `.js` file in a `"type": "module"` scope is not allowed.
1597
+ const parent = mod [ kModuleParent ] ;
1598
+ const parentPath = parent ?. filename ;
1599
+ const packageJsonPath = pkg ?. path ? path . resolve ( pkg . path , 'package.json' ) : null ;
1600
+ const usesEsm = containsModuleSyntax ( content , filename ) ;
1601
+ const err = new ERR_REQUIRE_ESM ( filename , usesEsm , parentPath ,
1602
+ packageJsonPath ) ;
1603
+ // Attempt to reconstruct the parent require frame.
1604
+ const parentModule = Module . _cache [ parentPath ] ;
1605
+ if ( parentModule ) {
1606
+ let parentSource ;
1607
+ try {
1608
+ ( { source : parentSource } = loadSource ( parentModule , parentPath ) ) ;
1609
+ } catch {
1610
+ // Continue regardless of error.
1611
+ }
1612
+ if ( parentSource ) {
1613
+ // TODO(joyeecheung): trim off internal frames from the stack.
1614
+ reconstructErrorStack ( err , parentPath , parentSource ) ;
1615
+ }
1577
1616
}
1578
- return content ;
1617
+ return err ;
1579
1618
}
1580
1619
1581
1620
/**
@@ -1584,57 +1623,25 @@ function getMaybeCachedSource(mod, filename) {
1584
1623
* @param {string } filename The file path of the module
1585
1624
*/
1586
1625
Module . _extensions [ '.js' ] = function ( module , filename ) {
1587
- // If already analyzed the source, then it will be cached.
1588
- const content = getMaybeCachedSource ( module , filename ) ;
1589
-
1590
- let format ;
1591
- if ( StringPrototypeEndsWith ( filename , '.js' ) ) {
1592
- const pkg = packageJsonReader . readPackageScope ( filename ) || { __proto__ : null } ;
1593
- // Function require shouldn't be used in ES modules.
1594
- if ( pkg . data ?. type === 'module' ) {
1595
- if ( getOptionValue ( '--experimental-require-module' ) ) {
1596
- module . _compile ( content , filename , 'module' ) ;
1597
- return ;
1598
- }
1599
-
1600
- // This is an error path because `require` of a `.js` file in a `"type": "module"` scope is not allowed.
1601
- const parent = module [ kModuleParent ] ;
1602
- const parentPath = parent ?. filename ;
1603
- const packageJsonPath = path . resolve ( pkg . path , 'package.json' ) ;
1604
- const usesEsm = containsModuleSyntax ( content , filename ) ;
1605
- const err = new ERR_REQUIRE_ESM ( filename , usesEsm , parentPath ,
1606
- packageJsonPath ) ;
1607
- // Attempt to reconstruct the parent require frame.
1608
- if ( Module . _cache [ parentPath ] ) {
1609
- let parentSource ;
1610
- try {
1611
- parentSource = fs . readFileSync ( parentPath , 'utf8' ) ;
1612
- } catch {
1613
- // Continue regardless of error.
1614
- }
1615
- if ( parentSource ) {
1616
- const errLine = StringPrototypeSplit (
1617
- StringPrototypeSlice ( err . stack , StringPrototypeIndexOf (
1618
- err . stack , ' at ' ) ) , '\n' , 1 ) [ 0 ] ;
1619
- const { 1 : line , 2 : col } =
1620
- RegExpPrototypeExec ( / ( \d + ) : ( \d + ) \) / , errLine ) || [ ] ;
1621
- if ( line && col ) {
1622
- const srcLine = StringPrototypeSplit ( parentSource , '\n' ) [ line - 1 ] ;
1623
- const frame = `${ parentPath } :${ line } \n${ srcLine } \n${
1624
- StringPrototypeRepeat ( ' ' , col - 1 ) } ^\n`;
1625
- setArrowMessage ( err , frame ) ;
1626
- }
1627
- }
1628
- }
1629
- throw err ;
1630
- } else if ( pkg . data ?. type === 'commonjs' ) {
1631
- format = 'commonjs' ;
1632
- }
1633
- } else if ( StringPrototypeEndsWith ( filename , '.cjs' ) ) {
1626
+ let format , pkg ;
1627
+ if ( StringPrototypeEndsWith ( filename , '.cjs' ) ) {
1634
1628
format = 'commonjs' ;
1629
+ } else if ( StringPrototypeEndsWith ( filename , '.mjs' ) ) {
1630
+ format = 'module' ;
1631
+ } else if ( StringPrototypeEndsWith ( filename , '.js' ) ) {
1632
+ pkg = packageJsonReader . readPackageScope ( filename ) || { __proto__ : null } ;
1633
+ const typeFromPjson = pkg . data ?. type ;
1634
+ if ( typeFromPjson === 'module' || typeFromPjson === 'commonjs' || ! typeFromPjson ) {
1635
+ format = typeFromPjson ;
1636
+ }
1635
1637
}
1636
-
1637
- module . _compile ( content , filename , format ) ;
1638
+ const { source, format : loadedFormat } = loadSource ( module , filename , format ) ;
1639
+ // Function require shouldn't be used in ES modules when require(esm) is disabled.
1640
+ if ( loadedFormat === 'module' && ! getOptionValue ( '--experimental-require-module' ) ) {
1641
+ const err = getRequireESMError ( module , pkg , source , filename ) ;
1642
+ throw err ;
1643
+ }
1644
+ module . _compile ( source , filename , loadedFormat ) ;
1638
1645
} ;
1639
1646
1640
1647
/**
0 commit comments