9
9
StringPrototype
10
10
} = primordials ;
11
11
12
+ const { Buffer } = require ( 'buffer' ) ;
13
+
12
14
const {
13
15
stripBOM,
14
16
loadNativeModule
@@ -23,6 +25,8 @@ const { debuglog } = require('internal/util/debuglog');
23
25
const { promisify } = require ( 'internal/util' ) ;
24
26
const esmLoader = require ( 'internal/process/esm_loader' ) ;
25
27
const {
28
+ ERR_INVALID_URL ,
29
+ ERR_INVALID_URL_SCHEME ,
26
30
ERR_UNKNOWN_BUILTIN_MODULE
27
31
} = require ( 'internal/errors' ) . codes ;
28
32
const readFileAsync = promisify ( fs . readFile ) ;
@@ -33,6 +37,31 @@ const debug = debuglog('esm');
33
37
const translators = new SafeMap ( ) ;
34
38
exports . translators = translators ;
35
39
40
+ const DATA_URL_PATTERN = / ^ [ ^ / ] + \/ [ ^ , ; ] + ( ; b a s e 6 4 ) ? , ( [ \s \S ] * ) $ / ;
41
+ function getSource ( url ) {
42
+ const parsed = new URL ( url ) ;
43
+ if ( parsed . protocol === 'file:' ) {
44
+ return readFileAsync ( parsed ) ;
45
+ } else if ( parsed . protocol === 'data:' ) {
46
+ const match = DATA_URL_PATTERN . exec ( parsed . pathname ) ;
47
+ if ( ! match ) {
48
+ throw new ERR_INVALID_URL ( url ) ;
49
+ }
50
+ const [ , base64 , body ] = match ;
51
+ return Buffer . from ( body , base64 ? 'base64' : 'utf8' ) ;
52
+ } else {
53
+ throw new ERR_INVALID_URL_SCHEME ( [ 'file' , 'data' ] ) ;
54
+ }
55
+ }
56
+
57
+ function errPath ( url ) {
58
+ const parsed = new URL ( url ) ;
59
+ if ( parsed . protocol === 'file:' ) {
60
+ return fileURLToPath ( parsed ) ;
61
+ }
62
+ return url ;
63
+ }
64
+
36
65
function initializeImportMeta ( meta , { url } ) {
37
66
meta . url = url ;
38
67
}
@@ -44,7 +73,7 @@ async function importModuleDynamically(specifier, { url }) {
44
73
45
74
// Strategy for loading a standard JavaScript module
46
75
translators . set ( 'module' , async function moduleStrategy ( url ) {
47
- const source = `${ await readFileAsync ( new URL ( url ) ) } ` ;
76
+ const source = `${ await getSource ( url ) } ` ;
48
77
debug ( `Translating StandardModule ${ url } ` ) ;
49
78
const { ModuleWrap, callbackMap } = internalBinding ( 'module_wrap' ) ;
50
79
const module = new ModuleWrap ( source , url ) ;
@@ -111,26 +140,32 @@ translators.set('builtin', async function builtinStrategy(url) {
111
140
translators . set ( 'json' , async function jsonStrategy ( url ) {
112
141
debug ( `Translating JSONModule ${ url } ` ) ;
113
142
debug ( `Loading JSONModule ${ url } ` ) ;
114
- const pathname = fileURLToPath ( url ) ;
115
- const modulePath = isWindows ?
116
- StringPrototype . replace ( pathname , winSepRegEx , '\\' ) : pathname ;
117
- let module = CJSModule . _cache [ modulePath ] ;
118
- if ( module && module . loaded ) {
119
- const exports = module . exports ;
120
- return createDynamicModule ( [ ] , [ 'default' ] , url , ( reflect ) => {
121
- reflect . exports . default . set ( exports ) ;
122
- } ) ;
143
+ const pathname = url . startsWith ( 'file:' ) ? fileURLToPath ( url ) : null ;
144
+ let modulePath ;
145
+ let module ;
146
+ if ( pathname ) {
147
+ modulePath = isWindows ?
148
+ StringPrototype . replace ( pathname , winSepRegEx , '\\' ) : pathname ;
149
+ module = CJSModule . _cache [ modulePath ] ;
150
+ if ( module && module . loaded ) {
151
+ const exports = module . exports ;
152
+ return createDynamicModule ( [ ] , [ 'default' ] , url , ( reflect ) => {
153
+ reflect . exports . default . set ( exports ) ;
154
+ } ) ;
155
+ }
123
156
}
124
- const content = await readFileAsync ( pathname , 'utf-8' ) ;
125
- // A require call could have been called on the same file during loading and
126
- // that resolves synchronously. To make sure we always return the identical
127
- // export, we have to check again if the module already exists or not.
128
- module = CJSModule . _cache [ modulePath ] ;
129
- if ( module && module . loaded ) {
130
- const exports = module . exports ;
131
- return createDynamicModule ( [ 'default' ] , url , ( reflect ) => {
132
- reflect . exports . default . set ( exports ) ;
133
- } ) ;
157
+ const content = `${ await getSource ( url ) } ` ;
158
+ if ( pathname ) {
159
+ // A require call could have been called on the same file during loading and
160
+ // that resolves synchronously. To make sure we always return the identical
161
+ // export, we have to check again if the module already exists or not.
162
+ module = CJSModule . _cache [ modulePath ] ;
163
+ if ( module && module . loaded ) {
164
+ const exports = module . exports ;
165
+ return createDynamicModule ( [ 'default' ] , url , ( reflect ) => {
166
+ reflect . exports . default . set ( exports ) ;
167
+ } ) ;
168
+ }
134
169
}
135
170
try {
136
171
const exports = JsonParse ( stripBOM ( content ) ) ;
@@ -143,10 +178,12 @@ translators.set('json', async function jsonStrategy(url) {
143
178
// parse error instead of just manipulating the original error message.
144
179
// That would allow to add further properties and maybe additional
145
180
// debugging information.
146
- err . message = pathname + ': ' + err . message ;
181
+ err . message = errPath ( url ) + ': ' + err . message ;
147
182
throw err ;
148
183
}
149
- CJSModule . _cache [ modulePath ] = module ;
184
+ if ( pathname ) {
185
+ CJSModule . _cache [ modulePath ] = module ;
186
+ }
150
187
return createDynamicModule ( [ ] , [ 'default' ] , url , ( reflect ) => {
151
188
debug ( `Parsing JSONModule ${ url } ` ) ;
152
189
reflect . exports . default . set ( module . exports ) ;
@@ -155,14 +192,13 @@ translators.set('json', async function jsonStrategy(url) {
155
192
156
193
// Strategy for loading a wasm module
157
194
translators . set ( 'wasm' , async function ( url ) {
158
- const pathname = fileURLToPath ( url ) ;
159
- const buffer = await readFileAsync ( pathname ) ;
195
+ const buffer = await getSource ( url ) ;
160
196
debug ( `Translating WASMModule ${ url } ` ) ;
161
197
let compiled ;
162
198
try {
163
199
compiled = await WebAssembly . compile ( buffer ) ;
164
200
} catch ( err ) {
165
- err . message = pathname + ': ' + err . message ;
201
+ err . message = errPath ( url ) + ': ' + err . message ;
166
202
throw err ;
167
203
}
168
204
0 commit comments