UNPKG

madrun

Version:

CLI tool to run multiple npm-scripts in a madly comfortable way

207 lines (151 loc) 4.49 kB
import {pathToFileURL} from 'node:url'; import keys from 'all-object-keys'; import {jessy} from 'jessy'; import wildcard from './wildcard.js'; import check from './check.js'; import supported from '../supported.json' with { type: 'json', }; const maybeArray = (a) => isArray(a) ? a : [a]; const isStr = (a) => typeof a === 'string'; const {isArray} = Array; async function getFindUp() { if (globalThis.MADRUN_FINDUP) return globalThis.MADRUN_FINDUP; const {findUpSync} = await import('find-up'); return findUpSync; } async function getScripts() { const findUp = await getFindUp(); const path = findUp(supported); if (!path) throw Error('.madrun.js is missing!'); return (await import(pathToFileURL(path))).default; } export const cutEnv = async (names, opts = '', env, scripts) => { names = maybeArray(names); scripts = scripts || await getScripts(); const isParallel = false; const commands = await runNames(names, opts, scripts, { env, cutEnv: true, isParallel, }); return joinByType(commands, { isParallel, }); }; export const run = async (name, opts = '', env, scripts) => { scripts = scripts || await getScripts(); const problems = check(scripts); if (problems) return problems; return await series(name, opts, env, scripts); }; export async function series(names, opts = '', env, scripts) { names = maybeArray(names); scripts = scripts || await getScripts(); const isParallel = false; const commands = await runNames(names, opts, scripts, { env, isParallel, }); return joinByType(commands, { isParallel, }); } export const parallel = async (names, opts = '', env, scripts) => { scripts = scripts || await getScripts(); names = maybeArray(names); const isParallel = true; const commands = await runNames(names, opts, scripts, { env, isParallel, }); return joinByType(commands, { isParallel, }); }; function joinByType(commands, {isParallel}) { const type = isParallel ? ' & ' : ' && '; return commands.join(type); } async function runNames(names, opts, scripts, {env, isParallel, cutEnv}) { const cmds = []; for (const name of names) { const cmd = await parse(name, { scripts, opts, env, isParallel, cutEnv, }); cmds.push(cmd); } return cmds; } const addOpts = (name, opts) => { if (!opts) return name; return `${name} ${opts}`; }; const addEnv = (cmd, env) => { const entries = env && Object.entries(env); if (!env || !entries.length) return cmd; const line = []; for (const [key, value] of entries) { line.push(`${key}=${value}`); } const envLine = line.join(' '); return `${envLine} ${cmd}`; }; const parse = async (name, {scripts, opts, env, isParallel, cutEnv}) => { const result = []; const all = keys(scripts); for (const key of all) { if (!wildcard(`^${name}$`).test(key)) continue; const fn = jessy(key, scripts); const {line, lineEnv} = await runScriptFn(fn); const cmd = addOpts(line, opts); const cmdEnv = addEnv(cmd, { ...cutEnv ? {} : lineEnv, ...env, }); const processed = await addPrePost(cmdEnv, key, scripts); result.push(processed); } if (!result.length) throw Error(`one of scripts not found: ${name}`); return joinByType(result, { isParallel, }); }; async function runScriptFn(fn) { const result = await fn(); if (!isArray(result)) return { line: result, lineEnv: {}, }; const [a, b] = result; if (isStr(a)) return { line: a, lineEnv: b, }; return { line: b, lineEnv: a, }; } async function addPrePost(cmd, key, scripts) { const pre = jessy(`pre${key}`, scripts); const post = jessy(`post${key}`, scripts); if (pre) cmd = `${await pre()} && ${cmd}`; if (post) cmd = `${cmd} && ${await post()}`; return cmd; }