99 StringPrototype
1010} = primordials ;
1111
12+ const { Buffer } = require ( 'buffer' ) ;
13+
1214const {
1315 stripShebang,
1416 stripBOM,
@@ -24,6 +26,8 @@ const { debuglog } = require('internal/util/debuglog');
2426const { promisify } = require ( 'internal/util' ) ;
2527const esmLoader = require ( 'internal/process/esm_loader' ) ;
2628const {
29+ ERR_INVALID_URL ,
30+ ERR_INVALID_URL_SCHEME ,
2731 ERR_UNKNOWN_BUILTIN_MODULE
2832} = require ( 'internal/errors' ) . codes ;
2933const readFileAsync = promisify ( fs . readFile ) ;
@@ -34,6 +38,31 @@ const debug = debuglog('esm');
3438const translators = new SafeMap ( ) ;
3539exports . translators = translators ;
3640
41+ const DATA_URL_PATTERN = / ^ [ ^ / ] + \/ [ ^ , ; ] + ( ; b a s e 6 4 ) ? , ( [ \s \S ] * ) $ / ;
42+ function getSource ( url ) {
43+ const parsed = new URL ( url ) ;
44+ if ( parsed . protocol === 'file:' ) {
45+ return readFileAsync ( parsed ) ;
46+ } else if ( parsed . protocol === 'data:' ) {
47+ const match = DATA_URL_PATTERN . exec ( parsed . pathname ) ;
48+ if ( ! match ) {
49+ throw new ERR_INVALID_URL ( url ) ;
50+ }
51+ const [ , base64 , body ] = match ;
52+ return Buffer . from ( body , base64 ? 'base64' : 'utf8' ) ;
53+ } else {
54+ throw new ERR_INVALID_URL_SCHEME ( [ 'file' , 'data' ] ) ;
55+ }
56+ }
57+
58+ function errPath ( url ) {
59+ const parsed = new URL ( url ) ;
60+ if ( parsed . protocol === 'file:' ) {
61+ return fileURLToPath ( parsed ) ;
62+ }
63+ return url ;
64+ }
65+
3766function initializeImportMeta ( meta , { url } ) {
3867 meta . url = url ;
3968}
@@ -45,7 +74,7 @@ async function importModuleDynamically(specifier, { url }) {
4574
4675// Strategy for loading a standard JavaScript module
4776translators . set ( 'module' , async function moduleStrategy ( url ) {
48- const source = `${ await readFileAsync ( new URL ( url ) ) } ` ;
77+ const source = `${ await getSource ( url ) } ` ;
4978 debug ( `Translating StandardModule ${ url } ` ) ;
5079 const { ModuleWrap, callbackMap } = internalBinding ( 'module_wrap' ) ;
5180 const module = new ModuleWrap ( stripShebang ( source ) , url ) ;
@@ -112,26 +141,32 @@ translators.set('builtin', async function builtinStrategy(url) {
112141translators . set ( 'json' , async function jsonStrategy ( url ) {
113142 debug ( `Translating JSONModule ${ url } ` ) ;
114143 debug ( `Loading JSONModule ${ url } ` ) ;
115- const pathname = fileURLToPath ( url ) ;
116- const modulePath = isWindows ?
117- StringPrototype . replace ( pathname , winSepRegEx , '\\' ) : pathname ;
118- let module = CJSModule . _cache [ modulePath ] ;
119- if ( module && module . loaded ) {
120- const exports = module . exports ;
121- return createDynamicModule ( [ ] , [ 'default' ] , url , ( reflect ) => {
122- reflect . exports . default . set ( exports ) ;
123- } ) ;
144+ const pathname = url . startsWith ( 'file:' ) ? fileURLToPath ( url ) : null ;
145+ let modulePath ;
146+ let module ;
147+ if ( pathname ) {
148+ modulePath = isWindows ?
149+ StringPrototype . replace ( pathname , winSepRegEx , '\\' ) : pathname ;
150+ module = CJSModule . _cache [ modulePath ] ;
151+ if ( module && module . loaded ) {
152+ const exports = module . exports ;
153+ return createDynamicModule ( [ ] , [ 'default' ] , url , ( reflect ) => {
154+ reflect . exports . default . set ( exports ) ;
155+ } ) ;
156+ }
124157 }
125- const content = await readFileAsync ( pathname , 'utf-8' ) ;
126- // A require call could have been called on the same file during loading and
127- // that resolves synchronously. To make sure we always return the identical
128- // export, we have to check again if the module already exists or not.
129- module = CJSModule . _cache [ modulePath ] ;
130- if ( module && module . loaded ) {
131- const exports = module . exports ;
132- return createDynamicModule ( [ 'default' ] , url , ( reflect ) => {
133- reflect . exports . default . set ( exports ) ;
134- } ) ;
158+ const content = `${ await getSource ( url ) } ` ;
159+ if ( pathname ) {
160+ // A require call could have been called on the same file during loading and
161+ // that resolves synchronously. To make sure we always return the identical
162+ // export, we have to check again if the module already exists or not.
163+ module = CJSModule . _cache [ modulePath ] ;
164+ if ( module && module . loaded ) {
165+ const exports = module . exports ;
166+ return createDynamicModule ( [ 'default' ] , url , ( reflect ) => {
167+ reflect . exports . default . set ( exports ) ;
168+ } ) ;
169+ }
135170 }
136171 try {
137172 const exports = JsonParse ( stripBOM ( content ) ) ;
@@ -144,10 +179,12 @@ translators.set('json', async function jsonStrategy(url) {
144179 // parse error instead of just manipulating the original error message.
145180 // That would allow to add further properties and maybe additional
146181 // debugging information.
147- err . message = pathname + ': ' + err . message ;
182+ err . message = errPath ( url ) + ': ' + err . message ;
148183 throw err ;
149184 }
150- CJSModule . _cache [ modulePath ] = module ;
185+ if ( pathname ) {
186+ CJSModule . _cache [ modulePath ] = module ;
187+ }
151188 return createDynamicModule ( [ ] , [ 'default' ] , url , ( reflect ) => {
152189 debug ( `Parsing JSONModule ${ url } ` ) ;
153190 reflect . exports . default . set ( module . exports ) ;
@@ -156,14 +193,13 @@ translators.set('json', async function jsonStrategy(url) {
156193
157194// Strategy for loading a wasm module
158195translators . set ( 'wasm' , async function ( url ) {
159- const pathname = fileURLToPath ( url ) ;
160- const buffer = await readFileAsync ( pathname ) ;
196+ const buffer = await getSource ( url ) ;
161197 debug ( `Translating WASMModule ${ url } ` ) ;
162198 let compiled ;
163199 try {
164200 compiled = await WebAssembly . compile ( buffer ) ;
165201 } catch ( err ) {
166- err . message = pathname + ': ' + err . message ;
202+ err . message = errPath ( url ) + ': ' + err . message ;
167203 throw err ;
168204 }
169205
0 commit comments