1'use strict'; 2 3const { 4 ArrayPrototypeJoin, 5 ArrayPrototypeMap, 6 JSONStringify, 7 ObjectCreate, 8 SafeSet, 9} = primordials; 10 11let debug = require('internal/util/debuglog').debuglog('esm', (fn) => { 12 debug = fn; 13}); 14 15function createImport(impt, index) { 16 const imptPath = JSONStringify(impt); 17 return `import * as $import_${index} from ${imptPath}; 18import.meta.imports[${imptPath}] = $import_${index};`; 19} 20 21function createExport(expt) { 22 const name = `${expt}`; 23 return `let $${name}; 24export { $${name} as ${name} }; 25import.meta.exports.${name} = { 26 get: () => $${name}, 27 set: (v) => $${name} = v, 28};`; 29} 30 31const createDynamicModule = (imports, exports, url = '', evaluate) => { 32 debug('creating ESM facade for %s with exports: %j', url, exports); 33 const source = ` 34${ArrayPrototypeJoin(ArrayPrototypeMap(imports, createImport), '\n')} 35${ArrayPrototypeJoin(ArrayPrototypeMap(exports, createExport), '\n')} 36import.meta.done(); 37`; 38 const { ModuleWrap, callbackMap } = internalBinding('module_wrap'); 39 const m = new ModuleWrap(`${url}`, undefined, source, 0, 0); 40 41 const readyfns = new SafeSet(); 42 const reflect = { 43 exports: ObjectCreate(null), 44 onReady: (cb) => { readyfns.add(cb); }, 45 }; 46 47 if (imports.length) 48 reflect.imports = ObjectCreate(null); 49 50 callbackMap.set(m, { 51 initializeImportMeta: (meta, wrap) => { 52 meta.exports = reflect.exports; 53 if (reflect.imports) 54 meta.imports = reflect.imports; 55 meta.done = () => { 56 evaluate(reflect); 57 reflect.onReady = (cb) => cb(reflect); 58 for (const fn of readyfns) { 59 readyfns.delete(fn); 60 fn(reflect); 61 } 62 }; 63 }, 64 }); 65 66 return { 67 module: m, 68 reflect, 69 }; 70}; 71 72module.exports = createDynamicModule; 73