11cb0ef41Sopenharmony_ciimport { register } from 'node:module';
21cb0ef41Sopenharmony_ciimport { MessageChannel } from 'node:worker_threads';
31cb0ef41Sopenharmony_ci
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ciconst { port1, port2 } = new MessageChannel();
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ciregister('./mock-loader.mjs', import.meta.url, {
81cb0ef41Sopenharmony_ci  data: {
91cb0ef41Sopenharmony_ci    port: port2,
101cb0ef41Sopenharmony_ci    mainImportURL: import.meta.url,
111cb0ef41Sopenharmony_ci  },
121cb0ef41Sopenharmony_ci  transferList: [port2],
131cb0ef41Sopenharmony_ci});
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_ci/**
161cb0ef41Sopenharmony_ci * This is the Map that saves *all* the mocked URL -> replacement Module
171cb0ef41Sopenharmony_ci * mappings
181cb0ef41Sopenharmony_ci * @type {Map<string, {namespace, listeners}>}
191cb0ef41Sopenharmony_ci */
201cb0ef41Sopenharmony_ciexport const mockedModules = new Map();
211cb0ef41Sopenharmony_cilet mockVersion = 0;
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_ci/**
241cb0ef41Sopenharmony_ci * @param {string} resolved an absolute URL HREF string
251cb0ef41Sopenharmony_ci * @param {object} replacementProperties an object to pick properties from
261cb0ef41Sopenharmony_ci *                                       to act as a module namespace
271cb0ef41Sopenharmony_ci * @returns {object} a mutator object that can update the module namespace
281cb0ef41Sopenharmony_ci *                   since we can't do something like old Object.observe
291cb0ef41Sopenharmony_ci */
301cb0ef41Sopenharmony_ciexport function mock(resolved, replacementProperties) {
311cb0ef41Sopenharmony_ci  const exportNames = Object.keys(replacementProperties);
321cb0ef41Sopenharmony_ci  const namespace = { __proto__: null };
331cb0ef41Sopenharmony_ci  /**
341cb0ef41Sopenharmony_ci   * @type {Array<(name: string)=>void>} functions to call whenever an
351cb0ef41Sopenharmony_ci   *                                     export name is updated
361cb0ef41Sopenharmony_ci   */
371cb0ef41Sopenharmony_ci  const listeners = [];
381cb0ef41Sopenharmony_ci  for (const name of exportNames) {
391cb0ef41Sopenharmony_ci    let currentValueForPropertyName = replacementProperties[name];
401cb0ef41Sopenharmony_ci    Object.defineProperty(namespace, name, {
411cb0ef41Sopenharmony_ci      __proto__: null,
421cb0ef41Sopenharmony_ci      enumerable: true,
431cb0ef41Sopenharmony_ci      get() {
441cb0ef41Sopenharmony_ci        return currentValueForPropertyName;
451cb0ef41Sopenharmony_ci      },
461cb0ef41Sopenharmony_ci      set(v) {
471cb0ef41Sopenharmony_ci        currentValueForPropertyName = v;
481cb0ef41Sopenharmony_ci        for (const fn of listeners) {
491cb0ef41Sopenharmony_ci          try {
501cb0ef41Sopenharmony_ci            fn(name);
511cb0ef41Sopenharmony_ci          } catch {
521cb0ef41Sopenharmony_ci            /* noop */
531cb0ef41Sopenharmony_ci          }
541cb0ef41Sopenharmony_ci        }
551cb0ef41Sopenharmony_ci      },
561cb0ef41Sopenharmony_ci    });
571cb0ef41Sopenharmony_ci  }
581cb0ef41Sopenharmony_ci  mockedModules.set(encodeURIComponent(resolved), {
591cb0ef41Sopenharmony_ci    namespace,
601cb0ef41Sopenharmony_ci    listeners,
611cb0ef41Sopenharmony_ci  });
621cb0ef41Sopenharmony_ci  mockVersion++;
631cb0ef41Sopenharmony_ci  // Inform the loader that the `resolved` URL should now use the specific
641cb0ef41Sopenharmony_ci  // `mockVersion` and has export names of `exportNames`
651cb0ef41Sopenharmony_ci  //
661cb0ef41Sopenharmony_ci  // This allows the loader to generate a fake module for that version
671cb0ef41Sopenharmony_ci  // and names the next time it resolves a specifier to equal `resolved`
681cb0ef41Sopenharmony_ci  port1.postMessage({ mockVersion, resolved, exports: exportNames });
691cb0ef41Sopenharmony_ci  return namespace;
701cb0ef41Sopenharmony_ci}
71