securityos/node_modules/synckit/lib/index.js

259 lines
9.5 KiB
JavaScript
Raw Normal View History

2024-09-06 15:32:35 +00:00
import { __awaiter } from "tslib";
import fs from 'node:fs';
import { createRequire } from 'node:module';
import path from 'node:path';
import { pathToFileURL } from 'node:url';
import { MessageChannel, Worker, receiveMessageOnPort, workerData, parentPort, } from 'node:worker_threads';
import { findUp, tryExtensions } from '@pkgr/utils';
export * from './types.js';
export const TsRunner = {
TsNode: 'ts-node',
EsbuildRegister: 'esbuild-register',
EsbuildRunner: 'esbuild-runner',
SWC: 'swc',
TSX: 'tsx',
};
const { SYNCKIT_BUFFER_SIZE, SYNCKIT_TIMEOUT, SYNCKIT_EXEC_ARGV, SYNCKIT_TS_RUNNER, NODE_OPTIONS, } = process.env;
export const DEFAULT_BUFFER_SIZE = SYNCKIT_BUFFER_SIZE
? +SYNCKIT_BUFFER_SIZE
: undefined;
export const DEFAULT_TIMEOUT = SYNCKIT_TIMEOUT ? +SYNCKIT_TIMEOUT : undefined;
export const DEFAULT_WORKER_BUFFER_SIZE = DEFAULT_BUFFER_SIZE || 1024;
export const DEFAULT_EXEC_ARGV = (SYNCKIT_EXEC_ARGV === null || SYNCKIT_EXEC_ARGV === void 0 ? void 0 : SYNCKIT_EXEC_ARGV.split(',')) || [];
export const DEFAULT_TS_RUNNER = (SYNCKIT_TS_RUNNER ||
TsRunner.TsNode);
export const MTS_SUPPORTED_NODE_VERSION = 16;
const syncFnCache = new Map();
export function extractProperties(object) {
if (object && typeof object === 'object') {
const properties = {};
for (const key in object) {
properties[key] = object[key];
}
return properties;
}
}
export function createSyncFn(workerPath, bufferSizeOrOptions, timeout) {
if (!path.isAbsolute(workerPath)) {
throw new Error('`workerPath` must be absolute');
}
const cachedSyncFn = syncFnCache.get(workerPath);
if (cachedSyncFn) {
return cachedSyncFn;
}
const syncFn = startWorkerThread(workerPath, typeof bufferSizeOrOptions === 'number'
? { bufferSize: bufferSizeOrOptions, timeout }
: bufferSizeOrOptions);
syncFnCache.set(workerPath, syncFn);
return syncFn;
}
const cjsRequire = typeof require === 'undefined'
? createRequire(import.meta.url)
: require;
const dataUrl = (code) => new URL(`data:text/javascript,${encodeURIComponent(code)}`);
export const isFile = (path) => {
try {
return fs.statSync(path).isFile();
}
catch (_a) {
return false;
}
};
const setupTsRunner = (workerPath, { execArgv, tsRunner }) => {
let ext = path.extname(workerPath);
if (!/[/\\]node_modules[/\\]/.test(workerPath) &&
(!ext || /^\.[cm]?js$/.test(ext))) {
const workPathWithoutExt = ext
? workerPath.slice(0, -ext.length)
: workerPath;
let extensions;
switch (ext) {
case '.cjs':
extensions = ['.cts', '.cjs'];
break;
case '.mjs':
extensions = ['.mts', '.mjs'];
break;
default:
extensions = ['.ts', '.js'];
break;
}
const found = tryExtensions(workPathWithoutExt, extensions);
let differentExt;
if (found && (!ext || (differentExt = found !== workPathWithoutExt))) {
workerPath = found;
if (differentExt) {
ext = path.extname(workerPath);
}
}
}
const isTs = /\.[cm]?ts$/.test(workerPath);
let tsUseEsm = workerPath.endsWith('.mts');
if (isTs) {
if (!tsUseEsm) {
const pkg = findUp(workerPath);
if (pkg) {
tsUseEsm =
cjsRequire(pkg).type ===
'module';
}
}
switch (tsRunner) {
case TsRunner.TsNode: {
if (tsUseEsm) {
if (!execArgv.includes('--loader')) {
execArgv = ['--loader', `${TsRunner.TsNode}/esm`, ...execArgv];
}
}
else if (!execArgv.includes('-r')) {
execArgv = ['-r', `${TsRunner.TsNode}/register`, ...execArgv];
}
break;
}
case TsRunner.EsbuildRegister: {
if (!execArgv.includes('-r')) {
execArgv = ['-r', TsRunner.EsbuildRegister, ...execArgv];
}
break;
}
case TsRunner.EsbuildRunner: {
if (!execArgv.includes('-r')) {
execArgv = ['-r', `${TsRunner.EsbuildRunner}/register`, ...execArgv];
}
break;
}
case TsRunner.SWC: {
if (!execArgv.includes('-r')) {
execArgv = ['-r', `@${TsRunner.SWC}-node/register`, ...execArgv];
}
break;
}
case TsRunner.TSX: {
if (!execArgv.includes('--loader')) {
execArgv = ['--loader', TsRunner.TSX, ...execArgv];
}
break;
}
default: {
throw new Error(`Unknown ts runner: ${String(tsRunner)}`);
}
}
}
if (process.versions.pnp) {
const nodeOptions = NODE_OPTIONS === null || NODE_OPTIONS === void 0 ? void 0 : NODE_OPTIONS.split(/\s+/);
let pnpApiPath;
try {
pnpApiPath = cjsRequire.resolve('pnpapi');
}
catch (_a) { }
if (pnpApiPath &&
!(nodeOptions === null || nodeOptions === void 0 ? void 0 : nodeOptions.some((option, index) => ['-r', '--require'].includes(option) &&
pnpApiPath === cjsRequire.resolve(nodeOptions[index + 1]))) &&
!execArgv.includes(pnpApiPath)) {
execArgv = ['-r', pnpApiPath, ...execArgv];
const pnpLoaderPath = path.resolve(pnpApiPath, '../.pnp.loader.mjs');
if (isFile(pnpLoaderPath)) {
const experimentalLoader = pathToFileURL(pnpLoaderPath).toString();
execArgv = ['--experimental-loader', experimentalLoader, ...execArgv];
}
}
}
return {
ext,
isTs,
tsUseEsm,
workerPath,
execArgv,
};
};
function startWorkerThread(workerPath, { bufferSize = DEFAULT_WORKER_BUFFER_SIZE, timeout = DEFAULT_TIMEOUT, execArgv = DEFAULT_EXEC_ARGV, tsRunner = DEFAULT_TS_RUNNER, } = {}) {
const { port1: mainPort, port2: workerPort } = new MessageChannel();
const { isTs, ext, tsUseEsm, workerPath: finalWorkerPath, execArgv: finalExecArgv, } = setupTsRunner(workerPath, { execArgv, tsRunner });
const workerPathUrl = pathToFileURL(finalWorkerPath);
if (/\.[cm]ts$/.test(finalWorkerPath)) {
const isTsxSupported = !tsUseEsm ||
Number.parseFloat(process.versions.node) >= MTS_SUPPORTED_NODE_VERSION;
if ([
TsRunner.EsbuildRegister,
TsRunner.EsbuildRunner,
TsRunner.SWC,
...(isTsxSupported ? [] : [TsRunner.TSX]),
].includes(tsRunner)) {
throw new Error(`${tsRunner} is not supported for ${ext} files yet` +
(isTsxSupported
? ', you can try [tsx](https://github.com/esbuild-kit/tsx) instead'
: ''));
}
}
const useEval = isTs && !tsUseEsm;
const worker = new Worker(tsUseEsm && tsRunner === TsRunner.TsNode
? dataUrl(`import '${String(workerPathUrl)}'`)
: useEval
? `require('${finalWorkerPath.replace(/\\/g, '\\\\')}')`
: workerPathUrl, {
eval: useEval,
workerData: { workerPort },
transferList: [workerPort],
execArgv: finalExecArgv,
});
let nextID = 0;
const syncFn = (...args) => {
const id = nextID++;
const sharedBuffer = new SharedArrayBuffer(bufferSize);
const sharedBufferView = new Int32Array(sharedBuffer);
const msg = { sharedBuffer, id, args };
worker.postMessage(msg);
const status = Atomics.wait(sharedBufferView, 0, 0, timeout);
if (!['ok', 'not-equal'].includes(status)) {
throw new Error('Internal error: Atomics.wait() failed: ' + status);
}
const { id: id2, result, error, properties, } = 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;
}
export function runAsWorker(fn) {
if (!workerData) {
return;
}
const { workerPort } = workerData;
try {
parentPort.on('message', ({ sharedBuffer, id, args }) => {
;
(() => __awaiter(this, void 0, void 0, function* () {
const sharedBufferView = new Int32Array(sharedBuffer);
let msg;
try {
msg = { id, result: yield fn(...args) };
}
catch (error) {
msg = { id, error, properties: extractProperties(error) };
}
workerPort.postMessage(msg);
Atomics.add(sharedBufferView, 0, 1);
Atomics.notify(sharedBufferView, 0);
}))();
});
}
catch (error) {
parentPort.on('message', ({ sharedBuffer, id }) => {
const sharedBufferView = new Int32Array(sharedBuffer);
workerPort.postMessage({
id,
error,
properties: extractProperties(error),
});
Atomics.add(sharedBufferView, 0, 1);
Atomics.notify(sharedBufferView, 0);
});
}
}
//# sourceMappingURL=index.js.map