@@ -101,6 +101,9 @@ const kIsMainSymbol = Symbol('kIsMainSymbol');
101
101
const kIsCachedByESMLoader = Symbol ( 'kIsCachedByESMLoader' ) ;
102
102
const kRequiredModuleSymbol = Symbol ( 'kRequiredModuleSymbol' ) ;
103
103
const kIsExecuting = Symbol ( 'kIsExecuting' ) ;
104
+
105
+ const kFormat = Symbol ( 'kFormat' ) ;
106
+
104
107
// Set first due to cycle with ESM loader functions.
105
108
module . exports = {
106
109
kModuleSource,
@@ -434,10 +437,6 @@ function initializeCJS() {
434
437
// TODO(joyeecheung): deprecate this in favor of a proper hook?
435
438
Module . runMain =
436
439
require ( 'internal/modules/run_main' ) . executeUserEntryPoint ;
437
-
438
- if ( getOptionValue ( '--experimental-require-module' ) ) {
439
- Module . _extensions [ '.mjs' ] = loadESMFromCJS ;
440
- }
441
440
}
442
441
443
442
// Given a module name, and a list of paths to test, returns the first
@@ -647,14 +646,7 @@ function resolveExports(nmPath, request) {
647
646
// We don't cache this in case user extends the extensions.
648
647
function getDefaultExtensions ( ) {
649
648
const extensions = ObjectKeys ( Module . _extensions ) ;
650
- if ( ! getOptionValue ( '--experimental-require-module' ) ) {
651
- return extensions ;
652
- }
653
- // If the .mjs extension is added by --experimental-require-module,
654
- // remove it from the supported default extensions to maintain
655
- // compatibility.
656
- // TODO(joyeecheung): allow both .mjs and .cjs?
657
- return ArrayPrototypeFilter ( extensions , ( ext ) => ext !== '.mjs' || Module . _extensions [ '.mjs' ] !== loadESMFromCJS ) ;
649
+ return extensions ;
658
650
}
659
651
660
652
/**
@@ -1263,10 +1255,6 @@ Module.prototype.load = function(filename) {
1263
1255
this . paths = Module . _nodeModulePaths ( path . dirname ( filename ) ) ;
1264
1256
1265
1257
const extension = findLongestRegisteredExtension ( filename ) ;
1266
- // allow .mjs to be overridden
1267
- if ( StringPrototypeEndsWith ( filename , '.mjs' ) && ! Module . _extensions [ '.mjs' ] ) {
1268
- throw new ERR_REQUIRE_ESM ( filename , true ) ;
1269
- }
1270
1258
1271
1259
Module . _extensions [ extension ] ( this , filename ) ;
1272
1260
this . loaded = true ;
@@ -1302,9 +1290,10 @@ let requireModuleWarningMode;
1302
1290
* Resolve and evaluate it synchronously as ESM if it's ESM.
1303
1291
* @param {Module } mod CJS module instance
1304
1292
* @param {string } filename Absolute path of the file.
1293
+ * @param {string } format Format of the module. If it had types, this would be what it is after type-stripping.
1294
+ * @param {string } source Source the module. If it had types, this would have the type stripped.
1305
1295
*/
1306
- function loadESMFromCJS ( mod , filename ) {
1307
- const source = getMaybeCachedSource ( mod , filename ) ;
1296
+ function loadESMFromCJS ( mod , filename , format , source ) {
1308
1297
const cascadedLoader = require ( 'internal/modules/esm/loader' ) . getOrInitializeCascadedLoader ( ) ;
1309
1298
const isMain = mod [ kIsMainSymbol ] ;
1310
1299
if ( isMain ) {
@@ -1480,7 +1469,9 @@ function wrapSafe(filename, content, cjsModuleInstance, format) {
1480
1469
* `exports`) to the file. Returns exception, if any.
1481
1470
* @param {string } content The source code of the module
1482
1471
* @param {string } filename The file path of the module
1483
- * @param {'module'|'commonjs'|undefined } format Intended format of the module.
1472
+ * @param {
1473
+ * 'module'|'commonjs'|'commonjs-typescript'|'module-typescript'
1474
+ * } format Intended format of the module.
1484
1475
*/
1485
1476
Module . prototype . _compile = function ( content , filename , format ) {
1486
1477
let moduleURL ;
@@ -1502,9 +1493,7 @@ Module.prototype._compile = function(content, filename, format) {
1502
1493
}
1503
1494
1504
1495
if ( format === 'module' ) {
1505
- // Pass the source into the .mjs extension handler indirectly through the cache.
1506
- this [ kModuleSource ] = content ;
1507
- loadESMFromCJS ( this , filename ) ;
1496
+ loadESMFromCJS ( this , filename , format , content ) ;
1508
1497
return ;
1509
1498
}
1510
1499
@@ -1532,22 +1521,72 @@ Module.prototype._compile = function(content, filename, format) {
1532
1521
1533
1522
/**
1534
1523
* Get the source code of a module, using cached ones if it's cached.
1524
+ * After this returns, mod[kFormat], mod[kModuleSource] and mod[kURL] will be set.
1535
1525
* @param {Module } mod Module instance whose source is potentially already cached.
1536
1526
* @param {string } filename Absolute path to the file of the module.
1537
- * @returns {string }
1527
+ * @returns {{source: string, format?: string} }
1538
1528
*/
1539
- function getMaybeCachedSource ( mod , filename ) {
1540
- // If already analyzed the source, then it will be cached.
1541
- let content ;
1542
- if ( mod [ kModuleSource ] !== undefined ) {
1543
- content = mod [ kModuleSource ] ;
1529
+ function loadSource ( mod , filename , formatFromNode ) {
1530
+ if ( formatFromNode !== undefined ) {
1531
+ mod [ kFormat ] = formatFromNode ;
1532
+ }
1533
+ const format = mod [ kFormat ] ;
1534
+
1535
+ let source = mod [ kModuleSource ] ;
1536
+ if ( source !== undefined ) {
1544
1537
mod [ kModuleSource ] = undefined ;
1545
1538
} else {
1546
1539
// TODO(joyeecheung): we can read a buffer instead to speed up
1547
1540
// compilation.
1548
- content = fs . readFileSync ( filename , 'utf8' ) ;
1541
+ source = fs . readFileSync ( filename , 'utf8' ) ;
1542
+ }
1543
+ return { source, format } ;
1544
+ }
1545
+
1546
+ function reconstructErrorStack ( err , parentPath , parentSource ) {
1547
+ const errLine = StringPrototypeSplit (
1548
+ StringPrototypeSlice ( err . stack , StringPrototypeIndexOf (
1549
+ err . stack , ' at ' ) ) , '\n' , 1 ) [ 0 ] ;
1550
+ const { 1 : line , 2 : col } =
1551
+ RegExpPrototypeExec ( / ( \d + ) : ( \d + ) \) / , errLine ) || [ ] ;
1552
+ if ( line && col ) {
1553
+ const srcLine = StringPrototypeSplit ( parentSource , '\n' ) [ line - 1 ] ;
1554
+ const frame = `${ parentPath } :${ line } \n${ srcLine } \n${ StringPrototypeRepeat ( ' ' , col - 1 ) } ^\n` ;
1555
+ setArrowMessage ( err , frame ) ;
1556
+ }
1557
+ }
1558
+
1559
+ /**
1560
+ * Generate the legacy ERR_REQUIRE_ESM for the cases where require(esm) is disabled.
1561
+ * @param {Module } mod The module being required.
1562
+ * @param {undefined|object } pkg Data of the nearest package.json of the module.
1563
+ * @param {string } content Source code of the module.
1564
+ * @param {string } filename Filename of the module
1565
+ * @returns {Error }
1566
+ */
1567
+ function getRequireESMError ( mod , pkg , content , filename ) {
1568
+ // This is an error path because `require` of a `.js` file in a `"type": "module"` scope is not allowed.
1569
+ const parent = mod [ kModuleParent ] ;
1570
+ const parentPath = parent ?. filename ;
1571
+ const packageJsonPath = pkg ?. path ? path . resolve ( pkg . path , 'package.json' ) : null ;
1572
+ const usesEsm = containsModuleSyntax ( content , filename ) ;
1573
+ const err = new ERR_REQUIRE_ESM ( filename , usesEsm , parentPath ,
1574
+ packageJsonPath ) ;
1575
+ // Attempt to reconstruct the parent require frame.
1576
+ const parentModule = Module . _cache [ parentPath ] ;
1577
+ if ( parentModule ) {
1578
+ let parentSource ;
1579
+ try {
1580
+ ( { source : parentSource } = loadSource ( parentModule , parentPath ) ) ;
1581
+ } catch {
1582
+ // Continue regardless of error.
1583
+ }
1584
+ if ( parentSource ) {
1585
+ // TODO(joyeecheung): trim off internal frames from the stack.
1586
+ reconstructErrorStack ( err , parentPath , parentSource ) ;
1587
+ }
1549
1588
}
1550
- return content ;
1589
+ return err ;
1551
1590
}
1552
1591
1553
1592
/**
@@ -1556,57 +1595,25 @@ function getMaybeCachedSource(mod, filename) {
1556
1595
* @param {string } filename The file path of the module
1557
1596
*/
1558
1597
Module . _extensions [ '.js' ] = function ( module , filename ) {
1559
- // If already analyzed the source, then it will be cached.
1560
- const content = getMaybeCachedSource ( module , filename ) ;
1561
-
1562
- let format ;
1563
- if ( StringPrototypeEndsWith ( filename , '.js' ) ) {
1564
- const pkg = packageJsonReader . readPackageScope ( filename ) || { __proto__ : null } ;
1565
- // Function require shouldn't be used in ES modules.
1566
- if ( pkg . data ?. type === 'module' ) {
1567
- if ( getOptionValue ( '--experimental-require-module' ) ) {
1568
- module . _compile ( content , filename , 'module' ) ;
1569
- return ;
1570
- }
1571
-
1572
- // This is an error path because `require` of a `.js` file in a `"type": "module"` scope is not allowed.
1573
- const parent = module [ kModuleParent ] ;
1574
- const parentPath = parent ?. filename ;
1575
- const packageJsonPath = path . resolve ( pkg . path , 'package.json' ) ;
1576
- const usesEsm = containsModuleSyntax ( content , filename ) ;
1577
- const err = new ERR_REQUIRE_ESM ( filename , usesEsm , parentPath ,
1578
- packageJsonPath ) ;
1579
- // Attempt to reconstruct the parent require frame.
1580
- if ( Module . _cache [ parentPath ] ) {
1581
- let parentSource ;
1582
- try {
1583
- parentSource = fs . readFileSync ( parentPath , 'utf8' ) ;
1584
- } catch {
1585
- // Continue regardless of error.
1586
- }
1587
- if ( parentSource ) {
1588
- const errLine = StringPrototypeSplit (
1589
- StringPrototypeSlice ( err . stack , StringPrototypeIndexOf (
1590
- err . stack , ' at ' ) ) , '\n' , 1 ) [ 0 ] ;
1591
- const { 1 : line , 2 : col } =
1592
- RegExpPrototypeExec ( / ( \d + ) : ( \d + ) \) / , errLine ) || [ ] ;
1593
- if ( line && col ) {
1594
- const srcLine = StringPrototypeSplit ( parentSource , '\n' ) [ line - 1 ] ;
1595
- const frame = `${ parentPath } :${ line } \n${ srcLine } \n${
1596
- StringPrototypeRepeat ( ' ' , col - 1 ) } ^\n`;
1597
- setArrowMessage ( err , frame ) ;
1598
- }
1599
- }
1600
- }
1601
- throw err ;
1602
- } else if ( pkg . data ?. type === 'commonjs' ) {
1603
- format = 'commonjs' ;
1604
- }
1605
- } else if ( StringPrototypeEndsWith ( filename , '.cjs' ) ) {
1598
+ let format , pkg ;
1599
+ if ( StringPrototypeEndsWith ( filename , '.cjs' ) ) {
1606
1600
format = 'commonjs' ;
1601
+ } else if ( StringPrototypeEndsWith ( filename , '.mjs' ) ) {
1602
+ format = 'module' ;
1603
+ } else if ( StringPrototypeEndsWith ( filename , '.js' ) ) {
1604
+ pkg = packageJsonReader . readPackageScope ( filename ) || { __proto__ : null } ;
1605
+ const typeFromPjson = pkg . data ?. type ;
1606
+ if ( typeFromPjson === 'module' || typeFromPjson === 'commonjs' || ! typeFromPjson ) {
1607
+ format = typeFromPjson ;
1608
+ }
1607
1609
}
1608
-
1609
- module . _compile ( content , filename , format ) ;
1610
+ const { source, format : loadedFormat } = loadSource ( module , filename , format ) ;
1611
+ // Function require shouldn't be used in ES modules when require(esm) is disabled.
1612
+ if ( loadedFormat === 'module' && ! getOptionValue ( '--experimental-require-module' ) ) {
1613
+ const err = getRequireESMError ( module , pkg , source , filename ) ;
1614
+ throw err ;
1615
+ }
1616
+ module . _compile ( source , filename , loadedFormat ) ;
1610
1617
} ;
1611
1618
1612
1619
/**
0 commit comments