@pnpm/releasing.exportable-manifest 1100.3.4 → 1100.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/lib/index.d.ts +3 -5
- package/lib/index.js +87 -156
- package/lib/jsrProtocol.d.ts +1 -0
- package/lib/jsrProtocol.js +16 -0
- package/lib/overridePublishConfig.js +2 -2
- package/lib/readme.d.ts +25 -0
- package/lib/readme.js +70 -0
- package/lib/transform/bin.d.ts +0 -1
- package/lib/transform/bin.js +0 -1
- package/lib/workspaceLookup.d.ts +7 -0
- package/lib/workspaceLookup.js +59 -0
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @pnpm/exportable-manifest
|
|
2
2
|
|
|
3
|
+
## 1100.3.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies:
|
|
8
|
+
- @pnpm/workspace.project-manifest-reader@1100.1.2
|
|
9
|
+
|
|
10
|
+
## 1100.3.5
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- `pnpm publish` now includes bare `README` files and README files with Markdown extensions such as `readme.markdown` in registry metadata [#12704](https://github.com/pnpm/pnpm/issues/12704).
|
|
15
|
+
|
|
3
16
|
## 1100.3.4
|
|
4
17
|
|
|
5
18
|
### Patch Changes
|
package/lib/index.d.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import type { Catalogs } from '@pnpm/catalogs.types';
|
|
2
2
|
import type { Hooks } from '@pnpm/hooks.pnpmfile';
|
|
3
3
|
import type { ProjectManifest } from '@pnpm/types';
|
|
4
|
+
import { getReadmeRank, isPreferredReadme, type ReadmeCandidate, type ReadmeRank, readReadmeFile } from './readme.js';
|
|
4
5
|
import { type ExportedManifest } from './transform/index.js';
|
|
6
|
+
import { type WorkspacePackageContainer, type WorkspacePackageLookup } from './workspaceLookup.js';
|
|
5
7
|
export { type ExportedManifest };
|
|
6
|
-
export type WorkspacePackageLookup
|
|
7
|
-
manifest: ProjectManifest;
|
|
8
|
-
rootDir?: string;
|
|
9
|
-
}> | Map<string, unknown> | Record<string, unknown> | ((depName: string) => ProjectManifest | undefined);
|
|
8
|
+
export { getReadmeRank, isPreferredReadme, type ReadmeCandidate, type ReadmeRank, readReadmeFile, type WorkspacePackageContainer, type WorkspacePackageLookup, };
|
|
10
9
|
export interface MakePublishManifestOptions {
|
|
11
10
|
catalogs: Catalogs;
|
|
12
11
|
hooks?: Hooks;
|
|
@@ -16,7 +15,6 @@ export interface MakePublishManifestOptions {
|
|
|
16
15
|
workspacePackages?: WorkspacePackageLookup;
|
|
17
16
|
}
|
|
18
17
|
export declare function createExportableManifest(dir: string, originalManifest: ProjectManifest, opts: MakePublishManifestOptions): Promise<ExportedManifest>;
|
|
19
|
-
export declare function readReadmeFile(projectDir: string): Promise<string | undefined>;
|
|
20
18
|
export type PublishDependencyConverter = (depName: string, depSpec: string, context: PublishDependencyConverterContext) => Promise<string> | string;
|
|
21
19
|
export interface PublishDependencyConverterContext {
|
|
22
20
|
dir: string;
|
package/lib/index.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
1
|
import path from 'node:path';
|
|
3
2
|
import { resolveFromCatalog } from '@pnpm/catalogs.resolver';
|
|
4
|
-
import {
|
|
5
|
-
import { parseJsrSpecifier } from '@pnpm/resolving.jsr-specifier-parser';
|
|
3
|
+
import { PnpmError } from '@pnpm/error';
|
|
6
4
|
import { tryReadProjectManifest } from '@pnpm/workspace.project-manifest-reader';
|
|
7
5
|
import { WorkspaceSpec } from '@pnpm/workspace.spec-parser';
|
|
8
6
|
import { clone, omit } from 'ramda';
|
|
7
|
+
import { replaceJsrProtocol } from './jsrProtocol.js';
|
|
9
8
|
import { overridePublishConfig } from './overridePublishConfig.js';
|
|
9
|
+
import { getReadmeRank, isPreferredReadme, readReadmeFile, } from './readme.js';
|
|
10
10
|
import { transform } from './transform/index.js';
|
|
11
|
+
import { buildWorkspaceManifestGetter, } from './workspaceLookup.js';
|
|
11
12
|
export {};
|
|
13
|
+
export { getReadmeRank, isPreferredReadme, readReadmeFile, };
|
|
12
14
|
const PREPUBLISH_SCRIPTS = [
|
|
13
15
|
'prepublishOnly',
|
|
14
16
|
'prepack',
|
|
@@ -18,24 +20,44 @@ const PREPUBLISH_SCRIPTS = [
|
|
|
18
20
|
'postpublish',
|
|
19
21
|
];
|
|
20
22
|
export async function createExportableManifest(dir, originalManifest, opts) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
const publishManifest = initPublishManifest(originalManifest, opts.skipManifestObfuscation);
|
|
24
|
+
const getWorkspaceManifest = buildWorkspaceManifestGetter(opts.workspacePackages);
|
|
25
|
+
await convertManifestDependencies({
|
|
26
|
+
catalogs: opts.catalogs,
|
|
27
|
+
dir,
|
|
28
|
+
getWorkspaceManifest,
|
|
29
|
+
modulesDir: opts.modulesDir,
|
|
30
|
+
originalManifest,
|
|
31
|
+
publishManifest,
|
|
32
|
+
});
|
|
33
|
+
overridePublishConfig(publishManifest);
|
|
34
|
+
if (publishManifest.readme == null && opts.embedReadme) {
|
|
35
|
+
const readme = await readReadmeFile(dir);
|
|
36
|
+
if (readme != null) {
|
|
37
|
+
publishManifest.readme = readme;
|
|
29
38
|
}
|
|
30
39
|
}
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
40
|
+
const finalManifest = await applyPublishHooks(publishManifest, dir, opts.hooks?.beforePacking);
|
|
41
|
+
return transform(finalManifest);
|
|
42
|
+
}
|
|
43
|
+
function initPublishManifest(originalManifest, skipObfuscation) {
|
|
44
|
+
if (skipObfuscation) {
|
|
45
|
+
return omit(['pnpm'], clone(originalManifest));
|
|
46
|
+
}
|
|
47
|
+
const publishManifest = omit(['scripts', 'packageManager', 'pnpm'], originalManifest);
|
|
48
|
+
if (originalManifest.scripts != null) {
|
|
49
|
+
publishManifest.scripts = omit(PREPUBLISH_SCRIPTS, originalManifest.scripts);
|
|
50
|
+
}
|
|
51
|
+
return publishManifest;
|
|
52
|
+
}
|
|
53
|
+
async function convertManifestDependencies(params) {
|
|
54
|
+
const { catalogs, dir, getWorkspaceManifest, modulesDir, originalManifest, publishManifest } = params;
|
|
55
|
+
const replaceCatalogProtocol = resolveCatalogProtocol.bind(null, resolveFromCatalog.bind(null, catalogs));
|
|
34
56
|
const convertDependencyForPublish = combineConverters(replaceCatalogProtocol, replaceWorkspaceProtocol, replaceJsrProtocol);
|
|
35
57
|
await Promise.all(['dependencies', 'devDependencies', 'optionalDependencies'].map(async (depsField) => {
|
|
36
58
|
const deps = await makePublishDependencies(dir, originalManifest[depsField], {
|
|
37
|
-
modulesDir: opts?.modulesDir,
|
|
38
59
|
convertDependencyForPublish,
|
|
60
|
+
modulesDir,
|
|
39
61
|
workspacePackages: getWorkspaceManifest,
|
|
40
62
|
});
|
|
41
63
|
if (deps != null) {
|
|
@@ -46,56 +68,25 @@ export async function createExportableManifest(dir, originalManifest, opts) {
|
|
|
46
68
|
if (peerDependencies) {
|
|
47
69
|
const convertPeersForPublish = combineConverters(replaceCatalogProtocol, replaceWorkspaceProtocolPeerDependency, replaceJsrProtocol);
|
|
48
70
|
publishManifest.peerDependencies = await makePublishDependencies(dir, peerDependencies, {
|
|
49
|
-
modulesDir: opts?.modulesDir,
|
|
50
71
|
convertDependencyForPublish: convertPeersForPublish,
|
|
72
|
+
modulesDir,
|
|
51
73
|
workspacePackages: getWorkspaceManifest,
|
|
52
74
|
});
|
|
53
75
|
}
|
|
54
|
-
overridePublishConfig(publishManifest);
|
|
55
|
-
if (publishManifest.readme == null && opts?.embedReadme) {
|
|
56
|
-
const readme = await readReadmeFile(dir);
|
|
57
|
-
if (readme != null) {
|
|
58
|
-
publishManifest.readme = readme;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
for (const hook of opts?.hooks?.beforePacking ?? []) {
|
|
62
|
-
// eslint-disable-next-line no-await-in-loop
|
|
63
|
-
publishManifest = await hook(publishManifest, dir) ?? publishManifest;
|
|
64
|
-
}
|
|
65
|
-
return transform(publishManifest);
|
|
66
76
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
const README_READ_FLAGS = fs.constants.O_RDONLY | (process.platform === 'win32' ? 0 : fs.constants.O_NOFOLLOW);
|
|
73
|
-
export async function readReadmeFile(projectDir) {
|
|
74
|
-
const entries = await fs.promises.readdir(projectDir, { withFileTypes: true });
|
|
75
|
-
// Only embed a regular README.md file — a symlink is skipped (see README_READ_FLAGS).
|
|
76
|
-
const readmeEntry = entries.find((entry) => entry.isFile() && /^readme\.md$/i.test(entry.name));
|
|
77
|
-
if (readmeEntry == null)
|
|
78
|
-
return undefined;
|
|
79
|
-
let handle;
|
|
80
|
-
try {
|
|
81
|
-
handle = await fs.promises.open(path.join(projectDir, readmeEntry.name), README_READ_FLAGS);
|
|
82
|
-
return await handle.readFile('utf8');
|
|
83
|
-
}
|
|
84
|
-
catch (err) {
|
|
85
|
-
// ELOOP: the entry is a symlink after all (a concurrent swap) — skip it, as the isFile() check intended.
|
|
86
|
-
if (isError(err) && 'code' in err && err.code === 'ELOOP')
|
|
87
|
-
return undefined;
|
|
88
|
-
throw err;
|
|
89
|
-
}
|
|
90
|
-
finally {
|
|
91
|
-
await handle?.close();
|
|
77
|
+
async function applyPublishHooks(manifest, dir, hooks) {
|
|
78
|
+
let result = manifest;
|
|
79
|
+
for (const hook of hooks ?? []) {
|
|
80
|
+
// eslint-disable-next-line no-await-in-loop -- each hook receives the manifest returned by the previous one
|
|
81
|
+
result = await hook(result, dir) ?? result;
|
|
92
82
|
}
|
|
83
|
+
return result;
|
|
93
84
|
}
|
|
94
85
|
function combineConverters(...converters) {
|
|
95
86
|
return async (depName, depSpec, context) => {
|
|
96
87
|
let bareSpecifier = depSpec;
|
|
97
88
|
for (const converter of converters) {
|
|
98
|
-
// eslint-disable-next-line no-await-in-loop
|
|
89
|
+
// eslint-disable-next-line no-await-in-loop -- each converter receives the specifier returned by the previous one
|
|
99
90
|
bareSpecifier = await converter(depName, bareSpecifier, context);
|
|
100
91
|
}
|
|
101
92
|
return bareSpecifier;
|
|
@@ -107,60 +98,6 @@ async function makePublishDependencies(dir, dependencies, { modulesDir, convertD
|
|
|
107
98
|
const publishDependencies = await Promise.all(Object.entries(dependencies).map(async ([depName, depSpec]) => [depName, await convertDependencyForPublish(depName, depSpec, { dir, modulesDir, workspacePackages })]));
|
|
108
99
|
return Object.fromEntries(publishDependencies);
|
|
109
100
|
}
|
|
110
|
-
function extractManifest(val) {
|
|
111
|
-
if (!val || typeof val !== 'object')
|
|
112
|
-
return undefined;
|
|
113
|
-
if ('manifest' in val && val.manifest && typeof val.manifest === 'object') {
|
|
114
|
-
return val.manifest;
|
|
115
|
-
}
|
|
116
|
-
if ('package' in val && val.package && typeof val.package === 'object' && 'manifest' in val.package && val.package.manifest && typeof val.package.manifest === 'object') {
|
|
117
|
-
return val.package.manifest;
|
|
118
|
-
}
|
|
119
|
-
if ('name' in val && typeof val.name === 'string') {
|
|
120
|
-
return val;
|
|
121
|
-
}
|
|
122
|
-
return undefined;
|
|
123
|
-
}
|
|
124
|
-
function buildWorkspaceManifestGetter(workspacePackages) {
|
|
125
|
-
if (!workspacePackages)
|
|
126
|
-
return undefined;
|
|
127
|
-
if (typeof workspacePackages === 'function') {
|
|
128
|
-
return workspacePackages;
|
|
129
|
-
}
|
|
130
|
-
const byName = new Map();
|
|
131
|
-
const addManifest = (val) => {
|
|
132
|
-
const manifest = extractManifest(val);
|
|
133
|
-
if (!manifest?.name)
|
|
134
|
-
return;
|
|
135
|
-
const existing = byName.get(manifest.name);
|
|
136
|
-
if (!existing || (!existing.version && manifest.version)) {
|
|
137
|
-
byName.set(manifest.name, manifest);
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
if (Array.isArray(workspacePackages)) {
|
|
141
|
-
for (const pkg of workspacePackages) {
|
|
142
|
-
addManifest(pkg);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
else if (workspacePackages instanceof Map) {
|
|
146
|
-
for (const val of workspacePackages.values()) {
|
|
147
|
-
if (val instanceof Map) {
|
|
148
|
-
for (const subVal of val.values()) {
|
|
149
|
-
addManifest(subVal);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
else {
|
|
153
|
-
addManifest(val);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
else if (typeof workspacePackages === 'object') {
|
|
158
|
-
for (const val of Object.values(workspacePackages)) {
|
|
159
|
-
addManifest(val);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
return (depName) => byName.get(depName);
|
|
163
|
-
}
|
|
164
101
|
async function readAndCheckManifest(depName, dependencyDir, getWorkspaceManifest, targetPkgName) {
|
|
165
102
|
const { manifest: dirManifest } = await tryReadProjectManifest(dependencyDir);
|
|
166
103
|
if (dirManifest?.name && dirManifest?.version) {
|
|
@@ -171,6 +108,9 @@ async function readAndCheckManifest(depName, dependencyDir, getWorkspaceManifest
|
|
|
171
108
|
if (workspaceManifest?.name && workspaceManifest?.version) {
|
|
172
109
|
return workspaceManifest;
|
|
173
110
|
}
|
|
111
|
+
return handleMissingOrInvalidManifest(depName, dirManifest ?? undefined, workspaceManifest);
|
|
112
|
+
}
|
|
113
|
+
function handleMissingOrInvalidManifest(depName, dirManifest, workspaceManifest) {
|
|
174
114
|
const found = dirManifest?.name || dirManifest?.version
|
|
175
115
|
? dirManifest
|
|
176
116
|
: workspaceManifest?.name || workspaceManifest?.version
|
|
@@ -195,36 +135,39 @@ function resolveCatalogProtocol(catalogResolver, alias, bareSpecifier) {
|
|
|
195
135
|
case 'misconfiguration': throw result.error;
|
|
196
136
|
}
|
|
197
137
|
}
|
|
198
|
-
async function replaceWorkspaceProtocol(depName, depSpec,
|
|
138
|
+
async function replaceWorkspaceProtocol(depName, depSpec, context) {
|
|
199
139
|
if (!depSpec.startsWith('workspace:')) {
|
|
200
140
|
return depSpec;
|
|
201
141
|
}
|
|
202
142
|
// Dependencies with bare "*", "^", "~" versions, or no version (workspace:)
|
|
203
143
|
const versionAliasSpecParts = /^workspace:(?:(.+)@)?([\^~*])?$/.exec(depSpec);
|
|
204
144
|
if (versionAliasSpecParts != null) {
|
|
205
|
-
|
|
206
|
-
const targetPkgName = versionAliasSpecParts[1];
|
|
207
|
-
const manifest = await readAndCheckManifest(depName, path.join(modulesDir, depName), workspacePackages, targetPkgName);
|
|
208
|
-
const specifierSuffix = versionAliasSpecParts[2];
|
|
209
|
-
const semverRangeToken = specifierSuffix === '^' || specifierSuffix === '~' ? specifierSuffix : '';
|
|
210
|
-
if (depName !== manifest.name) {
|
|
211
|
-
return `npm:${manifest.name}@${semverRangeToken}${manifest.version}`;
|
|
212
|
-
}
|
|
213
|
-
return `${semverRangeToken}${manifest.version}`;
|
|
145
|
+
return resolveVersionAliasWorkspaceSpec(depName, versionAliasSpecParts, context);
|
|
214
146
|
}
|
|
215
147
|
if (depSpec.startsWith('workspace:./') || depSpec.startsWith('workspace:../')) {
|
|
216
|
-
|
|
217
|
-
if (manifest.name === depName)
|
|
218
|
-
return `${manifest.version}`;
|
|
219
|
-
return `npm:${manifest.name}@${manifest.version}`;
|
|
220
|
-
}
|
|
221
|
-
depSpec = depSpec.slice(10);
|
|
222
|
-
if (depSpec.includes('@')) {
|
|
223
|
-
return `npm:${depSpec}`;
|
|
148
|
+
return resolveRelativeWorkspaceSpec(depName, depSpec.slice(10), context);
|
|
224
149
|
}
|
|
225
|
-
|
|
150
|
+
const spec = depSpec.slice(10);
|
|
151
|
+
return spec.includes('@') ? `npm:${spec}` : spec;
|
|
152
|
+
}
|
|
153
|
+
async function resolveVersionAliasWorkspaceSpec(depName, parts, context) {
|
|
154
|
+
const modulesDir = context.modulesDir ?? path.join(context.dir, 'node_modules');
|
|
155
|
+
const targetPkgName = parts[1];
|
|
156
|
+
const manifest = await readAndCheckManifest(depName, path.join(modulesDir, depName), context.workspacePackages, targetPkgName);
|
|
157
|
+
const specifierSuffix = parts[2];
|
|
158
|
+
const semverRangeToken = specifierSuffix === '^' || specifierSuffix === '~' ? specifierSuffix : '';
|
|
159
|
+
if (depName !== manifest.name) {
|
|
160
|
+
return `npm:${manifest.name}@${semverRangeToken}${manifest.version}`;
|
|
161
|
+
}
|
|
162
|
+
return `${semverRangeToken}${manifest.version}`;
|
|
226
163
|
}
|
|
227
|
-
async function
|
|
164
|
+
async function resolveRelativeWorkspaceSpec(depName, relPath, context) {
|
|
165
|
+
const manifest = await readAndCheckManifest(depName, path.join(context.dir, relPath), context.workspacePackages);
|
|
166
|
+
if (manifest.name === depName)
|
|
167
|
+
return `${manifest.version}`;
|
|
168
|
+
return `npm:${manifest.name}@${manifest.version}`;
|
|
169
|
+
}
|
|
170
|
+
async function replaceWorkspaceProtocolPeerDependency(depName, depSpec, context) {
|
|
228
171
|
if (!depSpec.includes('workspace:')) {
|
|
229
172
|
return depSpec;
|
|
230
173
|
}
|
|
@@ -236,35 +179,23 @@ async function replaceWorkspaceProtocolPeerDependency(depName, depSpec, { dir, m
|
|
|
236
179
|
return `npm:${workspaceSpec.alias}@${version}`;
|
|
237
180
|
}
|
|
238
181
|
if (workspaceSpec?.version.startsWith('./') || workspaceSpec?.version.startsWith('../')) {
|
|
239
|
-
return replaceWorkspaceProtocol(depName, depSpec,
|
|
182
|
+
return replaceWorkspaceProtocol(depName, depSpec, context);
|
|
240
183
|
}
|
|
241
|
-
|
|
242
|
-
const workspaceSemverRegex = /workspace:([\^~*]|>=|>|<=|<)?((\d+|[xX*])(\.(\d+|[xX*])){0,2})?/;
|
|
243
|
-
const versionAliasSpecParts = workspaceSemverRegex.exec(depSpec);
|
|
244
|
-
if (versionAliasSpecParts != null) {
|
|
245
|
-
const [, semverRangGroup = '', version] = versionAliasSpecParts;
|
|
246
|
-
if (version) {
|
|
247
|
-
return depSpec.replace('workspace:', '');
|
|
248
|
-
}
|
|
249
|
-
modulesDir = modulesDir ?? path.join(dir, 'node_modules');
|
|
250
|
-
const manifest = await readAndCheckManifest(depName, path.join(modulesDir, depName), workspacePackages);
|
|
251
|
-
const semverRangeToken = semverRangGroup !== '*' ? semverRangGroup : '';
|
|
252
|
-
return depSpec.replace(workspaceSemverRegex, `${semverRangeToken}${manifest.version}`);
|
|
253
|
-
}
|
|
254
|
-
return depSpec.replace('workspace:', '');
|
|
184
|
+
return resolvePeerWorkspaceSemver(depName, depSpec, context);
|
|
255
185
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
186
|
+
const WORKSPACE_SEMVER_REGEX = /workspace:([\^~*]|>=|>|<=|<)?((\d+|[xX*])(\.(\d+|[xX*])){0,2})?/;
|
|
187
|
+
async function resolvePeerWorkspaceSemver(depName, depSpec, context) {
|
|
188
|
+
const versionAliasSpecParts = WORKSPACE_SEMVER_REGEX.exec(depSpec);
|
|
189
|
+
if (versionAliasSpecParts == null) {
|
|
190
|
+
return depSpec.replace('workspace:', '');
|
|
191
|
+
}
|
|
192
|
+
const [, semverRangeGroup = '', version] = versionAliasSpecParts;
|
|
193
|
+
if (version) {
|
|
194
|
+
return depSpec.replace('workspace:', '');
|
|
195
|
+
}
|
|
196
|
+
const modulesDir = context.modulesDir ?? path.join(context.dir, 'node_modules');
|
|
197
|
+
const manifest = await readAndCheckManifest(depName, path.join(modulesDir, depName), context.workspacePackages);
|
|
198
|
+
const semverRangeToken = semverRangeGroup !== '*' ? semverRangeGroup : '';
|
|
199
|
+
return depSpec.replace(WORKSPACE_SEMVER_REGEX, `${semverRangeToken}${manifest.version}`);
|
|
269
200
|
}
|
|
270
201
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function replaceJsrProtocol(depName: string, depSpec: string): Promise<string>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { parseJsrSpecifier } from '@pnpm/resolving.jsr-specifier-parser';
|
|
2
|
+
export async function replaceJsrProtocol(depName, depSpec) {
|
|
3
|
+
const spec = parseJsrSpecifier(depSpec, depName);
|
|
4
|
+
if (spec == null) {
|
|
5
|
+
return depSpec;
|
|
6
|
+
}
|
|
7
|
+
return createNpmAliasedSpecifier(spec.npmPkgName, spec.versionSelector);
|
|
8
|
+
}
|
|
9
|
+
function createNpmAliasedSpecifier(npmPkgName, versionSelector) {
|
|
10
|
+
const npmPkgSpecifier = `npm:${npmPkgName}`;
|
|
11
|
+
if (!versionSelector) {
|
|
12
|
+
return npmPkgSpecifier;
|
|
13
|
+
}
|
|
14
|
+
return `${npmPkgSpecifier}@${versionSelector}`;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=jsrProtocol.js.map
|
|
@@ -33,11 +33,11 @@ export function overridePublishConfig(publishManifest) {
|
|
|
33
33
|
if (!publishManifest.publishConfig)
|
|
34
34
|
return;
|
|
35
35
|
const publishConfig = { ...publishManifest.publishConfig };
|
|
36
|
+
const manifestFields = publishManifest;
|
|
36
37
|
for (const key in publishConfig) {
|
|
37
38
|
if (!PUBLISH_CONFIG_WHITELIST.has(key))
|
|
38
39
|
continue;
|
|
39
|
-
|
|
40
|
-
publishManifest[key] = value; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
40
|
+
manifestFields[key] = publishConfig[key];
|
|
41
41
|
delete publishConfig[key];
|
|
42
42
|
}
|
|
43
43
|
if (isEmpty(publishConfig)) {
|
package/lib/readme.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
declare const README_RANK: {
|
|
2
|
+
readonly bare: 1;
|
|
3
|
+
readonly markdown: 2;
|
|
4
|
+
readonly readmeMd: 3;
|
|
5
|
+
};
|
|
6
|
+
export interface ReadmeCandidate {
|
|
7
|
+
fileName: string;
|
|
8
|
+
rank: ReadmeRank;
|
|
9
|
+
}
|
|
10
|
+
/** How npm ranks a package-root file as the package's README. A higher rank wins. */
|
|
11
|
+
export type ReadmeRank = typeof README_RANK[keyof typeof README_RANK];
|
|
12
|
+
/**
|
|
13
|
+
* Rank a filename as a README candidate, or return `undefined` if npm would not use it as the
|
|
14
|
+
* package's README. npm matches the bare `README` case-sensitively and accepts `README.*` whose
|
|
15
|
+
* extension matches `/.m?a?r?k?d?o?w?n?$/i`.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getReadmeRank(fileName: string): ReadmeRank | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Whether README `candidate` should replace the `current` selection. A higher rank wins. Equal
|
|
20
|
+
* ranks keep the lower filename, so the choice does not depend on directory or archive order, and
|
|
21
|
+
* an equal filename replaces, so the last duplicate archive entry wins as it would on extraction.
|
|
22
|
+
*/
|
|
23
|
+
export declare function isPreferredReadme(candidate: ReadmeCandidate, current: ReadmeCandidate | undefined): boolean;
|
|
24
|
+
export declare function readReadmeFile(projectDir: string): Promise<string | undefined>;
|
|
25
|
+
export {};
|
package/lib/readme.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { isError } from '@pnpm/error';
|
|
4
|
+
const README_RANK = {
|
|
5
|
+
bare: 1,
|
|
6
|
+
markdown: 2,
|
|
7
|
+
readmeMd: 3,
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Rank a filename as a README candidate, or return `undefined` if npm would not use it as the
|
|
11
|
+
* package's README. npm matches the bare `README` case-sensitively and accepts `README.*` whose
|
|
12
|
+
* extension matches `/.m?a?r?k?d?o?w?n?$/i`.
|
|
13
|
+
*/
|
|
14
|
+
export function getReadmeRank(fileName) {
|
|
15
|
+
if (/^readme\.md$/i.test(fileName))
|
|
16
|
+
return README_RANK.readmeMd;
|
|
17
|
+
if (fileName === 'README')
|
|
18
|
+
return README_RANK.bare;
|
|
19
|
+
if (/^readme\./i.test(fileName) && /\.m?a?r?k?d?o?w?n?$/i.test(fileName))
|
|
20
|
+
return README_RANK.markdown;
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Whether README `candidate` should replace the `current` selection. A higher rank wins. Equal
|
|
25
|
+
* ranks keep the lower filename, so the choice does not depend on directory or archive order, and
|
|
26
|
+
* an equal filename replaces, so the last duplicate archive entry wins as it would on extraction.
|
|
27
|
+
*/
|
|
28
|
+
export function isPreferredReadme(candidate, current) {
|
|
29
|
+
if (current == null || candidate.rank > current.rank)
|
|
30
|
+
return true;
|
|
31
|
+
return candidate.rank === current.rank && candidate.fileName <= current.fileName;
|
|
32
|
+
}
|
|
33
|
+
// `O_NOFOLLOW` makes the open itself refuse a symlink at the final path component, closing the
|
|
34
|
+
// TOCTOU window between the `readdir` type check and the read: a symlink swapped in for the
|
|
35
|
+
// selected README after the check can't redirect the read outside the project and leak its target
|
|
36
|
+
// into the published manifest. Windows lacks the flag (and requires privileges to create symlinks),
|
|
37
|
+
// so it falls back to a plain read.
|
|
38
|
+
const README_READ_FLAGS = fs.constants.O_RDONLY | (process.platform === 'win32' ? 0 : fs.constants.O_NOFOLLOW);
|
|
39
|
+
export async function readReadmeFile(projectDir) {
|
|
40
|
+
const entries = await fs.promises.readdir(projectDir, { withFileTypes: true });
|
|
41
|
+
let readme;
|
|
42
|
+
for (const entry of entries) {
|
|
43
|
+
const rank = getReadmeRank(entry.name);
|
|
44
|
+
if (rank == null || !entry.isFile())
|
|
45
|
+
continue;
|
|
46
|
+
const candidate = { fileName: entry.name, rank };
|
|
47
|
+
if (isPreferredReadme(candidate, readme))
|
|
48
|
+
readme = candidate;
|
|
49
|
+
}
|
|
50
|
+
if (readme == null)
|
|
51
|
+
return undefined;
|
|
52
|
+
return readReadmeContent(projectDir, readme.fileName);
|
|
53
|
+
}
|
|
54
|
+
async function readReadmeContent(projectDir, fileName) {
|
|
55
|
+
let handle;
|
|
56
|
+
try {
|
|
57
|
+
handle = await fs.promises.open(path.join(projectDir, fileName), README_READ_FLAGS);
|
|
58
|
+
return await handle.readFile('utf8');
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
// ELOOP: the entry is a symlink after all (a concurrent swap) — skip it, as the isFile() check intended.
|
|
62
|
+
if (isError(err) && 'code' in err && err.code === 'ELOOP')
|
|
63
|
+
return undefined;
|
|
64
|
+
throw err;
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
await handle?.close();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=readme.js.map
|
package/lib/transform/bin.d.ts
CHANGED
|
@@ -6,7 +6,6 @@ type Output<Manifest extends Input> = Omit<Manifest, 'bin'> & Pick<ExportedManif
|
|
|
6
6
|
export declare function transformBin<Manifest extends Input>(manifest: Manifest): Output<Manifest>;
|
|
7
7
|
/**
|
|
8
8
|
* The property `"bin"` of a `package.json` could be either an object or a string.
|
|
9
|
-
* This function normalizes either forms into an object.
|
|
10
9
|
*/
|
|
11
10
|
export declare function normalizeBinObject(pkgName: string, bin: string | Record<string, string>): Record<string, string>;
|
|
12
11
|
export declare class InvalidScopedPackageNameError extends PnpmError {
|
package/lib/transform/bin.js
CHANGED
|
@@ -10,7 +10,6 @@ export function transformBin(manifest) {
|
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
12
|
* The property `"bin"` of a `package.json` could be either an object or a string.
|
|
13
|
-
* This function normalizes either forms into an object.
|
|
14
13
|
*/
|
|
15
14
|
export function normalizeBinObject(pkgName, bin) {
|
|
16
15
|
if (typeof bin === 'object')
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ProjectManifest } from '@pnpm/types';
|
|
2
|
+
export type WorkspacePackageContainer = Array<{
|
|
3
|
+
manifest: ProjectManifest;
|
|
4
|
+
rootDir?: string;
|
|
5
|
+
}> | Map<string, unknown> | Record<string, unknown>;
|
|
6
|
+
export type WorkspacePackageLookup = WorkspacePackageContainer | ((depName: string) => ProjectManifest | undefined);
|
|
7
|
+
export declare function buildWorkspaceManifestGetter(workspacePackages?: WorkspacePackageLookup): ((depName: string) => ProjectManifest | undefined) | undefined;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export function buildWorkspaceManifestGetter(workspacePackages) {
|
|
2
|
+
if (!workspacePackages)
|
|
3
|
+
return undefined;
|
|
4
|
+
if (typeof workspacePackages === 'function') {
|
|
5
|
+
return workspacePackages;
|
|
6
|
+
}
|
|
7
|
+
const byName = new Map();
|
|
8
|
+
collectWorkspaceManifests(workspacePackages, byName);
|
|
9
|
+
return (depName) => byName.get(depName);
|
|
10
|
+
}
|
|
11
|
+
function collectWorkspaceManifests(workspacePackages, byName) {
|
|
12
|
+
const add = (val) => addManifestEntry(val, byName);
|
|
13
|
+
if (Array.isArray(workspacePackages)) {
|
|
14
|
+
for (const pkg of workspacePackages)
|
|
15
|
+
add(pkg);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (workspacePackages instanceof Map) {
|
|
19
|
+
collectFromMap(workspacePackages, add);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
for (const val of Object.values(workspacePackages))
|
|
23
|
+
add(val);
|
|
24
|
+
}
|
|
25
|
+
function collectFromMap(map, add) {
|
|
26
|
+
for (const val of map.values()) {
|
|
27
|
+
if (val instanceof Map) {
|
|
28
|
+
for (const subVal of val.values())
|
|
29
|
+
add(subVal);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
add(val);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function addManifestEntry(val, byName) {
|
|
37
|
+
const manifest = extractManifest(val);
|
|
38
|
+
if (!manifest?.name)
|
|
39
|
+
return;
|
|
40
|
+
const existing = byName.get(manifest.name);
|
|
41
|
+
if (!existing || (!existing.version && manifest.version)) {
|
|
42
|
+
byName.set(manifest.name, manifest);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function extractManifest(val) {
|
|
46
|
+
if (!val || typeof val !== 'object')
|
|
47
|
+
return undefined;
|
|
48
|
+
if ('manifest' in val && val.manifest && typeof val.manifest === 'object') {
|
|
49
|
+
return val.manifest;
|
|
50
|
+
}
|
|
51
|
+
if ('package' in val && val.package && typeof val.package === 'object' && 'manifest' in val.package && val.package.manifest && typeof val.package.manifest === 'object') {
|
|
52
|
+
return val.package.manifest;
|
|
53
|
+
}
|
|
54
|
+
if ('name' in val && typeof val.name === 'string') {
|
|
55
|
+
return val;
|
|
56
|
+
}
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=workspaceLookup.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnpm/releasing.exportable-manifest",
|
|
3
|
-
"version": "1100.3.
|
|
3
|
+
"version": "1100.3.6",
|
|
4
4
|
"description": "Creates an exportable manifest",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pnpm",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"@pnpm/error": "1100.2.1",
|
|
34
34
|
"@pnpm/resolving.jsr-specifier-parser": "1100.0.9",
|
|
35
35
|
"@pnpm/types": "1102.1.1",
|
|
36
|
-
"@pnpm/workspace.project-manifest-reader": "1100.1.
|
|
36
|
+
"@pnpm/workspace.project-manifest-reader": "1100.1.2",
|
|
37
37
|
"@pnpm/workspace.spec-parser": "1100.0.1",
|
|
38
38
|
"ramda": "npm:@pnpm/ramda@0.28.1"
|
|
39
39
|
},
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
"@jest/globals": "30.4.1",
|
|
42
42
|
"@pnpm/catalogs.config": "1100.0.9",
|
|
43
43
|
"@pnpm/catalogs.types": "1100.0.1",
|
|
44
|
-
"@pnpm/hooks.pnpmfile": "1100.0.
|
|
45
|
-
"@pnpm/prepare": "1100.0.
|
|
46
|
-
"@pnpm/releasing.exportable-manifest": "1100.3.
|
|
44
|
+
"@pnpm/hooks.pnpmfile": "1100.0.35",
|
|
45
|
+
"@pnpm/prepare": "1100.0.35",
|
|
46
|
+
"@pnpm/releasing.exportable-manifest": "1100.3.6",
|
|
47
47
|
"@types/cross-spawn": "^6.0.6",
|
|
48
48
|
"@types/ramda": "0.32.0",
|
|
49
49
|
"cross-spawn": "^7.0.6",
|