diff --git a/packages/tools/cli/package.json b/packages/tools/cli/package.json index a842f74..8756908 100644 --- a/packages/tools/cli/package.json +++ b/packages/tools/cli/package.json @@ -37,6 +37,7 @@ "commander": "^11.1.0", "detect-indent": "^6.1.0", "fast-npm-meta": "^0.2.2", + "package-manager-detector": "^0.1.1", "picocolors": "^1.0.1", "rollup-plugin-visualizer": "^5.12.0" }, diff --git a/packages/tools/cli/src/cli.ts b/packages/tools/cli/src/cli.ts index 94ff847..0351d47 100644 --- a/packages/tools/cli/src/cli.ts +++ b/packages/tools/cli/src/cli.ts @@ -2,7 +2,6 @@ import path from 'path'; import picocolors from 'picocolors'; import { Command, Option } from 'commander'; import handleError from './handle-error'; -import { detectPackageManager, type PackageManager } from './package-manager'; import { renderTree } from './renderTree'; import { overridesPackageJson } from './lib/json'; @@ -11,6 +10,7 @@ import { handleSigTerm } from './lib/handle-sigterm'; import { findPackagesCoveredByNolyfill, findPackagesNotCoveredByNolyfill } from './find-coverable-packages'; import { checkForUpdates } from './check-update'; import { generateIssue } from './generate-issue'; +import { detectPackageManager, type PackageManager } from './package-manager'; interface CliOptions { /** see full error messages, mostly for debugging */ @@ -32,7 +32,7 @@ const pmCommandOption = new Option('--pm [package manager]', 'specify which pack handleSigTerm(); -// eslint-disable-next-line @typescript-eslint/no-var-requires -- version +// eslint-disable-next-line @typescript-eslint/no-require-imports -- TBD const { version } = require('../package.json') as PKG; const checkUnsupportedPM = (packageManager: PackageManager) => { @@ -78,10 +78,10 @@ const program = new Command('nolyfill'); .addOption(pmCommandOption) .addOption(new Option('-f --format [format]', 'output format for console') .choices(['humanreadable', 'json']) - .default('humanreadable') - ) + .default('humanreadable')) .action(async (source: string | undefined, option: CheckCommandOptions) => { const projectPath = path.resolve(source ?? process.cwd()); + // TODO: use `package-manager-detector` agent option const packageManager = option.pm === 'auto' ? await detectPackageManager(projectPath) : option.pm; const format = option.format; @@ -120,6 +120,7 @@ const program = new Command('nolyfill'); .addOption(pmCommandOption) .action(async (source: string | undefined, option: PmCommandOptions) => { const projectPath = path.resolve(source ?? process.cwd()); + // TODO: use `package-manager-detector` agent option const packageManager = option.pm === 'auto' ? await detectPackageManager(projectPath) : option.pm; if (checkUnsupportedPM(packageManager)) { diff --git a/packages/tools/cli/src/index.ts b/packages/tools/cli/src/index.ts index 02b254e..382bdfe 100644 --- a/packages/tools/cli/src/index.ts +++ b/packages/tools/cli/src/index.ts @@ -2,5 +2,5 @@ export { allPackages } from './all-packages'; export { findPackagesCoveredByNolyfill, findPackagesNotCoveredByNolyfill } from './find-coverable-packages'; export { overridesPackageJson } from './lib/json'; -export { detectPackageManager, type PackageManager } from './package-manager'; +export { type PackageManager } from './package-manager'; export * from './types'; diff --git a/packages/tools/cli/src/package-manager.ts b/packages/tools/cli/src/package-manager.ts index 49faa6c..b6b53e4 100644 --- a/packages/tools/cli/src/package-manager.ts +++ b/packages/tools/cli/src/package-manager.ts @@ -1,32 +1,13 @@ -import path from 'path'; -import fs, { type PathLike } from 'fs'; -import fsp from 'fs/promises'; - -import { fileExists } from '@nolyfill/internal'; - -import PromiseAny from '@nolyfill/promise.any'; +import { detect } from 'package-manager-detector'; export type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun'; +type PackageManagerDetectorReturn = Awaited>; -const checkFile = (path: PathLike) => fsp.access(path, fs.constants.F_OK); - -export async function detectPackageManager(projectPath: string): Promise { - const packageJsonPath = path.join(projectPath, 'package.json'); - - if (!await fileExists(packageJsonPath)) { - throw new Error(`Failed to locate package.json at ${projectPath}. Are you sure the path is correct?`); - } - - try { - return await PromiseAny([ - checkFile(path.join(projectPath, 'yarn.lock')).then<'yarn'>(() => 'yarn'), - checkFile(path.join(projectPath, 'pnpm-lock.yaml')).then<'pnpm'>(() => 'pnpm'), - checkFile(path.join(projectPath, 'package-lock.json')).then<'npm'>(() => 'npm'), - checkFile(path.join(projectPath, 'npm-shrinkwrap.json')).then<'npm'>(() => 'npm'), - checkFile(path.join(projectPath, 'bun.lockb')).then<'bun'>(() => 'bun') - ]); - } catch (e) { - console.log(e); - throw new Error('Can not determine the preferred package manager.'); +export function tramsformPackageManager(input: PackageManagerDetectorReturn): PackageManager { + if (input.agent == null) { + throw new Error('Can not determine the preferred package manager'); } + return input.agent.split('@')[0] as PackageManager; } + +export const detectPackageManager = (cwd: string) => detect({ cwd }).then(tramsformPackageManager); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0cb4cd0..ad425b6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -895,6 +895,9 @@ importers: fast-npm-meta: specifier: ^0.2.2 version: 0.2.2 + package-manager-detector: + specifier: ^0.1.1 + version: 0.1.1 picocolors: specifier: ^1.0.1 version: 1.0.1 @@ -2043,10 +2046,6 @@ packages: resolution: {integrity: sha512-AQn9XqCzUXd4bAVEsAXM/Izk11Wx2u4H3BAfQVhSfzfDOm/wAON9nP7J5rpkCxts7E5TELmN845xTUCQrD1xIQ==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/types@8.0.0-alpha.36': - resolution: {integrity: sha512-D+w5uE8Y83K/P5VQZyKKi4pwTL2YkWOwtQOVJQI38Rp8f3pmY+Jmcps3wkSFSJK8wifTlvoHwwIBf1FsdCW/EA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/types@8.0.0-alpha.45': resolution: {integrity: sha512-yjTlmcSnkFV8IoqE0vinmWo+fl7TjkaGyGX/g9gKN/b2IO8g+AimB7BhilmlBqvZupvo2AfiHqcnZEVhQAXI8w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3583,6 +3582,9 @@ packages: package-json-from-dist@1.0.0: resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==} + package-manager-detector@0.1.1: + resolution: {integrity: sha512-KRfleQVD8jK1lIOo6fJxAtBH0fYo/r9q1+2Zs931cz0GLt1WeGYgIC0J+kETRZk8Ha2HghztDQSEqbeo00bzhw==} + pacote@15.2.0: resolution: {integrity: sha512-rJVZeIwHTUta23sIZgEIM62WYwbmGbThdbnkt81ravBplQv+HjyroqnLRNH2+sLJHcGZmLRmhPwACqhfTcOmnA==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -5724,8 +5726,6 @@ snapshots: '@typescript-eslint/types@7.16.1': {} - '@typescript-eslint/types@8.0.0-alpha.36': {} - '@typescript-eslint/types@8.0.0-alpha.45': {} '@typescript-eslint/typescript-estree@6.21.0(typescript@5.5.3)': @@ -5745,7 +5745,7 @@ snapshots: '@typescript-eslint/typescript-estree@7.16.1(typescript@5.5.3)': dependencies: - '@typescript-eslint/types': 8.0.0-alpha.36 + '@typescript-eslint/types': 7.16.1 '@typescript-eslint/visitor-keys': 7.16.1 debug: 4.3.5 globby: 11.1.0 @@ -5760,7 +5760,7 @@ snapshots: '@typescript-eslint/typescript-estree@8.0.0-alpha.45(typescript@5.5.3)': dependencies: - '@typescript-eslint/types': 8.0.0-alpha.36 + '@typescript-eslint/types': 8.0.0-alpha.45 '@typescript-eslint/visitor-keys': 8.0.0-alpha.45 debug: 4.3.5 globby: 11.1.0 @@ -5821,7 +5821,7 @@ snapshots: '@typescript-eslint/visitor-keys@8.0.0-alpha.45': dependencies: - '@typescript-eslint/types': 8.0.0-alpha.36 + '@typescript-eslint/types': 8.0.0-alpha.45 eslint-visitor-keys: 3.4.3 '@yarnpkg/parsers@3.0.0(patch_hash=zo4dj7i3lg4j65lzwjid24xbd4)': @@ -7475,6 +7475,8 @@ snapshots: package-json-from-dist@1.0.0: {} + package-manager-detector@0.1.1: {} + pacote@15.2.0: dependencies: '@npmcli/git': 4.1.0