pnpm-settings-migrator 0.15.0 → 0.16.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/README.md +27 -6
- package/dist/cli.mjs +64 -4
- package/dist/index.d.mts +40 -2
- package/dist/index.mjs +63 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -217,6 +217,26 @@ the lockfile. Existing linker strings and boolean `lockfile` values still work.
|
|
|
217
217
|
it from workspace configuration. Unsupported or invalid nested settings stay
|
|
218
218
|
intact in their source; the migrator does not add pnpm's defaults.
|
|
219
219
|
|
|
220
|
+
For pnpm 12.11.0 and later stable v12 releases, `permissions` maps dependency
|
|
221
|
+
names or package IDs to `build` and `skills` decisions. Boolean `build`
|
|
222
|
+
decisions override matching `allowBuilds` entries; strings are undecided prompts
|
|
223
|
+
and null leaves a capability unset. Both settings are preserved for pnpm to
|
|
224
|
+
apply its precedence. Unknown capabilities or invalid nested values keep the
|
|
225
|
+
entire source object intact.
|
|
226
|
+
|
|
227
|
+
`skills.dirs` accepts an array of workspace-relative agent skill directories;
|
|
228
|
+
an empty array disables linking. Workspace `provenance` also requires 12.11.0
|
|
229
|
+
for v12 targets and accepts boolean or null values. Its v11 support is unchanged.
|
|
230
|
+
For example, targeting 12.11.0 migrates
|
|
231
|
+
`{ "pnpm": { "permissions": { "example": { "build": false, "skills": true } }, "skills": { "dirs": [".agents/skills"] } } }`
|
|
232
|
+
to equivalent workspace YAML. Targeting 12.10.1 retains these settings with
|
|
233
|
+
diagnostics.
|
|
234
|
+
|
|
235
|
+
pnpm v12 reads `filter` and `filterProd` from CLI arguments or `updateConfig`
|
|
236
|
+
hooks, not workspace YAML. These settings remain in their source with
|
|
237
|
+
diagnostics for v12 targets; existing YAML containing them blocks migration.
|
|
238
|
+
The 12.11.2 hook fix does not add workspace support.
|
|
239
|
+
|
|
220
240
|
</details>
|
|
221
241
|
|
|
222
242
|
<details>
|
|
@@ -291,14 +311,15 @@ Notes:
|
|
|
291
311
|
- The migrator does not update the `packageManager` version, CI environment variables,
|
|
292
312
|
shell setup, or pnpm commands in scripts. When `packageManager` still pins pnpm 10,
|
|
293
313
|
pass `--compatibility v11` explicitly and update the pin separately.
|
|
294
|
-
- Compatibility checks cover pnpm 11.28.5 and 12.
|
|
314
|
+
- Compatibility checks cover pnpm 11.28.5 and 12.11.2, including 11.28.0,
|
|
295
315
|
11.28.1, 11.28.2, 11.28.3, 11.28.4, 12.7.0, 12.8.0, 12.8.1, 12.8.2,
|
|
296
|
-
12.9.0,
|
|
316
|
+
12.9.0, 12.9.1, 12.10.0, 12.10.1, 12.11.0, and 12.11.1.
|
|
317
|
+
Earlier regressions remain at 11.25.0,
|
|
297
318
|
11.26.0, 11.27.1, 12.2.1, 12.3.4, 12.4.0, 12.4.2, 12.5.0, 12.5.1, and 12.6.0.
|
|
298
|
-
As [audited on 2026-10-
|
|
299
|
-
npm `latest` is 12.
|
|
319
|
+
As [audited on 2026-10-10](docs/research/pnpm-settings-bump-2026-10-10.md),
|
|
320
|
+
npm `latest` is 12.10.1; the highest confirmed stable release is 12.11.2 on
|
|
300
321
|
`next-12`. The v11 target is 11.28.5 on `next-11`, while `latest-11` is
|
|
301
|
-
11.28.2. The project is pinned to 12.
|
|
322
|
+
11.28.2. The project is pinned to 12.10.1. These checks verify the documented
|
|
302
323
|
fixtures, not every setting in every release. v10 has unit regressions and
|
|
303
324
|
source review through 10.34.6; real v10 consumption remains unverified.
|
|
304
325
|
The removed `pnpm install --resolution-only` CLI flag is outside this settings
|
|
@@ -373,7 +394,7 @@ Strategy to handle conflicts when merging settings with existing `pnpm-workspace
|
|
|
373
394
|
`packageConfigs` matcher arrays preserve order and repeated entries because the
|
|
374
395
|
last matching entry wins. With `merge`, incoming matchers follow existing ones;
|
|
375
396
|
an overlapping end/start sequence is reused to keep repeated migrations stable.
|
|
376
|
-
`filter` and `filterProd` use the same ordered merging: a repeated inclusion can
|
|
397
|
+
For v11 targets, `filter` and `filterProd` use the same ordered merging: a repeated inclusion can
|
|
377
398
|
restore projects removed by an earlier exclusion. Cleanup verifies the combined
|
|
378
399
|
selector sequence. If package cleanup is disabled, later `.npmrc` selectors are
|
|
379
400
|
retained when needed to keep repeated migrations stable.
|
package/dist/cli.mjs
CHANGED
|
@@ -502,7 +502,12 @@ const PNPM_V11_WORKSPACE_SETTINGS_FIELDS = unique([...PNPM_V10_NPMRC_SETTINGS_FI
|
|
|
502
502
|
/**
|
|
503
503
|
* Settings that are supported by v11 but not by pnpm v12.
|
|
504
504
|
*/
|
|
505
|
-
const PNPM_V11_ONLY_WORKSPACE_SETTINGS = [
|
|
505
|
+
const PNPM_V11_ONLY_WORKSPACE_SETTINGS = [
|
|
506
|
+
"confirmModulesPurge",
|
|
507
|
+
"filter",
|
|
508
|
+
"filterProd",
|
|
509
|
+
"packageConfigs"
|
|
510
|
+
];
|
|
506
511
|
/**
|
|
507
512
|
* Fields pnpm v11 accepts inside a `packageConfigs` entry.
|
|
508
513
|
*/
|
|
@@ -614,6 +619,22 @@ const PNPM_V12_10_MINIMUM_VERSION = [
|
|
|
614
619
|
0
|
|
615
620
|
];
|
|
616
621
|
/**
|
|
622
|
+
* Release introducing package permissions, agent skills, and workspace provenance.
|
|
623
|
+
*/
|
|
624
|
+
const PNPM_V12_11_MINIMUM_VERSION = [
|
|
625
|
+
12,
|
|
626
|
+
11,
|
|
627
|
+
0
|
|
628
|
+
];
|
|
629
|
+
/**
|
|
630
|
+
* Workspace settings first consumed by pnpm v12 in 12.11.0.
|
|
631
|
+
*/
|
|
632
|
+
const PNPM_V12_11_WORKSPACE_SETTINGS = [
|
|
633
|
+
"permissions",
|
|
634
|
+
"skills",
|
|
635
|
+
"provenance"
|
|
636
|
+
];
|
|
637
|
+
/**
|
|
617
638
|
* Workspace settings first consumed by pnpm v12 in 12.10.0.
|
|
618
639
|
*/
|
|
619
640
|
const PNPM_V12_10_WORKSPACE_SETTINGS = ["failIfNoMatch"];
|
|
@@ -631,6 +652,11 @@ const PNPM_V12_7_WORKSPACE_SETTINGS = [
|
|
|
631
652
|
* @see https://github.com/pnpm/pnpm/blob/v12.4.0/pnpm/crates/config/src/workspace_yaml.rs
|
|
632
653
|
*/
|
|
633
654
|
const PNPM_SETTINGS_CAPABILITIES = [
|
|
655
|
+
{
|
|
656
|
+
minimumVersion: PNPM_V12_11_MINIMUM_VERSION,
|
|
657
|
+
workspaceFields: PNPM_V12_11_WORKSPACE_SETTINGS,
|
|
658
|
+
taskFields: []
|
|
659
|
+
},
|
|
634
660
|
{
|
|
635
661
|
minimumVersion: PNPM_V11_28_MINIMUM_VERSION,
|
|
636
662
|
workspaceFields: ["forceIgnoresPlatform"],
|
|
@@ -725,7 +751,7 @@ const PNPM_V12_REGISTRY_DECLARATION_FIELDS = [
|
|
|
725
751
|
/**
|
|
726
752
|
* Settings accepted by a pnpm v12 project workspace manifest.
|
|
727
753
|
*/
|
|
728
|
-
const PNPM_V12_WORKSPACE_SETTINGS_FIELDS = [...PNPM_V11_WORKSPACE_SETTINGS_FIELDS.filter((field) => !v11OnlyWorkspaceSettings.has(field) && !PNPM_V12_6_WORKSPACE_SETTINGS.includes(field) && !PNPM_V12_7_WORKSPACE_SETTINGS.includes(field) && !PNPM_V12_10_WORKSPACE_SETTINGS.includes(field)), ...PNPM_V12_ONLY_WORKSPACE_SETTINGS];
|
|
754
|
+
const PNPM_V12_WORKSPACE_SETTINGS_FIELDS = [...PNPM_V11_WORKSPACE_SETTINGS_FIELDS.filter((field) => !v11OnlyWorkspaceSettings.has(field) && !PNPM_V12_6_WORKSPACE_SETTINGS.includes(field) && !PNPM_V12_7_WORKSPACE_SETTINGS.includes(field) && !PNPM_V12_10_WORKSPACE_SETTINGS.includes(field) && !PNPM_V12_11_WORKSPACE_SETTINGS.includes(field)), ...PNPM_V12_ONLY_WORKSPACE_SETTINGS];
|
|
729
755
|
//#endregion
|
|
730
756
|
//#region src/constants/settings-schema.ts
|
|
731
757
|
/**
|
|
@@ -1093,6 +1119,37 @@ function formatSettingsIssues(options) {
|
|
|
1093
1119
|
return warnings;
|
|
1094
1120
|
}
|
|
1095
1121
|
//#endregion
|
|
1122
|
+
//#region src/features/settings/permissions.ts
|
|
1123
|
+
/**
|
|
1124
|
+
* Validate a dependency's capability map without dropping unknown permissions.
|
|
1125
|
+
*
|
|
1126
|
+
* @param value - Untrusted per-package permission entry
|
|
1127
|
+
*
|
|
1128
|
+
* @returns Whether pnpm cannot consume every capability in the entry
|
|
1129
|
+
*/
|
|
1130
|
+
function hasInvalidPackagePermissions(value) {
|
|
1131
|
+
if (value === null) return false;
|
|
1132
|
+
if (!value || typeof value !== "object" || isArray(value)) return true;
|
|
1133
|
+
return Object.entries(value).some(([capability, decision]) => !["build", "skills"].includes(capability) || decision !== null && !isBoolean(decision) && !isString(decision));
|
|
1134
|
+
}
|
|
1135
|
+
/**
|
|
1136
|
+
* Validate permissions and skill directories introduced in pnpm 12.11.
|
|
1137
|
+
* Preserve an entire object when a nested value is invalid or ignored upstream.
|
|
1138
|
+
*
|
|
1139
|
+
* @param key - Canonical workspace setting name
|
|
1140
|
+
* @param value - Untrusted source or existing workspace value
|
|
1141
|
+
*
|
|
1142
|
+
* @returns Whether the setting contains unsupported nested values
|
|
1143
|
+
*/
|
|
1144
|
+
function hasInvalidPermissionSettings(key, value) {
|
|
1145
|
+
if (!["permissions", "skills"].includes(key) || value === null) return false;
|
|
1146
|
+
if (!value || typeof value !== "object" || isArray(value)) return true;
|
|
1147
|
+
if (key === "permissions") return Object.values(value).some(hasInvalidPackagePermissions);
|
|
1148
|
+
if (Object.keys(value).some((field) => field !== "dirs")) return true;
|
|
1149
|
+
const dirs = Reflect.get(value, "dirs");
|
|
1150
|
+
return Object.hasOwn(value, "dirs") && dirs !== null && (!isArray(dirs) || !dirs.every(isString));
|
|
1151
|
+
}
|
|
1152
|
+
//#endregion
|
|
1096
1153
|
//#region src/features/settings/pnpm-v12-values.ts
|
|
1097
1154
|
/**
|
|
1098
1155
|
* Check a loaded linker object without discarding unsupported options.
|
|
@@ -1254,6 +1311,7 @@ function hasInvalidScalarValue(key, value, target) {
|
|
|
1254
1311
|
"ndjson",
|
|
1255
1312
|
"silent"
|
|
1256
1313
|
].includes(value);
|
|
1314
|
+
if (key === "provenance") return value !== null && !isBoolean(value);
|
|
1257
1315
|
if (key === "progress") return !isBoolean(value);
|
|
1258
1316
|
if (key === "tagVersionPrefix") return !isString(value);
|
|
1259
1317
|
if (key === "loglevel") return !isString(value) || !value.includes("${") && ![
|
|
@@ -1294,7 +1352,7 @@ function hasInvalidReleaseValue(key, value, target) {
|
|
|
1294
1352
|
* @returns Whether the value uses a shape unsupported by the selected release
|
|
1295
1353
|
*/
|
|
1296
1354
|
function hasIncompatibleSettingValue(key, value, target) {
|
|
1297
|
-
if (hasInvalidReleaseValue(key, value, target) || hasInvalidV11PatchValue(key, value, target) || hasIncompatibleV12SettingValue(key, value, target)) return true;
|
|
1355
|
+
if (hasInvalidPermissionSettings(key, value) || hasInvalidReleaseValue(key, value, target) || hasInvalidV11PatchValue(key, value, target) || hasIncompatibleV12SettingValue(key, value, target)) return true;
|
|
1298
1356
|
if (hasInvalidScalarValue(key, value, target)) return true;
|
|
1299
1357
|
const supportsV12_5 = supportsMinimumVersion(target.version, PNPM_V12_5_MINIMUM_VERSION);
|
|
1300
1358
|
if (key === "supportedArchitectures" && isArray(value)) return !supportsV12_5;
|
|
@@ -2321,6 +2379,7 @@ function resolveReplacementSettingKey(sourceKey, targetKey, npmrc) {
|
|
|
2321
2379
|
* @returns Original source keys that can be pruned
|
|
2322
2380
|
*/
|
|
2323
2381
|
function selectAppliedRootKeys({ appliedOrderedFilterKeys, finalSettings, normalizedSettings, keys, npmrc = false, runtimeApplied, runtimeVersion, sourceSettings }) {
|
|
2382
|
+
const hasUnappliedSkillsDisable = normalizedSettings.skills?.dirs?.length === 0 && finalSettings.skills?.dirs?.length !== 0;
|
|
2324
2383
|
return keys.filter((sourceKey) => {
|
|
2325
2384
|
const targetKey = npmrc ? Object.keys(camelcaseKeys({ [sourceKey]: true }))[0] ?? sourceKey : sourceKey;
|
|
2326
2385
|
if (!Object.hasOwn(normalizedSettings, targetKey)) {
|
|
@@ -2343,6 +2402,7 @@ function selectAppliedRootKeys({ appliedOrderedFilterKeys, finalSettings, normal
|
|
|
2343
2402
|
const expected = Reflect.get(normalizedSettings, targetKey);
|
|
2344
2403
|
return appliedOrderedFilterKeys.has(targetKey) && containsOrderedFilterValue(actual, expected);
|
|
2345
2404
|
}
|
|
2405
|
+
if (targetKey === "skills" && hasUnappliedSkillsDisable) return false;
|
|
2346
2406
|
return containsMigratedValue(Reflect.get(finalSettings, targetKey), Reflect.get(normalizedSettings, targetKey));
|
|
2347
2407
|
});
|
|
2348
2408
|
}
|
|
@@ -3147,7 +3207,7 @@ const bold = getColor("bold");
|
|
|
3147
3207
|
//#endregion
|
|
3148
3208
|
//#region package.json
|
|
3149
3209
|
var name = "pnpm-settings-migrator";
|
|
3150
|
-
var version = "0.
|
|
3210
|
+
var version = "0.16.0";
|
|
3151
3211
|
//#endregion
|
|
3152
3212
|
//#region src/cli/options.ts
|
|
3153
3213
|
/**
|
package/dist/index.d.mts
CHANGED
|
@@ -230,10 +230,43 @@ interface PnpmLockfileSettings {
|
|
|
230
230
|
*/
|
|
231
231
|
includeResolutionSettings?: boolean | null;
|
|
232
232
|
}
|
|
233
|
+
/**
|
|
234
|
+
* Dependency capabilities introduced in pnpm 12.11.0. Strings are undecided
|
|
235
|
+
* prompts; null leaves a capability unset.
|
|
236
|
+
*/
|
|
237
|
+
interface PnpmPackagePermissions {
|
|
238
|
+
/**
|
|
239
|
+
* Lifecycle script decision, taking precedence over the matching allowBuilds
|
|
240
|
+
* entry when boolean. An undecided string leaves that entry effective.
|
|
241
|
+
*/
|
|
242
|
+
build?: boolean | string | null;
|
|
243
|
+
/**
|
|
244
|
+
* Whether pnpm may link the agent skills shipped by the dependency.
|
|
245
|
+
*/
|
|
246
|
+
skills?: boolean | string | null;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Agent skill linking configuration introduced in pnpm 12.11.0.
|
|
250
|
+
*/
|
|
251
|
+
interface PnpmSkillsSettings {
|
|
252
|
+
/**
|
|
253
|
+
* Workspace-relative agent skill directories, replacing detected directories.
|
|
254
|
+
* An empty list disables linking; null leaves directory detection enabled.
|
|
255
|
+
*/
|
|
256
|
+
dirs?: string[] | null;
|
|
257
|
+
}
|
|
233
258
|
/**
|
|
234
259
|
* Settings supported by pnpm v12, subject to the resolved version capabilities.
|
|
235
260
|
*/
|
|
236
261
|
interface PnpmSettingsV12 {
|
|
262
|
+
/**
|
|
263
|
+
* Per-dependency build and agent skill permissions (pnpm 12.11+).
|
|
264
|
+
*/
|
|
265
|
+
permissions?: Record<string, PnpmPackagePermissions | null> | null;
|
|
266
|
+
/**
|
|
267
|
+
* Agent skill linking options (pnpm 12.11+).
|
|
268
|
+
*/
|
|
269
|
+
skills?: PnpmSkillsSettings | null;
|
|
237
270
|
/**
|
|
238
271
|
* Dependency linking mode. Loaded linking and its options require pnpm 12.10+.
|
|
239
272
|
*/
|
|
@@ -440,6 +473,11 @@ interface PnpmSettingsDeprecated {
|
|
|
440
473
|
* Settings introduced in pnpm v11.
|
|
441
474
|
*/
|
|
442
475
|
interface PnpmSettingsV11 {
|
|
476
|
+
/**
|
|
477
|
+
* Publish provenance preference. Consumed from workspace configuration by
|
|
478
|
+
* pnpm v11 and pnpm v12 starting with 12.11. Null leaves it unset.
|
|
479
|
+
*/
|
|
480
|
+
provenance?: boolean | null;
|
|
443
481
|
/**
|
|
444
482
|
* Fail when no workspace project matches a filter. Accepted by pnpm v11 and
|
|
445
483
|
* consumed from workspace configuration by pnpm v12 starting with 12.10.
|
|
@@ -484,7 +522,7 @@ interface PnpmSettingsV11 {
|
|
|
484
522
|
/**
|
|
485
523
|
* `pnpm-workspace.yaml` types.
|
|
486
524
|
*/
|
|
487
|
-
type PnpmWorkspace = Omit<PnpmSettings, 'lockfile' | 'nodeLinker' | 'registries' | 'supportedArchitectures' | 'tasks'> & PnpmSettingsDeprecated & PnpmSettingsV11 & PnpmSettingsV12 & PnpmWorkspaceLegacy;
|
|
525
|
+
type PnpmWorkspace = Omit<PnpmSettings, 'lockfile' | 'nodeLinker' | 'provenance' | 'registries' | 'supportedArchitectures' | 'tasks'> & PnpmSettingsDeprecated & PnpmSettingsV11 & PnpmSettingsV12 & PnpmWorkspaceLegacy;
|
|
488
526
|
//#endregion
|
|
489
527
|
//#region src/types/package-json.d.ts
|
|
490
528
|
/**
|
|
@@ -692,4 +730,4 @@ export declare function migratePnpmSettings(rawOptions?: Options): Promise<Migra
|
|
|
692
730
|
*/
|
|
693
731
|
export declare function resolveOptions(options?: Options): ResolvedOptions;
|
|
694
732
|
//#endregion
|
|
695
|
-
export type { CompatibilityTarget, GlobalShimPolicy, MergeStrategy, MigrationResult, NpmRC, Options, PackageJson, PackageManagerEngine, PnpmCargoSettings, PnpmLoadedNodeLinkerSettings, PnpmLockfileSettings, PnpmPythonSettings, PnpmRegistryDeclaration, PnpmSettingsDeprecated, PnpmSettingsV11, PnpmSettingsV12, PnpmTaskSettings, PnpmWorkspace, PnpmWorkspaceLegacy, ResolvedOptions, RuntimeEngine, SettingsChange };
|
|
733
|
+
export type { CompatibilityTarget, GlobalShimPolicy, MergeStrategy, MigrationResult, NpmRC, Options, PackageJson, PackageManagerEngine, PnpmCargoSettings, PnpmLoadedNodeLinkerSettings, PnpmLockfileSettings, PnpmPackagePermissions, PnpmPythonSettings, PnpmRegistryDeclaration, PnpmSettingsDeprecated, PnpmSettingsV11, PnpmSettingsV12, PnpmSkillsSettings, PnpmTaskSettings, PnpmWorkspace, PnpmWorkspaceLegacy, ResolvedOptions, RuntimeEngine, SettingsChange };
|
package/dist/index.mjs
CHANGED
|
@@ -500,7 +500,12 @@ const PNPM_V11_WORKSPACE_SETTINGS_FIELDS = unique([...PNPM_V10_NPMRC_SETTINGS_FI
|
|
|
500
500
|
/**
|
|
501
501
|
* Settings that are supported by v11 but not by pnpm v12.
|
|
502
502
|
*/
|
|
503
|
-
const PNPM_V11_ONLY_WORKSPACE_SETTINGS = [
|
|
503
|
+
const PNPM_V11_ONLY_WORKSPACE_SETTINGS = [
|
|
504
|
+
"confirmModulesPurge",
|
|
505
|
+
"filter",
|
|
506
|
+
"filterProd",
|
|
507
|
+
"packageConfigs"
|
|
508
|
+
];
|
|
504
509
|
/**
|
|
505
510
|
* Fields pnpm v11 accepts inside a `packageConfigs` entry.
|
|
506
511
|
*/
|
|
@@ -612,6 +617,22 @@ const PNPM_V12_10_MINIMUM_VERSION = [
|
|
|
612
617
|
0
|
|
613
618
|
];
|
|
614
619
|
/**
|
|
620
|
+
* Release introducing package permissions, agent skills, and workspace provenance.
|
|
621
|
+
*/
|
|
622
|
+
const PNPM_V12_11_MINIMUM_VERSION = [
|
|
623
|
+
12,
|
|
624
|
+
11,
|
|
625
|
+
0
|
|
626
|
+
];
|
|
627
|
+
/**
|
|
628
|
+
* Workspace settings first consumed by pnpm v12 in 12.11.0.
|
|
629
|
+
*/
|
|
630
|
+
const PNPM_V12_11_WORKSPACE_SETTINGS = [
|
|
631
|
+
"permissions",
|
|
632
|
+
"skills",
|
|
633
|
+
"provenance"
|
|
634
|
+
];
|
|
635
|
+
/**
|
|
615
636
|
* Workspace settings first consumed by pnpm v12 in 12.10.0.
|
|
616
637
|
*/
|
|
617
638
|
const PNPM_V12_10_WORKSPACE_SETTINGS = ["failIfNoMatch"];
|
|
@@ -629,6 +650,11 @@ const PNPM_V12_7_WORKSPACE_SETTINGS = [
|
|
|
629
650
|
* @see https://github.com/pnpm/pnpm/blob/v12.4.0/pnpm/crates/config/src/workspace_yaml.rs
|
|
630
651
|
*/
|
|
631
652
|
const PNPM_SETTINGS_CAPABILITIES = [
|
|
653
|
+
{
|
|
654
|
+
minimumVersion: PNPM_V12_11_MINIMUM_VERSION,
|
|
655
|
+
workspaceFields: PNPM_V12_11_WORKSPACE_SETTINGS,
|
|
656
|
+
taskFields: []
|
|
657
|
+
},
|
|
632
658
|
{
|
|
633
659
|
minimumVersion: PNPM_V11_28_MINIMUM_VERSION,
|
|
634
660
|
workspaceFields: ["forceIgnoresPlatform"],
|
|
@@ -723,7 +749,7 @@ const PNPM_V12_REGISTRY_DECLARATION_FIELDS = [
|
|
|
723
749
|
/**
|
|
724
750
|
* Settings accepted by a pnpm v12 project workspace manifest.
|
|
725
751
|
*/
|
|
726
|
-
const PNPM_V12_WORKSPACE_SETTINGS_FIELDS = [...PNPM_V11_WORKSPACE_SETTINGS_FIELDS.filter((field) => !v11OnlyWorkspaceSettings.has(field) && !PNPM_V12_6_WORKSPACE_SETTINGS.includes(field) && !PNPM_V12_7_WORKSPACE_SETTINGS.includes(field) && !PNPM_V12_10_WORKSPACE_SETTINGS.includes(field)), ...PNPM_V12_ONLY_WORKSPACE_SETTINGS];
|
|
752
|
+
const PNPM_V12_WORKSPACE_SETTINGS_FIELDS = [...PNPM_V11_WORKSPACE_SETTINGS_FIELDS.filter((field) => !v11OnlyWorkspaceSettings.has(field) && !PNPM_V12_6_WORKSPACE_SETTINGS.includes(field) && !PNPM_V12_7_WORKSPACE_SETTINGS.includes(field) && !PNPM_V12_10_WORKSPACE_SETTINGS.includes(field) && !PNPM_V12_11_WORKSPACE_SETTINGS.includes(field)), ...PNPM_V12_ONLY_WORKSPACE_SETTINGS];
|
|
727
753
|
//#endregion
|
|
728
754
|
//#region src/constants/settings-schema.ts
|
|
729
755
|
/**
|
|
@@ -1086,6 +1112,37 @@ function formatSettingsIssues(options) {
|
|
|
1086
1112
|
return warnings;
|
|
1087
1113
|
}
|
|
1088
1114
|
//#endregion
|
|
1115
|
+
//#region src/features/settings/permissions.ts
|
|
1116
|
+
/**
|
|
1117
|
+
* Validate a dependency's capability map without dropping unknown permissions.
|
|
1118
|
+
*
|
|
1119
|
+
* @param value - Untrusted per-package permission entry
|
|
1120
|
+
*
|
|
1121
|
+
* @returns Whether pnpm cannot consume every capability in the entry
|
|
1122
|
+
*/
|
|
1123
|
+
function hasInvalidPackagePermissions(value) {
|
|
1124
|
+
if (value === null) return false;
|
|
1125
|
+
if (!value || typeof value !== "object" || isArray(value)) return true;
|
|
1126
|
+
return Object.entries(value).some(([capability, decision]) => !["build", "skills"].includes(capability) || decision !== null && !isBoolean(decision) && !isString(decision));
|
|
1127
|
+
}
|
|
1128
|
+
/**
|
|
1129
|
+
* Validate permissions and skill directories introduced in pnpm 12.11.
|
|
1130
|
+
* Preserve an entire object when a nested value is invalid or ignored upstream.
|
|
1131
|
+
*
|
|
1132
|
+
* @param key - Canonical workspace setting name
|
|
1133
|
+
* @param value - Untrusted source or existing workspace value
|
|
1134
|
+
*
|
|
1135
|
+
* @returns Whether the setting contains unsupported nested values
|
|
1136
|
+
*/
|
|
1137
|
+
function hasInvalidPermissionSettings(key, value) {
|
|
1138
|
+
if (!["permissions", "skills"].includes(key) || value === null) return false;
|
|
1139
|
+
if (!value || typeof value !== "object" || isArray(value)) return true;
|
|
1140
|
+
if (key === "permissions") return Object.values(value).some(hasInvalidPackagePermissions);
|
|
1141
|
+
if (Object.keys(value).some((field) => field !== "dirs")) return true;
|
|
1142
|
+
const dirs = Reflect.get(value, "dirs");
|
|
1143
|
+
return Object.hasOwn(value, "dirs") && dirs !== null && (!isArray(dirs) || !dirs.every(isString));
|
|
1144
|
+
}
|
|
1145
|
+
//#endregion
|
|
1089
1146
|
//#region src/features/settings/pnpm-v12-values.ts
|
|
1090
1147
|
/**
|
|
1091
1148
|
* Check a loaded linker object without discarding unsupported options.
|
|
@@ -1247,6 +1304,7 @@ function hasInvalidScalarValue(key, value, target) {
|
|
|
1247
1304
|
"ndjson",
|
|
1248
1305
|
"silent"
|
|
1249
1306
|
].includes(value);
|
|
1307
|
+
if (key === "provenance") return value !== null && !isBoolean(value);
|
|
1250
1308
|
if (key === "progress") return !isBoolean(value);
|
|
1251
1309
|
if (key === "tagVersionPrefix") return !isString(value);
|
|
1252
1310
|
if (key === "loglevel") return !isString(value) || !value.includes("${") && ![
|
|
@@ -1287,7 +1345,7 @@ function hasInvalidReleaseValue(key, value, target) {
|
|
|
1287
1345
|
* @returns Whether the value uses a shape unsupported by the selected release
|
|
1288
1346
|
*/
|
|
1289
1347
|
function hasIncompatibleSettingValue(key, value, target) {
|
|
1290
|
-
if (hasInvalidReleaseValue(key, value, target) || hasInvalidV11PatchValue(key, value, target) || hasIncompatibleV12SettingValue(key, value, target)) return true;
|
|
1348
|
+
if (hasInvalidPermissionSettings(key, value) || hasInvalidReleaseValue(key, value, target) || hasInvalidV11PatchValue(key, value, target) || hasIncompatibleV12SettingValue(key, value, target)) return true;
|
|
1291
1349
|
if (hasInvalidScalarValue(key, value, target)) return true;
|
|
1292
1350
|
const supportsV12_5 = supportsMinimumVersion(target.version, PNPM_V12_5_MINIMUM_VERSION);
|
|
1293
1351
|
if (key === "supportedArchitectures" && isArray(value)) return !supportsV12_5;
|
|
@@ -2314,6 +2372,7 @@ function resolveReplacementSettingKey(sourceKey, targetKey, npmrc) {
|
|
|
2314
2372
|
* @returns Original source keys that can be pruned
|
|
2315
2373
|
*/
|
|
2316
2374
|
function selectAppliedRootKeys({ appliedOrderedFilterKeys, finalSettings, normalizedSettings, keys, npmrc = false, runtimeApplied, runtimeVersion, sourceSettings }) {
|
|
2375
|
+
const hasUnappliedSkillsDisable = normalizedSettings.skills?.dirs?.length === 0 && finalSettings.skills?.dirs?.length !== 0;
|
|
2317
2376
|
return keys.filter((sourceKey) => {
|
|
2318
2377
|
const targetKey = npmrc ? Object.keys(camelcaseKeys({ [sourceKey]: true }))[0] ?? sourceKey : sourceKey;
|
|
2319
2378
|
if (!Object.hasOwn(normalizedSettings, targetKey)) {
|
|
@@ -2336,6 +2395,7 @@ function selectAppliedRootKeys({ appliedOrderedFilterKeys, finalSettings, normal
|
|
|
2336
2395
|
const expected = Reflect.get(normalizedSettings, targetKey);
|
|
2337
2396
|
return appliedOrderedFilterKeys.has(targetKey) && containsOrderedFilterValue(actual, expected);
|
|
2338
2397
|
}
|
|
2398
|
+
if (targetKey === "skills" && hasUnappliedSkillsDisable) return false;
|
|
2339
2399
|
return containsMigratedValue(Reflect.get(finalSettings, targetKey), Reflect.get(normalizedSettings, targetKey));
|
|
2340
2400
|
});
|
|
2341
2401
|
}
|