/
index.ts
127 lines (116 loc) · 4.08 KB
/
index.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
126
127
import path from 'path'
import PnpmError from '@pnpm/error'
import { tryReadProjectManifest } from '@pnpm/read-project-manifest'
import { Dependencies, ProjectManifest } from '@pnpm/types'
import fromPairs from 'ramda/src/fromPairs'
import isEmpty from 'ramda/src/isEmpty'
import omit from 'ramda/src/omit'
// property keys that are copied from publishConfig into the manifest
const PUBLISH_CONFIG_WHITELIST = new Set([
// manifest fields that may make sense to overwrite
'bin',
'type',
'imports',
// https://github.com/stereobooster/package.json#package-bundlers
'main',
'module',
'typings',
'types',
'exports',
'browser',
'esnext',
'es2015',
'unpkg',
'umd:main',
// These are useful to hide in order to avoid warnings during local development
'os',
'cpu',
])
const PREPUBLISH_SCRIPTS = [
'prepublishOnly',
'prepack',
'prepare',
'postpack',
'publish',
'postpublish',
]
export default async function makePublishManifest (dir: string, originalManifest: ProjectManifest, opts?: { readmeFile?: string }) {
const publishManifest: ProjectManifest = omit(['pnpm', 'scripts'], originalManifest)
if (originalManifest.scripts != null) {
publishManifest.scripts = omit(PREPUBLISH_SCRIPTS, originalManifest.scripts)
}
for (const depsField of ['dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies']) {
const deps = await makePublishDependencies(dir, originalManifest[depsField])
if (deps != null) {
publishManifest[depsField] = deps
}
}
const { publishConfig } = publishManifest
if (publishConfig != null) {
Object.keys(publishConfig)
.filter(key => PUBLISH_CONFIG_WHITELIST.has(key))
.forEach(key => {
publishManifest[key] = publishConfig[key]
delete publishConfig[key]
})
if (isEmpty(publishConfig)) {
delete publishManifest.publishConfig
}
}
if (opts?.readmeFile) {
publishManifest.readme ??= opts.readmeFile
}
return publishManifest
}
async function makePublishDependencies (dir: string, dependencies: Dependencies | undefined) {
if (dependencies == null) return dependencies
const publishDependencies: Dependencies = fromPairs(
await Promise.all(
Object.entries(dependencies)
.map(async ([depName, depSpec]) => [
depName,
await makePublishDependency(depName, depSpec, dir),
])
) as any, // eslint-disable-line
)
return publishDependencies
}
async function makePublishDependency (depName: string, depSpec: string, dir: string) {
if (!depSpec.startsWith('workspace:')) {
return depSpec
}
// Dependencies with bare "*", "^" and "~" versions
const versionAliasSpecParts = /^workspace:([^@]+@)?([\^~*])$/.exec(depSpec)
if (versionAliasSpecParts != null) {
const { manifest } = await tryReadProjectManifest(path.join(dir, 'node_modules', depName))
if ((manifest == null) || !manifest.version) {
throw new PnpmError(
'CANNOT_RESOLVE_WORKSPACE_PROTOCOL',
`Cannot resolve workspace protocol of dependency "${depName}" ` +
'because this dependency is not installed. Try running "pnpm install".'
)
}
const semverRangeToken = versionAliasSpecParts[2] !== '*' ? versionAliasSpecParts[2] : ''
if (depName !== manifest.name) {
return `npm:${manifest.name!}@${semverRangeToken}${manifest.version}`
}
return `${semverRangeToken}${manifest.version}`
}
if (depSpec.startsWith('workspace:./') || depSpec.startsWith('workspace:../')) {
const { manifest } = await tryReadProjectManifest(path.join(dir, depSpec.slice(10)))
if ((manifest == null) || !manifest.name || !manifest.version) {
throw new PnpmError(
'CANNOT_RESOLVE_WORKSPACE_PROTOCOL',
`Cannot resolve workspace protocol of dependency "${depName}" ` +
'because this dependency is not installed. Try running "pnpm install".'
)
}
if (manifest.name === depName) return `${manifest.version}`
return `npm:${manifest.name}@${manifest.version}`
}
depSpec = depSpec.slice(10)
if (depSpec.includes('@')) {
return `npm:${depSpec}`
}
return depSpec
}