Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: use package-manager-detector #227

Merged
merged 1 commit into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions build.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ import { defineBuildConfig } from 'unbuild'
import fg from 'fast-glob'

export default defineBuildConfig({
entries: [
...fg.sync('src/commands/*.ts').map(i => ({
input: i.slice(0, -3),
name: basename(i).slice(0, -3),
})),
],
entries: fg.sync('src/commands/*.ts').map(i => ({
input: i.slice(0, -3),
name: basename(i).slice(0, -3),
})),
clean: true,
declaration: true,
rollup: {
emitCJS: true,
inlineDependencies: true,
commonjs: {
exclude: ['**/*.d.ts'],
},
},
})
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
},
"exports": {
".": {
"types": "./dist/index.d.ts",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why remove the types?

Copy link
Member Author

@userquin userquin Aug 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because we don't need it: d.mts, d.cts and d.ts generated, we can omit the types entry (if we include the types entry, CJS being masquerading, check https://publint.dev/@antfu/[email protected] or https://arethetypeswrong.github.io/?p=%40antfu%2Fni%400.22.4):

imagen
publint

imagen
arethetypeswrong

"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
}
Expand Down Expand Up @@ -58,10 +57,10 @@
"bumpp": "^9.4.2",
"eslint": "^9.8.0",
"fast-glob": "^3.3.2",
"find-up": "^6.3.0",
"fs-extra": "^11.2.0",
"fzf": "^0.5.2",
"ini": "^4.1.3",
"package-manager-detector": "^0.1.1",
"picocolors": "^1.0.1",
"taze": "^0.16.3",
"terminal-link": "^3.0.0",
Expand Down
56 changes: 8 additions & 48 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

106 changes: 4 additions & 102 deletions src/agents.ts
Original file line number Diff line number Diff line change
@@ -1,104 +1,6 @@
function npmRun(agent: string) {
return (args: string[]) => {
if (args.length > 1)
return `${agent} run ${args[0]} -- ${args.slice(1).join(' ')}`
else return `${agent} run ${args[0]}`
}
}
import type { Agent, Command } from 'package-manager-detector/agents'
import { AGENTS, COMMANDS, INSTALL_PAGE, LOCKS } from 'package-manager-detector/agents'

const yarn = {
'agent': 'yarn {0}',
'run': 'yarn run {0}',
'install': 'yarn install {0}',
'frozen': 'yarn install --frozen-lockfile',
'global': 'yarn global add {0}',
'add': 'yarn add {0}',
'upgrade': 'yarn upgrade {0}',
'upgrade-interactive': 'yarn upgrade-interactive {0}',
'execute': 'npx {0}',
'uninstall': 'yarn remove {0}',
'global_uninstall': 'yarn global remove {0}',
}
const pnpm = {
'agent': 'pnpm {0}',
'run': 'pnpm run {0}',
'install': 'pnpm i {0}',
'frozen': 'pnpm i --frozen-lockfile',
'global': 'pnpm add -g {0}',
'add': 'pnpm add {0}',
'upgrade': 'pnpm update {0}',
'upgrade-interactive': 'pnpm update -i {0}',
'execute': 'pnpm dlx {0}',
'uninstall': 'pnpm remove {0}',
'global_uninstall': 'pnpm remove --global {0}',
}
const bun = {
'agent': 'bun {0}',
'run': 'bun run {0}',
'install': 'bun install {0}',
'frozen': 'bun install --frozen-lockfile',
'global': 'bun add -g {0}',
'add': 'bun add {0}',
'upgrade': 'bun update {0}',
'upgrade-interactive': 'bun update {0}',
'execute': 'bun x {0}',
'uninstall': 'bun remove {0}',
'global_uninstall': 'bun remove -g {0}',
}
export { AGENTS, COMMANDS, INSTALL_PAGE, LOCKS }

export const AGENTS = {
'npm': {
'agent': 'npm {0}',
'run': npmRun('npm'),
'install': 'npm i {0}',
'frozen': 'npm ci',
'global': 'npm i -g {0}',
'add': 'npm i {0}',
'upgrade': 'npm update {0}',
'upgrade-interactive': null,
'execute': 'npx {0}',
'uninstall': 'npm uninstall {0}',
'global_uninstall': 'npm uninstall -g {0}',
},
'yarn': yarn,
'yarn@berry': {
...yarn,
'frozen': 'yarn install --immutable',
'upgrade': 'yarn up {0}',
'upgrade-interactive': 'yarn up -i {0}',
'execute': 'yarn dlx {0}',
// Yarn 2+ removed 'global', see https://github.com/yarnpkg/berry/issues/821
'global': 'npm i -g {0}',
'global_uninstall': 'npm uninstall -g {0}',
},
'pnpm': pnpm,
// pnpm v6.x or below
'pnpm@6': {
...pnpm,
run: npmRun('pnpm'),
},
'bun': bun,
}

export type Agent = keyof typeof AGENTS
export type Command = keyof typeof AGENTS.npm

export const agents = Object.keys(AGENTS) as Agent[]

// the order here matters, more specific one comes first
export const LOCKS: Record<string, Agent> = {
'bun.lockb': 'bun',
'pnpm-lock.yaml': 'pnpm',
'yarn.lock': 'yarn',
'package-lock.json': 'npm',
'npm-shrinkwrap.json': 'npm',
}

export const INSTALL_PAGE: Record<Agent, string> = {
'bun': 'https://bun.sh',
'pnpm': 'https://pnpm.io/installation',
'pnpm@6': 'https://pnpm.io/6.x/installation',
'yarn': 'https://classic.yarnpkg.com/en/docs/install',
'yarn@berry': 'https://yarnpkg.com/getting-started/install',
'npm': 'https://docs.npmjs.com/cli/v8/configuring-npm/install',
}
export type { Agent, Command }
54 changes: 11 additions & 43 deletions src/detect.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import fs from 'node:fs'
import path from 'node:path'
import process from 'node:process'
import { async as ezspawn } from '@jsdevtools/ez-spawn'
import { findUp } from 'find-up'
import { detect as detectPM } from 'package-manager-detector'
import terminalLink from 'terminal-link'
import prompts from '@posva/prompts'
import type { Agent } from './agents'
import { AGENTS, INSTALL_PAGE, LOCKS } from './agents'
import { INSTALL_PAGE } from './agents'
import { cmdExists } from './utils'

export interface DetectOptions {
Expand All @@ -16,46 +13,17 @@ export interface DetectOptions {
}

export async function detect({ autoInstall, programmatic, cwd }: DetectOptions = {}) {
let agent: Agent | null = null
let version: string | null = null

const lockPath = await findUp(Object.keys(LOCKS), { cwd })
let packageJsonPath: string | undefined

if (lockPath)
packageJsonPath = path.resolve(lockPath, '../package.json')
else
packageJsonPath = await findUp('package.json', { cwd })

// read `packageManager` field in package.json
if (packageJsonPath && fs.existsSync(packageJsonPath)) {
try {
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
if (typeof pkg.packageManager === 'string') {
const [name, ver] = pkg.packageManager.replace(/^\^/, '').split('@')
version = ver
if (name === 'yarn' && Number.parseInt(ver) > 1) {
agent = 'yarn@berry'
// the version in packageManager isn't the actual yarn package version
version = 'berry'
}
else if (name === 'pnpm' && Number.parseInt(ver) < 7) {
agent = 'pnpm@6'
}
else if (name in AGENTS) {
agent = name
}
else if (!programmatic) {
console.warn('[ni] Unknown packageManager:', pkg.packageManager)
}
const pmDetection = await detectPM({
cwd,
onUnknown: (packageManager) => {
if (!programmatic) {
console.warn('[ni] Unknown packageManager:', packageManager)
}
}
catch {}
}
},
})

// detect based on lock
if (!agent && lockPath)
agent = LOCKS[path.basename(lockPath)]
const agent = pmDetection?.agent ?? null
const version = pmDetection?.version ?? null

// auto install
if (agent && !cmdExists(agent.split('@')[0]) && !programmatic) {
Expand Down
Loading