• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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