UNPKG

@tapjs/run

Version:

Command-line interface for the node-tap runner

158 lines (155 loc) 5.74 kB
// load core so that the Test class is ready import '@tapjs/core'; import { defaultPlugins } from '@tapjs/test'; import chalk from 'chalk'; import { lstat } from 'node:fs/promises'; import { resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; import { resolveImport } from 'resolve-import'; import { build } from './build.js'; import { getInstallSet } from './get-install-set.js'; import { install, uninstall } from './npm.js'; const exists = (f) => lstat(f).then(() => true, () => false); const detectGlobalInstall = async (args, project) => { // find the tap that will be loaded from the project root const activeRunner = String(await resolveImport('@tapjs/run', import.meta.url)); const projectRunner = String(await resolveImport('tap', resolve(project, 'x')) .then(projectTap => resolveImport('@tapjs/run', projectTap)) .catch(() => resolveImport('@tapjs/run', project)) .catch(() => activeRunner)); if (activeRunner !== projectRunner) { const f = fileURLToPath(activeRunner).split('node_modules'); f.pop(); const myNM = f.join('node_modules'); console.error(`${chalk.bold.red('global/local mixup!')} The tap plugin command must be run by the ${chalk.yellow('locally installed')} tap executable, and this appears to be running in a global install location at ${chalk.yellow(myNM)} This will likely fail. Try: ${chalk.green(`npm exec tap plugin ${args .map(a => JSON.stringify(a)) .join(' ')}`)} `); } }; export const plugin = async (args, config, quiet = false) => { await detectGlobalInstall(args, config.projectRoot); switch (args[0]) { case 'add': return add(args.slice(1), config, quiet); case 'rm': case 'remove': return rm(args.slice(1), config); case 'list': case 'ls': return list(args.slice(1), config); case undefined: await list(args, config); return console.error(`(use 'tap plugin add ...' to add plugins, or ` + `'tap plugin rm ...' to remove them)`); default: throw new Error(`Unknown plugin command: ${args[0]}`); } }; const add = async (args, config, quiet = false) => { const error = quiet ? () => { } : console.error; const log = quiet ? () => { } : console.log; if (!args.length) throw new Error('no plugin name provided'); const { added, needInstall, needCleanup } = await getInstallSet(args, config); if (!added.size) { log('nothing to do, all plugins already installed'); return; } error('adding plugins:', [...added]); // roll back if it fails! let success = false; let installed = false; try { // install anything that needs to be installed if (needInstall.size) { const ni = [...needInstall]; error('installing:', ni); await install(ni, config); installed = true; } // ok, that succeeded, update the config /* c8 ignore start */ const pc = config.get('plugin') || []; /* c8 ignore stop */ config.values.plugin = [...pc]; // now rebuild await build([], config); // save the config change await config.editConfigFile({ plugin: [...pc] }, config.configFile); log('successfully added plugin(s):'); log([...added].join('\n')); success = true; } catch (er) { if (er instanceof Error) { error(chalk.red(er.message)); } } finally { if (!success) { process.exitCode = 1; const what = needInstall.size && !installed ? 'install' : 'build'; error(chalk.red(`${what} failed`)); if (installed && needCleanup.size) { error('attempting to clean up added packages'); await uninstall([...needCleanup], config).catch(() => error(chalk.red('uninstall failed'))); } } } }; const rm = async (args, config) => { /* c8 ignore start */ const pc = config.get('plugin') || []; /* c8 ignore stop */ const pl = config.pluginList; const removed = new Set(); const needRemove = new Set(); for (const plugin of args) { // not present, nothing to do if (!pl.includes(plugin)) continue; removed.add(plugin); // possibly a default if (defaultPlugins.includes(plugin)) { pc.push(`!${plugin}`); continue; } if (pc.includes(plugin)) { pc.splice(pc.indexOf(plugin), 1); } // if it's an installed plugin, remove it if (!(await exists(plugin)) && (await exists(resolve(config.projectRoot, '.tap/plugins/node_modules', plugin)))) { needRemove.add(plugin); } } if (!removed.size) { console.log('nothing to do, no specified plugins present'); return; } config.values.plugin = [...pc]; // now rebuild await build([], config); // save the config change await config.editConfigFile({ plugin: [...pc] }, config.configFile); // if not present, do nothing and exit // if a default plugin, then add the !plugin to the config // else, rm plugin from config // if not a file on disk, and exists in nm, echo npm rm command // rebuild console.log('successfully removed plugin(s):'); console.log([...removed].join('\n')); if (needRemove.size) { await uninstall([...needRemove], config); } }; const list = async (_, config) => { console.log(config.pluginList.join('\n')); }; //# sourceMappingURL=plugin.js.map