import { AnyObject, isFunction } from 'jsc-utils/type'; import { isFolder } from './file-system'; interface ProcessEnv extends NodeJS.ProcessEnv { PATH: string; } type Uncatch = () => void; /** * 将指定路径合并到 PATH 环境变量里 * @param {string} path * @param {NodeJS.ProcessEnv} env * @returns {ProcessEnv} */ export const mergeProcessEnvPath = (path: string, env?: NodeJS.ProcessEnv): ProcessEnv => { const isWindows = process.platform === 'win32'; const spliter = isWindows ? ';' : ':'; let finalEnv = env || {}; finalEnv = Object.assign({}, process.env, finalEnv); const inheritPath = finalEnv.PATH || finalEnv.Path || '.'; if (isFolder(path)) { const pathList = inheritPath.split(spliter); if (pathList[pathList.length - 1] === '.') { pathList.splice(-1, 0, path); } else { pathList.push(path, '.'); } finalEnv.PATH = pathList.join(spliter); } else { finalEnv.PATH = inheritPath; } if (isWindows) finalEnv.Path = finalEnv.PATH; return finalEnv as ProcessEnv; }; /** * @ref https://github.com/commitizen/cz-cli/pull/736/files * @ref https://github.com/SBoudrias/Inquirer.js/issues/405 * 捕获当前进程的 SIGINT 键盘事件,用于解决 inquirer 监听了 readline 相关事件, * 但是没有很好的处理 ctrl+c 这种情况,导致当前进程无法捕获该 SIGINT 事件 * @param {() => void} catcher * @returns {Uncatch} */ export const catchProcessSigintSignal = (catcher?: () => void): Uncatch => { const listener = (key: string) => { if (key.toString() === '\u0003') { if (isFunction(catcher)) catcher(); else process.exit(130); } }; process.stdin.on('data', listener); return () => { process.off('data', listener); }; }; /** * 捕获进程未捕获的异常 * @param {(err: Error) => void} catcher * @returns {Uncatch} */ export const catchProcessException = (catcher?: (err: Error) => void): Uncatch => { const events = ['uncaughtException', 'uncaughtExceptionMonitor']; const listener = (err: Error) => { if (isFunction(catcher)) { catcher(err); } else { console.error(err); process.exit(1); } }; events.forEach((ev) => { process.on(ev, listener); }); return () => { events.forEach((ev) => { process.off(ev, listener); }); }; }; /** * 捕获进程未捕获的拒绝 * @param {(err: Error) => void} catcher * @returns {Uncatch} */ export const catchProcessRejection = (catcher?: (err: Error) => void): Uncatch => { const listener = (reason: AnyObject | null | undefined, promise: Promise) => { const message = reason?.toString() || `unhandledRejection: ${promise.toString()}`; const err = new Error(message); if (isFunction(catcher)) { catcher(err); } else { console.error(err); process.exit(1); } }; process.on('unhandledRejection', listener); return () => { process.off('unhandledRejection', listener); }; };