99 StringPrototype
1010} = primordials ;
1111
12+ const { Buffer } = require ( 'buffer' ) ;
13+
1214const {
1315 stripBOM,
1416 loadNativeModule
@@ -23,6 +25,8 @@ const { debuglog } = require('internal/util/debuglog');
2325const { promisify } = require ( 'internal/util' ) ;
2426const esmLoader = require ( 'internal/process/esm_loader' ) ;
2527const {
28+ ERR_INVALID_URL ,
29+ ERR_INVALID_URL_SCHEME ,
2630 ERR_UNKNOWN_BUILTIN_MODULE
2731} = require ( 'internal/errors' ) . codes ;
2832const readFileAsync = promisify ( fs . readFile ) ;
@@ -33,6 +37,31 @@ const debug = debuglog('esm');
3337const translators = new SafeMap ( ) ;
3438exports . translators = translators ;
3539
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+
3665function initializeImportMeta ( meta , { url } ) {
3766 meta . url = url ;
3867}
@@ -44,7 +73,7 @@ async function importModuleDynamically(specifier, { url }) {
4473
4574// Strategy for loading a standard JavaScript module
4675translators . set ( 'module' , async function moduleStrategy ( url ) {
47- const source = `${ await readFileAsync ( new URL ( url ) ) } ` ;
76+ const source = `${ await getSource ( url ) } ` ;
4877 debug ( `Translating StandardModule ${ url } ` ) ;
4978 const { ModuleWrap, callbackMap } = internalBinding ( 'module_wrap' ) ;
5079 const module = new ModuleWrap ( source , url ) ;
@@ -111,26 +140,32 @@ translators.set('builtin', async function builtinStrategy(url) {
111140translators . set ( 'json' , async function jsonStrategy ( url ) {
112141 debug ( `Translating JSONModule ${ url } ` ) ;
113142 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+ }
123156 }
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+ }
134169 }
135170 try {
136171 const exports = JsonParse ( stripBOM ( content ) ) ;
@@ -143,10 +178,12 @@ translators.set('json', async function jsonStrategy(url) {
143178 // parse error instead of just manipulating the original error message.
144179 // That would allow to add further properties and maybe additional
145180 // debugging information.
146- err . message = pathname + ': ' + err . message ;
181+ err . message = errPath ( url ) + ': ' + err . message ;
147182 throw err ;
148183 }
149- CJSModule . _cache [ modulePath ] = module ;
184+ if ( pathname ) {
185+ CJSModule . _cache [ modulePath ] = module ;
186+ }
150187 return createDynamicModule ( [ ] , [ 'default' ] , url , ( reflect ) => {
151188 debug ( `Parsing JSONModule ${ url } ` ) ;
152189 reflect . exports . default . set ( module . exports ) ;
@@ -155,14 +192,13 @@ translators.set('json', async function jsonStrategy(url) {
155192
156193// Strategy for loading a wasm module
157194translators . set ( 'wasm' , async function ( url ) {
158- const pathname = fileURLToPath ( url ) ;
159- const buffer = await readFileAsync ( pathname ) ;
195+ const buffer = await getSource ( url ) ;
160196 debug ( `Translating WASMModule ${ url } ` ) ;
161197 let compiled ;
162198 try {
163199 compiled = await WebAssembly . compile ( buffer ) ;
164200 } catch ( err ) {
165- err . message = pathname + ': ' + err . message ;
201+ err . message = errPath ( url ) + ': ' + err . message ;
166202 throw err ;
167203 }
168204
0 commit comments