@pnpm/workspace.workspace-manifest-writer 1100.0.21 → 1100.1.1
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 +34 -0
- package/lib/index.d.ts +10 -1
- package/lib/index.js +112 -9
- package/package.json +11 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# @pnpm/workspace.manifest-writer
|
|
2
2
|
|
|
3
|
+
## 1100.1.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- `pnpm approve-builds` now removes `onlyBuiltDependencies`, `onlyBuiltDependenciesFile`, `neverBuiltDependencies`, and `ignoredBuiltDependencies` from `pnpm-workspace.yaml` when it writes `allowBuilds`. Those settings were replaced by `allowBuilds` in pnpm 11 and silently ignored since, so a workspace migrated from pnpm 10 kept them around looking active.
|
|
8
|
+
|
|
9
|
+
- `pnpm remove` now prunes undecided entries (`"set this to true or false"`) from `allowBuilds` in `pnpm-workspace.yaml` when `sharedWorkspaceLockfile: true` and the corresponding packages are removed [pnpm/pnpm#13892](https://github.com/pnpm/pnpm/issues/13892).
|
|
10
|
+
|
|
11
|
+
- Updated dependencies:
|
|
12
|
+
- @pnpm/building.policy@1100.0.20
|
|
13
|
+
- @pnpm/config.parse-overrides@1100.1.4
|
|
14
|
+
- @pnpm/config.version-policy@1100.2.1
|
|
15
|
+
- @pnpm/constants@1102.0.0
|
|
16
|
+
- @pnpm/lockfile.types@1100.0.20
|
|
17
|
+
- @pnpm/types@1102.0.0
|
|
18
|
+
- @pnpm/workspace.workspace-manifest-reader@1100.1.7
|
|
19
|
+
|
|
20
|
+
## 1100.1.0
|
|
21
|
+
|
|
22
|
+
### Minor Changes
|
|
23
|
+
|
|
24
|
+
- 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.
|
|
25
|
+
|
|
26
|
+
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.
|
|
27
|
+
|
|
28
|
+
### Patch Changes
|
|
29
|
+
|
|
30
|
+
- `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).
|
|
31
|
+
|
|
32
|
+
- Updated dependencies:
|
|
33
|
+
- @pnpm/config.parse-overrides@1100.1.3
|
|
34
|
+
- @pnpm/config.version-policy@1100.2.0
|
|
35
|
+
- @pnpm/workspace.workspace-manifest-reader@1100.1.6
|
|
36
|
+
|
|
3
37
|
## 1100.0.21
|
|
4
38
|
|
|
5
39
|
### Patch Changes
|
package/lib/index.d.ts
CHANGED
|
@@ -9,9 +9,18 @@ export declare function updateWorkspaceManifest(dir: string, opts: {
|
|
|
9
9
|
updatedCatalogs?: Catalogs;
|
|
10
10
|
updatedOverrides?: Record<string, string>;
|
|
11
11
|
addedMinimumReleaseAgeExcludes?: string[];
|
|
12
|
+
deletedLegacyKeys?: string[];
|
|
12
13
|
fileName?: FileName;
|
|
13
|
-
|
|
14
|
+
catalogPrune?: boolean;
|
|
14
15
|
allProjects?: Project[];
|
|
16
|
+
/**
|
|
17
|
+
* Package name → the versions the freshly resolved lockfile records.
|
|
18
|
+
* Supplied when a freshly resolved shared lockfile is available.
|
|
19
|
+
* `minimumReleaseAgeExcludePrune` gates only minimum-release-age cleanup;
|
|
20
|
+
* `allowBuilds` cleanup runs whenever this map is present.
|
|
21
|
+
*/
|
|
22
|
+
resolvedPackageVersions?: ReadonlyMap<string, ReadonlySet<string>>;
|
|
23
|
+
minimumReleaseAgeExcludePrune?: boolean;
|
|
15
24
|
}): Promise<void>;
|
|
16
25
|
export interface NewCatalogs {
|
|
17
26
|
[catalogName: string]: {
|
package/lib/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import util from 'node:util';
|
|
4
|
+
import { packageNameFromAllowBuildKey, UNDECIDED_ALLOW_BUILD } from '@pnpm/building.policy';
|
|
4
5
|
import { parsePkgAndParentSelector } from '@pnpm/config.parse-overrides';
|
|
5
|
-
import { mergePackageVersionSpecs } from '@pnpm/config.version-policy';
|
|
6
|
+
import { mergePackageVersionSpecs, parseVersionPolicyRule } from '@pnpm/config.version-policy';
|
|
6
7
|
import { WORKSPACE_MANIFEST_FILENAME } from '@pnpm/constants';
|
|
7
8
|
import { lexCompare } from '@pnpm/text.ordinal-comparator';
|
|
8
9
|
import { validateWorkspaceManifest } from '@pnpm/workspace.workspace-manifest-reader';
|
|
@@ -41,19 +42,31 @@ export async function updateWorkspaceManifest(dir, opts) {
|
|
|
41
42
|
manifest ??= {};
|
|
42
43
|
const originalKeyOrder = captureKeyOrder(manifest);
|
|
43
44
|
let shouldBeUpdated = opts.updatedCatalogs != null && addCatalogs(manifest, opts.updatedCatalogs);
|
|
44
|
-
if (opts.
|
|
45
|
+
if (opts.catalogPrune) {
|
|
45
46
|
shouldBeUpdated = removePackagesFromWorkspaceCatalog(manifest, opts.allProjects ?? []) || shouldBeUpdated;
|
|
46
47
|
}
|
|
47
48
|
const updatedFields = { ...opts.updatedFields };
|
|
48
49
|
for (const [key, value] of Object.entries(updatedFields)) {
|
|
49
|
-
if (
|
|
50
|
+
if (value == null) {
|
|
51
|
+
// Clearing a field the manifest never had changes nothing. Counting it as
|
|
52
|
+
// an update would take the empty-manifest branch below and try to remove a
|
|
53
|
+
// file that may not exist.
|
|
54
|
+
if (!Object.hasOwn(manifest, key))
|
|
55
|
+
continue;
|
|
56
|
+
shouldBeUpdated = true;
|
|
57
|
+
delete manifest[key];
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (equals(manifest[key], value))
|
|
61
|
+
continue;
|
|
62
|
+
shouldBeUpdated = true;
|
|
63
|
+
manifest[key] = value;
|
|
64
|
+
}
|
|
65
|
+
const untypedManifest = manifest;
|
|
66
|
+
for (const key of opts.deletedLegacyKeys ?? []) {
|
|
67
|
+
if (Object.hasOwn(untypedManifest, key)) {
|
|
68
|
+
delete untypedManifest[key];
|
|
50
69
|
shouldBeUpdated = true;
|
|
51
|
-
if (value == null) {
|
|
52
|
-
delete manifest[key];
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
manifest[key] = value;
|
|
56
|
-
}
|
|
57
70
|
}
|
|
58
71
|
}
|
|
59
72
|
if (opts.updatedOverrides) {
|
|
@@ -65,6 +78,14 @@ export async function updateWorkspaceManifest(dir, opts) {
|
|
|
65
78
|
}
|
|
66
79
|
}
|
|
67
80
|
}
|
|
81
|
+
if (opts.resolvedPackageVersions != null) {
|
|
82
|
+
if (opts.minimumReleaseAgeExcludePrune) {
|
|
83
|
+
shouldBeUpdated = pruneMinimumReleaseAgeExcludes(manifest, opts.resolvedPackageVersions) || shouldBeUpdated;
|
|
84
|
+
}
|
|
85
|
+
shouldBeUpdated = pruneAllowBuilds(manifest, opts.resolvedPackageVersions) || shouldBeUpdated;
|
|
86
|
+
}
|
|
87
|
+
// Merged after the cleanup pass so entries approved during this install
|
|
88
|
+
// are never pruned by it in the same write.
|
|
68
89
|
if (opts.addedMinimumReleaseAgeExcludes?.length) {
|
|
69
90
|
const existing = manifest.minimumReleaseAgeExclude ?? [];
|
|
70
91
|
const merged = mergePackageVersionSpecs([...existing, ...opts.addedMinimumReleaseAgeExcludes]);
|
|
@@ -196,6 +217,65 @@ function addPackageReference(packageReferences, pkgName, version) {
|
|
|
196
217
|
}
|
|
197
218
|
packageReferences[pkgName].add(version);
|
|
198
219
|
}
|
|
220
|
+
// The `minimumReleaseAgeExcludePrune` pass. An entry is dropped when the
|
|
221
|
+
// freshly resolved lockfile no longer contains what it names: exact versions
|
|
222
|
+
// that were not resolved are dropped (the entry goes away once none remain),
|
|
223
|
+
// and a bare-name entry goes away when the package is absent entirely. Glob
|
|
224
|
+
// patterns always stay — they are forward-looking and can't be proven stale.
|
|
225
|
+
// Entries that fail to parse stay untouched so cleanup never breaks an
|
|
226
|
+
// install.
|
|
227
|
+
function pruneMinimumReleaseAgeExcludes(manifest, resolvedPackageVersions) {
|
|
228
|
+
const excludes = manifest.minimumReleaseAgeExclude;
|
|
229
|
+
if (excludes == null || excludes.length === 0) {
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
const survivingSpecs = [];
|
|
233
|
+
let changed = false;
|
|
234
|
+
for (const entry of excludes) {
|
|
235
|
+
let packageName;
|
|
236
|
+
let exactVersions;
|
|
237
|
+
try {
|
|
238
|
+
const rule = parseVersionPolicyRule(entry);
|
|
239
|
+
packageName = rule.packageName;
|
|
240
|
+
exactVersions = rule.exactVersions;
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
survivingSpecs.push(entry);
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
if (exactVersions.length === 0) {
|
|
247
|
+
if (packageName.includes('*') || resolvedPackageVersions.has(packageName)) {
|
|
248
|
+
survivingSpecs.push(entry);
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
changed = true;
|
|
252
|
+
}
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
const resolved = resolvedPackageVersions.get(packageName);
|
|
256
|
+
const survivingVersions = exactVersions.filter((version) => resolved?.has(version));
|
|
257
|
+
if (survivingVersions.length === exactVersions.length) {
|
|
258
|
+
survivingSpecs.push(entry);
|
|
259
|
+
}
|
|
260
|
+
else if (survivingVersions.length > 0) {
|
|
261
|
+
survivingSpecs.push(...mergePackageVersionSpecs([`${packageName}@${survivingVersions.join(' || ')}`]));
|
|
262
|
+
changed = true;
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
changed = true;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
if (!changed) {
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
if (survivingSpecs.length === 0) {
|
|
272
|
+
delete manifest.minimumReleaseAgeExclude;
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
manifest.minimumReleaseAgeExclude = survivingSpecs;
|
|
276
|
+
}
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
199
279
|
// Captures only the key order at each nested level of a plain-object value,
|
|
200
280
|
// without duplicating the values themselves. Used as a lightweight snapshot of
|
|
201
281
|
// the original manifest layout so `reorderRecursive` can decide where to place
|
|
@@ -315,4 +395,27 @@ function propagateBlankLinesToNewPairs(document, originalTopLevelKeys) {
|
|
|
315
395
|
}
|
|
316
396
|
}
|
|
317
397
|
}
|
|
398
|
+
// Drops undecided placeholder entries whose package is provably absent from
|
|
399
|
+
// the resolved lockfile. Explicit decisions, keys with no provable package
|
|
400
|
+
// name, and entries for still-resolved packages always stay.
|
|
401
|
+
function pruneAllowBuilds(manifest, resolvedPackageVersions) {
|
|
402
|
+
const allowBuilds = manifest.allowBuilds;
|
|
403
|
+
if (allowBuilds == null) {
|
|
404
|
+
return false;
|
|
405
|
+
}
|
|
406
|
+
let changed = false;
|
|
407
|
+
for (const [key, value] of Object.entries(allowBuilds)) {
|
|
408
|
+
if (value !== UNDECIDED_ALLOW_BUILD)
|
|
409
|
+
continue;
|
|
410
|
+
const packageName = packageNameFromAllowBuildKey(key);
|
|
411
|
+
if (packageName == null || resolvedPackageVersions.has(packageName))
|
|
412
|
+
continue;
|
|
413
|
+
delete allowBuilds[key];
|
|
414
|
+
changed = true;
|
|
415
|
+
}
|
|
416
|
+
if (changed && Object.keys(allowBuilds).length === 0) {
|
|
417
|
+
delete manifest.allowBuilds;
|
|
418
|
+
}
|
|
419
|
+
return changed;
|
|
420
|
+
}
|
|
318
421
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnpm/workspace.workspace-manifest-writer",
|
|
3
|
-
"version": "1100.
|
|
3
|
+
"version": "1100.1.1",
|
|
4
4
|
"description": "Updates the workspace manifest file",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pnpm",
|
|
@@ -27,14 +27,15 @@
|
|
|
27
27
|
"!*.map"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
+
"@pnpm/building.policy": "1100.0.20",
|
|
30
31
|
"@pnpm/catalogs.types": "1100.0.1",
|
|
31
|
-
"@pnpm/config.parse-overrides": "1100.1.
|
|
32
|
-
"@pnpm/config.version-policy": "1100.1
|
|
33
|
-
"@pnpm/constants": "
|
|
34
|
-
"@pnpm/lockfile.types": "1100.0.
|
|
32
|
+
"@pnpm/config.parse-overrides": "1100.1.4",
|
|
33
|
+
"@pnpm/config.version-policy": "1100.2.1",
|
|
34
|
+
"@pnpm/constants": "1102.0.0",
|
|
35
|
+
"@pnpm/lockfile.types": "1100.0.20",
|
|
35
36
|
"@pnpm/text.ordinal-comparator": "1100.0.0",
|
|
36
|
-
"@pnpm/types": "
|
|
37
|
-
"@pnpm/workspace.workspace-manifest-reader": "1100.1.
|
|
37
|
+
"@pnpm/types": "1102.0.0",
|
|
38
|
+
"@pnpm/workspace.workspace-manifest-reader": "1100.1.7",
|
|
38
39
|
"@pnpm/yaml.document-sync": "1100.0.1",
|
|
39
40
|
"ramda": "npm:@pnpm/ramda@0.28.1",
|
|
40
41
|
"write-file-atomic": "^7.0.1",
|
|
@@ -42,10 +43,10 @@
|
|
|
42
43
|
},
|
|
43
44
|
"devDependencies": {
|
|
44
45
|
"@jest/globals": "30.4.1",
|
|
45
|
-
"@pnpm/prepare": "1100.0.
|
|
46
|
+
"@pnpm/prepare": "1100.0.27",
|
|
46
47
|
"@pnpm/prepare-temp-dir": "1100.0.1",
|
|
47
|
-
"@pnpm/workspace.projects-reader": "1101.0.
|
|
48
|
-
"@pnpm/workspace.workspace-manifest-writer": "1100.
|
|
48
|
+
"@pnpm/workspace.projects-reader": "1101.0.24",
|
|
49
|
+
"@pnpm/workspace.workspace-manifest-writer": "1100.1.1",
|
|
49
50
|
"@types/ramda": "0.32.0",
|
|
50
51
|
"@types/write-file-atomic": "^4.0.3",
|
|
51
52
|
"read-yaml-file": "^3.0.0",
|