Skip to content

Commit

Permalink
refactor: make a subcommand
Browse files Browse the repository at this point in the history
  • Loading branch information
zkochan committed Nov 17, 2022
1 parent 4e795f8 commit 2176e74
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 72 deletions.
3 changes: 2 additions & 1 deletion .changeset/nice-cycles-search.md
@@ -1,6 +1,7 @@
---
'@pnpm/license-scanner': major
'@pnpm/plugin-commands-licenses': major
"pnpm": minor
---

Added new command named licenses which displays the licenses of the packages
Added a new command `pnpm licenses list`, which displays the licenses of the packages [#2825](https://github.com/pnpm/pnpm/issues/2825)
80 changes: 13 additions & 67 deletions packages/plugin-commands-licenses/src/licenses.ts
@@ -1,23 +1,18 @@
import {
docsUrl,
readDepNameCompletions,
readProjectManifestOnly,
} from '@pnpm/cli-utils'
import { getStorePath } from '@pnpm/store-path'
import { CompletionFunc } from '@pnpm/command'
import { WANTED_LOCKFILE } from '@pnpm/constants'
import { readWantedLockfile } from '@pnpm/lockfile-file'
import {
FILTERING,
OPTIONS,
UNIVERSAL_OPTIONS,
} from '@pnpm/common-cli-options-help'
import { Config, types as allTypes } from '@pnpm/config'
import { types as allTypes } from '@pnpm/config'
import { PnpmError } from '@pnpm/error'
import { findDependencyLicenses } from '@pnpm/license-scanner'
import pick from 'ramda/src/pick'
import renderHelp from 'render-help'
import { renderLicences } from './outputRenderer'
import { licensesList, LicensesCommandOptions } from './licensesList'

export function rcOptionsTypes () {
return {
Expand Down Expand Up @@ -47,9 +42,8 @@ export function help () {
description: `Check for licenses packages. The check can be limited to a subset of the installed packages by providing arguments (patterns are supported).
Examples:
pnpm licenses
pnpm licenses --long
pnpm licenses gulp-* @babel/core`,
pnpm licenses list
pnpm licenses list --long`,
descriptionLists: [
{
title: 'Options',
Expand Down Expand Up @@ -94,67 +88,19 @@ export const completion: CompletionFunc = async (cliOpts) => {
return readDepNameCompletions(cliOpts.dir as string)
}

export type LicensesCommandOptions = {
compatible?: boolean
long?: boolean
recursive?: boolean
json?: boolean
} & Pick<
Config,
| 'dev'
| 'dir'
| 'lockfileDir'
| 'registries'
| 'optional'
| 'production'
| 'storeDir'
| 'virtualStoreDir'
| 'modulesDir'
| 'pnpmHomeDir'
> &
Partial<Pick<Config, 'userConfig'>>

export async function handler (
opts: LicensesCommandOptions,
params: string[] = []
) {
const lockfile = await readWantedLockfile(opts.lockfileDir ?? opts.dir, {
ignoreIncompatible: true,
})
if (lockfile == null) {
throw new PnpmError(
'LICENSES_NO_LOCKFILE',
`No ${WANTED_LOCKFILE} found: Cannot check a project without a lockfile`
)
if (params.length === 0) {
throw new PnpmError('LICENCES_NO_SUBCOMMAND', 'Please specify the subcommand')
}
switch (params[0]) {
case 'list':
case 'ls':
return licensesList(opts)
default: {
throw new PnpmError('LICENSES_UNKNOWN_SUBCOMMAND', 'This subcommand is not known')
}

const include = {
dependencies: opts.production !== false,
devDependencies: opts.dev !== false,
optionalDependencies: opts.optional !== false,
}

const manifest = await readProjectManifestOnly(opts.dir, {})

const storeDir = await getStorePath({
pkgRoot: opts.dir,
storePath: opts.storeDir,
pnpmHomeDir: opts.pnpmHomeDir,
})

const licensePackages = await findDependencyLicenses({
include,
lockfileDir: opts.dir,
storeDir,
virtualStoreDir: opts.virtualStoreDir ?? '.',
modulesDir: opts.modulesDir,
registries: opts.registries,
wantedLockfile: lockfile,
manifest,
})

if (licensePackages.length === 0)
return { output: 'No licenses in packages found', exitCode: 0 }

return renderLicences(licensePackages, opts)
}
70 changes: 70 additions & 0 deletions packages/plugin-commands-licenses/src/licensesList.ts
@@ -0,0 +1,70 @@
import { readProjectManifestOnly } from '@pnpm/cli-utils'
import { Config } from '@pnpm/config'
import { PnpmError } from '@pnpm/error'
import { getStorePath } from '@pnpm/store-path'
import { WANTED_LOCKFILE } from '@pnpm/constants'
import { readWantedLockfile } from '@pnpm/lockfile-file'
import { findDependencyLicenses } from '@pnpm/license-scanner'
import { renderLicences } from './outputRenderer'

export type LicensesCommandOptions = {
compatible?: boolean
long?: boolean
recursive?: boolean
json?: boolean
} & Pick<
Config,
| 'dev'
| 'dir'
| 'lockfileDir'
| 'registries'
| 'optional'
| 'production'
| 'storeDir'
| 'virtualStoreDir'
| 'modulesDir'
| 'pnpmHomeDir'
> &
Partial<Pick<Config, 'userConfig'>>

export async function licensesList (opts: LicensesCommandOptions) {
const lockfile = await readWantedLockfile(opts.lockfileDir ?? opts.dir, {
ignoreIncompatible: true,
})
if (lockfile == null) {
throw new PnpmError(
'LICENSES_NO_LOCKFILE',
`No ${WANTED_LOCKFILE} found: Cannot check a project without a lockfile`
)
}

const include = {
dependencies: opts.production !== false,
devDependencies: opts.dev !== false,
optionalDependencies: opts.optional !== false,
}

const manifest = await readProjectManifestOnly(opts.dir, {})

const storeDir = await getStorePath({
pkgRoot: opts.dir,
storePath: opts.storeDir,
pnpmHomeDir: opts.pnpmHomeDir,
})

const licensePackages = await findDependencyLicenses({
include,
lockfileDir: opts.dir,
storeDir,
virtualStoreDir: opts.virtualStoreDir ?? '.',
modulesDir: opts.modulesDir,
registries: opts.registries,
wantedLockfile: lockfile,
manifest,
})

if (licensePackages.length === 0)
return { output: 'No licenses in packages found', exitCode: 0 }

return renderLicences(licensePackages, opts)
}
8 changes: 4 additions & 4 deletions packages/plugin-commands-licenses/test/index.ts
Expand Up @@ -47,7 +47,7 @@ test('pnpm licenses', async () => {
// we need to prefix it with v3 otherwise licenses tool can't find anything
// in the content-addressable directory
storeDir: path.resolve(storeDir, 'v3'),
})
}, ['list'])

expect(exitCode).toBe(0)
expect(stripAnsi(output)).toMatchSnapshot('show-packages')
Expand All @@ -74,7 +74,7 @@ test('pnpm licenses: show details', async () => {
// we need to prefix it with v3 otherwise licenses tool can't find anything
// in the content-addressable directory
storeDir: path.resolve(storeDir, 'v3'),
})
}, ['list'])

expect(exitCode).toBe(0)
expect(stripAnsi(output)).toMatchSnapshot('show-packages-details')
Expand Down Expand Up @@ -102,7 +102,7 @@ test('pnpm licenses: output as json', async () => {
// we need to prefix it with v3 otherwise licenses tool can't find anything
// in the content-addressable directory
storeDir: path.resolve(storeDir, 'v3'),
})
}, ['list'])

expect(exitCode).toBe(0)
expect(output).not.toHaveLength(0)
Expand All @@ -129,7 +129,7 @@ test('pnpm licenses: fails when lockfile is missing', async () => {
dir: path.resolve('./test/fixtures/invalid'),
pnpmHomeDir: '',
long: true,
})
}, ['list'])
).rejects.toThrowErrorMatchingInlineSnapshot(
'"No pnpm-lock.yaml found: Cannot check a project without a lockfile"'
)
Expand Down

0 comments on commit 2176e74

Please sign in to comment.