···65656666/**
6767 * picks the best version from a packument that satisfies a range.
6868- * follows npm's algorithm:
6868+ * follows npm/pnpm's algorithm:
6969 * 1. if range is a dist-tag, use that version
7070- * 2. if range is a specific version, use that
7171- * 3. otherwise, find highest version that satisfies the semver range
7070+ * 2. if range is empty, treat as 'latest'
7171+ * 3. if range is a specific version (possibly with v prefix), use that
7272+ * 4. if 'latest' tag satisfies the range, prefer it over newer versions
7373+ * 5. otherwise, find highest non-deprecated version that satisfies the range
7474+ * 6. fall back to deprecated version if no non-deprecated match
7275 *
7376 * @param versions available versions (version string -> manifest)
7477 * @param distTags dist-tags mapping (e.g., { latest: "1.2.3" })
···8083 distTags: Record<string, string>,
8184 range: string,
8285): AbbreviatedManifest | null {
8686+ // empty range means latest
8787+ if (range === '') {
8888+ return versions[distTags.latest] ?? null;
8989+ }
9090+8391 // check if range is a dist-tag
8492 if (range in distTags) {
8593 const taggedVersion = distTags[range];
8694 return versions[taggedVersion] ?? null;
8795 }
88969797+ // normalize loose version formats (v1.0.0, = 1.0.0)
9898+ const cleanedRange = semver.validRange(range, { loose: true }) ?? range;
9999+89100 // check if range is an exact version
90101 if (versions[range]) {
91102 return versions[range];
92103 }
931049494- // find highest version satisfying the range
105105+ // check cleaned version (handles v1.0.0 -> 1.0.0)
106106+ const cleanedVersion = semver.clean(range, { loose: true });
107107+ if (cleanedVersion && versions[cleanedVersion]) {
108108+ return versions[cleanedVersion];
109109+ }
110110+111111+ // for wildcard ranges, use loose mode to include prereleases
112112+ const isWildcard = range === '*' || range === 'x' || range === '';
113113+ const satisfiesOptions = { loose: true, includePrerelease: isWildcard };
114114+115115+ // prefer 'latest' tag if it satisfies the range (pnpm behavior)
116116+ // publishers tag 'latest' intentionally, so respect that choice
117117+ const latestVersion = distTags.latest;
118118+ if (latestVersion && versions[latestVersion]) {
119119+ if (semver.satisfies(latestVersion, cleanedRange, satisfiesOptions)) {
120120+ return versions[latestVersion];
121121+ }
122122+ }
123123+124124+ // find all versions satisfying the range
95125 const validVersions = Object.keys(versions)
9696- .filter((v) => semver.satisfies(v, range))
126126+ .filter((v) => semver.satisfies(v, cleanedRange, satisfiesOptions))
97127 .sort(semver.rcompare);
9812899129 if (validVersions.length === 0) {
100130 return null;
101131 }
102132133133+ // prefer non-deprecated versions (pnpm behavior)
134134+ const nonDeprecated = validVersions.filter((v) => !versions[v].deprecated);
135135+ if (nonDeprecated.length > 0) {
136136+ return versions[nonDeprecated[0]];
137137+ }
138138+139139+ // fall back to deprecated if no alternatives
103140 return versions[validVersions[0]];
104141}
105142