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',
+ ],
})