From 2bde918c5ca35592dad89ec05143393d50c7b92a Mon Sep 17 00:00:00 2001 From: Kevin Deng Date: Fri, 4 Sep 2026 14:21:14 +0900 Subject: [PATCH] feat: add explicit `Than` comparison helpers closes #13 --- README.md | 55 ++++++++++++++++++++------------------- src/version.ts | 4 +++ src/version/comparison.ts | 21 ++++++++++++--- tests/comparison.test.ts | 20 +++++++------- tests/readme.test.ts | 2 ++ 5 files changed, 62 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 834f3fd..49781d8 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ tree-shakeable APIs. - 💙 First-class TypeScript declarations. - 🌳 Functional, tree-shakeable named exports. - 🔁 Mutable `SemVer` and `SemVerRange` records. -- ⚡ 23.8% smaller for full CDN imports. -- 🪶 60.3% smaller with common bundled imports. +- ⚡ 23.3% smaller for full CDN imports. +- 🪶 60.2% smaller with common bundled imports. - 🛡️ Immutable collection operations. ## Install @@ -56,10 +56,11 @@ versions omit it. ## Comparison ```ts -import { compare, compareBuild, sortReversed } from 'verkit' +import { compare, compareBuild, isGreaterThan, sortReversed } from 'verkit' compare('1.0.0+one', '1.0.0+two') // 0 compareBuild('1.0.0+one', '1.0.0+two') // -1 +isGreaterThan('2.0.0', '1.0.0') // true sortReversed(['1.0.0', '2.0.0']) // ['2.0.0', '1.0.0'] ``` @@ -113,25 +114,25 @@ their documented `null`/`false` behavior. Only renamed or reshaped [node-semver] APIs are listed; same-named functions such as `clean`, `coerce`, `compare`, and `satisfies` are omitted. -| node-semver | verkit | -| ---------------------------------------------- | ----------------------------------------------------------------------------------- | -| `SemVer` | `parse` | -| `parse` | `tryParse` | -| `valid` | `normalize` | -| `inc`, `diff` | `increment`, `difference` | -| `major`, `minor`, `patch`, `prerelease` | `getMajor`, `getMinor`, `getPatch`, `getPrerelease` | -| `rcompare`, `compareLoose`, `cmp` | `compareReversed`, `compare` with `{ loose: true }`, `compareWithOperator` | -| `eq`, `neq`, `gt`, `gte`, `lt`, `lte` | `isEqual`, `isNotEqual`, `isGreater`, `isGreaterOrEqual`, `isLess`, `isLessOrEqual` | -| `rsort` | `sortReversed` | -| `rcompareIdentifiers` | `compareIdentifiersReversed` | -| `Comparator` | `SemVerComparator`, `parseComparator`, `tryParseComparator` | -| Comparator formatting, test, and intersection | `normalizeComparator`, `satisfiesComparator`, `comparatorsIntersect` | -| `Range` | `parseRange` | -| `toComparators`, `validRange` | `rangeToComparators`, `normalizeRange` | -| `maxSatisfying`, `minSatisfying`, `minVersion` | `findMaxSatisfying`, `findMinSatisfying`, `findMinimumForRange` | -| `outside`, `gtr`, `ltr` | `isOutsideRange`, `isGreaterThanRange`, `isLessThanRange` | -| `intersects`, `subset` | `rangesIntersect`, `isRangeSubset` | -| `RELEASE_TYPES` | `INCREMENT_TYPES` (also includes `release`) | +| node-semver | verkit | +| ---------------------------------------------- | --------------------------------------------------------------------------------------------------- | +| `SemVer` | `parse` | +| `parse` | `tryParse` | +| `valid` | `normalize` | +| `inc`, `diff` | `increment`, `difference` | +| `major`, `minor`, `patch`, `prerelease` | `getMajor`, `getMinor`, `getPatch`, `getPrerelease` | +| `rcompare`, `compareLoose`, `cmp` | `compareReversed`, `compare` with `{ loose: true }`, `compareWithOperator` | +| `eq`, `neq`, `gt`, `gte`, `lt`, `lte` | `isEqual`, `isNotEqual`, `isGreaterThan`, `isGreaterThanOrEqual`, `isLessThan`, `isLessThanOrEqual` | +| `rsort` | `sortReversed` | +| `rcompareIdentifiers` | `compareIdentifiersReversed` | +| `Comparator` | `SemVerComparator`, `parseComparator`, `tryParseComparator` | +| Comparator formatting, test, and intersection | `normalizeComparator`, `satisfiesComparator`, `comparatorsIntersect` | +| `Range` | `parseRange` | +| `toComparators`, `validRange` | `rangeToComparators`, `normalizeRange` | +| `maxSatisfying`, `minSatisfying`, `minVersion` | `findMaxSatisfying`, `findMinSatisfying`, `findMinimumForRange` | +| `outside`, `gtr`, `ltr` | `isOutsideRange`, `isGreaterThanRange`, `isLessThanRange` | +| `intersects`, `subset` | `rangesIntersect`, `isRangeSubset` | +| `RELEASE_TYPES` | `INCREMENT_TYPES` (also includes `release`) | `valid` returns a normalized `string | null` in node-semver, so its equivalent is `normalize`. Use `isValid` when you only need a boolean. @@ -156,9 +157,9 @@ Full package imports, minified with Rolldown: | Package | Minified | gzip | Brotli | | --------------------- | -------: | ------: | ------: | -| verkit | 18,754 B | 5,874 B | 5,341 B | -| [semver][node-semver] | 24,603 B | 7,356 B | 6,703 B | -| verkit reduction | 23.8% | 20.1% | 20.3% | +| verkit | 18,868 B | 5,923 B | 5,394 B | +| [semver][node-semver] | 24,585 B | 7,355 B | 6,696 B | +| verkit reduction | 23.3% | 19.5% | 19.4% | Common validation, range, comparison, increment, and coercion imports, tree-shaken and minified with Rolldown: @@ -166,8 +167,8 @@ tree-shaken and minified with Rolldown: | Package | Minified | gzip | Brotli | | --------------------- | -------: | ------: | ------: | | verkit | 9,834 B | 3,361 B | 3,086 B | -| [semver][node-semver] | 24,754 B | 7,427 B | 6,764 B | -| verkit reduction | 60.3% | 54.7% | 54.4% | +| [semver][node-semver] | 24,736 B | 7,426 B | 6,762 B | +| verkit reduction | 60.2% | 54.7% | 54.4% | Run `pnpm test:size` to reproduce the comparison. diff --git a/src/version.ts b/src/version.ts index 85a4603..7d683e2 100644 --- a/src/version.ts +++ b/src/version.ts @@ -8,8 +8,12 @@ export { isEqual, isGreater, isGreaterOrEqual, + isGreaterThan, + isGreaterThanOrEqual, isLess, isLessOrEqual, + isLessThan, + isLessThanOrEqual, isNotEqual, sort, sortReversed, diff --git a/src/version/comparison.ts b/src/version/comparison.ts index ce4c928..5d6f72e 100644 --- a/src/version/comparison.ts +++ b/src/version/comparison.ts @@ -151,7 +151,7 @@ export function isNotEqual( return compare(left, right, options) !== 0 } -export function isGreater( +export function isGreaterThan( left: VersionInput, right: VersionInput, options: VersionOptions = {}, @@ -159,7 +159,7 @@ export function isGreater( return compare(left, right, options) > 0 } -export function isGreaterOrEqual( +export function isGreaterThanOrEqual( left: VersionInput, right: VersionInput, options: VersionOptions = {}, @@ -167,7 +167,7 @@ export function isGreaterOrEqual( return compare(left, right, options) >= 0 } -export function isLess( +export function isLessThan( left: VersionInput, right: VersionInput, options: VersionOptions = {}, @@ -175,7 +175,7 @@ export function isLess( return compare(left, right, options) < 0 } -export function isLessOrEqual( +export function isLessThanOrEqual( left: VersionInput, right: VersionInput, options: VersionOptions = {}, @@ -183,6 +183,19 @@ export function isLessOrEqual( return compare(left, right, options) <= 0 } +/** @deprecated Use {@link isGreaterThan} instead. */ +export const isGreater: typeof isGreaterThan = isGreaterThan + +/** @deprecated Use {@link isGreaterThanOrEqual} instead. */ +export const isGreaterOrEqual: typeof isGreaterThanOrEqual = + isGreaterThanOrEqual + +/** @deprecated Use {@link isLessThan} instead. */ +export const isLess: typeof isLessThan = isLessThan + +/** @deprecated Use {@link isLessThanOrEqual} instead. */ +export const isLessOrEqual: typeof isLessThanOrEqual = isLessThanOrEqual + export function sort( versions: readonly T[], options: VersionOptions = {}, diff --git a/tests/comparison.test.ts b/tests/comparison.test.ts index 10b6d9c..99181ba 100644 --- a/tests/comparison.test.ts +++ b/tests/comparison.test.ts @@ -10,10 +10,10 @@ import { compareReversed, compareWithOperator, isEqual, - isGreater, - isGreaterOrEqual, - isLess, - isLessOrEqual, + isGreaterThan, + isGreaterThanOrEqual, + isLessThan, + isLessThanOrEqual, isNotEqual, parse, sort, @@ -38,7 +38,7 @@ describe('version comparison', () => { expect(compare(left, right)).toBe(1) expect(compareBuild(left, '2.0.0+one')).toBe(1) expect(compareBuild(right, { ...right, build: ['one'] })).toBe(-1) - expect(isGreater(left, right)).toBe(true) + expect(isGreaterThan(left, right)).toBe(true) }) it('orders every comparison fixture', () => { @@ -47,10 +47,10 @@ describe('version comparison', () => { const options = versionOptions(rawOptions) expect(compare(left, right, options)).toBe(1) expect(compareReversed(left, right, options)).toBe(-1) - expect(isGreater(left, right, options)).toBe(true) - expect(isGreaterOrEqual(left, right, options)).toBe(true) - expect(isLess(right, left, options)).toBe(true) - expect(isLessOrEqual(right, left, options)).toBe(true) + expect(isGreaterThan(left, right, options)).toBe(true) + expect(isGreaterThanOrEqual(left, right, options)).toBe(true) + expect(isLessThan(right, left, options)).toBe(true) + expect(isLessThanOrEqual(right, left, options)).toBe(true) expect(isNotEqual(left, right, options)).toBe(true) } }) @@ -61,6 +61,8 @@ describe('version comparison', () => { const options = versionOptions(rawOptions) expect(compare(left, right, options)).toBe(0) expect(isEqual(left, right, options)).toBe(true) + expect(isGreaterThanOrEqual(left, right, options)).toBe(true) + expect(isLessThanOrEqual(left, right, options)).toBe(true) expect(compareWithOperator(left, '=', right, options)).toBe(true) } }) diff --git a/tests/readme.test.ts b/tests/readme.test.ts index d5762cf..b296858 100644 --- a/tests/readme.test.ts +++ b/tests/readme.test.ts @@ -6,6 +6,7 @@ import { compareBuild, findMaxSatisfying, increment, + isGreaterThan, normalize, normalizeFull, normalizeRange, @@ -31,6 +32,7 @@ describe('README examples', () => { it('keeps comparison and range examples executable', () => { expect(compare('1.0.0+one', '1.0.0+two')).toBe(0) expect(compareBuild('1.0.0+one', '1.0.0+two')).toBe(-1) + expect(isGreaterThan('2.0.0', '1.0.0')).toBe(true) expect(sortReversed(['1.0.0', '2.0.0'])).toEqual(['2.0.0', '1.0.0']) const range = parseRange('^1.2.3') expect(normalizeRange(range)).toBe('>=1.2.3 <2.0.0-0') -- 2.54.0