Skip to content

Commit b17e405

Browse files
cameroncookeclaude
andcommitted
fix(cli): Compare prerelease identifiers in ASCII order per SemVer 2.0.0
SemVer 2.0.0 §11 requires lexical comparison of prerelease identifiers in ASCII sort order. The previous implementation used String.prototype.localeCompare, which applies locale-dependent collation and can differ from ASCII ordering. For example, "Alpha".localeCompare("alpha") returns 1 in common locales while ASCII comparison returns -1. Replace localeCompare with a UTF-16 code-unit comparison, which matches ASCII ordering for the [0-9A-Za-z-] character set SemVer permits. Reported in PR review by Cursor Bugbot. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 59d3e80 commit b17e405

2 files changed

Lines changed: 10 additions & 1 deletion

File tree

src/cli/commands/__tests__/upgrade.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,15 @@ describe('upgrade command', () => {
301301
).toBe('older');
302302
});
303303

304+
it('compares prerelease identifiers in ASCII order (uppercase before lowercase)', () => {
305+
expect(
306+
compareVersions(
307+
{ major: 1, minor: 0, patch: 0, prerelease: 'Alpha' },
308+
{ major: 1, minor: 0, patch: 0, prerelease: 'alpha' },
309+
),
310+
).toBe('older');
311+
});
312+
304313
it('numeric prerelease identifier is less than string identifier', () => {
305314
expect(
306315
compareVersions(

src/cli/commands/upgrade.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ function comparePrereleaseIdentifiers(a: string, b: string): number {
100100
if (aIsNum) return -1;
101101
if (bIsNum) return 1;
102102

103-
const cmp = aParts[i].localeCompare(bParts[i]);
103+
const cmp = aParts[i] < bParts[i] ? -1 : aParts[i] > bParts[i] ? 1 : 0;
104104
if (cmp !== 0) return cmp;
105105
}
106106

0 commit comments

Comments
 (0)