diff --git a/build.config.ts b/build.config.ts index 452ddfc4..3d288133 100644 --- a/build.config.ts +++ b/build.config.ts @@ -3,7 +3,10 @@ import { defineBuildConfig } from 'unbuild' import { globSync } from 'tinyglobby' export default defineBuildConfig({ - entries: globSync(['src/commands/*.ts'], { expandDirectories: false }).map(i => ({ + entries: globSync( + ['src/commands/*.ts'], + { expandDirectories: false }, + ).map(i => ({ input: i.slice(0, -3), name: basename(i).slice(0, -3), })), diff --git a/package.json b/package.json index f3eaed4b..e73363e6 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,6 @@ }, "devDependencies": { "@antfu/eslint-config": "^2.27.2", - "@jsdevtools/ez-spawn": "^3.0.4", "@posva/prompts": "^2.4.4", "@types/fs-extra": "^11.0.4", "@types/ini": "^4.1.1", @@ -62,11 +61,12 @@ "fzf": "^0.5.2", "ini": "^4.1.3", "lint-staged": "^15.2.9", - "package-manager-detector": "^0.1.2", + "package-manager-detector": "^0.2.0", "picocolors": "^1.0.1", "simple-git-hooks": "^2.11.1", "taze": "^0.16.6", "terminal-link": "^3.0.0", + "tinyexec": "^0.3.0", "tinyglobby": "^0.2.5", "tsx": "^4.18.0", "typescript": "^5.5.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 937fdb02..458d0b3e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,9 +11,6 @@ importers: '@antfu/eslint-config': specifier: ^2.27.2 version: 2.27.2(@typescript-eslint/utils@8.2.0(eslint@9.9.1(jiti@1.21.6))(typescript@5.5.4))(@vue/compiler-sfc@3.4.31)(eslint@9.9.1(jiti@1.21.6))(typescript@5.5.4)(vitest@2.0.5(@types/node@22.5.0)) - '@jsdevtools/ez-spawn': - specifier: ^3.0.4 - version: 3.0.4 '@posva/prompts': specifier: ^2.4.4 version: 2.4.4 @@ -48,8 +45,8 @@ importers: specifier: ^15.2.9 version: 15.2.9 package-manager-detector: - specifier: ^0.1.2 - version: 0.1.2 + specifier: ^0.2.0 + version: 0.2.0 picocolors: specifier: ^1.0.1 version: 1.0.1 @@ -62,6 +59,9 @@ importers: terminal-link: specifier: ^3.0.0 version: 3.0.0 + tinyexec: + specifier: ^0.3.0 + version: 0.3.0 tinyglobby: specifier: ^0.2.5 version: 0.2.5 @@ -2453,9 +2453,6 @@ packages: package-json-from-dist@1.0.0: resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==} - package-manager-detector@0.1.2: - resolution: {integrity: sha512-iePyefLTOm2gEzbaZKSW+eBMjg+UYsQvUKxmvGXAQ987K16efBg10MxIjZs08iyX+DY2/owKY9DIdu193kX33w==} - package-manager-detector@0.2.0: resolution: {integrity: sha512-E385OSk9qDcXhcM9LNSe4sdhx8a9mAPrZ4sMLW+tmxl5ZuGtPUcdFu+MPP2jbgiWAZ6Pfe5soGFMd+0Db5Vrog==} @@ -5470,8 +5467,6 @@ snapshots: package-json-from-dist@1.0.0: {} - package-manager-detector@0.1.2: {} - package-manager-detector@0.2.0: {} parent-module@1.0.1: diff --git a/src/agents.ts b/src/agents.ts deleted file mode 100644 index 40d2728c..00000000 --- a/src/agents.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { Agent, Command } from 'package-manager-detector/agents' -import { AGENTS, COMMANDS, INSTALL_PAGE, LOCKS } from 'package-manager-detector/agents' - -export { AGENTS, COMMANDS, INSTALL_PAGE, LOCKS } - -export type { Agent, Command } diff --git a/src/config.ts b/src/config.ts index 22f59cb2..6f097243 100644 --- a/src/config.ts +++ b/src/config.ts @@ -2,7 +2,7 @@ import fs from 'node:fs' import path from 'node:path' import process from 'node:process' import ini from 'ini' -import type { Agent } from './agents' +import type { Agent } from 'package-manager-detector' import { detect } from './detect' const customRcPath = process.env.NI_CONFIG_FILE diff --git a/src/detect.ts b/src/detect.ts index acd90118..e768705f 100644 --- a/src/detect.ts +++ b/src/detect.ts @@ -1,39 +1,48 @@ import process from 'node:process' -import { async as ezspawn } from '@jsdevtools/ez-spawn' import { detect as detectPM } from 'package-manager-detector' +import { x } from 'tinyexec' import terminalLink from 'terminal-link' import prompts from '@posva/prompts' -import { INSTALL_PAGE } from './agents' +import { INSTALL_PAGE } from 'package-manager-detector/constants' import { cmdExists } from './utils' export interface DetectOptions { autoInstall?: boolean programmatic?: boolean cwd?: string + /** + * Should use Volta when present + * + * @see https://volta.sh/ + * @default true + */ + detectVolta?: boolean } export async function detect({ autoInstall, programmatic, cwd }: DetectOptions = {}) { - const pmDetection = await detectPM({ + const { + name, + agent, + version, + } = await detectPM({ cwd, onUnknown: (packageManager) => { if (!programmatic) { console.warn('[ni] Unknown packageManager:', packageManager) } + return undefined }, - }) - - const agent = pmDetection?.agent ?? null - const version = pmDetection?.version ?? null + }) || {} // auto install - if (agent && !cmdExists(agent.split('@')[0]) && !programmatic) { + if (name && !cmdExists(name) && !programmatic) { if (!autoInstall) { - console.warn(`[ni] Detected ${agent} but it doesn't seem to be installed.\n`) + console.warn(`[ni] Detected ${name} but it doesn't seem to be installed.\n`) if (process.env.CI) process.exit(1) - const link = terminalLink(agent, INSTALL_PAGE[agent]) + const link = terminalLink(name, INSTALL_PAGE[name]) const { tryInstall } = await prompts({ name: 'tryInstall', type: 'confirm', @@ -43,7 +52,17 @@ export async function detect({ autoInstall, programmatic, cwd }: DetectOptions = process.exit(1) } - await ezspawn(`npm i -g ${agent.split('@')[0]}${version ? `@${version}` : ''}`, { stdio: 'inherit', cwd }) + await x( + 'npm', + ['i', '-g', `${name}${version ? `@${version}` : ''}`], + { + nodeOptions: { + stdio: 'inherit', + cwd, + }, + throwOnError: true, + }, + ) } return agent diff --git a/src/index.ts b/src/index.ts index 7bbc4b91..1107bf74 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,6 @@ -export * from './agents' +export * from 'package-manager-detector/constants' +export * from 'package-manager-detector/commands' + export * from './config' export * from './detect' export * from './parse' diff --git a/src/parse.ts b/src/parse.ts index 3a9a19cc..1da70c7a 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -1,7 +1,7 @@ -import type { Agent, Command } from './agents' -import { AGENTS, COMMANDS } from './agents' +import type { Agent, Command, ResolvedCommand } from 'package-manager-detector' import { exclude } from './utils' import type { Runner } from './runner' +import { COMMANDS, constructCommand } from '.' export class UnsupportedCommand extends Error { constructor({ agent, command }: { agent: Agent, command: Command }) { @@ -13,23 +13,13 @@ export function getCommand( agent: Agent, command: Command, args: string[] = [], -) { - if (!AGENTS.includes(agent)) +): ResolvedCommand { + if (!COMMANDS[agent]) throw new Error(`Unsupported agent "${agent}"`) - - const c = COMMANDS[agent][command] - - if (typeof c === 'function') - return c(args) - - if (!c) + if (!COMMANDS[agent][command]) throw new UnsupportedCommand({ agent, command }) - const quote = (arg: string) => (!arg.startsWith('--') && arg.includes(' ')) - ? JSON.stringify(arg) - : arg - - return c.replace('{0}', args.map(quote).join(' ')).trim() + return constructCommand(COMMANDS[agent][command], args)! } export const parseNi = ((agent, args, ctx) => { @@ -58,12 +48,20 @@ export const parseNr = ((agent, args) => { if (args.length === 0) args.push('start') + let hasIfPresent = false if (args.includes('--if-present')) { args = exclude(args, '--if-present') - args[0] = `--if-present ${args[0]}` + hasIfPresent = true } - return getCommand(agent, 'run', args) + const cmd = getCommand(agent, 'run', args) + if (!cmd) + return cmd + + if (hasIfPresent) + cmd.args.splice(1, 0, '--if-present') + + return cmd }) export const parseNu = ((agent, args) => { @@ -86,3 +84,11 @@ export const parseNlx = ((agent, args) => { export const parseNa = ((agent, args) => { return getCommand(agent, 'agent', args) }) + +export function serializeCommand(command?: ResolvedCommand) { + if (!command) + return undefined + if (command.args.length === 0) + return command.command + return `${command.command} ${command.args.map(i => i.includes(' ') ? `"${i}"` : i).join(' ')}` +} diff --git a/src/runner.ts b/src/runner.ts index 3dd8127a..88e71874 100644 --- a/src/runner.ts +++ b/src/runner.ts @@ -2,16 +2,16 @@ import { resolve } from 'node:path' import process from 'node:process' import prompts from '@posva/prompts' -import type { Options as EzSpawnOptions } from '@jsdevtools/ez-spawn' -import { async as ezspawn } from '@jsdevtools/ez-spawn' +import type { Options as TinyExecOptions } from 'tinyexec' +import { x } from 'tinyexec' import c from 'picocolors' +import type { Agent, ResolvedCommand } from 'package-manager-detector' +import { AGENTS } from 'package-manager-detector' import { version } from '../package.json' -import type { Agent } from './agents' -import { AGENTS } from './agents' import { getDefaultAgent, getGlobalAgent } from './config' import type { DetectOptions } from './detect' import { detect } from './detect' -import { getVoltaPrefix, remove } from './utils' +import { cmdExists, remove } from './utils' import { UnsupportedCommand, getCommand } from './parse' const DEBUG_SIGN = '?' @@ -22,7 +22,7 @@ export interface RunnerContext { cwd?: string } -export type Runner = (agent: Agent, args: string[], ctx?: RunnerContext) => Promise | string | undefined +export type Runner = (agent: Agent, args: string[], ctx?: RunnerContext) => Promise | ResolvedCommand | undefined export async function runCli(fn: Runner, options: DetectOptions & { args?: string[] } = {}) { const { @@ -74,6 +74,10 @@ export async function getCliCommand( } export async function run(fn: Runner, args: string[], options: DetectOptions = {}) { + const { + detectVolta = true, + } = options + const debug = args.includes(DEBUG_SIGN) if (debug) remove(args, DEBUG_SIGN) @@ -85,13 +89,26 @@ export async function run(fn: Runner, args: string[], options: DetectOptions = { } if (args.length === 1 && (args[0]?.toLowerCase() === '-v' || args[0] === '--version')) { - const getCmd = (a: Agent) => AGENTS.includes(a) ? getCommand(a, 'agent', ['-v']) : `${a} -v` - const getV = (a: string, o: EzSpawnOptions = {}) => ezspawn(getCmd(a as Agent), o).then(e => e.stdout).then(e => e.startsWith('v') ? e : `v${e}`) + const getCmd = (a: Agent) => AGENTS.includes(a) + ? getCommand(a, 'agent', ['-v']) + : { command: a, args: ['-v'] } + const xVersionOptions = { + nodeOptions: { + cwd, + }, + throwOnError: true, + } satisfies Partial + const getV = (a: string) => { + const { command, args } = getCmd(a as Agent) + return x(command, args, xVersionOptions) + .then(e => e.stdout) + .then(e => e.startsWith('v') ? e : `v${e}`) + } const globalAgentPromise = getGlobalAgent() const globalAgentVersionPromise = globalAgentPromise.then(getV) const agentPromise = detect({ ...options, cwd }).then(a => a || '') - const agentVersionPromise = agentPromise.then(a => a && getV(a, { cwd })) - const nodeVersionPromise = getV('node', { cwd }) + const agentVersionPromise = agentPromise.then(a => a && getV(a)) + const nodeVersionPromise = getV('node') console.log(`@antfu/ni ${c.cyan(`v${version}`)}`) console.log(`node ${c.green(await nodeVersionPromise)}`) @@ -126,19 +143,30 @@ export async function run(fn: Runner, args: string[], options: DetectOptions = { return } - let command = await getCliCommand(fn, args, options, cwd) + const command = await getCliCommand(fn, args, options, cwd) if (!command) return - const voltaPrefix = getVoltaPrefix() - if (voltaPrefix) - command = voltaPrefix.concat(' ').concat(command) + if (detectVolta && cmdExists('volta')) { + command.args = ['run', command.command, ...command.args] + command.command = 'volta' + } if (debug) { console.log(command) return } - await ezspawn(command, { stdio: 'inherit', cwd }) + await x( + command.command, + command.args, + { + nodeOptions: { + stdio: 'inherit', + cwd, + }, + throwOnError: true, + }, + ) } diff --git a/src/utils.ts b/src/utils.ts index 28575fa4..46a0ec6d 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -25,13 +25,6 @@ export function cmdExists(cmd: string) { return which.sync(cmd, { nothrow: true }) !== null } -export function getVoltaPrefix(): string { - // https://blog.volta.sh/2020/11/25/command-spotlight-volta-run/ - const VOLTA_PREFIX = 'volta run' - const hasVoltaCommand = cmdExists('volta') - return hasVoltaCommand ? VOLTA_PREFIX : '' -} - interface TempFile { path: string fd: fs.FileHandle diff --git a/test/na/bun.spec.ts b/test/na/bun.spec.ts index 0d411151..0a061da5 100644 --- a/test/na/bun.spec.ts +++ b/test/na/bun.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNa } from '../../src/commands' +import { parseNa, serializeCommand } from '../../src/commands' const agent = 'bun' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNa(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNa(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/na/npm.spec.ts b/test/na/npm.spec.ts index 082d743d..880d0ba0 100644 --- a/test/na/npm.spec.ts +++ b/test/na/npm.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNa } from '../../src/commands' +import { parseNa, serializeCommand } from '../../src/commands' const agent = 'npm' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNa(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNa(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/na/pnpm.spec.ts b/test/na/pnpm.spec.ts index b87f3bed..a62be537 100644 --- a/test/na/pnpm.spec.ts +++ b/test/na/pnpm.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNa } from '../../src/commands' +import { parseNa, serializeCommand } from '../../src/commands' const agent = 'pnpm' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNa(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNa(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/na/yarn.spec.ts b/test/na/yarn.spec.ts index 91051211..7c8c0200 100644 --- a/test/na/yarn.spec.ts +++ b/test/na/yarn.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNa } from '../../src/commands' +import { parseNa, serializeCommand } from '../../src/commands' const agent = 'yarn' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNa(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNa(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/na/yarn@berry.spec.ts b/test/na/yarn@berry.spec.ts index 3b056aa4..53d14edb 100644 --- a/test/na/yarn@berry.spec.ts +++ b/test/na/yarn@berry.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNa } from '../../src/commands' +import { parseNa, serializeCommand } from '../../src/commands' const agent = 'yarn@berry' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNa(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNa(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/ni/bun.spec.ts b/test/ni/bun.spec.ts index ed7ded82..22baa94a 100644 --- a/test/ni/bun.spec.ts +++ b/test/ni/bun.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNi } from '../../src/commands' +import { parseNi, serializeCommand } from '../../src/commands' const agent = 'bun' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNi(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNi(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/ni/npm.spec.ts b/test/ni/npm.spec.ts index 043ddabb..427126e6 100644 --- a/test/ni/npm.spec.ts +++ b/test/ni/npm.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNi } from '../../src/commands' +import { parseNi, serializeCommand } from '../../src/commands' const agent = 'npm' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNi(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNi(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/ni/pnpm.spec.ts b/test/ni/pnpm.spec.ts index 6cc896a2..af0a5fc3 100644 --- a/test/ni/pnpm.spec.ts +++ b/test/ni/pnpm.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNi } from '../../src/commands' +import { parseNi, serializeCommand } from '../../src/commands' const agent = 'pnpm' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNi(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNi(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/ni/yarn.spec.ts b/test/ni/yarn.spec.ts index bfebc5ec..1f345782 100644 --- a/test/ni/yarn.spec.ts +++ b/test/ni/yarn.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNi } from '../../src/commands' +import { parseNi, serializeCommand } from '../../src/commands' const agent = 'yarn' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNi(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNi(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/ni/yarn@berry.spec.ts b/test/ni/yarn@berry.spec.ts index 00f6c7aa..70c73a10 100644 --- a/test/ni/yarn@berry.spec.ts +++ b/test/ni/yarn@berry.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNi } from '../../src/commands' +import { parseNi, serializeCommand } from '../../src/commands' const agent = 'yarn@berry' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNi(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNi(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/nlx/bun.spec.ts b/test/nlx/bun.spec.ts index 7e730857..c1908f68 100644 --- a/test/nlx/bun.spec.ts +++ b/test/nlx/bun.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNlx } from '../../src/commands' +import { parseNlx, serializeCommand } from '../../src/commands' const agent = 'bun' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNlx(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNlx(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/nlx/npm.spec.ts b/test/nlx/npm.spec.ts index f177d9eb..598b6a50 100644 --- a/test/nlx/npm.spec.ts +++ b/test/nlx/npm.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNlx } from '../../src/commands' +import { parseNlx, serializeCommand } from '../../src/commands' const agent = 'npm' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNlx(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNlx(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/nlx/pnpm.spec.ts b/test/nlx/pnpm.spec.ts index 4e3fd1fe..d5e0cc37 100644 --- a/test/nlx/pnpm.spec.ts +++ b/test/nlx/pnpm.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNlx } from '../../src/commands' +import { parseNlx, serializeCommand } from '../../src/commands' const agent = 'pnpm' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNlx(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNlx(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/nlx/yarn.spec.ts b/test/nlx/yarn.spec.ts index aec21089..49f9fa6b 100644 --- a/test/nlx/yarn.spec.ts +++ b/test/nlx/yarn.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNlx } from '../../src/commands' +import { parseNlx, serializeCommand } from '../../src/commands' const agent = 'yarn' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNlx(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNlx(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/nlx/yarn@berry.spec.ts b/test/nlx/yarn@berry.spec.ts index 428e4f8b..6b5bfa4f 100644 --- a/test/nlx/yarn@berry.spec.ts +++ b/test/nlx/yarn@berry.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNlx } from '../../src/commands' +import { parseNlx, serializeCommand } from '../../src/commands' const agent = 'yarn@berry' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNlx(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNlx(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/nr/bun.spec.ts b/test/nr/bun.spec.ts index 46987788..a31d353e 100644 --- a/test/nr/bun.spec.ts +++ b/test/nr/bun.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNr } from '../../src/commands' +import { parseNr, serializeCommand } from '../../src/commands' const agent = 'bun' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNr(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNr(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/nr/npm.spec.ts b/test/nr/npm.spec.ts index 496b8ad4..bfe5944e 100644 --- a/test/nr/npm.spec.ts +++ b/test/nr/npm.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNr } from '../../src/commands' +import { parseNr, serializeCommand } from '../../src/commands' const agent = 'npm' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNr(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNr(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/nr/pnpm.spec.ts b/test/nr/pnpm.spec.ts index a3923338..65f0043b 100644 --- a/test/nr/pnpm.spec.ts +++ b/test/nr/pnpm.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNr } from '../../src/commands' +import { parseNr, serializeCommand } from '../../src/commands' const agent = 'pnpm' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNr(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNr(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/nr/yarn.spec.ts b/test/nr/yarn.spec.ts index 507f84e7..5c90f829 100644 --- a/test/nr/yarn.spec.ts +++ b/test/nr/yarn.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNr } from '../../src/commands' +import { parseNr, serializeCommand } from '../../src/commands' const agent = 'yarn' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNr(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNr(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/nr/yarn@berry.spec.ts b/test/nr/yarn@berry.spec.ts index 75ea2348..f7728940 100644 --- a/test/nr/yarn@berry.spec.ts +++ b/test/nr/yarn@berry.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNr } from '../../src/commands' +import { parseNr, serializeCommand } from '../../src/commands' const agent = 'yarn@berry' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNr(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNr(agent, arg.split(/\s/g).filter(Boolean))), ).toBe( expected, ) diff --git a/test/nu/bun.spec.ts b/test/nu/bun.spec.ts index aa55dede..337827b6 100644 --- a/test/nu/bun.spec.ts +++ b/test/nu/bun.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNu } from '../../src/commands' +import { parseNu, serializeCommand } from '../../src/commands' const agent = 'bun' function _(arg: string, expected: string | null) { - return () => { + return async () => { expect( - parseNu(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNu(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/nu/npm.spec.ts b/test/nu/npm.spec.ts index 7b6127fb..d607d47b 100644 --- a/test/nu/npm.spec.ts +++ b/test/nu/npm.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNu } from '../../src/commands' +import { parseNu, serializeCommand } from '../../src/commands' const agent = 'npm' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNu(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNu(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/nu/pnpm.spec.ts b/test/nu/pnpm.spec.ts index 6c854093..8332ca90 100644 --- a/test/nu/pnpm.spec.ts +++ b/test/nu/pnpm.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNu } from '../../src/commands' +import { parseNu, serializeCommand } from '../../src/commands' const agent = 'pnpm' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNu(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNu(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/nu/yarn.spec.ts b/test/nu/yarn.spec.ts index 37f24309..da75dde1 100644 --- a/test/nu/yarn.spec.ts +++ b/test/nu/yarn.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNu } from '../../src/commands' +import { parseNu, serializeCommand } from '../../src/commands' const agent = 'yarn' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNu(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNu(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/nu/yarn@berry.spec.ts b/test/nu/yarn@berry.spec.ts index 8f3766cb..f5336268 100644 --- a/test/nu/yarn@berry.spec.ts +++ b/test/nu/yarn@berry.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNu } from '../../src/commands' +import { parseNu, serializeCommand } from '../../src/commands' const agent = 'yarn@berry' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNu(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNu(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/nun/bun.spec.ts b/test/nun/bun.spec.ts index cd8cf355..df8874da 100644 --- a/test/nun/bun.spec.ts +++ b/test/nun/bun.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNun } from '../../src/commands' +import { parseNun, serializeCommand } from '../../src/commands' const agent = 'bun' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNun(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNun(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/nun/npm.spec.ts b/test/nun/npm.spec.ts index 3bb32e5e..e87cd4d6 100644 --- a/test/nun/npm.spec.ts +++ b/test/nun/npm.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNun } from '../../src/commands' +import { parseNun, serializeCommand } from '../../src/commands' const agent = 'npm' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNun(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNun(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/nun/pnpm.spec.ts b/test/nun/pnpm.spec.ts index 4b34b11f..85aec5d3 100644 --- a/test/nun/pnpm.spec.ts +++ b/test/nun/pnpm.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNun } from '../../src/commands' +import { parseNun, serializeCommand } from '../../src/commands' const agent = 'pnpm' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNun(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNun(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/nun/yarn.spec.ts b/test/nun/yarn.spec.ts index be3ed166..80ede1d8 100644 --- a/test/nun/yarn.spec.ts +++ b/test/nun/yarn.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNun } from '../../src/commands' +import { parseNun, serializeCommand } from '../../src/commands' const agent = 'yarn' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNun(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNun(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/nun/yarn@berry.spec.ts b/test/nun/yarn@berry.spec.ts index 4ced0376..5cb2fe4a 100644 --- a/test/nun/yarn@berry.spec.ts +++ b/test/nun/yarn@berry.spec.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest' -import { parseNun } from '../../src/commands' +import { parseNun, serializeCommand } from '../../src/commands' const agent = 'yarn@berry' function _(arg: string, expected: string) { - return () => { + return async () => { expect( - parseNun(agent, arg.split(' ').filter(Boolean)), + serializeCommand(await parseNun(agent, arg.split(' ').filter(Boolean))), ).toBe( expected, ) diff --git a/test/programmatic/__snapshots__/detect.spec.ts.snap b/test/programmatic/__snapshots__/detect.spec.ts.snap index 845725dd..ef388f35 100644 --- a/test/programmatic/__snapshots__/detect.spec.ts.snap +++ b/test/programmatic/__snapshots__/detect.spec.ts.snap @@ -8,7 +8,7 @@ exports[`lockfile > pnpm 1`] = `"pnpm"`; exports[`lockfile > pnpm@6 1`] = `"pnpm"`; -exports[`lockfile > unknown 1`] = `null`; +exports[`lockfile > unknown 1`] = `undefined`; exports[`lockfile > yarn 1`] = `"yarn"`; @@ -22,7 +22,7 @@ exports[`packager > pnpm 1`] = `"pnpm"`; exports[`packager > pnpm@6 1`] = `"pnpm@6"`; -exports[`packager > unknown 1`] = `null`; +exports[`packager > unknown 1`] = `undefined`; exports[`packager > yarn 1`] = `"yarn"`; diff --git a/test/programmatic/runCli.spec.ts b/test/programmatic/runCli.spec.ts index d6473371..08ccd8ad 100644 --- a/test/programmatic/runCli.spec.ts +++ b/test/programmatic/runCli.spec.ts @@ -41,14 +41,14 @@ beforeAll(() => { errorLog = vi.spyOn(console, 'error') infoLog = vi.spyOn(console, 'info') - vi.mock('@jsdevtools/ez-spawn', async (importOriginal) => { + vi.mock('tinyexec', async (importOriginal) => { const mod = await importOriginal() as any return { ...mod, - async: (cmd: string) => { + x: (cmd: string, args?: string[]) => { // break execution flow for easier snapshotting // eslint-disable-next-line no-throw-literal - throw { command: cmd } + throw { command: [cmd, ...(args ?? [])].join(' ') } }, } })