Skip to content

Commit

Permalink
do not mutate import.meta, trailing commas, add doDrainPort back
Browse files Browse the repository at this point in the history
  • Loading branch information
aduh95 committed Sep 3, 2023
1 parent 844fe45 commit d1bedb7
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 22 deletions.
2 changes: 1 addition & 1 deletion test/es-module/test-esm-loader-mock.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Flags: --import ./test/fixtures/es-module-loaders/mock.mjs
import '../common/index.mjs';
import assert from 'node:assert/strict';
import { mock } from '../fixtures/es-module-loaders/mock.mjs';

Expand Down
57 changes: 40 additions & 17 deletions test/fixtures/es-module-loaders/mock-loader.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { receiveMessageOnPort } from 'node:worker_threads';
const mockedModuleExports = new Map();
let currentMockVersion = 0;

// This loader enables code running on the application thread to
// These hooks enable code running on the application thread to
// swap module resolution results for mocking purposes. It uses this instead
// of import.meta so that CommonJS can still use the functionality.
//
Expand Down Expand Up @@ -33,18 +34,40 @@ let currentMockVersion = 0;
// assert(namespace1 === namespace2);
// ```

/** @type {string} */
let mainImportURL;
/**
* @param param0 message from the application context
*/
function onPreloadPortMessage({
mockVersion, resolved, exports
}) {
currentMockVersion = mockVersion;
mockedModuleExports.set(resolved, exports);
}

/** @type {URL['href']} */
let mainImportURL
/** @type {MessagePort} */
let preloadPort;
export async function initialize(data) {
mainImportURL = data.mainImportURL;
data.port.on('message', ({ mockVersion, resolved, exports }) => {
currentMockVersion = mockVersion;
mockedModuleExports.set(resolved, exports);
});
({ mainImportURL, port: preloadPort } = data);

data.port.on('message', onPreloadPortMessage);
}

/**
* FIXME: this is a hack to workaround loaders being
* single threaded for now, just ensures that the MessagePort drains
*/
function doDrainPort() {
let msg;
while (msg = receiveMessageOnPort(preloadPort)) {
onPreloadPortMessage(msg.message);
}
}

// Rewrites node: loading to mock-facade: so that it can be intercepted
export async function resolve(specifier, context, defaultResolve) {
doDrainPort();
const def = await defaultResolve(specifier, context);
if (context.parentURL?.startsWith('mock-facade:')) {
// Do nothing, let it get the "real" module
Expand All @@ -61,17 +84,17 @@ export async function resolve(specifier, context, defaultResolve) {
}

export async function load(url, context, defaultLoad) {
doDrainPort();
/**
* Mocked fake module, not going to be handled in default way so it
* generates the source text, then short circuits
*/
if (url.startsWith('mock-facade:')) {
let [_proto, _version, encodedTargetURL] = url.split(':');
let source = generateModule(encodedTargetURL);
const encodedTargetURL = url.slice(url.lastIndexOf(':') + 1);
return {
shortCircuit: true,
source,
format: 'module'
source: generateModule(encodedTargetURL),
format: 'module',
};
}
return defaultLoad(url, context);
Expand All @@ -89,19 +112,19 @@ function generateModule(encodedTargetURL) {
let body = [
`import { mockedModules } from ${JSON.stringify(mainImportURL)};`,
'export {};',
'let mapping = {__proto__: null};'
'let mapping = {__proto__: null};',
`const mock = mockedModules.get(${JSON.stringify(encodedTargetURL)});`,
];
for (const [i, name] of Object.entries(exports)) {
let key = JSON.stringify(name);
body.push(`import.meta.mock = mockedModules.get(${JSON.stringify(encodedTargetURL)});`);
body.push(`var _${i} = import.meta.mock.namespace[${key}];`);
body.push(`var _${i} = mock.namespace[${key}];`);
body.push(`Object.defineProperty(mapping, ${key}, { enumerable: true, set(v) {_${i} = v;}, get() {return _${i};} });`);
body.push(`export {_${i} as ${name}};`);
}
body.push(`import.meta.mock.listeners.push(${
body.push(`mock.listeners.push(${
() => {
for (var k in mapping) {
mapping[k] = import.meta.mock.namespace[k];
mapping[k] = mock.namespace[k];
}
}
});`);
Expand Down
7 changes: 3 additions & 4 deletions test/fixtures/es-module-loaders/mock.mjs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import * as fixtures from '../../common/fixtures.mjs';
import { register } from 'node:module';
import { MessageChannel } from 'node:worker_threads';


const { port1, port2 } = new MessageChannel();

register(fixtures.fileURL('es-module-loaders/mock-loader.mjs'), {
register('./mock-loader.mjs', import.meta.url, {
data: {
port: port2,
mainImportURL: import.meta.url,
Expand Down Expand Up @@ -53,12 +52,12 @@ export function mock(resolved, replacementProperties) {
/* noop */
}
}
}
},
});
}
mockedModules.set(encodeURIComponent(resolved), {
namespace,
listeners
listeners,
});
mockVersion++;
// Inform the loader that the `resolved` URL should now use the specific
Expand Down

0 comments on commit d1bedb7

Please sign in to comment.