@swissquote/eslint-plugin-swissquote
Version:
- Provide a style guide for your JavaScript - Warns on common mistakes in JavaScript - Works with EcmaScript 2015+
150 lines (111 loc) • 3.29 kB
JavaScript
/**
* This is a simplifed version of synckit
* https://www.npmjs.com/package/synckit
* All credit goes to the original authors
*/
;
const path = require("node:path");
const node_url = require("node:url");
const node_worker_threads = require("node:worker_threads");
const INT32_BYTES = 4;
let syncFnCache;
function extractProperties(object) {
if (object && typeof object === "object") {
const properties = {};
for (const key in object) {
properties[key] = object[key];
}
return properties;
}
}
function createSyncFn(workerPath, timeoutOrOptions) {
if (!syncFnCache) {
syncFnCache = new Map();
}
const cachedSyncFn = syncFnCache.get(workerPath);
if (cachedSyncFn) {
return cachedSyncFn;
}
if (!path.isAbsolute(workerPath)) {
throw new Error("`workerPath` must be absolute");
}
const syncFn = startWorkerThread(
workerPath,
/* istanbul ignore next */
typeof timeoutOrOptions === "number"
? { timeout: timeoutOrOptions }
: timeoutOrOptions
);
syncFnCache.set(workerPath, syncFn);
return syncFn;
}
let sharedBuffer;
let sharedBufferView;
function startWorkerThread(
workerPath,
{ timeout, execArgv = [], transferList = [] } = {}
) {
const { port1: mainPort, port2: workerPort } =
new node_worker_threads.MessageChannel();
const workerPathUrl = node_url.pathToFileURL(workerPath);
if (!sharedBuffer) {
sharedBuffer = new SharedArrayBuffer(INT32_BYTES);
}
if (!sharedBufferView) {
sharedBufferView = new Int32Array(sharedBuffer, 0, 1);
}
const worker = new node_worker_threads.Worker(workerPathUrl, {
workerData: { sharedBuffer, workerPort },
transferList: [workerPort, ...transferList],
execArgv,
});
let nextID = 0;
const syncFn = (...args) => {
const id = nextID++;
const msg = { id, args };
worker.postMessage(msg);
const status = Atomics.wait(sharedBufferView, 0, 0, timeout);
Atomics.store(sharedBufferView, 0, 0);
if (!["ok", "not-equal"].includes(status)) {
throw new Error("Internal error: Atomics.wait() failed: " + status);
}
const {
id: id2,
result,
error,
properties,
} = node_worker_threads.receiveMessageOnPort(mainPort).message;
if (id !== id2) {
throw new Error(`Internal error: Expected id ${id} but got id ${id2}`);
}
if (error) {
throw Object.assign(error, properties);
}
return result;
};
worker.unref();
return syncFn;
}
function runAsWorker(fn) {
if (!node_worker_threads.workerData) {
return;
}
const { workerPort, sharedBuffer } = node_worker_threads.workerData;
const sharedBufferView = new Int32Array(sharedBuffer, 0, 1);
node_worker_threads.parentPort.on("message", ({ id, args }) => {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
(async () => {
let msg;
try {
msg = { id, result: await fn(...args) };
} catch (error) {
msg = { id, error, properties: extractProperties(error) };
}
workerPort.postMessage(msg);
Atomics.add(sharedBufferView, 0, 1);
Atomics.notify(sharedBufferView, 0);
})();
});
}
exports.createSyncFn = createSyncFn;
exports.runAsWorker = runAsWorker;