Nicolò Ribaudo 885e1e02f5
Expose @babel/eslint-parser/experimental-worker (#13398)
* Expose `@babel/eslint-parser/experimental-worker`

* Fix `@babel/runtime` build on Windows
2021-08-03 23:23:32 +02:00

106 lines
2.8 KiB
JavaScript

const path = require("path");
const ACTIONS = {
GET_VERSION: "GET_VERSION",
GET_TYPES_INFO: "GET_TYPES_INFO",
GET_VISITOR_KEYS: "GET_VISITOR_KEYS",
GET_TOKEN_LABELS: "GET_TOKEN_LABELS",
MAYBE_PARSE: "MAYBE_PARSE",
MAYBE_PARSE_SYNC: "MAYBE_PARSE_SYNC",
};
class Client {
#send;
constructor(send) {
this.#send = send;
}
#vCache;
getVersion() {
return (this.#vCache ??= this.#send(ACTIONS.GET_VERSION, undefined));
}
#tiCache;
getTypesInfo() {
return (this.#tiCache ??= this.#send(ACTIONS.GET_TYPES_INFO, undefined));
}
#vkCache;
getVisitorKeys() {
return (this.#vkCache ??= this.#send(ACTIONS.GET_VISITOR_KEYS, undefined));
}
#tlCache;
getTokLabels() {
return (this.#tlCache ??= this.#send(ACTIONS.GET_TOKEN_LABELS, undefined));
}
maybeParse(code, options) {
return this.#send(ACTIONS.MAYBE_PARSE, { code, options });
}
}
// We need to run Babel in a worker for two reasons:
// 1. ESLint workers must be CJS files, and this is a problem
// since Babel 8+ uses native ESM
// 2. ESLint parsers must run synchronously, but many steps
// of Babel's config loading (which is done for each file)
// can be asynchronous
// If ESLint starts supporting async parsers, we can move
// everything back to the main thread.
exports.WorkerClient = class WorkerClient extends Client {
static #worker_threads_cache;
static get #worker_threads() {
return (WorkerClient.#worker_threads_cache ??= require("worker_threads"));
}
#worker = new WorkerClient.#worker_threads.Worker(
path.resolve(__dirname, "../lib/worker/index.cjs"),
{ env: WorkerClient.#worker_threads.SHARE_ENV },
);
#signal = new Int32Array(new SharedArrayBuffer(4));
constructor() {
super((action, payload) => {
this.#signal[0] = 0;
const subChannel = new WorkerClient.#worker_threads.MessageChannel();
this.#worker.postMessage(
{ signal: this.#signal, port: subChannel.port1, action, payload },
[subChannel.port1],
);
Atomics.wait(this.#signal, 0, 0);
const { message } = WorkerClient.#worker_threads.receiveMessageOnPort(
subChannel.port2,
);
if (message.error) throw Object.assign(message.error, message.errorData);
else return message.result;
});
// The worker will never exit by itself. Prevent it from keeping
// the main process alive.
this.#worker.unref();
}
};
if (!process.env.BABEL_8_BREAKING) {
exports.LocalClient = class LocalClient extends Client {
static #handleMessage;
constructor() {
LocalClient.#handleMessage ??= require("./worker/handle-message.cjs");
super((action, payload) => {
return LocalClient.#handleMessage(
action === ACTIONS.MAYBE_PARSE ? ACTIONS.MAYBE_PARSE_SYNC : action,
payload,
);
});
}
};
}