/
licenses.ts
125 lines (111 loc) · 3.97 KB
/
licenses.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import { WANTED_LOCKFILE } from '@pnpm/constants'
import { PnpmError } from '@pnpm/error'
import {
getLockfileImporterId,
Lockfile,
} from '@pnpm/lockfile-file'
import { nameVerFromPkgSnapshot } from '@pnpm/lockfile-utils'
import { getAllDependenciesFromManifest } from '@pnpm/manifest-utils'
import {
DependenciesField,
DEPENDENCIES_FIELDS,
IncludedDependencies,
PackageManifest,
ProjectManifest,
Registries,
} from '@pnpm/types'
import * as dp from 'dependency-path'
import { getPkgInfo } from './getPkgInfo'
export interface LicensePackage {
alias: string
belongsTo: DependenciesField
version: string
packageManifest?: PackageManifest
packageName: string
license: string
licenseContents?: string
author?: string
packageDirectory?: string
}
export async function licences (
opts: {
compatible?: boolean
currentLockfile: Lockfile | null
ignoreDependencies?: Set<string>
include?: IncludedDependencies
lockfileDir: string
manifest: ProjectManifest
match?: (dependencyName: string) => boolean
prefix: string
registries: Registries
wantedLockfile: Lockfile | null
}
): Promise<LicensePackage[]> {
if (packageHasNoDeps(opts.manifest)) return []
if (opts.wantedLockfile == null) {
throw new PnpmError('LICENSES_NO_LOCKFILE', `No lockfile in directory "${opts.lockfileDir}". Run \`pnpm install\` to generate one.`)
}
const allDeps = getAllDependenciesFromManifest(opts.manifest)
const importerId = getLockfileImporterId(opts.lockfileDir, opts.prefix)
const licenses: LicensePackage[] = []
await Promise.all(
DEPENDENCIES_FIELDS.map(async (depType) => {
if (
opts.include?.[depType] === false ||
(opts.wantedLockfile!.importers[importerId][depType] == null)
) return
let pkgs = Object.keys(opts.wantedLockfile!.importers[importerId][depType]!)
if (opts.match != null) {
pkgs = pkgs.filter((pkgName) => opts.match!(pkgName))
}
await Promise.all(
pkgs.map(async (alias) => {
if (!allDeps[alias]) return
const ref = opts.wantedLockfile!.importers[importerId][depType]![alias]
if (
ref.startsWith('file:') || // ignoring linked packages. (For backward compatibility)
opts.ignoreDependencies?.has(alias)
) {
return
}
const relativeDepPath = dp.refToRelative(ref, alias)
// ignoring linked packages
if (relativeDepPath === null) return
const pkgSnapshot = opts.wantedLockfile!.packages?.[relativeDepPath]
if (pkgSnapshot == null) {
throw new Error(`Invalid ${WANTED_LOCKFILE} file. ${relativeDepPath} not found in packages field`)
}
const { name: packageName, version: packageVersion } = nameVerFromPkgSnapshot(relativeDepPath, pkgSnapshot)
const name = dp.parse(relativeDepPath).name ?? packageName
// Fetch the most recent package by the give name
const { packageManifest, packageInfo } = await getPkgInfo({
alias,
name,
version: packageVersion,
prefix: opts.prefix,
})
licenses.push({
alias,
belongsTo: depType,
version: packageVersion,
packageManifest,
packageName,
license: packageInfo.license,
licenseContents: packageInfo.licenseContents,
author: packageInfo.author,
packageDirectory: packageInfo.path,
})
})
)
})
)
return licenses.sort((pkg1, pkg2) => pkg1.packageName.localeCompare(pkg2.packageName))
}
function packageHasNoDeps (manifest: ProjectManifest) {
return ((manifest.dependencies == null) || isEmpty(manifest.dependencies)) &&
((manifest.devDependencies == null) || isEmpty(manifest.devDependencies)) &&
((manifest.optionalDependencies == null) || isEmpty(manifest.optionalDependencies))
}
function isEmpty (obj: object) {
return Object.keys(obj).length === 0
}