pnpm-settings-migrator 0.5.0 → 0.6.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/README.md CHANGED
@@ -39,10 +39,19 @@ Sort keys when write `pnpm-workspace.yaml`.
39
39
  Compatibility target for migrated settings:
40
40
 
41
41
  - `auto`: infer from `packageManager` (`pnpm@11+` => `v11`, otherwise `v10`)
42
- - `v10`: keep legacy settings as-is
42
+ - `v10`: keep legacy settings as-is and migrate schema-aligned pnpm config keys from `.npmrc`
43
43
  - `v11`: normalize to v11-compatible settings (`allowBuilds`, `allowUnusedPatches`, etc.)
44
44
  and migrate all non auth/registry `.npmrc` entries to `pnpm-workspace.yaml`
45
45
 
46
+ Notes:
47
+
48
+ - `.npmrc` migration is aligned with pnpm workspace config fields such as `node-linker`,
49
+ hoist settings, lockfile settings, store settings, proxy settings, and other pnpm
50
+ runtime/install options.
51
+ - Workspace manifest-only fields such as `packages`, `catalog`, and `catalogs` are not
52
+ migrated from `.npmrc`.
53
+ - In `v11`, auth/registry-related keys still stay in `.npmrc`.
54
+
46
55
  ### `--replace-deprecated`
47
56
 
48
57
  - **Type**: `boolean`
package/dist/cli.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import process from "node:process";
2
2
  import { cac } from "cac";
3
- import consola, { consola as consola$1 } from "consola";
3
+ import consola$1, { consola } from "consola";
4
4
  import { isPlainObject, isUndefined, pick } from "@ntnyq/utils";
5
5
  import { defu } from "defu";
6
6
  import detectIndent from "detect-indent";
@@ -13,7 +13,7 @@ import { readIniFile } from "read-ini-file";
13
13
  import { kebabCase } from "uncase";
14
14
  //#region package.json
15
15
  var name = "pnpm-settings-migrator";
16
- var version = "0.5.0";
16
+ var version = "0.6.1";
17
17
  //#endregion
18
18
  //#region src/constants.ts
19
19
  const NPMRC = ".npmrc";
@@ -21,6 +21,14 @@ const PACKAGE_JSON = "package.json";
21
21
  const PNPM_WORKSPACE_YAML = "pnpm-workspace.yaml";
22
22
  /**
23
23
  * @see {@link https://github.com/pnpm/pnpm/blob/main/packages/types/src/package.ts}
24
+ * Schema-aligned pnpm config fields that can be migrated from `.npmrc`.
25
+ *
26
+ * Intentionally excluded workspace manifest-only fields:
27
+ * - `catalog`
28
+ * - `catalogMode`
29
+ * - `catalogs`
30
+ * - `cleanupUnusedCatalogs`
31
+ * - `packages`
24
32
  */
25
33
  const PNPM_SETTINGS_FIELDS = [
26
34
  "allowBuilds",
@@ -29,26 +37,96 @@ const PNPM_SETTINGS_FIELDS = [
29
37
  "allowUnusedPatches",
30
38
  "auditConfig",
31
39
  "configDependencies",
40
+ "dedupeDirectDeps",
41
+ "dedupeInjectedDeps",
42
+ "dedupePeerDependents",
43
+ "deployAllFiles",
44
+ "engineStrict",
32
45
  "executionEnv",
46
+ "fetchMinSpeedKiBps",
47
+ "fetchRetryFactor",
48
+ "fetchRetryMaxtimeout",
49
+ "fetchRetryMintimeout",
50
+ "fetchRetryTimeout",
51
+ "fetchWarnTimeoutMs",
52
+ "forceLegacyDeploy",
53
+ "gitChecks",
54
+ "gitShallowHosts",
55
+ "globalVirtualStore",
56
+ "globalVirtualStoreDir",
57
+ "hoist",
58
+ "hoistPattern",
59
+ "hoistWorkspacePackages",
33
60
  "httpProxy",
34
61
  "httpsProxy",
35
62
  "ignoredBuiltDependencies",
63
+ "ignoreDeps",
36
64
  "ignoredOptionalDependencies",
37
65
  "ignorePatchFailures",
66
+ "ignoreWorkspaceCycles",
67
+ "injectWorkspacePackages",
68
+ "linkWorkspacePackages",
69
+ "lockfile",
70
+ "lockfileDir",
71
+ "managePackageManagerVersions",
72
+ "mergeGitBranchLockfiles",
73
+ "mergeGitBranchLockfilesBranchPattern",
74
+ "modulesCacheMaxAge",
75
+ "networkConcurrency",
38
76
  "neverBuiltDependencies",
39
77
  "nodeDownloadMirrors",
78
+ "nodeLinker",
79
+ "noproxy",
40
80
  "noProxy",
81
+ "npmPath",
41
82
  "npmrcAuthFile",
42
83
  "onlyBuiltDependencies",
43
84
  "onlyBuiltDependenciesFile",
85
+ "optimisticRepeatInstall",
86
+ "optional",
44
87
  "overrides",
45
88
  "packageExtensions",
89
+ "packageImportMethod",
46
90
  "patchedDependencies",
47
91
  "peerDependencyRules",
92
+ "peersSuffixMaxLength",
93
+ "pnpmfile",
94
+ "pnpmfileIgnorePkgManifest",
95
+ "preferFrozenLockfile",
96
+ "preferWorkspacePackages",
97
+ "production",
98
+ "proxy",
99
+ "publicHoistPattern",
100
+ "recursiveInstall",
48
101
  "registries",
49
102
  "requiredScripts",
103
+ "resolutionMode",
104
+ "resolvePeersFromWorkspaceRoot",
105
+ "saveExact",
106
+ "savePrefix",
107
+ "scriptShell",
108
+ "shamefullyHoist",
109
+ "sharedWorkspaceLockfile",
110
+ "shellEmulator",
111
+ "sideEffectsCache",
112
+ "sideEffectsCacheReadonly",
113
+ "storeDir",
114
+ "strictDepBuilds",
115
+ "strictPeerDependencies",
116
+ "strictSsl",
50
117
  "supportedArchitectures",
51
- "updateConfig"
118
+ "syncInjectedDepsAfterScripts",
119
+ "tag",
120
+ "targetDependenciesField",
121
+ "timeout",
122
+ "updateConfig",
123
+ "useBetaCli",
124
+ "useNodeVersion",
125
+ "verifyDepsBeforeRun",
126
+ "verifyStoreIntegrity",
127
+ "virtualStoreDir",
128
+ "virtualStoreDirMaxLength",
129
+ "workspaceConcurrency"
52
130
  ];
53
131
  const PNPM_V11_REMOVED_SETTINGS = [
54
132
  "allowNonAppliedPatches",
@@ -231,7 +309,7 @@ function mergeWithArrayDedupe(existing, incoming) {
231
309
  for (const [key, incomingValue] of Object.entries(incoming)) {
232
310
  const existingValue = result[key];
233
311
  if (isUndefined(existingValue)) result[key] = incomingValue;
234
- else if (Array.isArray(existingValue) && Array.isArray(incomingValue)) result[key] = Array.from(new Set([...existingValue, ...incomingValue]));
312
+ else if (Array.isArray(existingValue) && Array.isArray(incomingValue)) result[key] = Array.from(/* @__PURE__ */ new Set([...existingValue, ...incomingValue]));
235
313
  else if (isPlainObject(existingValue) && isPlainObject(incomingValue)) result[key] = mergeWithArrayDedupe(existingValue, incomingValue);
236
314
  }
237
315
  return result;
@@ -399,10 +477,10 @@ async function migratePnpmSettings(rawOptions = {}) {
399
477
  fsExists(packageJsonPath),
400
478
  fsExists(pnpmWorkspaceYamlPath)
401
479
  ]);
402
- if (!npmrcExists) consola.info(`${dim(NPMRC)} not found`);
403
- if (!packageJsonExists) consola.info(`${dim(PACKAGE_JSON)} not found`);
480
+ if (!npmrcExists) consola$1.info(`${dim(NPMRC)} not found`);
481
+ if (!packageJsonExists) consola$1.info(`${dim(PACKAGE_JSON)} not found`);
404
482
  if (!npmrcExists && !packageJsonExists) {
405
- consola.warn("No pnpm settings files to migrate");
483
+ consola$1.warn("No pnpm settings files to migrate");
406
484
  return;
407
485
  }
408
486
  let packageJsonIndent = 2;
@@ -416,8 +494,8 @@ async function migratePnpmSettings(rawOptions = {}) {
416
494
  }
417
495
  if (pnpmWorkspaceExists) {
418
496
  const content = await fsReadFile(pnpmWorkspaceYamlPath);
419
- pnpmWorkspaceYamlIndent = detectIndent(content).amount;
420
- pnpmWorkspaceYamlObject = parse(content);
497
+ pnpmWorkspaceYamlIndent = resolveYamlIndent(content);
498
+ pnpmWorkspaceYamlObject = parse(content) ?? {};
421
499
  }
422
500
  const compatibility = resolveCompatibilityTarget(options.compatibility, packageJsonObject.packageManager);
423
501
  const npmrcMigratable = npmrcExists ? compatibility === "v10" ? {
@@ -432,7 +510,7 @@ async function migratePnpmSettings(rawOptions = {}) {
432
510
  const hasResolutions = options.yarnResolutions && !!packageJsonObject.resolutions;
433
511
  const hasNpmrcSettings = Object.keys(pnpmSettingsInNpmrc).length > 0;
434
512
  if (!hasPnpmInPackageJson && !hasResolutions && !hasNpmrcSettings) {
435
- consola.warn("No pnpm settings fields to migrate");
513
+ consola$1.warn("No pnpm settings fields to migrate");
436
514
  return;
437
515
  }
438
516
  const pnpmSettingsInPackageJson = options.yarnResolutions && packageJsonObject.resolutions ? {
@@ -462,7 +540,7 @@ async function migratePnpmSettings(rawOptions = {}) {
462
540
  await fsWriteFile(packageJsonPath, JSON.stringify(packageJsonObject, null, packageJsonIndent));
463
541
  }
464
542
  } catch (err) {
465
- consola.error("Failed to migrate pnpm settings:", err);
543
+ consola$1.error("Failed to migrate pnpm settings:", err);
466
544
  throw err;
467
545
  }
468
546
  }
@@ -497,19 +575,23 @@ function resolveCompatibilityTarget(compatibility, packageManager) {
497
575
  const [, major] = (packageManager || "").match(/^pnpm@(\d+)(?:\.|$)/) || [];
498
576
  return Number(major) >= 11 ? "v11" : "v10";
499
577
  }
578
+ function resolveYamlIndent(content) {
579
+ const detectedIndent = detectIndent(content).amount;
580
+ return detectedIndent > 0 ? detectedIndent : 2;
581
+ }
500
582
  //#endregion
501
583
  //#region src/cli.ts
502
584
  const cli = cac(name);
503
585
  cli.version(version).option("--cwd [cwd]", "Current working directory").option("--sort-keys", "Sort keys when write pnpm-workspace.yaml").option("--compatibility <compatibility>", "Compatibility target (auto, v10, v11)").option("--replace-deprecated", "Replace deprecated pnpm settings with new ones and remove old keys").option("--strategy <strategy>", "Strategy to handle conflicts (discard, merge, overwrite)").option("--no-yarn-resolutions", "Disable migrating resolutions field in package.json").option("--no-newline-between", "Disable adding newlines between each root keys").option("--no-clean-npmrc", "Disable removing pnpm settings in .npmrc file").option("--no-clean-package-json", "Disable removing pnpm fields in package.json").help();
504
586
  cli.command("").action(async (options) => {
505
587
  try {
506
- consola$1.log(`\n${bold(magenta(name))} ${dim(`v${version}`)}`);
507
- consola$1.log(dim("\n--------------\n"));
588
+ consola.log(`\n${bold(magenta(name))} ${dim(`v${version}`)}`);
589
+ consola.log(dim("\n--------------\n"));
508
590
  await migratePnpmSettings(options);
509
- consola$1.success(green("pnpm settings migrate has finished"));
591
+ consola.success(green("pnpm settings migrate has finished"));
510
592
  } catch (err) {
511
- consola$1.fail(red(String(err)));
512
- if (err instanceof Error && err.stack) consola$1.fail(dim(err.stack?.split("\n").slice(1).join("\n")));
593
+ consola.fail(red(String(err)));
594
+ if (err instanceof Error && err.stack) consola.fail(dim(err.stack?.split("\n").slice(1).join("\n")));
513
595
  process.exit(1);
514
596
  }
515
597
  });
package/dist/index.mjs CHANGED
@@ -16,6 +16,14 @@ const PACKAGE_JSON = "package.json";
16
16
  const PNPM_WORKSPACE_YAML = "pnpm-workspace.yaml";
17
17
  /**
18
18
  * @see {@link https://github.com/pnpm/pnpm/blob/main/packages/types/src/package.ts}
19
+ * Schema-aligned pnpm config fields that can be migrated from `.npmrc`.
20
+ *
21
+ * Intentionally excluded workspace manifest-only fields:
22
+ * - `catalog`
23
+ * - `catalogMode`
24
+ * - `catalogs`
25
+ * - `cleanupUnusedCatalogs`
26
+ * - `packages`
19
27
  */
20
28
  const PNPM_SETTINGS_FIELDS = [
21
29
  "allowBuilds",
@@ -24,26 +32,96 @@ const PNPM_SETTINGS_FIELDS = [
24
32
  "allowUnusedPatches",
25
33
  "auditConfig",
26
34
  "configDependencies",
35
+ "dedupeDirectDeps",
36
+ "dedupeInjectedDeps",
37
+ "dedupePeerDependents",
38
+ "deployAllFiles",
39
+ "engineStrict",
27
40
  "executionEnv",
41
+ "fetchMinSpeedKiBps",
42
+ "fetchRetryFactor",
43
+ "fetchRetryMaxtimeout",
44
+ "fetchRetryMintimeout",
45
+ "fetchRetryTimeout",
46
+ "fetchWarnTimeoutMs",
47
+ "forceLegacyDeploy",
48
+ "gitChecks",
49
+ "gitShallowHosts",
50
+ "globalVirtualStore",
51
+ "globalVirtualStoreDir",
52
+ "hoist",
53
+ "hoistPattern",
54
+ "hoistWorkspacePackages",
28
55
  "httpProxy",
29
56
  "httpsProxy",
30
57
  "ignoredBuiltDependencies",
58
+ "ignoreDeps",
31
59
  "ignoredOptionalDependencies",
32
60
  "ignorePatchFailures",
61
+ "ignoreWorkspaceCycles",
62
+ "injectWorkspacePackages",
63
+ "linkWorkspacePackages",
64
+ "lockfile",
65
+ "lockfileDir",
66
+ "managePackageManagerVersions",
67
+ "mergeGitBranchLockfiles",
68
+ "mergeGitBranchLockfilesBranchPattern",
69
+ "modulesCacheMaxAge",
70
+ "networkConcurrency",
33
71
  "neverBuiltDependencies",
34
72
  "nodeDownloadMirrors",
73
+ "nodeLinker",
74
+ "noproxy",
35
75
  "noProxy",
76
+ "npmPath",
36
77
  "npmrcAuthFile",
37
78
  "onlyBuiltDependencies",
38
79
  "onlyBuiltDependenciesFile",
80
+ "optimisticRepeatInstall",
81
+ "optional",
39
82
  "overrides",
40
83
  "packageExtensions",
84
+ "packageImportMethod",
41
85
  "patchedDependencies",
42
86
  "peerDependencyRules",
87
+ "peersSuffixMaxLength",
88
+ "pnpmfile",
89
+ "pnpmfileIgnorePkgManifest",
90
+ "preferFrozenLockfile",
91
+ "preferWorkspacePackages",
92
+ "production",
93
+ "proxy",
94
+ "publicHoistPattern",
95
+ "recursiveInstall",
43
96
  "registries",
44
97
  "requiredScripts",
98
+ "resolutionMode",
99
+ "resolvePeersFromWorkspaceRoot",
100
+ "saveExact",
101
+ "savePrefix",
102
+ "scriptShell",
103
+ "shamefullyHoist",
104
+ "sharedWorkspaceLockfile",
105
+ "shellEmulator",
106
+ "sideEffectsCache",
107
+ "sideEffectsCacheReadonly",
108
+ "storeDir",
109
+ "strictDepBuilds",
110
+ "strictPeerDependencies",
111
+ "strictSsl",
45
112
  "supportedArchitectures",
46
- "updateConfig"
113
+ "syncInjectedDepsAfterScripts",
114
+ "tag",
115
+ "targetDependenciesField",
116
+ "timeout",
117
+ "updateConfig",
118
+ "useBetaCli",
119
+ "useNodeVersion",
120
+ "verifyDepsBeforeRun",
121
+ "verifyStoreIntegrity",
122
+ "virtualStoreDir",
123
+ "virtualStoreDirMaxLength",
124
+ "workspaceConcurrency"
47
125
  ];
48
126
  const PNPM_V11_REMOVED_SETTINGS = [
49
127
  "allowNonAppliedPatches",
@@ -226,7 +304,7 @@ function mergeWithArrayDedupe(existing, incoming) {
226
304
  for (const [key, incomingValue] of Object.entries(incoming)) {
227
305
  const existingValue = result[key];
228
306
  if (isUndefined(existingValue)) result[key] = incomingValue;
229
- else if (Array.isArray(existingValue) && Array.isArray(incomingValue)) result[key] = Array.from(new Set([...existingValue, ...incomingValue]));
307
+ else if (Array.isArray(existingValue) && Array.isArray(incomingValue)) result[key] = Array.from(/* @__PURE__ */ new Set([...existingValue, ...incomingValue]));
230
308
  else if (isPlainObject(existingValue) && isPlainObject(incomingValue)) result[key] = mergeWithArrayDedupe(existingValue, incomingValue);
231
309
  }
232
310
  return result;
@@ -411,8 +489,8 @@ async function migratePnpmSettings(rawOptions = {}) {
411
489
  }
412
490
  if (pnpmWorkspaceExists) {
413
491
  const content = await fsReadFile(pnpmWorkspaceYamlPath);
414
- pnpmWorkspaceYamlIndent = detectIndent(content).amount;
415
- pnpmWorkspaceYamlObject = parse(content);
492
+ pnpmWorkspaceYamlIndent = resolveYamlIndent(content);
493
+ pnpmWorkspaceYamlObject = parse(content) ?? {};
416
494
  }
417
495
  const compatibility = resolveCompatibilityTarget(options.compatibility, packageJsonObject.packageManager);
418
496
  const npmrcMigratable = npmrcExists ? compatibility === "v10" ? {
@@ -492,5 +570,9 @@ function resolveCompatibilityTarget(compatibility, packageManager) {
492
570
  const [, major] = (packageManager || "").match(/^pnpm@(\d+)(?:\.|$)/) || [];
493
571
  return Number(major) >= 11 ? "v11" : "v10";
494
572
  }
573
+ function resolveYamlIndent(content) {
574
+ const detectedIndent = detectIndent(content).amount;
575
+ return detectedIndent > 0 ? detectedIndent : 2;
576
+ }
495
577
  //#endregion
496
578
  export { migratePnpmSettings, resolveOptions };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pnpm-settings-migrator",
3
3
  "type": "module",
4
- "version": "0.5.0",
4
+ "version": "0.6.1",
5
5
  "description": "Move pnpm settings from `pnpm` field in `package.json` and `.npmrc` file to `pnpm-workspace.yaml`",
6
6
  "keywords": [
7
7
  "migrator",
@@ -14,7 +14,10 @@
14
14
  "email": "ntnyq13@gmail.com"
15
15
  },
16
16
  "homepage": "https://github.com/ntnyq/pnpm-settings-migrator#readme",
17
- "repository": "ntnyq/pnpm-settings-migrator",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "ntnyq/pnpm-settings-migrator"
20
+ },
18
21
  "bugs": {
19
22
  "url": "https://github.com/ntnyq/pnpm-settings-migrator/issues"
20
23
  },
@@ -36,8 +39,8 @@
36
39
  },
37
40
  "sideEffects": false,
38
41
  "dependencies": {
39
- "@ntnyq/utils": "^0.13.2",
40
- "@pnpm/types": "^1101.1.0",
42
+ "@ntnyq/utils": "^0.15.0",
43
+ "@pnpm/types": "^1101.3.2",
41
44
  "cac": "^7.0.0",
42
45
  "camelcase-keys": "^10.0.2",
43
46
  "consola": "^3.4.2",
@@ -49,17 +52,17 @@
49
52
  "yaml": "^2.9.0"
50
53
  },
51
54
  "devDependencies": {
52
- "@ntnyq/eslint-config": "^6.1.3",
53
- "@types/node": "^25.7.0",
54
- "@typescript/native-preview": "^7.0.0-dev.20260512.1",
55
+ "@ntnyq/eslint-config": "^6.1.5",
56
+ "@types/node": "^26.0.0",
57
+ "@typescript/native-preview": "^7.0.0-dev.20260620.1",
55
58
  "bumpp": "^11.1.0",
56
- "eslint": "^10.3.0",
59
+ "eslint": "^10.5.0",
57
60
  "husky": "^9.1.7",
58
61
  "nano-staged": "^1.0.2",
59
- "npm-run-all2": "^8.0.4",
60
- "oxfmt": "^0.49.0",
61
- "tsdown": "^0.22.0",
62
- "vitest": "^4.1.6"
62
+ "npm-run-all2": "^9.0.2",
63
+ "oxfmt": "^0.55.0",
64
+ "tsdown": "^0.22.3",
65
+ "vitest": "^4.1.9"
63
66
  },
64
67
  "nano-staged": {
65
68
  "*.{js,ts,mjs,tsx,md,yml,yaml,toml,json}": "eslint --fix",