diff --git a/README.md b/README.md index fa21038..59ea448 100644 --- a/README.md +++ b/README.md @@ -12,10 +12,8 @@ npm i -g @antfu/ni npm · yarn · pnpm · bun -
- ### `ni` - install ```bash @@ -55,20 +53,6 @@ ni --frozen # bun install --no-save ``` -```bash -ni -i - -# interactively select the dependency to install -# fetches all similar packages by name -``` - -```bash -ni - - -# uninstall the last -# installed package -``` - ```bash ni -g eslint @@ -80,6 +64,13 @@ ni -g eslint # this uses default agent, regardless your current working directory ``` +```bash +ni -i + +# interactively select the dependency to install +# search for packages by name +``` +
### `nr` - run @@ -158,14 +149,14 @@ nun webpack ```bash nun -# interactively select +# interactively select # the dependency to remove ``` ```bash nun -m -# interactive select, +# interactive select, # but with multiple dependencies ``` @@ -178,13 +169,6 @@ nun -g silent # bun remove -g silent ``` -```bash -nun - - -# uninstall the last -# installed package -``` -
### `nci` - clean install diff --git a/src/commands/ni.ts b/src/commands/ni.ts index f343671..0822c19 100644 --- a/src/commands/ni.ts +++ b/src/commands/ni.ts @@ -1,10 +1,11 @@ +import process from 'node:process' import type { Choice } from '@posva/prompts' import prompts from '@posva/prompts' import { Fzf } from 'fzf' -import terminalLink from 'terminal-link' +import c from 'kleur' import { parseNi } from '../parse' import { runCli } from '../runner' -import { exclude, invariant } from '../utils' +import { exclude } from '../utils' import { fetchNpmPackages } from '../fetch' runCli(async (agent, args, ctx) => { @@ -20,17 +21,24 @@ runCli(async (agent, args, ctx) => { const { pattern } = await prompts({ type: 'text', name: 'pattern', - message: 'package name', + message: 'search for package', }) fetchPattern = pattern } - invariant(fetchPattern) + if (!fetchPattern) { + process.exitCode = 1 + return + } const packages = await fetchNpmPackages(fetchPattern) - invariant(packages.length, 'No results found') + if (!packages.length) { + console.error('No results found') + process.exitCode = 1 + return + } const fzf = new Fzf(packages, { selector: (item: Choice) => item.title, @@ -42,15 +50,18 @@ runCli(async (agent, args, ctx) => { name: 'dependency', choices: packages, instructions: false, - message: 'choose package', - limit: 25, + message: 'choose a package to install', + limit: 15, async suggest(input: string, choices: Choice[]) { const results = fzf.find(input) return results.map(r => choices.find((c: any) => c.value === r.item.value)) }, }) - invariant(dependency) + if (!dependency) { + process.exitCode = 1 + return + } args = exclude(args, '-d', '-p', '-i') @@ -60,14 +71,10 @@ runCli(async (agent, args, ctx) => { */ const canInstallPeers = ['npm', 'pnpm'].includes(agent) - const { npm, repository } = dependency.links - - const pkgLink = terminalLink(dependency.name, repository ?? npm) - const { mode } = await prompts({ type: 'select', name: 'mode', - message: `install ${pkgLink} as`, + message: `install ${c.yellow(dependency.name)} as`, choices: [ { title: 'prod', diff --git a/src/commands/nr.ts b/src/commands/nr.ts index d06ece3..da0fc8a 100644 --- a/src/commands/nr.ts +++ b/src/commands/nr.ts @@ -77,7 +77,7 @@ runCli(async (agent, args, ctx) => { return args.push(fn) } - catch (e) { + catch { process.exit(1) } } diff --git a/src/commands/nun.ts b/src/commands/nun.ts index 43b0f50..9399ee6 100644 --- a/src/commands/nun.ts +++ b/src/commands/nun.ts @@ -5,7 +5,7 @@ import { Fzf } from 'fzf' import { parseNun } from '../parse' import { runCli } from '../runner' import { getPackageJSON } from '../fs' -import { exclude, invariant } from '../utils' +import { exclude } from '../utils' runCli(async (agent, args, ctx) => { const isInteractive = !args.length && !ctx?.programmatic @@ -17,7 +17,10 @@ runCli(async (agent, args, ctx) => { const raw = Object.entries(allDependencies) as [string, string][] - invariant(raw.length, 'No dependencies found') + if (!raw.length) { + console.error('No dependencies found') + return + } const fzf = new Fzf(raw, { selector: ([dep, version]) => `${dep} ${version}`, @@ -52,7 +55,10 @@ runCli(async (agent, args, ctx) => { }, }) - invariant(depsToRemove.length) + if (!depsToRemove) { + process.exitCode = 1 + return + } const isSingleDependency = typeof depsToRemove === 'string' @@ -60,7 +66,7 @@ runCli(async (agent, args, ctx) => { args.push(depsToRemove) else args.push(...depsToRemove) } - catch (e) { + catch { process.exit(1) } } diff --git a/src/fetch.ts b/src/fetch.ts index a7b91cf..29d67a3 100644 --- a/src/fetch.ts +++ b/src/fetch.ts @@ -1,7 +1,7 @@ import process from 'node:process' import type { Choice } from '@posva/prompts' -import terminalLink from 'terminal-link' -import { limitText } from './utils' +import c from 'kleur' +import { formatPackageWithUrl } from './utils' export interface NpmPackage { name: string @@ -31,12 +31,15 @@ export async function fetchNpmPackages(pattern: string): Promise { .then(res => res.json()) as NpmRegistryResponse return result.objects.map(({ package: pkg }) => ({ - title: terminalLink(pkg.name, pkg.links.repository ?? pkg.links.npm), + title: formatPackageWithUrl( + `${pkg.name.padEnd(30, ' ')} ${c.blue(`v${pkg.version}`)}`, + pkg.links.repository ?? pkg.links.npm, + terminalColumns, + ), value: pkg, - description: limitText(pkg.version, terminalColumns - 20), })) } - catch (e) { + catch { console.error('Error when fetching npm registry') process.exit(1) } diff --git a/src/utils.ts b/src/utils.ts index efe569e..cd309c8 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -5,6 +5,7 @@ import type { Buffer } from 'node:buffer' import process from 'node:process' import which from 'which' import c from 'kleur' +import terminalLink from 'terminal-link' export const CLI_TEMP_DIR = join(os.tmpdir(), 'antfu-ni') @@ -93,24 +94,22 @@ export async function writeFileSafe( return false } -export function invariant(condition: unknown, errorMsg?: string) { - if (condition) - return - - if (errorMsg) { - console.error(errorMsg) - process.exit(1) - } - - /** - * if message is not provided - * just silently exit - */ - process.exit(0) -} - export function limitText(text: string, maxWidth: number) { if (text.length <= maxWidth) return text return `${text.slice(0, maxWidth)}${c.dim('…')}` } + +export function formatPackageWithUrl(pkg: string, url?: string, limits = 80) { + return url + ? terminalLink( + pkg, + url, + { + fallback: (_, url) => (pkg.length + url.length > limits) + ? pkg + : pkg + c.dim(` - ${url}`), + }, + ) + : pkg +} diff --git a/taze.config.ts b/taze.config.ts index 509f1f7..fcf4217 100644 --- a/taze.config.ts +++ b/taze.config.ts @@ -2,6 +2,6 @@ import { defineConfig } from 'taze' export default defineConfig({ ignorePaths: [ - 'test/fixtures' - ] + 'test/fixtures', + ], })