UNPKG

@ts-bridge/cli

Version:

Bridge the gap between ES modules and CommonJS modules with an easy-to-use alternative to `tsc`.

102 lines (101 loc) 3.67 kB
import assert from 'assert'; import { availableParallelism } from 'os'; /** * Check if a value is an object (and not an array or `null`). * * @param value - The value to check. * @returns `true` if the value is an object, `false` otherwise. */ export function isObject(value) { return value !== null && typeof value === 'object' && !Array.isArray(value); } /** * Convert a string value to a safe identifier name. This basically removes any * characters that can be invalid for identifiers. * * @param value - The value to convert to camelCase. * @returns The identifier name. */ export function getIdentifierName(value) { const sanitisedValue = value.replace(/[\W0-9]/gu, ''); if (sanitisedValue.length === 0) { return '_'; } return sanitisedValue; } /** * Get the defined values from an array, removing all `undefined` values. If the * array itself is `undefined`, an empty array is returned. * * @param array - The array to get the defined values from. * @returns The array with all `undefined` values removed. */ export function getDefinedArray(array) { if (!array) { return []; } return array.filter((value) => value !== undefined); } /** * Run a function in parallel for each value in the graph. This means that the * function is run for each value in the graph, but the order in which the * values are processed is determined by the topological sort of the graph. * Values that are not dependent on each other, or that are dependent on each * other, but the dependencies have been resolved, are processed in parallel. * * @param sortedValues - The sorted values from the graph. * @param graph - The dependency graph. * @param fn - The function to run for each value. This function is expected to * spawn a new process or thread for each value, to properly parallelise the * work. * @param maxConcurrency - The maximum number of concurrent functions to run. */ export async function parallelise(sortedValues, graph, fn, maxConcurrency = availableParallelism()) { const resolved = new Set(); const queue = [...sortedValues]; const running = new Map(); /** * Check if a value is ready to be processed. A value is ready if all its * dependencies have been resolved. * * @param value - The value to check. * @returns Whether the value is ready to be processed. */ function isReady(value) { const dependencies = graph.get(value) ?? []; return dependencies.every((dep) => resolved.has(dep)); } /** * Run a task. This will call the provided function and add the value to the * resolved set when the function has completed. * * @param value - The value to run the function for. * @returns A promise that resolves when the function has completed. */ async function run(value) { try { await fn(value); resolved.add(value); } finally { running.delete(value); } } while (queue.length > 0 || running.size > 0) { while (running.size < maxConcurrency && queue.length > 0) { const nextTaskIndex = queue.findIndex(isReady); if (nextTaskIndex === -1) { break; } const nextTask = queue.splice(nextTaskIndex, 1)[0]; assert(nextTask); const taskPromise = run(nextTask); running.set(nextTask, taskPromise); } // Wait for any running task to complete. /* istanbul ignore else -- @preserve */ if (running.size > 0) { await Promise.race(running.values()); } } }