@pnpm/workspace.workspace-manifest-writer 1100.2.2 → 1100.2.4

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 CHANGED
@@ -1,5 +1,22 @@
1
1
  # @pnpm/workspace.manifest-writer
2
2
 
3
+ ## 1100.2.4
4
+
5
+ ### Patch Changes
6
+
7
+ - Catalogs now work with entries and catalog names such as `constructor` or `toString`. Pruning unused catalog entries crashed on such names, and a new named catalog called `toString` was silently not written.
8
+
9
+ ## 1100.2.3
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies:
14
+ - @pnpm/building.policy@1100.1.4
15
+ - @pnpm/config.parse-overrides@1100.1.7
16
+ - @pnpm/config.version-policy@1100.2.5
17
+ - @pnpm/lockfile.types@1100.1.4
18
+ - @pnpm/workspace.workspace-manifest-reader@1100.2.1
19
+
3
20
  ## 1100.2.2
4
21
 
5
22
  ### Patch Changes
@@ -0,0 +1,12 @@
1
+ import type { WorkspaceManifest } from '@pnpm/workspace.workspace-manifest-reader';
2
+ /**
3
+ * Set the audit ignore list to `ghsas` (the complete desired list) in
4
+ * whichever spelling the manifest uses — the canonical `audit.ignore` wins
5
+ * over the deprecated `auditConfig.ignoreGhsas`, matching the reader's
6
+ * precedence, so a stale canonical list can't shadow the update on the next
7
+ * read. When both spellings are present, the shadowed deprecated list is
8
+ * removed as part of the write. `auditConfig.ignoreGhsas` is created when
9
+ * neither is present. An empty `ghsas` removes the list, dropping its parent
10
+ * block when nothing else remains in it. Returns whether anything changed.
11
+ */
12
+ export declare function setAuditIgnoreGhsas(manifest: Partial<WorkspaceManifest>, ghsas: string[]): boolean;
@@ -0,0 +1,53 @@
1
+ import { equals } from 'ramda';
2
+ /**
3
+ * Set the audit ignore list to `ghsas` (the complete desired list) in
4
+ * whichever spelling the manifest uses — the canonical `audit.ignore` wins
5
+ * over the deprecated `auditConfig.ignoreGhsas`, matching the reader's
6
+ * precedence, so a stale canonical list can't shadow the update on the next
7
+ * read. When both spellings are present, the shadowed deprecated list is
8
+ * removed as part of the write. `auditConfig.ignoreGhsas` is created when
9
+ * neither is present. An empty `ghsas` removes the list, dropping its parent
10
+ * block when nothing else remains in it. Returns whether anything changed.
11
+ */
12
+ export function setAuditIgnoreGhsas(manifest, ghsas) {
13
+ if (manifest.audit?.ignore != null) {
14
+ let changed = setCanonicalAuditIgnore(manifest, manifest.audit, ghsas);
15
+ if (manifest.auditConfig?.ignoreGhsas != null) {
16
+ changed = removeAuditConfigIgnoreGhsas(manifest) || changed;
17
+ }
18
+ return changed;
19
+ }
20
+ if (ghsas.length === 0) {
21
+ return removeAuditConfigIgnoreGhsas(manifest);
22
+ }
23
+ if (equals(manifest.auditConfig?.ignoreGhsas, ghsas)) {
24
+ return false;
25
+ }
26
+ manifest.auditConfig = { ...manifest.auditConfig, ignoreGhsas: ghsas };
27
+ return true;
28
+ }
29
+ function setCanonicalAuditIgnore(manifest, audit, ghsas) {
30
+ if (ghsas.length === 0) {
31
+ delete audit.ignore;
32
+ if (Object.keys(audit).length === 0) {
33
+ delete manifest.audit;
34
+ }
35
+ return true;
36
+ }
37
+ if (equals(audit.ignore, ghsas)) {
38
+ return false;
39
+ }
40
+ audit.ignore = ghsas;
41
+ return true;
42
+ }
43
+ function removeAuditConfigIgnoreGhsas(manifest) {
44
+ if (manifest.auditConfig?.ignoreGhsas == null) {
45
+ return false;
46
+ }
47
+ delete manifest.auditConfig.ignoreGhsas;
48
+ if (Object.keys(manifest.auditConfig).length === 0) {
49
+ delete manifest.auditConfig;
50
+ }
51
+ return true;
52
+ }
53
+ //# sourceMappingURL=auditIgnoreGhsas.js.map
@@ -0,0 +1,5 @@
1
+ import type { Catalogs } from '@pnpm/catalogs.types';
2
+ import type { Project } from '@pnpm/types';
3
+ import type { WorkspaceManifest } from '@pnpm/workspace.workspace-manifest-reader';
4
+ export declare function addCatalogs(manifest: Partial<WorkspaceManifest>, newCatalogs: Catalogs): boolean;
5
+ export declare function removePackagesFromWorkspaceCatalog(manifest: Partial<WorkspaceManifest>, packagesJson: Project[]): boolean;
@@ -0,0 +1,149 @@
1
+ import { parsePkgAndParentSelector } from '@pnpm/config.parse-overrides';
2
+ export function addCatalogs(manifest, newCatalogs) {
3
+ let shouldBeUpdated = false;
4
+ for (const catalogName in newCatalogs) {
5
+ const existingCatalog = findCatalog(manifest, catalogName);
6
+ const { catalog, changed } = mergeCatalogEntries(existingCatalog, newCatalogs[catalogName] ?? {});
7
+ shouldBeUpdated = changed || shouldBeUpdated;
8
+ if (catalog == null || existingCatalog != null)
9
+ continue;
10
+ attachCatalog(manifest, catalogName, catalog);
11
+ }
12
+ return shouldBeUpdated;
13
+ }
14
+ function findCatalog(manifest, catalogName) {
15
+ if (catalogName === 'default') {
16
+ return manifest.catalog ?? manifest.catalogs?.default;
17
+ }
18
+ return manifest.catalogs != null && Object.hasOwn(manifest.catalogs, catalogName)
19
+ ? manifest.catalogs[catalogName]
20
+ : undefined;
21
+ }
22
+ function mergeCatalogEntries(existingCatalog, newEntries) {
23
+ let catalog = existingCatalog;
24
+ let changed = false;
25
+ for (const [dependencyName, specifier] of Object.entries(newEntries)) {
26
+ if (specifier == null) {
27
+ continue;
28
+ }
29
+ catalog ??= {};
30
+ if (catalog[dependencyName] !== specifier) {
31
+ catalog[dependencyName] = specifier;
32
+ changed = true;
33
+ }
34
+ }
35
+ return { catalog, changed };
36
+ }
37
+ function attachCatalog(manifest, catalogName, catalog) {
38
+ if (catalogName === 'default') {
39
+ manifest.catalog = catalog;
40
+ }
41
+ else {
42
+ manifest.catalogs ??= {};
43
+ manifest.catalogs[catalogName] = catalog;
44
+ }
45
+ }
46
+ export function removePackagesFromWorkspaceCatalog(manifest, packagesJson) {
47
+ if (packagesJson.length === 0 || (manifest.catalog == null && manifest.catalogs == null)) {
48
+ return false;
49
+ }
50
+ const packageReferences = collectCatalogReferences(packagesJson, manifest.overrides ?? {});
51
+ const defaultCatalogChanged = pruneDefaultCatalog(manifest, packageReferences);
52
+ const namedCatalogsChanged = pruneNamedCatalogs(manifest, packageReferences);
53
+ return defaultCatalogChanged || namedCatalogsChanged;
54
+ }
55
+ function collectCatalogReferences(packagesJson, overrides) {
56
+ const packageReferences = new Map();
57
+ for (const pkg of packagesJson) {
58
+ const pkgManifest = pkg.manifest;
59
+ const dependencyTypes = [
60
+ pkgManifest.dependencies,
61
+ pkgManifest.devDependencies,
62
+ pkgManifest.optionalDependencies,
63
+ pkgManifest.peerDependencies,
64
+ ];
65
+ for (const deps of dependencyTypes) {
66
+ addPackageReferences(packageReferences, deps ?? {});
67
+ }
68
+ }
69
+ for (const [selector, version] of Object.entries(overrides)) {
70
+ if (!version.startsWith('catalog:')) {
71
+ continue;
72
+ }
73
+ const pkgName = overrideTargetName(selector);
74
+ if (pkgName == null)
75
+ continue;
76
+ addPackageReference(packageReferences, pkgName, version);
77
+ }
78
+ return packageReferences;
79
+ }
80
+ function addPackageReferences(packageReferences, deps) {
81
+ for (const [pkgName, version] of Object.entries(deps)) {
82
+ addPackageReference(packageReferences, pkgName, version);
83
+ }
84
+ }
85
+ function overrideTargetName(selector) {
86
+ try {
87
+ return parsePkgAndParentSelector(selector).targetPkg.name;
88
+ }
89
+ catch {
90
+ return undefined;
91
+ }
92
+ }
93
+ function addPackageReference(packageReferences, pkgName, version) {
94
+ let references = packageReferences.get(pkgName);
95
+ if (references == null) {
96
+ references = new Set();
97
+ packageReferences.set(pkgName, references);
98
+ }
99
+ references.add(version);
100
+ }
101
+ function pruneDefaultCatalog(manifest, packageReferences) {
102
+ if (!manifest.catalog)
103
+ return false;
104
+ let shouldBeUpdated = false;
105
+ const packagesToRemove = Object.keys(manifest.catalog).filter(pkg => !packageReferences.get(pkg)?.has('catalog:'));
106
+ for (const pkg of packagesToRemove) {
107
+ delete manifest.catalog[pkg];
108
+ shouldBeUpdated = true;
109
+ }
110
+ if (Object.keys(manifest.catalog).length === 0) {
111
+ delete manifest.catalog;
112
+ shouldBeUpdated = true;
113
+ }
114
+ return shouldBeUpdated;
115
+ }
116
+ function pruneNamedCatalogs(manifest, packageReferences) {
117
+ if (!manifest.catalogs)
118
+ return false;
119
+ let shouldBeUpdated = false;
120
+ const catalogsToRemove = [];
121
+ for (const [catalogName, catalog] of Object.entries(manifest.catalogs)) {
122
+ if (!catalog)
123
+ continue;
124
+ shouldBeUpdated = pruneNamedCatalog(catalogName, catalog, packageReferences) || shouldBeUpdated;
125
+ if (Object.keys(catalog).length === 0) {
126
+ catalogsToRemove.push(catalogName);
127
+ shouldBeUpdated = true;
128
+ }
129
+ }
130
+ for (const catalogName of catalogsToRemove) {
131
+ delete manifest.catalogs[catalogName];
132
+ }
133
+ if (Object.keys(manifest.catalogs).length === 0) {
134
+ delete manifest.catalogs;
135
+ shouldBeUpdated = true;
136
+ }
137
+ return shouldBeUpdated;
138
+ }
139
+ function pruneNamedCatalog(catalogName, catalog, packageReferences) {
140
+ const packagesToRemove = Object.keys(catalog).filter(pkg => {
141
+ const references = packageReferences.get(pkg);
142
+ return !references?.has(`catalog:${catalogName}`) && !references?.has('catalog:');
143
+ });
144
+ for (const pkg of packagesToRemove) {
145
+ delete catalog[pkg];
146
+ }
147
+ return packagesToRemove.length > 0;
148
+ }
149
+ //# sourceMappingURL=catalogs.js.map
package/lib/index.d.ts CHANGED
@@ -4,7 +4,7 @@ import type { ResolvedCatalogEntry } from '@pnpm/lockfile.types';
4
4
  import type { Project } from '@pnpm/types';
5
5
  import { type WorkspaceManifest } from '@pnpm/workspace.workspace-manifest-reader';
6
6
  export type FileName = typeof GLOBAL_CONFIG_YAML_FILENAME | typeof WORKSPACE_MANIFEST_FILENAME;
7
- export declare function updateWorkspaceManifest(dir: string, opts: {
7
+ export interface UpdateWorkspaceManifestOptions {
8
8
  updatedFields?: Partial<WorkspaceManifest>;
9
9
  updatedCatalogs?: Catalogs;
10
10
  updatedOverrides?: Record<string, string>;
@@ -28,7 +28,8 @@ export declare function updateWorkspaceManifest(dir: string, opts: {
28
28
  resolvedPackageVersions?: ReadonlyMap<string, ReadonlySet<string>>;
29
29
  minimumReleaseAgeExcludePrune?: boolean;
30
30
  trustPolicyExcludePrune?: boolean;
31
- }): Promise<void>;
31
+ }
32
+ export declare function updateWorkspaceManifest(dir: string, opts: UpdateWorkspaceManifestOptions): Promise<void>;
32
33
  export interface NewCatalogs {
33
34
  [catalogName: string]: {
34
35
  [dependencyName: string]: Pick<ResolvedCatalogEntry, 'specifier'>;
package/lib/index.js CHANGED
@@ -1,15 +1,16 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
- import { packageNameFromAllowBuildKey, UNDECIDED_ALLOW_BUILD } from '@pnpm/building.policy';
4
- import { parsePkgAndParentSelector } from '@pnpm/config.parse-overrides';
5
- import { mergePackageVersionSpecs, parseVersionPolicyRule } from '@pnpm/config.version-policy';
3
+ import { mergePackageVersionSpecs } from '@pnpm/config.version-policy';
6
4
  import { WORKSPACE_MANIFEST_FILENAME } from '@pnpm/constants';
7
- import { lexCompare } from '@pnpm/text.ordinal-comparator';
8
5
  import { validateWorkspaceManifest } from '@pnpm/workspace.workspace-manifest-reader';
9
6
  import { patchDocument } from '@pnpm/yaml.document-sync';
10
7
  import { equals } from 'ramda';
11
8
  import writeFileAtomic from 'write-file-atomic';
12
9
  import yaml from 'yaml';
10
+ import { setAuditIgnoreGhsas } from './auditIgnoreGhsas.js';
11
+ import { addCatalogs, removePackagesFromWorkspaceCatalog } from './catalogs.js';
12
+ import { captureKeyOrder, propagateBlankLinesToNewPairs, reorderRecursive } from './keyOrder.js';
13
+ import { pruneAllowBuilds, pruneExcludeList } from './pruneResolvedLists.js';
13
14
  const DEFAULT_FILENAME = WORKSPACE_MANIFEST_FILENAME;
14
15
  async function writeManifestFile(dir, fileName, manifest) {
15
16
  const manifestStr = manifest.toString({
@@ -40,435 +41,103 @@ export async function updateWorkspaceManifest(dir, opts) {
40
41
  validateWorkspaceManifest(manifest);
41
42
  manifest ??= {};
42
43
  const originalKeyOrder = captureKeyOrder(manifest);
43
- let shouldBeUpdated = opts.updatedCatalogs != null && addCatalogs(manifest, opts.updatedCatalogs);
44
- if (opts.catalogPrune) {
45
- shouldBeUpdated = removePackagesFromWorkspaceCatalog(manifest, opts.allProjects ?? []) || shouldBeUpdated;
46
- }
47
- const updatedFields = { ...opts.updatedFields };
48
- for (const [key, value] of Object.entries(updatedFields)) {
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;
55
- shouldBeUpdated = true;
56
- delete manifest[key];
57
- continue;
58
- }
59
- if (equals(manifest[key], value))
60
- continue;
61
- shouldBeUpdated = true;
62
- manifest[key] = value;
44
+ if (!applyManifestUpdates(manifest, opts)) {
45
+ return;
63
46
  }
64
- const untypedManifest = manifest;
65
- for (const key of opts.deletedLegacyKeys ?? []) {
66
- if (Object.hasOwn(untypedManifest, key)) {
67
- delete untypedManifest[key];
68
- shouldBeUpdated = true;
69
- }
47
+ if (Object.keys(manifest).length === 0) {
48
+ await fs.promises.rm(path.join(dir, fileName));
49
+ return;
70
50
  }
51
+ manifest = reorderRecursive(originalKeyOrder, manifest);
52
+ patchDocument(document, manifest, { preserveScalarAliases: true });
53
+ propagateBlankLinesToNewPairs(document, originalKeyOrder?.keys ?? []);
54
+ await writeManifestFile(dir, fileName, document);
55
+ }
56
+ function applyManifestUpdates(manifest, opts) {
57
+ let shouldBeUpdated = applyCatalogUpdates(manifest, opts);
58
+ shouldBeUpdated = applyUpdatedFields(manifest, { ...opts.updatedFields }) || shouldBeUpdated;
59
+ shouldBeUpdated = deleteKeys(manifest, opts.deletedLegacyKeys ?? []) || shouldBeUpdated;
71
60
  if (opts.updatedOverrides) {
72
- manifest.overrides ??= {};
73
- for (const [key, value] of Object.entries(opts.updatedOverrides)) {
74
- if (!equals(manifest.overrides[key], value)) {
75
- shouldBeUpdated = true;
76
- manifest.overrides[key] = value;
77
- }
78
- }
61
+ shouldBeUpdated = applyUpdatedOverrides(manifest, opts.updatedOverrides) || shouldBeUpdated;
79
62
  }
80
63
  if (opts.updatedAuditIgnoreGhsas != null) {
81
64
  shouldBeUpdated = setAuditIgnoreGhsas(manifest, opts.updatedAuditIgnoreGhsas) || shouldBeUpdated;
82
65
  }
83
66
  if (opts.resolvedPackageVersions != null) {
84
- if (opts.minimumReleaseAgeExcludePrune) {
85
- shouldBeUpdated = pruneExcludeList(manifest, 'minimumReleaseAgeExclude', opts.resolvedPackageVersions) || shouldBeUpdated;
86
- }
87
- if (opts.trustPolicyExcludePrune) {
88
- shouldBeUpdated = pruneExcludeList(manifest, 'trustPolicyExclude', opts.resolvedPackageVersions) || shouldBeUpdated;
89
- }
90
- shouldBeUpdated = pruneAllowBuilds(manifest, opts.resolvedPackageVersions) || shouldBeUpdated;
67
+ shouldBeUpdated = pruneResolvedPackageLists(manifest, opts, opts.resolvedPackageVersions) || shouldBeUpdated;
91
68
  }
92
69
  // Merged after the cleanup pass so entries approved during this install
93
70
  // are never pruned by it in the same write.
94
71
  if (opts.addedMinimumReleaseAgeExcludes?.length) {
95
- const existing = manifest.minimumReleaseAgeExclude ?? [];
96
- const merged = mergePackageVersionSpecs([...existing, ...opts.addedMinimumReleaseAgeExcludes]);
97
- if (!equals(existing, merged)) {
98
- shouldBeUpdated = true;
99
- manifest.minimumReleaseAgeExclude = merged;
100
- }
101
- }
102
- if (!shouldBeUpdated) {
103
- return;
72
+ shouldBeUpdated = addMinimumReleaseAgeExcludes(manifest, opts.addedMinimumReleaseAgeExcludes) || shouldBeUpdated;
104
73
  }
105
- if (Object.keys(manifest).length === 0) {
106
- await fs.promises.rm(path.join(dir, fileName));
107
- return;
74
+ return shouldBeUpdated;
75
+ }
76
+ function applyCatalogUpdates(manifest, opts) {
77
+ const catalogsAdded = opts.updatedCatalogs != null && addCatalogs(manifest, opts.updatedCatalogs);
78
+ if (!opts.catalogPrune) {
79
+ return catalogsAdded;
108
80
  }
109
- manifest = reorderRecursive(originalKeyOrder, manifest);
110
- patchDocument(document, manifest, { preserveScalarAliases: true });
111
- propagateBlankLinesToNewPairs(document, originalKeyOrder?.keys ?? []);
112
- await writeManifestFile(dir, fileName, document);
81
+ return removePackagesFromWorkspaceCatalog(manifest, opts.allProjects ?? []) || catalogsAdded;
113
82
  }
114
- function addCatalogs(manifest, newCatalogs) {
83
+ function applyUpdatedFields(manifest, updatedFields) {
115
84
  let shouldBeUpdated = false;
116
- for (const catalogName in newCatalogs) {
117
- let targetCatalog = catalogName === 'default'
118
- ? manifest.catalog ?? manifest.catalogs?.default
119
- : manifest.catalogs?.[catalogName];
120
- const targetCatalogWasNil = targetCatalog == null;
121
- for (const [dependencyName, specifier] of Object.entries(newCatalogs[catalogName] ?? {})) {
122
- if (specifier == null) {
85
+ for (const [key, value] of Object.entries(updatedFields)) {
86
+ if (value == null) {
87
+ // Clearing a field the manifest never had changes nothing. Counting it as
88
+ // an update would take the empty-manifest branch below and try to remove a
89
+ // file that may not exist.
90
+ if (!Object.hasOwn(manifest, key))
123
91
  continue;
124
- }
125
- targetCatalog ??= {};
126
- if (targetCatalog[dependencyName] !== specifier) {
127
- targetCatalog[dependencyName] = specifier;
128
- shouldBeUpdated = true;
129
- }
130
- }
131
- if (targetCatalog == null)
92
+ shouldBeUpdated = true;
93
+ delete manifest[key];
132
94
  continue;
133
- if (targetCatalogWasNil) {
134
- if (catalogName === 'default') {
135
- manifest.catalog = targetCatalog;
136
- }
137
- else {
138
- manifest.catalogs ??= {};
139
- manifest.catalogs[catalogName] = targetCatalog;
140
- }
141
95
  }
96
+ if (equals(manifest[key], value))
97
+ continue;
98
+ shouldBeUpdated = true;
99
+ manifest[key] = value;
142
100
  }
143
101
  return shouldBeUpdated;
144
102
  }
145
- function removePackagesFromWorkspaceCatalog(manifest, packagesJson) {
103
+ function deleteKeys(manifest, keys) {
146
104
  let shouldBeUpdated = false;
147
- if (packagesJson.length === 0 || (manifest.catalog == null && manifest.catalogs == null)) {
148
- return shouldBeUpdated;
149
- }
150
- const packageReferences = {};
151
- for (const pkg of packagesJson) {
152
- const pkgManifest = pkg.manifest;
153
- const dependencyTypes = [
154
- pkgManifest.dependencies,
155
- pkgManifest.devDependencies,
156
- pkgManifest.optionalDependencies,
157
- pkgManifest.peerDependencies,
158
- ];
159
- for (const deps of dependencyTypes) {
160
- if (!deps)
161
- continue;
162
- for (const [pkgName, version] of Object.entries(deps)) {
163
- addPackageReference(packageReferences, pkgName, version);
164
- }
165
- }
166
- }
167
- for (const [selector, version] of Object.entries(manifest.overrides ?? {})) {
168
- if (!version.startsWith('catalog:')) {
169
- continue;
170
- }
171
- let pkgName;
172
- try {
173
- pkgName = parsePkgAndParentSelector(selector).targetPkg.name;
174
- }
175
- catch {
176
- continue;
177
- }
178
- addPackageReference(packageReferences, pkgName, version);
179
- }
180
- if (manifest.catalog) {
181
- const packagesToRemove = Object.keys(manifest.catalog).filter(pkg => !packageReferences[pkg]?.has('catalog:'));
182
- for (const pkg of packagesToRemove) {
183
- delete manifest.catalog[pkg];
184
- shouldBeUpdated = true;
185
- }
186
- if (Object.keys(manifest.catalog).length === 0) {
187
- delete manifest.catalog;
105
+ for (const key of keys) {
106
+ if (Object.hasOwn(manifest, key)) {
107
+ delete manifest[key];
188
108
  shouldBeUpdated = true;
189
109
  }
190
110
  }
191
- if (manifest.catalogs) {
192
- const catalogsToRemove = [];
193
- for (const [catalogName, catalog] of Object.entries(manifest.catalogs)) {
194
- if (!catalog)
195
- continue;
196
- const packagesToRemove = Object.keys(catalog).filter(pkg => {
197
- const references = packageReferences[pkg];
198
- return !references?.has(`catalog:${catalogName}`) && !references?.has('catalog:');
199
- });
200
- for (const pkg of packagesToRemove) {
201
- delete catalog[pkg];
202
- shouldBeUpdated = true;
203
- }
204
- if (Object.keys(catalog).length === 0) {
205
- catalogsToRemove.push(catalogName);
206
- shouldBeUpdated = true;
207
- }
208
- }
209
- for (const catalogName of catalogsToRemove) {
210
- delete manifest.catalogs[catalogName];
211
- }
212
- if (Object.keys(manifest.catalogs).length === 0) {
213
- delete manifest.catalogs;
111
+ return shouldBeUpdated;
112
+ }
113
+ function applyUpdatedOverrides(manifest, updatedOverrides) {
114
+ let shouldBeUpdated = false;
115
+ manifest.overrides ??= {};
116
+ for (const [key, value] of Object.entries(updatedOverrides)) {
117
+ if (!equals(manifest.overrides[key], value)) {
214
118
  shouldBeUpdated = true;
119
+ manifest.overrides[key] = value;
215
120
  }
216
121
  }
217
122
  return shouldBeUpdated;
218
123
  }
219
- function addPackageReference(packageReferences, pkgName, version) {
220
- if (!packageReferences[pkgName]) {
221
- packageReferences[pkgName] = new Set();
222
- }
223
- packageReferences[pkgName].add(version);
224
- }
225
- // The `minimumReleaseAgeExcludePrune` / `trustPolicyExcludePrune` pass over
226
- // the exclude list `field` names. An entry is dropped when the freshly
227
- // resolved lockfile no longer contains what it names: exact versions that
228
- // were not resolved are dropped (the entry goes away once none remain), and a
229
- // bare-name entry goes away when the package is absent entirely. Glob patterns
230
- // always stay — they are forward-looking and can't be proven stale. Entries
231
- // that fail to parse stay untouched so cleanup never breaks an install.
232
- function pruneExcludeList(manifest, field, resolvedPackageVersions) {
233
- const excludes = manifest[field];
234
- if (excludes == null || excludes.length === 0) {
235
- return false;
236
- }
237
- const survivingSpecs = [];
238
- let changed = false;
239
- for (const entry of excludes) {
240
- let packageName;
241
- let exactVersions;
242
- try {
243
- const rule = parseVersionPolicyRule(entry);
244
- packageName = rule.packageName;
245
- exactVersions = rule.exactVersions;
246
- }
247
- catch {
248
- survivingSpecs.push(entry);
249
- continue;
250
- }
251
- if (exactVersions.length === 0) {
252
- if (packageName.includes('*') || resolvedPackageVersions.has(packageName)) {
253
- survivingSpecs.push(entry);
254
- }
255
- else {
256
- changed = true;
257
- }
258
- continue;
259
- }
260
- const resolved = resolvedPackageVersions.get(packageName);
261
- const survivingVersions = exactVersions.filter((version) => resolved?.has(version));
262
- if (survivingVersions.length === exactVersions.length) {
263
- survivingSpecs.push(entry);
264
- }
265
- else if (survivingVersions.length > 0) {
266
- survivingSpecs.push(...mergePackageVersionSpecs([`${packageName}@${survivingVersions.join(' || ')}`]));
267
- changed = true;
268
- }
269
- else {
270
- changed = true;
271
- }
272
- }
273
- if (!changed) {
274
- return false;
275
- }
276
- if (survivingSpecs.length === 0) {
277
- delete manifest[field];
124
+ function pruneResolvedPackageLists(manifest, opts, resolvedPackageVersions) {
125
+ let shouldBeUpdated = false;
126
+ if (opts.minimumReleaseAgeExcludePrune) {
127
+ shouldBeUpdated = pruneExcludeList(manifest, 'minimumReleaseAgeExclude', resolvedPackageVersions) || shouldBeUpdated;
278
128
  }
279
- else {
280
- manifest[field] = survivingSpecs;
129
+ if (opts.trustPolicyExcludePrune) {
130
+ shouldBeUpdated = pruneExcludeList(manifest, 'trustPolicyExclude', resolvedPackageVersions) || shouldBeUpdated;
281
131
  }
282
- return true;
132
+ return pruneAllowBuilds(manifest, resolvedPackageVersions) || shouldBeUpdated;
283
133
  }
284
- /**
285
- * Set the audit ignore list to `ghsas` (the complete desired list) in
286
- * whichever spelling the manifest uses — the canonical `audit.ignore` wins
287
- * over the deprecated `auditConfig.ignoreGhsas`, matching the reader's
288
- * precedence, so a stale canonical list can't shadow the update on the next
289
- * read. When both spellings are present, the shadowed deprecated list is
290
- * removed as part of the write. `auditConfig.ignoreGhsas` is created when
291
- * neither is present. An empty `ghsas` removes the list, dropping its parent
292
- * block when nothing else remains in it. Returns whether anything changed.
293
- */
294
- function setAuditIgnoreGhsas(manifest, ghsas) {
295
- let changed = false;
296
- if (manifest.audit?.ignore != null) {
297
- if (ghsas.length === 0) {
298
- delete manifest.audit.ignore;
299
- if (Object.keys(manifest.audit).length === 0) {
300
- delete manifest.audit;
301
- }
302
- changed = true;
303
- }
304
- else if (!equals(manifest.audit.ignore, ghsas)) {
305
- manifest.audit.ignore = ghsas;
306
- changed = true;
307
- }
308
- if (manifest.auditConfig?.ignoreGhsas != null) {
309
- changed = removeAuditConfigIgnoreGhsas(manifest) || changed;
310
- }
311
- return changed;
312
- }
313
- if (ghsas.length === 0) {
314
- return removeAuditConfigIgnoreGhsas(manifest);
315
- }
316
- if (equals(manifest.auditConfig?.ignoreGhsas, ghsas)) {
134
+ function addMinimumReleaseAgeExcludes(manifest, addedExcludes) {
135
+ const existing = manifest.minimumReleaseAgeExclude ?? [];
136
+ const merged = mergePackageVersionSpecs([...existing, ...addedExcludes]);
137
+ if (equals(existing, merged)) {
317
138
  return false;
318
139
  }
319
- manifest.auditConfig = { ...manifest.auditConfig, ignoreGhsas: ghsas };
140
+ manifest.minimumReleaseAgeExclude = merged;
320
141
  return true;
321
142
  }
322
- function removeAuditConfigIgnoreGhsas(manifest) {
323
- if (manifest.auditConfig?.ignoreGhsas == null) {
324
- return false;
325
- }
326
- delete manifest.auditConfig.ignoreGhsas;
327
- if (Object.keys(manifest.auditConfig).length === 0) {
328
- delete manifest.auditConfig;
329
- }
330
- return true;
331
- }
332
- // Captures only the key order at each nested level of a plain-object value,
333
- // without duplicating the values themselves. Used as a lightweight snapshot of
334
- // the original manifest layout so `reorderRecursive` can decide where to place
335
- // new keys without holding a structural clone of the entire manifest.
336
- function captureKeyOrder(value) {
337
- if (!isPlainObject(value))
338
- return null;
339
- const children = {};
340
- for (const [key, child] of Object.entries(value)) {
341
- const childOrder = captureKeyOrder(child);
342
- if (childOrder != null) {
343
- children[key] = childOrder;
344
- }
345
- }
346
- return { keys: Object.keys(value), children };
347
- }
348
- // Reorders the keys of `current` based on how the keys were arranged in the
349
- // original manifest. Two "sorted" layouts are recognized:
350
- //
351
- // 1. fully alphabetical
352
- // 2. a leading "packages" key followed by alphabetical
353
- //
354
- // When the original matches one of those layouts, new keys are inserted in
355
- // alphabetical position (preserving the leading "packages" if applicable).
356
- // Otherwise the existing order is preserved and new keys are appended at the
357
- // end. New manifests (no original keys) default to layout (2) to match the
358
- // pnpm convention of placing "packages" first.
359
- function reorderRecursive(originalOrder, current) {
360
- if (!isPlainObject(current))
361
- return current;
362
- const originalKeys = originalOrder?.keys ?? [];
363
- const originalKeySet = new Set(originalKeys);
364
- const survivingOriginal = originalKeys.filter((key) => Object.hasOwn(current, key));
365
- const newKeys = Object.keys(current).filter((key) => !originalKeySet.has(key));
366
- let orderedKeys;
367
- if (newKeys.length === 0) {
368
- orderedKeys = survivingOriginal;
369
- }
370
- else {
371
- const layout = detectKeyLayout(originalKeys);
372
- orderedKeys = layout === 'unordered'
373
- ? [...survivingOriginal, ...newKeys]
374
- : sortKeys([...survivingOriginal, ...newKeys], layout);
375
- }
376
- const result = {};
377
- for (const key of orderedKeys) {
378
- result[key] = reorderRecursive(originalOrder?.children[key] ?? null, current[key]);
379
- }
380
- return result;
381
- }
382
- function detectKeyLayout(keys) {
383
- if (keys.length === 0)
384
- return 'packages-first';
385
- const packagesFirst = keys[0] === 'packages';
386
- const start = packagesFirst ? 1 : 0;
387
- for (let i = start + 1; i < keys.length; i++) {
388
- if (lexCompare(keys[i - 1], keys[i]) > 0)
389
- return 'unordered';
390
- }
391
- return packagesFirst ? 'packages-first' : 'alphabetical';
392
- }
393
- function sortKeys(keys, layout) {
394
- if (layout === 'packages-first' && keys.includes('packages')) {
395
- return ['packages', ...keys.filter((key) => key !== 'packages').sort(lexCompare)];
396
- }
397
- return [...keys].sort(lexCompare);
398
- }
399
- function isPlainObject(value) {
400
- return value != null && typeof value === 'object' && !Array.isArray(value);
401
- }
402
- // New top-level pairs are inserted without `spaceBefore`, which glues them to
403
- // the preceding pair even when the document otherwise uses blank-line
404
- // separators between fields. Detect that style and propagate it to inserted
405
- // entries (including reordering-induced changes such as a new key sorting to
406
- // the front, which demotes the previously-first existing pair to a position
407
- // that should now have a blank before it).
408
- //
409
- // The yaml library reads `spaceBefore` from the pair's key node when rendering
410
- // block collections, not from the pair itself.
411
- function propagateBlankLinesToNewPairs(document, originalTopLevelKeys) {
412
- if (!yaml.isMap(document.contents))
413
- return;
414
- const items = document.contents.items;
415
- const keyOf = (pair) => yaml.isScalar(pair.key) && typeof pair.key.value === 'string'
416
- ? pair.key
417
- : null;
418
- const originalKeySet = new Set(originalTopLevelKeys);
419
- // The originally-first pair never had `spaceBefore` set even in a
420
- // blank-line-separated document — exclude it when judging the document's
421
- // style so we still detect the style when that pair has been moved.
422
- const originalFirstKey = originalTopLevelKeys[0] ?? null;
423
- let originalNonFirstCount = 0;
424
- let originalNonFirstWithBlank = 0;
425
- for (const item of items) {
426
- const k = keyOf(item);
427
- if (k == null || !originalKeySet.has(k.value) || k.value === originalFirstKey)
428
- continue;
429
- originalNonFirstCount++;
430
- if (k.spaceBefore)
431
- originalNonFirstWithBlank++;
432
- }
433
- const usesBlankLineStyle = originalNonFirstCount > 0 && originalNonFirstWithBlank === originalNonFirstCount;
434
- for (let i = 1; i < items.length; i++) {
435
- const key = keyOf(items[i]);
436
- if (key == null || key.spaceBefore)
437
- continue;
438
- if (usesBlankLineStyle) {
439
- key.spaceBefore = true;
440
- continue;
441
- }
442
- if (originalKeySet.has(key.value))
443
- continue;
444
- const nextKey = items[i + 1] ? keyOf(items[i + 1]) : null;
445
- const prevKey = items[i - 1] ? keyOf(items[i - 1]) : null;
446
- if (nextKey?.spaceBefore || (nextKey == null && prevKey?.spaceBefore)) {
447
- key.spaceBefore = true;
448
- }
449
- }
450
- }
451
- // Drops undecided placeholder entries whose package is provably absent from
452
- // the resolved lockfile. Explicit decisions, keys with no provable package
453
- // name, and entries for still-resolved packages always stay.
454
- function pruneAllowBuilds(manifest, resolvedPackageVersions) {
455
- const allowBuilds = manifest.allowBuilds;
456
- if (allowBuilds == null) {
457
- return false;
458
- }
459
- let changed = false;
460
- for (const [key, value] of Object.entries(allowBuilds)) {
461
- if (value !== UNDECIDED_ALLOW_BUILD)
462
- continue;
463
- const packageName = packageNameFromAllowBuildKey(key);
464
- if (packageName == null || resolvedPackageVersions.has(packageName))
465
- continue;
466
- delete allowBuilds[key];
467
- changed = true;
468
- }
469
- if (changed && Object.keys(allowBuilds).length === 0) {
470
- delete manifest.allowBuilds;
471
- }
472
- return changed;
473
- }
474
143
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,8 @@
1
+ import yaml from 'yaml';
2
+ export interface KeyOrderNode {
3
+ keys: string[];
4
+ children: Map<string, KeyOrderNode>;
5
+ }
6
+ export declare function captureKeyOrder(value: unknown): KeyOrderNode | null;
7
+ export declare function reorderRecursive(originalOrder: KeyOrderNode | null, current: unknown): unknown;
8
+ export declare function propagateBlankLinesToNewPairs(document: yaml.Document, originalTopLevelKeys: readonly string[]): void;
@@ -0,0 +1,125 @@
1
+ import { lexCompare } from '@pnpm/text.ordinal-comparator';
2
+ import yaml from 'yaml';
3
+ // Captures only the key order at each nested level of a plain-object value,
4
+ // without duplicating the values themselves. Used as a lightweight snapshot of
5
+ // the original manifest layout so `reorderRecursive` can decide where to place
6
+ // new keys without holding a structural clone of the entire manifest.
7
+ export function captureKeyOrder(value) {
8
+ if (!isPlainObject(value))
9
+ return null;
10
+ const children = new Map();
11
+ for (const [key, child] of Object.entries(value)) {
12
+ const childOrder = captureKeyOrder(child);
13
+ if (childOrder != null) {
14
+ children.set(key, childOrder);
15
+ }
16
+ }
17
+ return { keys: Object.keys(value), children };
18
+ }
19
+ // Reorders the keys of `current` based on how the keys were arranged in the
20
+ // original manifest. Two "sorted" layouts are recognized:
21
+ //
22
+ // 1. fully alphabetical
23
+ // 2. a leading "packages" key followed by alphabetical
24
+ //
25
+ // When the original matches one of those layouts, new keys are inserted in
26
+ // alphabetical position (preserving the leading "packages" if applicable).
27
+ // Otherwise the existing order is preserved and new keys are appended at the
28
+ // end. New manifests (no original keys) default to layout (2) to match the
29
+ // pnpm convention of placing "packages" first.
30
+ export function reorderRecursive(originalOrder, current) {
31
+ if (!isPlainObject(current))
32
+ return current;
33
+ const originalKeys = originalOrder?.keys ?? [];
34
+ const originalKeySet = new Set(originalKeys);
35
+ const survivingOriginal = originalKeys.filter((key) => Object.hasOwn(current, key));
36
+ const newKeys = Object.keys(current).filter((key) => !originalKeySet.has(key));
37
+ let orderedKeys;
38
+ if (newKeys.length === 0) {
39
+ orderedKeys = survivingOriginal;
40
+ }
41
+ else {
42
+ const layout = detectKeyLayout(originalKeys);
43
+ orderedKeys = layout === 'unordered'
44
+ ? [...survivingOriginal, ...newKeys]
45
+ : sortKeys([...survivingOriginal, ...newKeys], layout);
46
+ }
47
+ const result = {};
48
+ for (const key of orderedKeys) {
49
+ result[key] = reorderRecursive(originalOrder?.children.get(key) ?? null, current[key]);
50
+ }
51
+ return result;
52
+ }
53
+ function detectKeyLayout(keys) {
54
+ if (keys.length === 0)
55
+ return 'packages-first';
56
+ const packagesFirst = keys[0] === 'packages';
57
+ const start = packagesFirst ? 1 : 0;
58
+ for (let keyIndex = start + 1; keyIndex < keys.length; keyIndex++) {
59
+ if (lexCompare(keys[keyIndex - 1], keys[keyIndex]) > 0)
60
+ return 'unordered';
61
+ }
62
+ return packagesFirst ? 'packages-first' : 'alphabetical';
63
+ }
64
+ function sortKeys(keys, layout) {
65
+ if (layout === 'packages-first' && keys.includes('packages')) {
66
+ return ['packages', ...keys.filter((key) => key !== 'packages').sort(lexCompare)];
67
+ }
68
+ return [...keys].sort(lexCompare);
69
+ }
70
+ function isPlainObject(value) {
71
+ return value != null && typeof value === 'object' && !Array.isArray(value);
72
+ }
73
+ // New top-level pairs are inserted without `spaceBefore`, which glues them to
74
+ // the preceding pair even when the document otherwise uses blank-line
75
+ // separators between fields. Detect that style and propagate it to inserted
76
+ // entries (including reordering-induced changes such as a new key sorting to
77
+ // the front, which demotes the previously-first existing pair to a position
78
+ // that should now have a blank before it).
79
+ //
80
+ // The yaml library reads `spaceBefore` from the pair's key node when rendering
81
+ // block collections, not from the pair itself.
82
+ export function propagateBlankLinesToNewPairs(document, originalTopLevelKeys) {
83
+ if (!yaml.isMap(document.contents))
84
+ return;
85
+ const items = document.contents.items;
86
+ const originalKeySet = new Set(originalTopLevelKeys);
87
+ const usesBlankLineStyle = detectBlankLineStyle(items, originalTopLevelKeys);
88
+ for (let itemIndex = 1; itemIndex < items.length; itemIndex++) {
89
+ const key = stringKeyOf(items[itemIndex]);
90
+ if (key == null || key.spaceBefore)
91
+ continue;
92
+ if (usesBlankLineStyle || (!originalKeySet.has(key.value) && neighborHasBlankLine(items, itemIndex))) {
93
+ key.spaceBefore = true;
94
+ }
95
+ }
96
+ }
97
+ function detectBlankLineStyle(items, originalTopLevelKeys) {
98
+ const originalKeySet = new Set(originalTopLevelKeys);
99
+ // The originally-first pair never had `spaceBefore` set even in a
100
+ // blank-line-separated document — exclude it when judging the document's
101
+ // style so we still detect the style when that pair has been moved.
102
+ const originalFirstKey = originalTopLevelKeys[0] ?? null;
103
+ let originalNonFirstCount = 0;
104
+ let originalNonFirstWithBlank = 0;
105
+ for (const item of items) {
106
+ const itemKey = stringKeyOf(item);
107
+ if (itemKey == null || !originalKeySet.has(itemKey.value) || itemKey.value === originalFirstKey)
108
+ continue;
109
+ originalNonFirstCount++;
110
+ if (itemKey.spaceBefore)
111
+ originalNonFirstWithBlank++;
112
+ }
113
+ return originalNonFirstCount > 0 && originalNonFirstWithBlank === originalNonFirstCount;
114
+ }
115
+ function neighborHasBlankLine(items, itemIndex) {
116
+ const nextKey = items[itemIndex + 1] ? stringKeyOf(items[itemIndex + 1]) : null;
117
+ const prevKey = items[itemIndex - 1] ? stringKeyOf(items[itemIndex - 1]) : null;
118
+ return Boolean(nextKey?.spaceBefore || (nextKey == null && prevKey?.spaceBefore));
119
+ }
120
+ function stringKeyOf(pair) {
121
+ return yaml.isScalar(pair.key) && typeof pair.key.value === 'string'
122
+ ? pair.key
123
+ : null;
124
+ }
125
+ //# sourceMappingURL=keyOrder.js.map
@@ -0,0 +1,8 @@
1
+ import type { WorkspaceManifest } from '@pnpm/workspace.workspace-manifest-reader';
2
+ export type ExcludeListField = 'minimumReleaseAgeExclude' | 'trustPolicyExclude';
3
+ type ResolvedPackageVersions = ReadonlyMap<string, ReadonlySet<string>>;
4
+ export declare function pruneExcludeList(manifest: Partial<WorkspaceManifest> & {
5
+ [key in ExcludeListField]?: string[];
6
+ }, field: ExcludeListField, resolvedPackageVersions: ResolvedPackageVersions): boolean;
7
+ export declare function pruneAllowBuilds(manifest: Partial<WorkspaceManifest>, resolvedPackageVersions: ResolvedPackageVersions): boolean;
8
+ export {};
@@ -0,0 +1,89 @@
1
+ import { packageNameFromAllowBuildKey, UNDECIDED_ALLOW_BUILD } from '@pnpm/building.policy';
2
+ import { mergePackageVersionSpecs, parseVersionPolicyRule } from '@pnpm/config.version-policy';
3
+ // The `minimumReleaseAgeExcludePrune` / `trustPolicyExcludePrune` pass over
4
+ // the exclude list `field` names. An entry is dropped when the freshly
5
+ // resolved lockfile no longer contains what it names: exact versions that
6
+ // were not resolved are dropped (the entry goes away once none remain), and a
7
+ // bare-name entry goes away when the package is absent entirely. Glob patterns
8
+ // always stay — they are forward-looking and can't be proven stale. Entries
9
+ // that fail to parse stay untouched so cleanup never breaks an install.
10
+ export function pruneExcludeList(manifest, field, resolvedPackageVersions) {
11
+ const excludes = manifest[field];
12
+ if (excludes == null || excludes.length === 0) {
13
+ return false;
14
+ }
15
+ const survivingSpecs = [];
16
+ let changed = false;
17
+ for (const entry of excludes) {
18
+ const prunedEntry = pruneExcludeEntry(entry, resolvedPackageVersions);
19
+ survivingSpecs.push(...prunedEntry.survivingSpecs);
20
+ changed = prunedEntry.changed || changed;
21
+ }
22
+ if (!changed) {
23
+ return false;
24
+ }
25
+ if (survivingSpecs.length === 0) {
26
+ delete manifest[field];
27
+ }
28
+ else {
29
+ manifest[field] = survivingSpecs;
30
+ }
31
+ return true;
32
+ }
33
+ function pruneExcludeEntry(entry, resolvedPackageVersions) {
34
+ const rule = tryParseVersionPolicyRule(entry);
35
+ if (rule == null) {
36
+ return { survivingSpecs: [entry], changed: false };
37
+ }
38
+ const { packageName, exactVersions } = rule;
39
+ if (exactVersions.length === 0) {
40
+ const isStillRelevant = packageName.includes('*') || resolvedPackageVersions.has(packageName);
41
+ return isStillRelevant
42
+ ? { survivingSpecs: [entry], changed: false }
43
+ : { survivingSpecs: [], changed: true };
44
+ }
45
+ const resolved = resolvedPackageVersions.get(packageName);
46
+ const survivingVersions = exactVersions.filter((version) => resolved?.has(version));
47
+ if (survivingVersions.length === exactVersions.length) {
48
+ return { survivingSpecs: [entry], changed: false };
49
+ }
50
+ if (survivingVersions.length === 0) {
51
+ return { survivingSpecs: [], changed: true };
52
+ }
53
+ return {
54
+ survivingSpecs: mergePackageVersionSpecs([`${packageName}@${survivingVersions.join(' || ')}`]),
55
+ changed: true,
56
+ };
57
+ }
58
+ function tryParseVersionPolicyRule(entry) {
59
+ try {
60
+ return parseVersionPolicyRule(entry);
61
+ }
62
+ catch {
63
+ return undefined;
64
+ }
65
+ }
66
+ // Drops undecided placeholder entries whose package is provably absent from
67
+ // the resolved lockfile. Explicit decisions, keys with no provable package
68
+ // name, and entries for still-resolved packages always stay.
69
+ export function pruneAllowBuilds(manifest, resolvedPackageVersions) {
70
+ const allowBuilds = manifest.allowBuilds;
71
+ if (allowBuilds == null) {
72
+ return false;
73
+ }
74
+ let changed = false;
75
+ for (const [key, value] of Object.entries(allowBuilds)) {
76
+ if (value !== UNDECIDED_ALLOW_BUILD)
77
+ continue;
78
+ const packageName = packageNameFromAllowBuildKey(key);
79
+ if (packageName == null || resolvedPackageVersions.has(packageName))
80
+ continue;
81
+ delete allowBuilds[key];
82
+ changed = true;
83
+ }
84
+ if (changed && Object.keys(allowBuilds).length === 0) {
85
+ delete manifest.allowBuilds;
86
+ }
87
+ return changed;
88
+ }
89
+ //# sourceMappingURL=pruneResolvedLists.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnpm/workspace.workspace-manifest-writer",
3
- "version": "1100.2.2",
3
+ "version": "1100.2.4",
4
4
  "description": "Updates the workspace manifest file",
5
5
  "keywords": [
6
6
  "pnpm",
@@ -27,15 +27,15 @@
27
27
  "!*.map"
28
28
  ],
29
29
  "dependencies": {
30
- "@pnpm/building.policy": "1100.1.3",
30
+ "@pnpm/building.policy": "1100.1.4",
31
31
  "@pnpm/catalogs.types": "1100.0.1",
32
- "@pnpm/config.parse-overrides": "1100.1.6",
33
- "@pnpm/config.version-policy": "1100.2.4",
32
+ "@pnpm/config.parse-overrides": "1100.1.7",
33
+ "@pnpm/config.version-policy": "1100.2.5",
34
34
  "@pnpm/constants": "1102.0.0",
35
- "@pnpm/lockfile.types": "1100.1.3",
35
+ "@pnpm/lockfile.types": "1100.1.4",
36
36
  "@pnpm/text.ordinal-comparator": "1100.0.0",
37
37
  "@pnpm/types": "1102.1.1",
38
- "@pnpm/workspace.workspace-manifest-reader": "1100.2.0",
38
+ "@pnpm/workspace.workspace-manifest-reader": "1100.2.1",
39
39
  "@pnpm/yaml.document-sync": "1100.0.2",
40
40
  "ramda": "npm:@pnpm/ramda@0.28.1",
41
41
  "write-file-atomic": "^7.0.1",
@@ -43,10 +43,10 @@
43
43
  },
44
44
  "devDependencies": {
45
45
  "@jest/globals": "30.4.1",
46
- "@pnpm/prepare": "1100.0.32",
46
+ "@pnpm/prepare": "1100.0.34",
47
47
  "@pnpm/prepare-temp-dir": "1100.0.1",
48
- "@pnpm/workspace.projects-reader": "1101.1.0",
49
- "@pnpm/workspace.workspace-manifest-writer": "1100.2.2",
48
+ "@pnpm/workspace.projects-reader": "1101.1.1",
49
+ "@pnpm/workspace.workspace-manifest-writer": "1100.2.4",
50
50
  "@types/ramda": "0.32.0",
51
51
  "@types/write-file-atomic": "^4.0.3",
52
52
  "read-yaml-file": "^3.0.0",