UNPKG

daizong

Version:

`package.json` script runner for ES Modules

192 lines (190 loc) 6.25 kB
#!/usr/bin/env node import chalk from 'chalk'; import { inspect } from 'util'; import pMap from 'p-map'; import { readFile } from 'fs/promises'; import * as np from 'path'; import { fileURLToPath } from 'url'; import spawn from './spawn.js'; import { loadConfig } from './config.js'; import getTask from './getTask.js'; import { runBTCommands } from './btCmd.js'; import { parseArgs, Command } from './argsParser.js'; import { envPreset } from './envPreset.js'; import * as lib from './lib.js'; function log(s) { console.log(s); } function logError(s) { return log(chalk.red(s)); } const cliArgs = process.argv.slice(2); if (!cliArgs.length) { logError('Missing task path.\nTry `daizong --help` for help.'); process.exit(1); } const cmd = parseArgs(cliArgs); if (cmd.error) { logError(cmd.error); process.exit(1); } if (cmd.command === Command.help) { log(` Usage $ daizong [options] <task-path> [task arguments] Options --config Explicitly specify the config file, \`--config config.js\` --verbose Print verbose information during execution --private Allow private tasks to be called from CLI --version, -v Print version information Examples $ daizong --verbose test-browser --script-arg1 --script-arg2 `); process.exit(0); } if (cmd.command === Command.version) { const dirname = np.dirname(fileURLToPath(import.meta.url)); const pkg = JSON.parse(await readFile(np.join(dirname, '../package.json'), 'utf8')); log(pkg.version); process.exit(0); } const verboseLog = cmd.verbose ? (s) => log(`[DEBUG] ${s}`) : null; function processError(err) { if (err instanceof Error) { logError(err.message); verboseLog?.(err.stack); } else { logError(`${err}`); } process.exit(1); } async function runString(ctx, value, args, workingDir) { if (value.startsWith('#')) { return runTaskByName(ctx, value, workingDir); } const argsText = args ? ` ${chalk.cyan(lib.getArgsDisplayString(args))}` : ''; const workingDirText = workingDir ? ` [wd: ${workingDir}]` : ''; log(`>> ${chalk.yellow(value)}${argsText}${workingDirText}`); return spawn(value, args ?? [], ctx.inheritedEnv, verboseLog, workingDir); } async function runTask(ctx, task, args, taskName, workingDir) { const runValue = task.run; if (task.workingDir) { workingDir = task.workingDir; } if (runValue === undefined) { throw new Error(`No \`run\` field found in task "${JSON.stringify(task)}"`); } const { settings } = ctx.config; const { env: taskEnv, envGroups, before, after } = task; let envGroupNames = []; if (envGroups !== undefined) { envGroupNames = typeof envGroups === 'string' ? [envGroups] : envGroups; } const groupEnv = {}; for (const groupName of envGroupNames) { if (typeof groupName !== 'string') { throw new Error(`Env group names must be strings, got ${JSON.stringify(groupName)}.`); } if (groupName) { let vars = settings.envGroups[groupName]; if (!vars) { const preset = envPreset(groupName); if (preset) { vars = preset; } if (!vars) { throw new Error(`Env group "${groupName}" is not defined`); } } Object.assign(groupEnv, vars); } } const env = { ...settings.defaultEnv, ...ctx.inheritedEnv, ...groupEnv, ...taskEnv, }; const hasBeforeOrAfter = !!(before || after); if (before) { log(`>> #${taskName} [before]`); await runUnknown(ctx, before, null, undefined, workingDir); } if (hasBeforeOrAfter) { log(`>> #${taskName} [run]`); } try { await runUnknown({ ...ctx, inheritedEnv: env }, runValue, task, args, workingDir); } catch (err) { if (!task.ignoreError) { throw err; } } if (after) { log(`>> #${taskName} [after]`); await runUnknown(ctx, after, null, undefined, workingDir); } } async function runTaskByName(ctx, nameWithPrefix, workingDir) { const name = nameWithPrefix.substring(1); if (!name) { throw new Error('"#" is not a valid task name'); } const task = getTask(ctx.config, name, true); log(`>> ${nameWithPrefix}`); return runTask(ctx, task, undefined, name, workingDir); } async function runUnknown(ctx, value, task, args, workingDir) { if (!value) { throw new Error(`Empty run field ${JSON.stringify(value)}`); } if (typeof value === 'string') { return runString(ctx, value, args, workingDir); } if (Array.isArray(value)) { await pMap(value, (childVal) => runUnknown(ctx, childVal, null, undefined, workingDir), { concurrency: task?.parallel ? undefined : 1, stopOnError: task?.continueOnChildError !== undefined ? !task.continueOnChildError : true, }); return Promise.resolve(); } if (typeof value === 'object') { return runBTCommands(value, workingDir); } throw new Error(`Invalid run field ${JSON.stringify(value)}`); } (async () => { try { verboseLog?.(`CWD: ${process.cwd()}`); verboseLog?.(`Loading config "${cmd.configFile}"`); const config = await loadConfig(cmd.configFile); const { settings } = config; verboseLog?.(`Loaded config file at "${np.resolve(config.path)}" ${JSON.stringify(config)} `); if (settings.defaultEnv) { log(`Loaded default environment variables: ${inspect(settings.defaultEnv, { compact: false, sorted: true, })}`); } const task = getTask(config, cmd.taskName, cmd.private ?? false); log(`>> #${cmd.taskName}`); const ctx = { config, inheritedEnv: {}, }; await runTask(ctx, task, cmd.taskArgs.length ? cmd.taskArgs : undefined, cmd.taskName, undefined); } catch (err) { processError(err); } })(); //# sourceMappingURL=main.js.map