Skip to content

Commit

Permalink
v4.1.0 - support .x,.x.x ranges, add browser export, close #132
Browse files Browse the repository at this point in the history
  • Loading branch information
balupton committed Nov 19, 2023
1 parent 3a0ce9a commit baa6aab
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 18 deletions.
6 changes: 6 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# History

## v4.1.0 2023 November 20

- Support `.x` and `.x.x` suffixes in version ranges
- Added browser export, close [#132](https://github.com/bevry/version-range/pull/132)
- Updated dependencies, [base files](https://github.com/bevry/base), and [editions](https://editions.bevry.me) using [boundation](https://github.com/bevry/boundation)

## v4.0.0 2023 November 19

- Support `^` and `~` in version ranges
Expand Down
37 changes: 33 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Check version ranges like `>=N` and `X || Y || Z` with support for Node.js, Web

[Complete API Documentation.](http://master.version-range.bevry.surge.sh/docs/)

Super fast and super compatible version range comparison for the most common use cases. As semver has two different behaviours based on whether the version is coerced or not, this library differs to match our actual expectations, unlike semver. For example:
Range comparison of versions for the most common use cases. Fast with broad ecosystem support.

```typescript
import satisfies from 'version-range'
Expand All @@ -62,12 +62,16 @@ console.log(satisfies('1.0', '>=1.0.0')) // true
console.log(satisfies('1.0.0', '>=1.0.0')) // true

console.log(satisfies('1', '^1')) // true
console.log(satisfies('1', '~1')) // false
console.log(satisfies('1', '~1')) // false, not all 1.x versions (1.1, 1.2, etc) match 1.0.x
console.log(satisfies('1', '^1.1')) // false, not all 1.x versions (1.0) match >=1.1<2
console.log(satisfies('1', '~1.1')) // false, not all 1.x versions (1.0) match 1.1.x
console.log(satisfies('1.0.0', '^1')) // true
console.log(satisfies('1.0.0', '~1')) // true
```

Doesn't support ranges that include `.x`, `&&`, `-releaseTag`, and `>X <Y`.
The above results are expected, but not what the [`semver` package](https://www.npmjs.com/package/semver) returns. The semver package has two different behaviours based on whether the version is coerced or not, alternating between expected and unexpected results. This package differs to match our actual expectations, as you can see above.

Doesn't support ranges that include `&&`, `-releaseTag`, and `>X <Y`, and does not do the special handling for `0.x` versions.

<!-- INSTALL/ -->

Expand All @@ -83,14 +87,39 @@ Doesn't support ranges that include `.x`, `&&`, `-releaseTag`, and `>X <Y`.
<a href="https://deno.land" title="Deno is a secure runtime for JavaScript and TypeScript, it is an alternative for Node.js"><h3>Deno</h3></a>

``` typescript
import pkg from 'https://unpkg.com/version-range@^4.0.0/edition-deno/index.ts'
import pkg from 'https://unpkg.com/version-range@^4.1.0/edition-deno/index.ts'
```

<a href="https://www.skypack.dev" title="Skypack is a JavaScript Delivery Network for modern web apps"><h3>Skypack</h3></a>

``` html
<script type="module">
import pkg from '//cdn.skypack.dev/version-range@^4.1.0'
</script>
```

<a href="https://unpkg.com" title="unpkg is a fast, global content delivery network for everything on npm"><h3>unpkg</h3></a>

``` html
<script type="module">
import pkg from '//unpkg.com/version-range@^4.1.0'
</script>
```

<a href="https://jspm.io" title="Native ES Modules CDN"><h3>jspm</h3></a>

``` html
<script type="module">
import pkg from '//dev.jspm.io/version-range@4.1.0'
</script>
```

<h3><a href="https://editions.bevry.me" title="Editions are the best way to produce and consume packages you care about.">Editions</a></h3>

<p>This package is published with the following editions:</p>

<ul><li><code>version-range/source/index.ts</code> is <a href="https://www.typescriptlang.org/" title="TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. ">TypeScript</a> source code with <a href="https://babeljs.io/docs/learn-es2015/#modules" title="ECMAScript Modules">Import</a> for modules</li>
<li><code>version-range/edition-browsers/index.js</code> is <a href="https://www.typescriptlang.org/" title="TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. ">TypeScript</a> compiled against ES2022 for web browsers with <a href="https://babeljs.io/docs/learn-es2015/#modules" title="ECMAScript Modules">Import</a> for modules</li>
<li><code>version-range</code> aliases <code>version-range/edition-es2022/index.js</code></li>
<li><code>version-range/edition-es2022/index.js</code> is <a href="https://www.typescriptlang.org/" title="TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. ">TypeScript</a> compiled against ES2022 for <a href="https://nodejs.org" title="Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine">Node.js</a> 8 || 10 || 12 || 14 || 16 || 18 || 20 || 21 with <a href="https://nodejs.org/dist/latest-v5.x/docs/api/modules.html" title="Node/CJS Modules">Require</a> for modules</li>
<li><code>version-range/edition-es2022-esm/index.js</code> is <a href="https://www.typescriptlang.org/" title="TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. ">TypeScript</a> compiled against ES2022 for <a href="https://nodejs.org" title="Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine">Node.js</a> 12 || 14 || 16 || 18 || 20 || 21 with <a href="https://babeljs.io/docs/learn-es2015/#modules" title="ECMAScript Modules">Import</a> for modules</li>
Expand Down
25 changes: 22 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 30 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
{
"name": "version-range",
"version": "4.0.0",
"version": "4.1.0",
"description": "Check version ranges like `>=N` and `X || Y || Z` with support for Node.js, Web Browsers, Deno, and TypeScript.",
"homepage": "https://github.com/bevry/version-range",
"license": "Artistic-2.0",
"keywords": [
"browser",
"compare",
"conditional",
"deno",
Expand All @@ -14,6 +15,7 @@
"es2022",
"export-default",
"gte",
"module",
"node",
"node.js",
"nodejs",
Expand Down Expand Up @@ -95,6 +97,20 @@
],
"engines": false
},
{
"description": "TypeScript compiled against ES2022 for web browsers with Import for modules",
"directory": "edition-browsers",
"entry": "index.js",
"tags": [
"compiled",
"javascript",
"import"
],
"engines": {
"node": false,
"browsers": "defaults"
}
},
{
"description": "TypeScript compiled against ES2022 for Node.js 8 || 10 || 12 || 14 || 16 || 18 || 20 || 21 with Require for modules",
"directory": "edition-es2022",
Expand Down Expand Up @@ -136,7 +152,7 @@
],
"engines": {
"deno": true,
"browsers": false
"browsers": true
}
}
],
Expand All @@ -147,9 +163,14 @@
"node": {
"import": "./edition-es2022-esm/index.js",
"require": "./edition-es2022/index.js"
},
"browser": {
"import": "./edition-browsers/index.js"
}
},
"deno": "edition-deno/index.ts",
"browser": "edition-browsers/index.js",
"module": "edition-browsers/index.js",
"devDependencies": {
"@bevry/json": "^1.9.0",
"@bevry/update-contributors": "^1.23.0",
Expand All @@ -168,12 +189,14 @@
"surge": "^0.23.1",
"typedoc": "^0.25.3",
"typescript": "5.2.2",
"valid-directory": "^4.4.0"
"valid-directory": "^4.4.0",
"valid-module": "^2.3.0"
},
"scripts": {
"our:clean": "rm -rf ./docs ./edition* ./es2015 ./es5 ./out ./.next",
"our:compile": "npm run our:compile:deno && npm run our:compile:edition-es2022 && npm run our:compile:edition-es2022-esm && npm run our:compile:types",
"our:compile": "npm run our:compile:deno && npm run our:compile:edition-browsers && npm run our:compile:edition-es2022 && npm run our:compile:edition-es2022-esm && npm run our:compile:types",
"our:compile:deno": "make-deno-edition --attempt",
"our:compile:edition-browsers": "tsc --module ESNext --target ES2022 --outDir ./edition-browsers --project tsconfig.json && ( test ! -d edition-browsers/source || ( mv edition-browsers/source edition-temp && rm -rf edition-browsers && mv edition-temp edition-browsers ) )",
"our:compile:edition-es2022": "tsc --module commonjs --target ES2022 --outDir ./edition-es2022 --project tsconfig.json && ( test ! -d edition-es2022/source || ( mv edition-es2022/source edition-temp && rm -rf edition-es2022 && mv edition-temp edition-es2022 ) ) && printf '%s' '{\"type\": \"commonjs\"}' > edition-es2022/package.json",
"our:compile:edition-es2022-esm": "tsc --module ESNext --target ES2022 --outDir ./edition-es2022-esm --project tsconfig.json && ( test ! -d edition-es2022-esm/source || ( mv edition-es2022-esm/source edition-temp && rm -rf edition-es2022-esm && mv edition-temp edition-es2022-esm ) ) && printf '%s' '{\"type\": \"module\"}' > edition-es2022-esm/package.json",
"our:compile:types": "tsc --project tsconfig.json --emitDeclarationOnly --declaration --declarationMap --declarationDir ./compiled-types && ( test ! -d compiled-types/source || ( mv compiled-types/source edition-temp && rm -rf compiled-types && mv edition-temp compiled-types ) )",
Expand All @@ -192,9 +215,10 @@
"our:setup": "npm run our:setup:install",
"our:setup:install": "npm install",
"our:test": "npm run our:verify && npm test",
"our:verify": "npm run our:verify:directory && npm run our:verify:eslint && npm run our:verify:prettier",
"our:verify": "npm run our:verify:directory && npm run our:verify:eslint && npm run our:verify:module && npm run our:verify:prettier",
"our:verify:directory": "valid-directory",
"our:verify:eslint": "eslint --fix --ignore-pattern '**/*.d.ts' --ignore-pattern '**/vendor/' --ignore-pattern '**/node_modules/' --ext .mjs,.js,.jsx,.ts,.tsx ./source",
"our:verify:module": "valid-module",
"our:verify:prettier": "prettier --write .",
"test": "node ./edition-es2022/test.js"
},
Expand All @@ -209,6 +233,7 @@
"trailingComma": "es5"
},
"boundation": {
"browser": true,
"nodeVersionTestedMinimum": 8
}
}
14 changes: 8 additions & 6 deletions source/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export type Version = string | number
export type Range = Version | Version[]

const orRegex = /\s*\|\|\s*/
const rangeRegex = /^\s*([<>=~^]*)\s*([\d.]+)(-.+)?\s*$/
const rangeRegex = /^\s*([<>=~^]*)\s*([\d.]+?)[.x]*(-.+)?\s*$/

/**
* Check if the version is within the range
Expand All @@ -23,20 +23,22 @@ export default function withinVersionRange(
const subjectMinorNumber = Number(subjectMinor || 0)
const subjectPatchNumber = Number(subjectPatch || 0)

// cycle through the or conditions
// cycle through the conditions
let combinedResult: boolean = false
if (!Array.isArray(range)) range = String(range).split(orRegex)
for (const orRange of range) {
for (const condition of range) {
// process range
const [_, comparator, target, prerelease] =
String(orRange).match(rangeRegex) || []
String(condition).match(rangeRegex) || []

// prepare and verify target
const [targetMajor = null, targetMinor = null, targetPatch = null] = (
target || ''
).split('.')
if (!target || targetMajor == null || prerelease)
throw new Error(`range was invalid: ${JSON.stringify(orRange)}`)
throw new Error(
`range condition was invalid: ${JSON.stringify(condition)}`
)
const targetMajorNumber = Number(targetMajor || 0)
const targetMinorNumber = Number(targetMinor || 0)
const targetPatchNumber = Number(targetPatch || 0)
Expand Down Expand Up @@ -164,7 +166,7 @@ export default function withinVersionRange(
break
default:
throw new Error(
`range comparator was invalid: ${JSON.stringify(orRange)}`
`range comparator was invalid: ${JSON.stringify(condition)}`
)
}
if (pass) combinedResult = true
Expand Down
36 changes: 36 additions & 0 deletions source/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type Results = Array<
>

const versions = [
// don't put .x.x here, as .x is a range, not a version
'1',
'2',
'1.0',
Expand Down Expand Up @@ -68,6 +69,8 @@ const readmeResults: Results = [

['1', '^1', true],
['1', '~1', false],
['1', '^1.1', false],
['1', '~1.1', false],
['1.0.0', '^1', true],
['1.0.0', '~1', true],
]
Expand All @@ -78,10 +81,21 @@ const indexResults: Results = [
['1.1', '^1.0', true],
['1', '^1.1', false],

['1', '^1', true],
['1', '~1', false],
['1.0', '^1', true],
['1.0', '~1', true],
['1.0', '^1.0', true],
['1.0', '~1.0', true],
['1.0.0', '^1', true],
['1.0.0', '~1', true],
['1.0.1', '^1', true],
['1.0.1', '~1', true],
['1.1.0', '^1', true],
['1.1.0', '~1', false],
['1.1', '^1.0', true],
['1.1', '~1.0', false],
['1', '^1.1', false],
['1', '~1.1', false],

['1', '>2', false],
Expand Down Expand Up @@ -206,6 +220,28 @@ const indexResults: Results = [
['1.1.1', '1', true],
['1.1.1', '1.1.1', true],
['1.1.1', '1.1.2', false],

['1', '1.x', true],
['2', '1.x', false],
['1.0', '1.x', true],
['1.1', '1.x', true],
['2.0', '1.x', false],
['2.1', '1.x', false],
['1.0.0', '1.x', true],
['1.1.1', '1.x', true],
['2.0.0', '1.x', false],
['2.1.1', '1.x', false],

['1', '1.x.x', true],
['2', '1.x.x', false],
['1.0', '1.x.x', true],
['1.1', '1.x.x', true],
['2.0', '1.x.x', false],
['2.1', '1.x.x', false],
['1.0.0', '1.x.x', true],
['1.1.1', '1.x.x', true],
['2.0.0', '1.x.x', false],
['2.1.1', '1.x.x', false],
]

kava.suite('version-range', function (suite, test) {
Expand Down

0 comments on commit baa6aab

Please sign in to comment.