@pnpm/workspace.workspace-manifest-writer 1100.0.21 → 1100.1.0
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 +17 -0
- package/lib/index.d.ts +8 -1
- package/lib/index.js +78 -9
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @pnpm/workspace.manifest-writer
|
|
2
2
|
|
|
3
|
+
## 1100.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Added a new setting `minimumReleaseAgeExcludePrune`. When enabled, `pnpm add`, `pnpm update`, and `pnpm remove` prune the entries of `minimumReleaseAgeExclude` in `pnpm-workspace.yaml` that the freshly written lockfile no longer resolves: versions that are gone are dropped (an entry is removed once none of its versions remain), and entries for packages that are no longer in the lockfile are removed too. Name patterns (`@scope/*`) are always kept. The cleanup is skipped when the install's lockfile does not cover the whole workspace (`sharedWorkspaceLockfile: false`), since entries another project still needs would look stale.
|
|
8
|
+
|
|
9
|
+
Renamed `cleanupUnusedCatalogs` to `catalogPrune`, so that catalog pruning and release-age exclude pruning use one vocabulary. `cleanupUnusedCatalogs` continues to work; when both are set, `catalogPrune` wins.
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- `pnpm config delete <key>` no longer fails with `ENOENT` when the config file it would edit does not exist. Clearing a setting that was never set is a no-op [#13651](https://github.com/pnpm/pnpm/issues/13651).
|
|
14
|
+
|
|
15
|
+
- Updated dependencies:
|
|
16
|
+
- @pnpm/config.parse-overrides@1100.1.3
|
|
17
|
+
- @pnpm/config.version-policy@1100.2.0
|
|
18
|
+
- @pnpm/workspace.workspace-manifest-reader@1100.1.6
|
|
19
|
+
|
|
3
20
|
## 1100.0.21
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
package/lib/index.d.ts
CHANGED
|
@@ -10,8 +10,15 @@ export declare function updateWorkspaceManifest(dir: string, opts: {
|
|
|
10
10
|
updatedOverrides?: Record<string, string>;
|
|
11
11
|
addedMinimumReleaseAgeExcludes?: string[];
|
|
12
12
|
fileName?: FileName;
|
|
13
|
-
|
|
13
|
+
catalogPrune?: boolean;
|
|
14
14
|
allProjects?: Project[];
|
|
15
|
+
/**
|
|
16
|
+
* Package name → the versions the freshly resolved lockfile records.
|
|
17
|
+
* Present only under `minimumReleaseAgeExcludePrune`, and only when the
|
|
18
|
+
* lockfile covers every project `minimumReleaseAgeExclude` governs;
|
|
19
|
+
* absent, the cleanup pass does not run.
|
|
20
|
+
*/
|
|
21
|
+
resolvedPackageVersions?: ReadonlyMap<string, ReadonlySet<string>>;
|
|
15
22
|
}): Promise<void>;
|
|
16
23
|
export interface NewCatalogs {
|
|
17
24
|
[catalogName: string]: {
|
package/lib/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import util from 'node:util';
|
|
4
4
|
import { parsePkgAndParentSelector } from '@pnpm/config.parse-overrides';
|
|
5
|
-
import { mergePackageVersionSpecs } from '@pnpm/config.version-policy';
|
|
5
|
+
import { mergePackageVersionSpecs, parseVersionPolicyRule } from '@pnpm/config.version-policy';
|
|
6
6
|
import { WORKSPACE_MANIFEST_FILENAME } from '@pnpm/constants';
|
|
7
7
|
import { lexCompare } from '@pnpm/text.ordinal-comparator';
|
|
8
8
|
import { validateWorkspaceManifest } from '@pnpm/workspace.workspace-manifest-reader';
|
|
@@ -41,20 +41,25 @@ export async function updateWorkspaceManifest(dir, opts) {
|
|
|
41
41
|
manifest ??= {};
|
|
42
42
|
const originalKeyOrder = captureKeyOrder(manifest);
|
|
43
43
|
let shouldBeUpdated = opts.updatedCatalogs != null && addCatalogs(manifest, opts.updatedCatalogs);
|
|
44
|
-
if (opts.
|
|
44
|
+
if (opts.catalogPrune) {
|
|
45
45
|
shouldBeUpdated = removePackagesFromWorkspaceCatalog(manifest, opts.allProjects ?? []) || shouldBeUpdated;
|
|
46
46
|
}
|
|
47
47
|
const updatedFields = { ...opts.updatedFields };
|
|
48
48
|
for (const [key, value] of Object.entries(updatedFields)) {
|
|
49
|
-
if (
|
|
49
|
+
if (value == null) {
|
|
50
|
+
// Clearing a field the manifest never had changes nothing. Counting it as
|
|
51
|
+
// an update would take the empty-manifest branch below and try to remove a
|
|
52
|
+
// file that may not exist.
|
|
53
|
+
if (!Object.hasOwn(manifest, key))
|
|
54
|
+
continue;
|
|
50
55
|
shouldBeUpdated = true;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
manifest[key] = value;
|
|
56
|
-
}
|
|
56
|
+
delete manifest[key];
|
|
57
|
+
continue;
|
|
57
58
|
}
|
|
59
|
+
if (equals(manifest[key], value))
|
|
60
|
+
continue;
|
|
61
|
+
shouldBeUpdated = true;
|
|
62
|
+
manifest[key] = value;
|
|
58
63
|
}
|
|
59
64
|
if (opts.updatedOverrides) {
|
|
60
65
|
manifest.overrides ??= {};
|
|
@@ -65,6 +70,11 @@ export async function updateWorkspaceManifest(dir, opts) {
|
|
|
65
70
|
}
|
|
66
71
|
}
|
|
67
72
|
}
|
|
73
|
+
if (opts.resolvedPackageVersions != null) {
|
|
74
|
+
shouldBeUpdated = pruneMinimumReleaseAgeExcludes(manifest, opts.resolvedPackageVersions) || shouldBeUpdated;
|
|
75
|
+
}
|
|
76
|
+
// Merged after the cleanup pass so entries approved during this install
|
|
77
|
+
// are never pruned by it in the same write.
|
|
68
78
|
if (opts.addedMinimumReleaseAgeExcludes?.length) {
|
|
69
79
|
const existing = manifest.minimumReleaseAgeExclude ?? [];
|
|
70
80
|
const merged = mergePackageVersionSpecs([...existing, ...opts.addedMinimumReleaseAgeExcludes]);
|
|
@@ -196,6 +206,65 @@ function addPackageReference(packageReferences, pkgName, version) {
|
|
|
196
206
|
}
|
|
197
207
|
packageReferences[pkgName].add(version);
|
|
198
208
|
}
|
|
209
|
+
// The `minimumReleaseAgeExcludePrune` pass. An entry is dropped when the
|
|
210
|
+
// freshly resolved lockfile no longer contains what it names: exact versions
|
|
211
|
+
// that were not resolved are dropped (the entry goes away once none remain),
|
|
212
|
+
// and a bare-name entry goes away when the package is absent entirely. Glob
|
|
213
|
+
// patterns always stay — they are forward-looking and can't be proven stale.
|
|
214
|
+
// Entries that fail to parse stay untouched so cleanup never breaks an
|
|
215
|
+
// install.
|
|
216
|
+
function pruneMinimumReleaseAgeExcludes(manifest, resolvedPackageVersions) {
|
|
217
|
+
const excludes = manifest.minimumReleaseAgeExclude;
|
|
218
|
+
if (excludes == null || excludes.length === 0) {
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
const survivingSpecs = [];
|
|
222
|
+
let changed = false;
|
|
223
|
+
for (const entry of excludes) {
|
|
224
|
+
let packageName;
|
|
225
|
+
let exactVersions;
|
|
226
|
+
try {
|
|
227
|
+
const rule = parseVersionPolicyRule(entry);
|
|
228
|
+
packageName = rule.packageName;
|
|
229
|
+
exactVersions = rule.exactVersions;
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
survivingSpecs.push(entry);
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
if (exactVersions.length === 0) {
|
|
236
|
+
if (packageName.includes('*') || resolvedPackageVersions.has(packageName)) {
|
|
237
|
+
survivingSpecs.push(entry);
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
changed = true;
|
|
241
|
+
}
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
const resolved = resolvedPackageVersions.get(packageName);
|
|
245
|
+
const survivingVersions = exactVersions.filter((version) => resolved?.has(version));
|
|
246
|
+
if (survivingVersions.length === exactVersions.length) {
|
|
247
|
+
survivingSpecs.push(entry);
|
|
248
|
+
}
|
|
249
|
+
else if (survivingVersions.length > 0) {
|
|
250
|
+
survivingSpecs.push(...mergePackageVersionSpecs([`${packageName}@${survivingVersions.join(' || ')}`]));
|
|
251
|
+
changed = true;
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
changed = true;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (!changed) {
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
if (survivingSpecs.length === 0) {
|
|
261
|
+
delete manifest.minimumReleaseAgeExclude;
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
manifest.minimumReleaseAgeExclude = survivingSpecs;
|
|
265
|
+
}
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
199
268
|
// Captures only the key order at each nested level of a plain-object value,
|
|
200
269
|
// without duplicating the values themselves. Used as a lightweight snapshot of
|
|
201
270
|
// the original manifest layout so `reorderRecursive` can decide where to place
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnpm/workspace.workspace-manifest-writer",
|
|
3
|
-
"version": "1100.0
|
|
3
|
+
"version": "1100.1.0",
|
|
4
4
|
"description": "Updates the workspace manifest file",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pnpm",
|
|
@@ -28,13 +28,13 @@
|
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@pnpm/catalogs.types": "1100.0.1",
|
|
31
|
-
"@pnpm/config.parse-overrides": "1100.1.
|
|
32
|
-
"@pnpm/config.version-policy": "1100.
|
|
31
|
+
"@pnpm/config.parse-overrides": "1100.1.3",
|
|
32
|
+
"@pnpm/config.version-policy": "1100.2.0",
|
|
33
33
|
"@pnpm/constants": "1101.0.0",
|
|
34
34
|
"@pnpm/lockfile.types": "1100.0.19",
|
|
35
35
|
"@pnpm/text.ordinal-comparator": "1100.0.0",
|
|
36
36
|
"@pnpm/types": "1101.9.0",
|
|
37
|
-
"@pnpm/workspace.workspace-manifest-reader": "1100.1.
|
|
37
|
+
"@pnpm/workspace.workspace-manifest-reader": "1100.1.6",
|
|
38
38
|
"@pnpm/yaml.document-sync": "1100.0.1",
|
|
39
39
|
"ramda": "npm:@pnpm/ramda@0.28.1",
|
|
40
40
|
"write-file-atomic": "^7.0.1",
|
|
@@ -42,10 +42,10 @@
|
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@jest/globals": "30.4.1",
|
|
45
|
-
"@pnpm/prepare": "1100.0.
|
|
45
|
+
"@pnpm/prepare": "1100.0.26",
|
|
46
46
|
"@pnpm/prepare-temp-dir": "1100.0.1",
|
|
47
|
-
"@pnpm/workspace.projects-reader": "1101.0.
|
|
48
|
-
"@pnpm/workspace.workspace-manifest-writer": "1100.0
|
|
47
|
+
"@pnpm/workspace.projects-reader": "1101.0.23",
|
|
48
|
+
"@pnpm/workspace.workspace-manifest-writer": "1100.1.0",
|
|
49
49
|
"@types/ramda": "0.32.0",
|
|
50
50
|
"@types/write-file-atomic": "^4.0.3",
|
|
51
51
|
"read-yaml-file": "^3.0.0",
|