Repository: keithamus/sort-package-json
Pull request #314 (2024-03-27 23:11:04)

feat: improve pnpm sorting
https://github.com/keithamus/sort-package-json/pull/313 added the ability to deeply sort a `pnpm` object in `package.json`. This PR improves `pnpm` sorting in the following ways:

- groups similar fields together
- sorts `pnpm.overrides` entries with the same package name using semver rather than alphabetically

**Example:**

Before this change:
```
"pnpm": {
  "overrides": {
      "@react-stately/selection@~3.10.3": "3.10.3",
      "@react-stately/selection@~3.7.0": "3.7.0"
  }
}
```

After this change:
```
"pnpm": {
  "overrides": {
      "@react-stately/selection@~3.7.0": "3.7.0",
      "@react-stately/selection@~3.10.3": "3.10.3"
  }
}
```

keithamus: @samsternatretool what do you think?
samsternatretool: @keithamus LGTM from me! @westrik is on my team at Retool and he noticed some subtlety when it comes to sorting `pnpm` overrides after we merged my original change.
keithamus: Some failing tests in Node 12 because of `Array#at`. Will need to use an alternative or polyfill.
westrik: > Some failing tests in Node 12 because of `Array#at`. Will need to use an alternative or polyfill.

updated with alternative

Patch:
diff --git a/index.js b/index.js
index 2558022..660b16f 100755
--- a/index.js
+++ b/index.js
@@ -3,6 +3,7 @@ import detectIndent from 'detect-indent'
 import { detectNewlineGraceful as detectNewline } from 'detect-newline'
 import gitHooks from 'git-hooks-list'
 import isPlainObject from 'is-plain-obj'
+import semver from 'semver'
 
 const hasOwn =
   Object.hasOwn ||
@@ -54,6 +55,38 @@ const overProperty =
       : object
 const sortGitHooks = sortObjectBy(gitHooks)
 
+const sortObjectBySemver = sortObjectBy((a, b) => {
+  const parseNameAndVersionRange = (specifier) => {
+    // Ignore anything after > & rely on fallback alphanumeric sorting for that
+    const [nameAndVersion] = specifier.split('>')
+    const atMatches = [...nameAndVersion.matchAll('@')]
+    if (
+      !atMatches.length ||
+      (atMatches.length === 1 && atMatches[0].index === 0)
+    ) {
+      return { name: specifier }
+    }
+    const splitIndex = atMatches.pop().index
+    return {
+      name: nameAndVersion.substring(0, splitIndex),
+      range: nameAndVersion.substring(splitIndex + 1),
+    }
+  }
+  const { name: aName, range: aRange } = parseNameAndVersionRange(a)
+  const { name: bName, range: bRange } = parseNameAndVersionRange(b)
+
+  if (aName !== bName) {
+    return aName.localeCompare(bName)
+  }
+  if (!aRange) {
+    return -1
+  }
+  if (!bRange) {
+    return 1
+  }
+  return semver.compare(semver.minVersion(aRange), semver.minVersion(bRange))
+})
+
 // https://github.com/eslint/eslint/blob/acc0e47572a9390292b4e313b4a4bf360d236358/conf/config-schema.js
 const eslintBaseConfigProperties = [
   // `files` and `excludedFiles` are only on `overrides[]`
@@ -128,6 +161,29 @@ const sortPrettierConfig = onObject(
 
 const sortVolta = sortObjectBy(['node', 'npm', 'yarn'])
 
+const pnpmBaseConfigProperties = [
+  'peerDependencyRules',
+  'neverBuiltDependencies',
+  'onlyBuiltDependencies',
+  'onlyBuiltDependenciesFile',
+  'allowedDeprecatedVersions',
+  'allowNonAppliedPatches',
+  'updateConfig',
+  'auditConfig',
+  'requiredScripts',
+  'supportedArchitectures',
+  'overrides',
+  'patchedDependencies',
+  'packageExtensions',
+]
+
+const sortPnpmConfig = onObject(
+  pipe([
+    sortObjectBy(pnpmBaseConfigProperties, true),
+    overProperty('overrides', sortObjectBySemver),
+  ]),
+)
+
 // See https://docs.npmjs.com/misc/scripts
 const defaultNpmScripts = new Set([
   'install',
@@ -312,7 +368,7 @@ const fields = [
   /* vscode */ { key: 'galleryBanner', over: sortObject },
   /* vscode */ { key: 'preview' },
   /* vscode */ { key: 'markdown' },
-  { key: 'pnpm', over: sortObjectBy(undefined, true) },
+  { key: 'pnpm', over: sortPnpmConfig },
 ]
 
 const defaultSortOrder = fields.map(({ key }) => key)
diff --git a/package-lock.json b/package-lock.json
index a55696f..bde4d40 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,6 +15,7 @@
         "git-hooks-list": "^3.0.0",
         "globby": "^13.1.2",
         "is-plain-obj": "^4.1.0",
+        "semver": "^7.6.0",
         "sort-object-keys": "^1.1.3"
       },
       "bin": {
@@ -109,6 +110,15 @@
         "url": "https://opencollective.com/babel"
       }
     },
+    "node_modules/@babel/core/node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
     "node_modules/@babel/generator": {
       "version": "7.23.6",
       "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz",
@@ -152,6 +162,15 @@
         "@babel/core": "^7.0.0"
       }
     },
+    "node_modules/@babel/helper-compilation-targets/node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
     "node_modules/@babel/helper-environment-visitor": {
       "version": "7.22.20",
       "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
@@ -1381,21 +1400,6 @@
         "npmlog": "2 || ^3.1.0 || ^4.0.0"
       }
     },
-    "node_modules/@qiwi/npm-registry-client/node_modules/semver": {
-      "version": "7.3.7",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
-      "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
-      "dev": true,
-      "dependencies": {
-        "lru-cache": "^6.0.0"
-      },
-      "bin": {
-        "semver": "bin/semver.js"
-      },
-      "engines": {
-        "node": ">=10"
-      }
-    },
     "node_modules/@semantic-release/commit-analyzer": {
       "version": "9.0.2",
       "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-9.0.2.tgz",
@@ -1731,21 +1735,6 @@
         "url": "https://github.com/sponsors/isaacs"
       }
     },
-    "node_modules/@semantic-release/npm/node_modules/semver": {
-      "version": "7.3.5",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
-      "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
-      "dev": true,
-      "dependencies": {
-        "lru-cache": "^6.0.0"
-      },
-      "bin": {
-        "semver": "bin/semver.js"
-      },
-      "engines": {
-        "node": ">=10"
-      }
-    },
     "node_modules/@semantic-release/npm/node_modules/tempy": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/tempy/-/tempy-1.0.1.tgz",
@@ -2714,21 +2703,6 @@
         "semver": "^7.0.0"
       }
     },
-    "node_modules/builtins/node_modules/semver": {
-      "version": "7.3.7",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
-      "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
-      "dev": true,
-      "dependencies": {
-        "lru-cache": "^6.0.0"
-      },
-      "bin": {
-        "semver": "bin/semver.js"
-      },
-      "engines": {
-        "node": ">=10"
-      }
-    },
     "node_modules/caching-transform": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz",
@@ -3287,21 +3261,6 @@
         "node": ">=10.18.0 <11 || >=12.14.0 <13 || >=14"
       }
     },
-    "node_modules/concordance/node_modules/semver": {
-      "version": "7.3.5",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
-      "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
-      "dev": true,
-      "dependencies": {
-        "lru-cache": "^6.0.0"
-      },
-      "bin": {
-        "semver": "bin/semver.js"
-      },
-      "engines": {
-        "node": ">=10"
-      }
-    },
     "node_modules/console-control-strings": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
@@ -3359,6 +3318,15 @@
         "node": ">=10"
       }
     },
+    "node_modules/conventional-changelog-writer/node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
     "node_modules/conventional-commits-filter": {
       "version": "2.0.7",
       "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz",
@@ -3918,6 +3886,15 @@
         "url": "https://github.com/sponsors/isaacs"
       }
     },
+    "node_modules/dts-critic/node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
     "node_modules/dts-critic/node_modules/string-width": {
       "version": "4.2.3",
       "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@@ -4699,21 +4676,6 @@
         "eslint": ">=7.0.0"
       }
     },
-    "node_modules/eslint-plugin-n/node_modules/semver": {
-      "version": "7.3.7",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
-      "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
-      "dev": true,
-      "dependencies": {
-        "lru-cache": "^6.0.0"
-      },
-      "bin": {
-        "semver": "bin/semver.js"
-      },
-      "engines": {
-        "node": ">=10"
-      }
-    },
     "node_modules/eslint-plugin-prettier": {
       "version": "4.2.1",
       "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz",
@@ -6712,6 +6674,15 @@
         "node": ">=8"
       }
     },
+    "node_modules/istanbul-lib-instrument/node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
     "node_modules/istanbul-lib-processinfo": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz",
@@ -7606,7 +7577,6 @@
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
       "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
-      "dev": true,
       "dependencies": {
         "yallist": "^4.0.0"
       },
@@ -7629,6 +7599,15 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/make-dir/node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
     "node_modules/make-error": {
       "version": "1.3.6",
       "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
@@ -8093,21 +8072,6 @@
         "node": ">=10"
       }
     },
-    "node_modules/normalize-package-data/node_modules/semver": {
-      "version": "7.3.5",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
-      "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
-      "dev": true,
-      "dependencies": {
-        "lru-cache": "^6.0.0"
-      },
-      "bin": {
-        "semver": "bin/semver.js"
-      },
-      "engines": {
-        "node": ">=10"
-      }
-    },
     "node_modules/normalize-path": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@@ -8308,21 +8272,6 @@
         "node": ">=10"
       }
     },
-    "node_modules/npm-package-arg/node_modules/semver": {
-      "version": "7.3.7",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
-      "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
-      "dev": true,
-      "dependencies": {
-        "lru-cache": "^6.0.0"
-      },
-      "bin": {
-        "semver": "bin/semver.js"
-      },
-      "engines": {
-        "node": ">=10"
-      }
-    },
     "node_modules/npm-run-path": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
@@ -12198,21 +12147,6 @@
         "node": ">=8"
       }
     },
-    "node_modules/semantic-release/node_modules/semver": {
-      "version": "7.3.5",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
-      "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
-      "dev": true,
-      "dependencies": {
-        "lru-cache": "^6.0.0"
-      },
-      "bin": {
-        "semver": "bin/semver.js"
-      },
-      "engines": {
-        "node": ">=10"
-      }
-    },
     "node_modules/semantic-release/node_modules/string-width": {
       "version": "4.2.3",
       "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@@ -12258,12 +12192,17 @@
       }
     },
     "node_modules/semver": {
-      "version": "6.3.0",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-      "dev": true,
+      "version": "7.6.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
+      "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
       "bin": {
         "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
       }
     },
     "node_modules/semver-diff": {
@@ -12278,6 +12217,15 @@
         "node": ">=8"
       }
     },
+    "node_modules/semver-diff/node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
     "node_modules/semver-regex": {
       "version": "3.1.4",
       "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-3.1.4.tgz",
@@ -13909,8 +13857,7 @@
     "node_modules/yallist": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
-      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-      "dev": true
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
     },
     "node_modules/yaml": {
       "version": "1.10.2",
@@ -14076,6 +14023,14 @@
         "gensync": "^1.0.0-beta.2",
         "json5": "^2.1.2",
         "semver": "^6.3.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "6.3.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+          "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+          "dev": true
+        }
       }
     },
     "@babel/generator": {
@@ -14112,6 +14067,14 @@
         "@babel/helper-validator-option": "^7.16.7",
         "browserslist": "^4.17.5",
         "semver": "^6.3.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "6.3.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+          "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+          "dev": true
+        }
       }
     },
     "@babel/helper-environment-visitor": {
@@ -15071,17 +15034,6 @@
         "semver": "2 >=2.2.1 || 3.x || 4 || 5 || 7",
         "slide": "^1.1.6",
         "ssri": "^8.0.0"
-      },
-      "dependencies": {
-        "semver": {
-          "version": "7.3.7",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
-          "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
-          "dev": true,
-          "requires": {
-            "lru-cache": "^6.0.0"
-          }
-        }
       }
     },
     "@semantic-release/commit-analyzer": {
@@ -15330,15 +15282,6 @@
             "glob": "^7.1.3"
           }
         },
-        "semver": {
-          "version": "7.3.5",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
-          "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
-          "dev": true,
-          "requires": {
-            "lru-cache": "^6.0.0"
-          }
-        },
         "tempy": {
           "version": "1.0.1",
           "resolved": "https://registry.npmjs.org/tempy/-/tempy-1.0.1.tgz",
@@ -16074,17 +16017,6 @@
       "dev": true,
       "requires": {
         "semver": "^7.0.0"
-      },
-      "dependencies": {
-        "semver": {
-          "version": "7.3.7",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
-          "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
-          "dev": true,
-          "requires": {
-            "lru-cache": "^6.0.0"
-          }
-        }
       }
     },
     "caching-transform": {
@@ -16521,17 +16453,6 @@
         "md5-hex": "^3.0.1",
         "semver": "^7.3.2",
         "well-known-symbols": "^2.0.0"
-      },
-      "dependencies": {
-        "semver": {
-          "version": "7.3.5",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
-          "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
-          "dev": true,
-          "requires": {
-            "lru-cache": "^6.0.0"
-          }
-        }
       }
     },
     "console-control-strings": {
@@ -16577,6 +16498,14 @@
         "semver": "^6.0.0",
         "split": "^1.0.0",
         "through2": "^4.0.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "6.3.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+          "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+          "dev": true
+        }
       }
     },
     "conventional-commits-filter": {
@@ -16988,6 +16917,12 @@
             "glob": "^7.1.3"
           }
         },
+        "semver": {
+          "version": "6.3.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+          "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+          "dev": true
+        },
         "string-width": {
           "version": "4.2.3",
           "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@@ -17790,17 +17725,6 @@
         "minimatch": "^3.1.2",
         "resolve": "^1.22.1",
         "semver": "^7.3.7"
-      },
-      "dependencies": {
-        "semver": {
-          "version": "7.3.7",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
-          "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
-          "dev": true,
-          "requires": {
-            "lru-cache": "^6.0.0"
-          }
-        }
       }
     },
     "eslint-plugin-prettier": {
@@ -19052,6 +18976,14 @@
         "@istanbuljs/schema": "^0.1.2",
         "istanbul-lib-coverage": "^3.0.0",
         "semver": "^6.3.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "6.3.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+          "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+          "dev": true
+        }
       }
     },
     "istanbul-lib-processinfo": {
@@ -19727,7 +19659,6 @@
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
       "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
-      "dev": true,
       "requires": {
         "yallist": "^4.0.0"
       }
@@ -19739,6 +19670,14 @@
       "dev": true,
       "requires": {
         "semver": "^6.0.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "6.3.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+          "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+          "dev": true
+        }
       }
     },
     "make-error": {
@@ -20068,17 +20007,6 @@
         "is-core-module": "^2.5.0",
         "semver": "^7.3.4",
         "validate-npm-package-license": "^3.0.1"
-      },
-      "dependencies": {
-        "semver": {
-          "version": "7.3.5",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
-          "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
-          "dev": true,
-          "requires": {
-            "lru-cache": "^6.0.0"
-          }
-        }
       }
     },
     "normalize-path": {
@@ -21891,17 +21819,6 @@
         "hosted-git-info": "^4.0.1",
         "semver": "^7.3.4",
         "validate-npm-package-name": "^3.0.0"
-      },
-      "dependencies": {
-        "semver": {
-          "version": "7.3.7",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
-          "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
-          "dev": true,
-          "requires": {
-            "lru-cache": "^6.0.0"
-          }
-        }
       }
     },
     "npm-run-path": {
@@ -22966,15 +22883,6 @@
           "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
           "dev": true
         },
-        "semver": {
-          "version": "7.3.5",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
-          "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
-          "dev": true,
-          "requires": {
-            "lru-cache": "^6.0.0"
-          }
-        },
         "string-width": {
           "version": "4.2.3",
           "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@@ -23013,10 +22921,12 @@
       }
     },
     "semver": {
-      "version": "6.3.0",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-      "dev": true
+      "version": "7.6.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
+      "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
+      "requires": {
+        "lru-cache": "^6.0.0"
+      }
     },
     "semver-diff": {
       "version": "3.1.1",
@@ -23025,6 +22935,14 @@
       "dev": true,
       "requires": {
         "semver": "^6.3.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "6.3.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+          "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+          "dev": true
+        }
       }
     },
     "semver-regex": {
@@ -24285,8 +24203,7 @@
     "yallist": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
-      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-      "dev": true
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
     },
     "yaml": {
       "version": "1.10.2",
diff --git a/package.json b/package.json
index b437f73..564aa1f 100644
--- a/package.json
+++ b/package.json
@@ -73,6 +73,7 @@
     "git-hooks-list": "^3.0.0",
     "globby": "^13.1.2",
     "is-plain-obj": "^4.1.0",
+    "semver": "^7.6.0",
     "sort-object-keys": "^1.1.3"
   },
   "devDependencies": {


Test patch:
diff --git a/tests/fields.js b/tests/fields.js
index bc6bc1b..458c8ae 100644
--- a/tests/fields.js
+++ b/tests/fields.js
@@ -263,9 +263,16 @@ test('pnpm', macro.sortObject, {
   path: 'pnpm',
   value: {
     overrides: {
+      '@react-stately/selection@~3.10.3': '3.10.3',
       'aws-sdk@1.2345.0': '1.123.0',
       'react-native-notifications@^3.4.5': '3.4.5',
       'antd@^2.23.4': '2.23.4',
+      '@react-stately/select@~3.1.3': '3.1.3',
+      '@react-stately/selection@~3.7.0': '3.7.0',
+      '@react-stately/select@3': '3.3.1',
+      '@react-aria/selection@3.10.1>@react-stately/selection': '3.10.3',
+      '@react-aria/selection@3.10.1>@react-aria/focus': '3.8.0',
+      '@react-aria/selection@3.5.1>@react-stately/selection': '3.10.3',
     },
     patchedDependencies: {
       'esbuild-sass-plugin@1.20.0': 'foo.patch',
@@ -289,10 +296,22 @@ test('pnpm', macro.sortObject, {
   expect: {
     allowNonAppliedPatches: true,
     overrides: {
+      '@react-aria/selection@3.5.1>@react-stately/selection': '3.10.3',
+      '@react-aria/selection@3.10.1>@react-aria/focus': '3.8.0',
+      '@react-aria/selection@3.10.1>@react-stately/selection': '3.10.3',
+      '@react-stately/select@3': '3.3.1',
+      '@react-stately/select@~3.1.3': '3.1.3',
+      '@react-stately/selection@~3.7.0': '3.7.0',
+      '@react-stately/selection@~3.10.3': '3.10.3',
       'antd@^2.23.4': '2.23.4',
       'aws-sdk@1.2345.0': '1.123.0',
       'react-native-notifications@^3.4.5': '3.4.5',
     },
+    patchedDependencies: {
+      'domino@4.5.6': 'bar.patch',
+      'es5-ext@0.12.3': 'baz.patch',
+      'esbuild-sass-plugin@1.20.0': 'foo.patch',
+    },
     packageExtensions: {
       '@rjsf/core': {
         dependencies: {
@@ -305,10 +324,5 @@ test('pnpm', macro.sortObject, {
         },
       },
     },
-    patchedDependencies: {
-      'domino@4.5.6': 'bar.patch',
-      'es5-ext@0.12.3': 'baz.patch',
-      'esbuild-sass-plugin@1.20.0': 'foo.patch',
-    },
   },
 })