1
1
'use strict' ;
2
+
2
3
const {
3
4
RegExpPrototypeExec,
4
5
ObjectPrototypeHasOwnProperty,
5
6
PromisePrototypeThen,
6
7
PromiseResolve,
8
+ StringPrototypeIncludes,
7
9
StringPrototypeCharCodeAt,
8
10
StringPrototypeSlice,
9
11
} = primordials ;
10
12
const { basename, relative } = require ( 'path' ) ;
11
13
const { getOptionValue } = require ( 'internal/options' ) ;
12
14
const {
13
15
extensionFormatMap,
16
+ getFormatOfExtensionlessFile,
14
17
mimeToFormat,
15
18
} = require ( 'internal/modules/esm/formats' ) ;
16
19
17
20
const experimentalNetworkImports =
18
21
getOptionValue ( '--experimental-network-imports' ) ;
22
+ const defaultTypeFlag = getOptionValue ( '--experimental-default-type' ) ;
23
+ // The next line is where we flip the default to ES modules someday.
24
+ const defaultType = defaultTypeFlag === 'module' ? 'module' : 'commonjs' ;
19
25
const { getPackageType, getPackageScopeConfig } = require ( 'internal/modules/esm/resolve' ) ;
20
26
const { fileURLToPath } = require ( 'internal/url' ) ;
21
27
const { ERR_UNKNOWN_FILE_EXTENSION } = require ( 'internal/errors' ) . codes ;
@@ -66,6 +72,18 @@ function extname(url) {
66
72
return '' ;
67
73
}
68
74
75
+ /**
76
+ * Determine whether the given file URL is under a `node_modules` folder.
77
+ * This function assumes that the input has already been verified to be a `file:` URL,
78
+ * and is a file rather than a folder.
79
+ * @param {URL } url
80
+ */
81
+ function underNodeModules ( url ) {
82
+ if ( url . protocol !== 'file:' ) { return false ; } // We determine module types for other protocols based on MIME header
83
+
84
+ return StringPrototypeIncludes ( url . pathname , '/node_modules/' ) ;
85
+ }
86
+
69
87
/**
70
88
* @param {URL } url
71
89
* @param {{parentURL: string} } context
@@ -74,8 +92,37 @@ function extname(url) {
74
92
*/
75
93
function getFileProtocolModuleFormat ( url , context , ignoreErrors ) {
76
94
const ext = extname ( url ) ;
95
+
77
96
if ( ext === '.js' ) {
78
- return getPackageType ( url ) === 'module' ? 'module' : 'commonjs' ;
97
+ const packageType = getPackageType ( url ) ;
98
+ if ( packageType !== 'none' ) {
99
+ return packageType ;
100
+ }
101
+ // The controlling `package.json` file has no `type` field.
102
+ if ( defaultType === 'module' ) {
103
+ // An exception to the type flag making ESM the default everywhere is that package scopes under `node_modules`
104
+ // should retain the assumption that a lack of a `type` field means CommonJS.
105
+ return underNodeModules ( url ) ? 'commonjs' : 'module' ;
106
+ }
107
+ return 'commonjs' ;
108
+ }
109
+
110
+ if ( ext === '' ) {
111
+ const packageType = getPackageType ( url ) ;
112
+ if ( defaultType === 'commonjs' ) { // Legacy behavior
113
+ if ( packageType === 'none' || packageType === 'commonjs' ) {
114
+ return 'commonjs' ;
115
+ }
116
+ // If package type is `module`, fall through to the error case below
117
+ } else { // Else defaultType === 'module'
118
+ if ( underNodeModules ( url ) ) { // Exception for package scopes under `node_modules`
119
+ return 'commonjs' ;
120
+ }
121
+ if ( packageType === 'none' || packageType === 'module' ) {
122
+ return getFormatOfExtensionlessFile ( url ) ;
123
+ } // Else packageType === 'commonjs'
124
+ return 'commonjs' ;
125
+ }
79
126
}
80
127
81
128
const format = extensionFormatMap [ ext ] ;
@@ -89,12 +136,10 @@ function getFileProtocolModuleFormat(url, context, ignoreErrors) {
89
136
const config = getPackageScopeConfig ( url ) ;
90
137
const fileBasename = basename ( filepath ) ;
91
138
const relativePath = StringPrototypeSlice ( relative ( config . pjsonPath , filepath ) , 1 ) ;
92
- suggestion = 'Loading extensionless files is not supported inside of ' +
93
- '"type":"module" package.json contexts. The package.json file ' +
94
- `${ config . pjsonPath } caused this "type":"module" context. Try ` +
95
- `changing ${ filepath } to have a file extension. Note the "bin" ` +
96
- 'field of package.json can point to a file with an extension, for example ' +
97
- `{"type":"module","bin":{"${ fileBasename } ":"${ relativePath } .js"}}` ;
139
+ suggestion = 'Loading extensionless files is not supported inside of "type":"module" package.json contexts ' +
140
+ `without --experimental-default-type=module. The package.json file ${ config . pjsonPath } caused this "type":"module" ` +
141
+ `context. Try changing ${ filepath } to have a file extension. Note the "bin" field of package.json can point ` +
142
+ `to a file with an extension, for example {"type":"module","bin":{"${ fileBasename } ":"${ relativePath } .js"}}` ;
98
143
}
99
144
throw new ERR_UNKNOWN_FILE_EXTENSION ( ext , filepath , suggestion ) ;
100
145
}
0 commit comments