diff options
Diffstat (limited to 'lib/internal/modules/esm/CreateDynamicModule.js')
-rw-r--r-- | lib/internal/modules/esm/CreateDynamicModule.js | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/lib/internal/modules/esm/CreateDynamicModule.js b/lib/internal/modules/esm/CreateDynamicModule.js new file mode 100644 index 0000000000..7e9777af51 --- /dev/null +++ b/lib/internal/modules/esm/CreateDynamicModule.js @@ -0,0 +1,61 @@ +'use strict'; + +const { internalBinding } = require('internal/bootstrap/loaders'); +const { ModuleWrap } = internalBinding('module_wrap'); +const debug = require('util').debuglog('esm'); +const ArrayJoin = Function.call.bind(Array.prototype.join); +const ArrayMap = Function.call.bind(Array.prototype.map); + +const createDynamicModule = (exports, url = '', evaluate) => { + debug( + `creating ESM facade for ${url} with exports: ${ArrayJoin(exports, ', ')}` + ); + const names = ArrayMap(exports, (name) => `${name}`); + // Create two modules: One whose exports are get- and set-able ('reflective'), + // and one which re-exports all of these but additionally may + // run an executor function once everything is set up. + const src = ` + export let executor; + ${ArrayJoin(ArrayMap(names, (name) => `export let $${name};`), '\n')} + /* This function is implicitly returned as the module's completion value */ + (() => ({ + setExecutor: fn => executor = fn, + reflect: { + exports: { ${ + ArrayJoin(ArrayMap(names, (name) => ` + ${name}: { + get: () => $${name}, + set: v => $${name} = v + }`), ', \n')} + } + } + }));`; + const reflectiveModule = new ModuleWrap(src, `cjs-facade:${url}`); + reflectiveModule.instantiate(); + const { setExecutor, reflect } = reflectiveModule.evaluate()(); + // public exposed ESM + const reexports = ` + import { + executor, + ${ArrayMap(names, (name) => `$${name}`)} + } from ""; + export { + ${ArrayJoin(ArrayMap(names, (name) => `$${name} as ${name}`), ', ')} + } + if (typeof executor === "function") { + // add await to this later if top level await comes along + executor() + }`; + if (typeof evaluate === 'function') { + setExecutor(() => evaluate(reflect)); + } + const module = new ModuleWrap(reexports, `${url}`); + module.link(async () => reflectiveModule); + module.instantiate(); + return { + module, + reflect + }; +}; + +module.exports = createDynamicModule; |