diff --git a/Makefile b/Makefile
index a5ab378..97c6bed 100644
--- a/Makefile
+++ b/Makefile
@@ -7,8 +7,7 @@
SHELL:=bash
default: all
-
-PHONY_TARGETS:=all default
+PHONY_TARGETS:=default
BUILD_TARGETS:=
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..0ae0e7b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,705 @@
+# semver-plus
+## API reference
+_API generated with [dmd-readme-api](https://www.npmjs.com/package/dmd-readme-api)._
+
+
+- Functions:
+ - _Comparison operations_
+ - [`cmp()`](#cmp): Returns a number indicating whether a version is greater than, equal to, or less than another version.
+ - [`compare()`](#compare): Returns 0 if `v1 == v2`, 1 if `v1 > v2`, and -1 if `v1 < v2`.
+ - [`compareBuild()`](#compareBuild): Same as [compare](#compare) except it compares build if two versions are otherwise equal.
+ - [`compareLoose()`](#compareLoose): Short for [compare](#compare) with `options.loose = true`.
+ - [`diff()`](#diff): Returns the difference between two versions.
+ - [`eq()`](#eq): Returns `true` if `v1` is equal to `v2`, `false` otherwise.
+ - [`gt()`](#gt): Returns `true` if `v1` is greater than `v2`, `false` otherwise.
+ - [`gte()`](#gte): Returns `true` if `v1` is greater than or equal to `v2`, `false` otherwise.
+ - [`lt()`](#lt): Returns `true` if `v1` is less than `v2`, `false` otherwise.
+ - [`lte()`](#lte): Returns `true` if `v1` is less than or equal to `v2`, `false` otherwise.
+ - [`neq()`](#neq): Returns `true` if `v1` is not equal to `v2`, `false` otherwise.
+ - [`rcompare()`](#rcompare): Reverse of [compare](#compare).
+ - [`rsort()`](#rsort): Sorts an array of versions in descending order using [compareBuild](#compareBuild).
+ - [`sort()`](#sort): Sorts an array of versions in ascending order using [compareBuild](#compareBuild).
+ - [`xSort()`](#xSort): Ascend sorts a mix of semver versions and x-range specified ranges (e.g., 1.2.* or 1.2.x).
+ - _Range operations_
+ - [`gtr()`](#gtr): Returns `true` if `version` is greater than is greater than any version in `range`, `false` otherwise.
+ - [`intersects()`](#intersects): Returns `true` if any of the comparators in the range intersect with each other.
+ - [`ltr()`](#ltr): Returns `true` if `version` is less than is less than any version in `range`, `false` otherwise.
+ - [`maxSatisfying()`](#maxSatisfying): Returns the highest version in `versions` that satisfies the range, or null if no version satisfies the range.
+ - [`minSatisfying()`](#minSatisfying): Returns the lowest version in `versions` that satisfies the range, or null if no version satisfies the range.
+ - [`minVersion()`](#minVersion): Returns the lowest version that satisfies the range, or null if no version satisfies the range.
+ - [`outside()`](#outside): Returns `true` if `version` is outside of `range` in the indicated direction, `false` otherwise.
+ - [`satisfies()`](#satisfies): Returns `true` if the version satisfies the range, `false` otherwise.
+ - [`simplifyRange()`](#simplifyRange): Return a "simplified" range that matches the same items in the versions list as the range specified.
+ - [`subset()`](#subset): Returns `true` if `subRange` is a subset of `superRange`, `false` otherwise.
+ - [`upperBound()`](#upperBound): Finds the ceiling of a range.
+ - [`validRange()`](#validRange): Returns a parsed, normalized range string or null if the range is invalid.
+ - [`validVersionOrRange()`](#validVersionOrRange): Validates a string to be a valid version or range.
+ - _Version operations_
+ - [`clean()`](#clean): Returns a cleaned version string removing unecessary comparators and, if `options.loose` is true, fixing space issues.
+ - [`coerce()`](#coerce): Aggressively attempts to coerce a string into a valid semver string.
+ - [`inc()`](#inc): Returns a new version string incremented by the specified part.
+ - [`major()`](#major): Returns the major version number.
+ - [`minor()`](#minor): Returns the minor version number.
+ - [`nextVersion()`](#nextVersion): Given a current version generates the next version string accourding to `increment`.
+ - [`parse()`](#parse): Attempts to parse and normalize a string as a semver string.
+ - [`patch()`](#patch): Returns the patch version number.
+ - [`prerelease()`](#prerelease): Returns an array of prerelease components or `null` if the version is not a prerelease.
+ - [`valid()`](#valid): Returns a parsed, normalized version string or null if the version is invalid.
+
+
+### `cmp(v1, comparator, v2, options)` ⇒ `number` ↱[source code](./src/semver-comparison-ops.mjs#L87) ⇧[global index](#global-function-index)
+
+Returns a number indicating whether a version is greater than, equal to, or less than another version.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `v1` | `string` | The first version to compare. |
+| `comparator` | `string` | The comparator to use. May be '<', '<=', '>', '>=', '=', '==', '!=', '===', or '!=='. An exception is thrown if an invalid comparator is provided. |
+| `v2` | `string` | The second version to compare. |
+| `options` | `object` | The options to pass to the semver.cmp function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `number` - - A number indicating whether a version is greater than, equal to, or less than another version.
+
+__Category__: [Comparison operations](#global-function-Comparison-operations-index)
+
+
+### `compare(v1, v2, options)` ⇒ `number` ↱[source code](./src/semver-comparison-ops.mjs#L100) ⇧[global index](#global-function-index)
+
+Returns 0 if `v1 == v2`, 1 if `v1 > v2`, and -1 if `v1 < v2`. Will sort an array of versions in ascending order if
+passed to `Array.sort()`.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `v1` | `string` | The first version to compare. |
+| `v2` | `string` | The second version to compare. |
+| `options` | `object` | The options to pass to the semver.compare function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `number` - - 0 if `v1 == v2`, 1 if `v1 > v2`, and -1 if `v1 < v2`.
+
+__Category__: [Comparison operations](#global-function-Comparison-operations-index)
+
+
+### `compareBuild(v1, v2, options)` ⇒ `number` ↱[source code](./src/semver-comparison-ops.mjs#L112) ⇧[global index](#global-function-index)
+
+Same as [compare](#compare) except it compares build if two versions are otherwise equal.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `v1` | `string` | The first version to compare. |
+| `v2` | `string` | The second version to compare. |
+| `options` | `object` | The options to pass to the semver.compareBuild function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `number` - - 0 if `v1 == v2`, 1 if `v1 > v2`, and -1 if `v1 < v2`.
+
+__Category__: [Comparison operations](#global-function-Comparison-operations-index)
+
+
+### `compareLoose(v1, v2)` ⇒ `number` ↱[source code](./src/semver-comparison-ops.mjs#L134) ⇧[global index](#global-function-index)
+
+Short for [compare](#compare) with `options.loose = true`.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `v1` | `string` | The first version to compare. |
+| `v2` | `string` | The second version to compare. |
+
+**Returns**: `number` - - 0 if `v1 == v2`, 1 if `v1 > v2`, and -1 if `v1 < v2`.
+
+__Category__: [Comparison operations](#global-function-Comparison-operations-index)
+
+
+### `diff(v1, v2, options)` ⇒ `string` \| `null` ↱[source code](./src/semver-comparison-ops.mjs#L148) ⇧[global index](#global-function-index)
+
+Returns the difference between two versions. I.e., the most significant version component by which `v1` and `v2`
+differ.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `v1` | `string` | The first version to compare. |
+| `v2` | `string` | The second version to compare. |
+| `options` | `object` | The options to pass to the semver.diff function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `string` \| `null` - - `major`, 'minor', 'patch', 'prerelease', 'premajor', 'preminor', or 'prepatch' or null if
+the `v1` and `v2` are identical (disregarding build metadata).
+
+__Category__: [Comparison operations](#global-function-Comparison-operations-index)
+
+
+### `eq(v1, v2, options)` ⇒ `boolean` ↱[source code](./src/semver-comparison-ops.mjs#L61) ⇧[global index](#global-function-index)
+
+Returns `true` if `v1` is equal to `v2`, `false` otherwise.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `v1` | `string` | The first version to compare. |
+| `v2` | `string` | The second version to compare. |
+| `options` | `object` | The options to pass to the semver.eq function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `boolean` - - `true` if `v1` is equal to `v2`, `false` otherwise.
+
+__Category__: [Comparison operations](#global-function-Comparison-operations-index)
+
+
+### `gt(v1, v2, options)` ⇒ `boolean` ↱[source code](./src/semver-comparison-ops.mjs#L13) ⇧[global index](#global-function-index)
+
+Returns `true` if `v1` is greater than `v2`, `false` otherwise.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `v1` | `string` | The first version to compare. |
+| `v2` | `string` | The second version to compare. |
+| `options` | `object` | The options to pass to the semver.gt function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `boolean` - - `true` if `v1` is greater than `v2`, `false` otherwise.
+
+__Category__: [Comparison operations](#global-function-Comparison-operations-index)
+
+
+### `gte(v1, v2, options)` ⇒ `boolean` ↱[source code](./src/semver-comparison-ops.mjs#L25) ⇧[global index](#global-function-index)
+
+Returns `true` if `v1` is greater than or equal to `v2`, `false` otherwise.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `v1` | `string` | The first version to compare. |
+| `v2` | `string` | The second version to compare. |
+| `options` | `object` | The options to pass to the semver.gte function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `boolean` - - `true` if `v1` is greater than or equal to `v2`, `false` otherwise.
+
+__Category__: [Comparison operations](#global-function-Comparison-operations-index)
+
+
+### `lt(v1, v2, options)` ⇒ `boolean` ↱[source code](./src/semver-comparison-ops.mjs#L37) ⇧[global index](#global-function-index)
+
+Returns `true` if `v1` is less than `v2`, `false` otherwise.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `v1` | `string` | The first version to compare. |
+| `v2` | `string` | The second version to compare. |
+| `options` | `object` | The options to pass to the semver.lt function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `boolean` - - `true` if `v1` is less than `v2`, `false` otherwise.
+
+__Category__: [Comparison operations](#global-function-Comparison-operations-index)
+
+
+### `lte(v1, v2, options)` ⇒ `boolean` ↱[source code](./src/semver-comparison-ops.mjs#L49) ⇧[global index](#global-function-index)
+
+Returns `true` if `v1` is less than or equal to `v2`, `false` otherwise.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `v1` | `string` | The first version to compare. |
+| `v2` | `string` | The second version to compare. |
+| `options` | `object` | The options to pass to the semver.lte function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `boolean` - - `true` if `v1` is less than or equal to `v2`, `false` otherwise.
+
+__Category__: [Comparison operations](#global-function-Comparison-operations-index)
+
+
+### `neq(v1, v2, options)` ⇒ `boolean` ↱[source code](./src/semver-comparison-ops.mjs#L73) ⇧[global index](#global-function-index)
+
+Returns `true` if `v1` is not equal to `v2`, `false` otherwise.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `v1` | `string` | The first version to compare. |
+| `v2` | `string` | The second version to compare. |
+| `options` | `object` | The options to pass to the semver.neq function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `boolean` - - `true` if `v1` is not equal to `v2`, `false` otherwise.
+
+__Category__: [Comparison operations](#global-function-Comparison-operations-index)
+
+
+### `rcompare(v1, v2, options)` ⇒ `number` ↱[source code](./src/semver-comparison-ops.mjs#L124) ⇧[global index](#global-function-index)
+
+Reverse of [compare](#compare).
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `v1` | `string` | The first version to compare. |
+| `v2` | `string` | The second version to compare. |
+| `options` | `object` | The options to pass to the semver.rcompare function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `number` - - 0 if `v1 == v2`, -1 if `v1 > v2`, and 1 if `v1 < v2`.
+
+__Category__: [Comparison operations](#global-function-Comparison-operations-index)
+
+
+### `rsort(versions, options)` ⇒ `Array.` ↱[source code](./src/semver-comparison-ops.mjs#L170) ⇧[global index](#global-function-index)
+
+Sorts an array of versions in descending order using [compareBuild](#compareBuild).
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `versions` | `Array.` | The versions to sort. |
+| `options` | `object` | The options to pass to the semver.rsort function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `Array.` - - The sorted versions.
+
+__Category__: [Comparison operations](#global-function-Comparison-operations-index)
+
+
+### `sort(versions, options)` ⇒ `Array.` ↱[source code](./src/semver-comparison-ops.mjs#L159) ⇧[global index](#global-function-index)
+
+Sorts an array of versions in ascending order using [compareBuild](#compareBuild).
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `versions` | `Array.` | The versions to sort. |
+| `options` | `object` | The options to pass to the semver.sort function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `Array.` - - The sorted versions.
+
+__Category__: [Comparison operations](#global-function-Comparison-operations-index)
+
+
+### `xSort(versionsAndRanges)` ⇒ `Array.` ↱[source code](./src/x-sort.mjs#L12) ⇧[global index](#global-function-index)
+
+Ascend sorts a mix of semver versions and x-range specified ranges (e.g., 1.2.* or 1.2.x). The ranges are sorted according to their highest version; e.g., 1.3.34 < 1.3.*. (I believe it can accept caret ranges too, but I would need to review the spec.)
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `versionsAndRanges` | `Array.` | The versions and ranges to sort. |
+
+**Returns**: `Array.` - - The sorted versions and ranges.
+
+__Category__: [Comparison operations](#global-function-Comparison-operations-index)
+
+
+### `gtr(version, range, options)` ⇒ `boolean` ↱[source code](./src/semver-range-ops.mjs#L52) ⇧[global index](#global-function-index)
+
+Returns `true` if `version` is greater than is greater than any version in `range`, `false` otherwise.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `version` | `string` | The version to check. |
+| `range` | `string` | The range to check. |
+| `options` | `object` | The options to pass to the semver.gtr function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `boolean` - - `true` if `version` is greater than is greater than any version in `range`, `false` otherwise.
+
+__Category__: [Range operations](#global-function-Range-operations-index)
+
+
+### `intersects(range, options)` ⇒ `boolean` ↱[source code](./src/semver-range-ops.mjs#L89) ⇧[global index](#global-function-index)
+
+Returns `true` if any of the comparators in the range intersect with each other.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `range` | `string` | The first version range or comparator. |
+| `options` | `object` | The options to pass to the semver.intersects function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `boolean` - - `true` if any of the comparators in the range intersect with each other, `false` otherwise.
+
+__Category__: [Range operations](#global-function-Range-operations-index)
+
+
+### `ltr(version, range, options)` ⇒ `boolean` ↱[source code](./src/semver-range-ops.mjs#L64) ⇧[global index](#global-function-index)
+
+Returns `true` if `version` is less than is less than any version in `range`, `false` otherwise.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `version` | `string` | The version to check. |
+| `range` | `string` | The range to check. |
+| `options` | `object` | The options to pass to the semver.ltr function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `boolean` - - `true` if `version` is less than is less than any version in `range`, `false` otherwise.
+
+__Category__: [Range operations](#global-function-Range-operations-index)
+
+
+### `maxSatisfying(versions, range, options)` ⇒ `string` \| `null` ↱[source code](./src/max-satisfying.mjs#L26) ⇧[global index](#global-function-index)
+
+Returns the highest version in `versions` that satisfies the range, or null if no version satisfies the range. This
+implementation differs from the base `semver.maxSatisfying` in that it correctly handles the following case:
+`maxSatisfying(['1.0.0-alpha.0', '1.0.0'], '<1.0.0')` -> '1.0.0-alpha.0'. The base `semver.maxSatisfying` function
+returns `null` in this case. Note, support for this syntax is not comprehensive and more complicated expressions are
+likely to yield incorrect results.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `versions` | `Array.` | The versions to check. |
+| `range` | `string` | The range to check. |
+| `options` | `object` | The options to pass to the semver.maxSatisfying function. |
+| `options.compat` | `boolean` | If true, then uses the base `semver.maxSatisfying` function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+| `options.includePrerelease` | `boolean` | Include prerelease versions in the result. This is effectively implied if the range contains prerelease components. |
+| `options.throwIfInvalid` | `boolean` | If true, throws an exception if any version or the range is invalid. |
+
+**Returns**: `string` \| `null` - - The highest version that satisfies the range, or null if no version satisfies the range.
+
+__Category__: [Range operations](#global-function-Range-operations-index)
+
+
+### `minSatisfying(versions, range, options)` ⇒ `string` \| `null` ↱[source code](./src/semver-range-ops.mjs#L40) ⇧[global index](#global-function-index)
+
+Returns the lowest version in `versions` that satisfies the range, or null if no version satisfies the range.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `versions` | `Array.` | The versions to check. |
+| `range` | `string` | The range to check. |
+| `options` | `object` | The options to pass to the semver.minSatisfying function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `string` \| `null` - - The lowest version that satisfies the range, or null if no version satisfies the range.
+
+__Category__: [Range operations](#global-function-Range-operations-index)
+
+
+### `minVersion(range, options)` ⇒ `string` \| `null` ↱[source code](./src/min-version.mjs#L19) ⇧[global index](#global-function-index)
+
+Returns the lowest version that satisfies the range, or null if no version satisfies the range. This implementation
+differs from the base `semver.minVersion` in that it correctly handles simple prerelease x-ranges. E.g.,
+'1.0.0-alpha.x' -> '1.0.0-alpha.0'. To suppress this behavior, pass `options.compat = true`. Note, support for this
+syntax is not comprehensive and more complicated expressions are likely to yield incorrect results.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `range` | `string` | The range to check. |
+| `options` | `object` | The options to pass to the semver.minVersion function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+| `options.includePrerelease` | `boolean` | Whether to include prerelease versions. |
+| `options.compat` | `boolean` | If true, prerelease ranges are treated the same as in the base semver package; e.g. `minVersion('1.0.0-alpha.x', { compat: true })` -> '1.0.0-alpha.x'. |
+
+**Returns**: `string` \| `null` - - The lowest version that satisfies the range, or null if no version satisfies the range.
+
+__Category__: [Range operations](#global-function-Range-operations-index)
+
+
+### `outside(version, range, direction, options)` ⇒ `boolean` ↱[source code](./src/semver-range-ops.mjs#L78) ⇧[global index](#global-function-index)
+
+Returns `true` if `version` is outside of `range` in the indicated direction, `false` otherwise. `outside(v, r, '>)`
+is equivalent to `gtr(v, r)`.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `version` | `string` | The version to check. |
+| `range` | `string` | The range to check. |
+| `direction` | `string` | The direction to check. Must be '>' or '<'. |
+| `options` | `object` | The options to pass to the semver.outside function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `boolean` - - `true` if `version` is outside of `range` in the indicated direction, `false` otherwise.
+
+__Category__: [Range operations](#global-function-Range-operations-index)
+
+
+### `satisfies(version, range, options)` ⇒ `boolean` ↱[source code](./src/semver-range-ops.mjs#L28) ⇧[global index](#global-function-index)
+
+Returns `true` if the version satisfies the range, `false` otherwise.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `version` | `string` | The version to check. |
+| `range` | `string` | The range to check. |
+| `options` | `object` | The options to pass to the semver.satisfies function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `boolean` - - `true` if the version satisfies the range, `false` otherwise.
+
+__Category__: [Range operations](#global-function-Range-operations-index)
+
+
+### `simplifyRange(versions, range, options)` ⇒ `string` ↱[source code](./src/semver-range-ops.mjs#L105) ⇧[global index](#global-function-index)
+
+Return a "simplified" range that matches the same items in the versions list as the range specified. Note that it
+does not guarantee that it would match the same versions in all cases, only for the set of versions provided. This
+is useful when generating ranges by joining together multiple versions with || programmatically, to provide the user
+with something a bit more ergonomic. If the provided range is shorter in string-length than the generated range,
+then that is returned.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `versions` | `Array.` | The versions to check. |
+| `range` | `string` | The range to simplify. |
+| `options` | `object` | The options to pass to the semver.simplifyRange function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `string` - - The simplified range.
+
+__Category__: [Range operations](#global-function-Range-operations-index)
+
+
+### `subset(subRange, superRange, options)` ⇒ `boolean` ↱[source code](./src/semver-range-ops.mjs#L117) ⇧[global index](#global-function-index)
+
+Returns `true` if `subRange` is a subset of `superRange`, `false` otherwise.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `subRange` | `string` | The sub-range to check. |
+| `superRange` | `string` | The super-range to check. |
+| `options` | `object` | The options to pass to the semver.subset function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `boolean` - - `true` if `subRange` is a subset of `superRange`, `false` otherwise.
+
+__Category__: [Range operations](#global-function-Range-operations-index)
+
+
+### `upperBound(range)` ⇒ `string` ↱[source code](./src/upper-bound.mjs#L11) ⇧[global index](#global-function-index)
+
+Finds the ceiling of a range. For '*', the ceiling is '*'. For specific versions or any range capped by a specific
+version, the ceiling is that version. For any open-ended range, the ceiling is defined by a '-0' range
+function where 'verision-0' least range above the given range.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `range` | `string` | The range to find the ceiling for. |
+
+**Returns**: `string` - - Either '*', a specific version, or a '-0'.
+
+__Category__: [Range operations](#global-function-Range-operations-index)
+
+
+### `validRange(range, options)` ⇒ `string` \| `null` ↱[source code](./src/semver-range-ops.mjs#L16) ⇧[global index](#global-function-index)
+
+Returns a parsed, normalized range string or null if the range is invalid.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `range` | `string` | The range to parse. |
+| `options` | `object` | The options to pass to the semver.validRange function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `string` \| `null` - - The parsed, normalized range string or null if the range is invalid.
+
+__Category__: [Range operations](#global-function-Range-operations-index)
+
+
+### `validVersionOrRange(input, options)` ⇒ `string` \| `null` ↱[source code](./src/valid-version-or-range.mjs#L20) ⇧[global index](#global-function-index)
+
+Validates a string to be a valid version or range. By default, an exception is raised unless `options.disallowVersions`
+is `true`, in which case it filters out invalid strings and returns a new array.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `input` | `string` | The string to validate. |
+| `options` | `object` | The options to pass to the semver.valid function. |
+| `options.disallowRanges` | `boolean` | Whether to disallow ranges. |
+| `options.disallowVersions` | `boolean` | Whether to disallow versions and ranges which are valid versions. |
+| `options.includePrerelease` | `boolean` | Whether to include prerelease versions. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+| `options.onlyXRange` | `boolean` | Whether to only allow x-ranges. Note, even if this is `true`, and a valid x-range is presented, the returned string will still be normalized. |
+| `options.throwIfInvalid` | `boolean` | If true, throws an exception if the string is invalid. |
+
+**Returns**: `string` \| `null` - - A normalized version or range string or `null` if the string is invalid (if
+`options.throwIfInvalid` is `true`, in which case an exception is thrown).
+
+
+### `clean(version, options)` ⇒ `string` \| `null` ↱[source code](./src/semver-version-ops.mjs#L109) ⇧[global index](#global-function-index)
+
+Returns a cleaned version string removing unecessary comparators and, if `options.loose` is true, fixing space
+issues. Only works for versions, not ranges.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `version` | `string` | The version to clean. |
+| `options` | `object` | The options to pass to the semver.clean function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `string` \| `null` - - The cleaned version string or null if the version is invalid.
+
+__Category__: [Version operations](#global-function-Version-operations-index)
+
+
+### `coerce(version, options)` ⇒ `string` \| `null` ↱[source code](./src/semver-version-ops.mjs#L97) ⇧[global index](#global-function-index)
+
+Aggressively attempts to coerce a string into a valid semver string. Basically, starting from the left side of the
+string, it looks for a digit and then includes anything to the right of the digit that looks like part of a semver.
+So, 'Number 1!' -> '1.0.0', 'Upgrade 1.2 to 1.3' -> '1.2.0', etc.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `version` | `string` | The version to coerce. |
+| `options` | `object` | The options to pass to the semver.coerce function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+| `options.includePrerelease` | `boolean` | Unless true, prerelease tags (and build metadata) are stripped. If |
+| `options.rtl` | `boolean` | Instead of searching for a digit from the left, start searching from the right. true, then they are preserved. |
+
+**Returns**: `string` \| `null` - - The coerced version string or null if the version is invalid.
+
+__Category__: [Version operations](#global-function-Version-operations-index)
+
+
+### `inc(version, increment, options, identifier, identifierBase)` ⇒ `string` ↱[source code](./src/semver-version-ops.mjs#L29) ⇧[global index](#global-function-index)
+
+Returns a new version string incremented by the specified part.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `version` | `string` | The version to increment. |
+| `increment` | `string` | The increment to use. |
+| `options` | `object` | The options to pass to the semver.inc function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+| `options.includePrerelease` | `boolean` | Whether to include prerelease versions. |
+| `identifier` | `string` | Used to specify the prerelease name for prerelease increments. |
+| `identifierBase` | `false` \| `0` \| `1` | When incrementing to a new prerelease name, specifies the base number or `false` for no number. |
+
+**Returns**: `string` - - The new version string.
+
+__Category__: [Version operations](#global-function-Version-operations-index)
+
+
+### `major(version, options)` ⇒ `number` ↱[source code](./src/semver-version-ops.mjs#L52) ⇧[global index](#global-function-index)
+
+Returns the major version number.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `version` | `string` | The version to parse. |
+| `options` | `object` | The options to pass to the semver.major function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `number` - - The major version number.
+
+__Category__: [Version operations](#global-function-Version-operations-index)
+
+
+### `minor(version, options)` ⇒ `number` ↱[source code](./src/semver-version-ops.mjs#L63) ⇧[global index](#global-function-index)
+
+Returns the minor version number.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `version` | `string` | The version to parse. |
+| `options` | `object` | The options to pass to the semver.minor function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `number` - - The minor version number.
+
+__Category__: [Version operations](#global-function-Version-operations-index)
+
+
+### `nextVersion(currVer, increment)` ⇒ `string` ↱[source code](./src/next-version.mjs#L23) ⇧[global index](#global-function-index)
+
+Given a current version generates the next version string accourding to `increment`. This method is similar to
+[inc](#inc) from the [base semver library](https://semver.org) with two differences.
+1) It supports a specific pre-release sequence prototype -> 'alpha' -> 'beta' -> 'rc' -> released and the 'pretype'
+ increment will advance the prerelease ID through these stages.
+2) The 'prerelease' increment can only be used to advance the prerelease version number and does not function as
+ 'prepatch' on a non-prerelease version.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `currVer` | `string` | The current version to increment. |
+| `increment` | `string` | The increment to use. |
+
+**Returns**: `string` - - The next version string.
+
+__Category__: [Version operations](#global-function-Version-operations-index)
+
+
+### `parse()` ↱[source code](./src/semver-version-ops.mjs#L81) ⇧[global index](#global-function-index)
+
+Attempts to parse and normalize a string as a semver string. An aliase for [valid](#valid).
+
+__Category__: [Version operations](#global-function-Version-operations-index)
+
+
+### `patch(version, options)` ⇒ `number` ↱[source code](./src/semver-version-ops.mjs#L74) ⇧[global index](#global-function-index)
+
+Returns the patch version number.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `version` | `string` | The version to parse. |
+| `options` | `object` | The options to pass to the semver.patch function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `number` - - The patch version number.
+
+__Category__: [Version operations](#global-function-Version-operations-index)
+
+
+### `prerelease(version, options)` ⇒ `Array.` \| `null` ↱[source code](./src/semver-version-ops.mjs#L41) ⇧[global index](#global-function-index)
+
+Returns an array of prerelease components or `null` if the version is not a prerelease. A 'component' is just a '.'
+separated string.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `version` | `string` | The version to parse. |
+| `options` | `object` | The options to pass to the semver.inc function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+
+**Returns**: `Array.` \| `null` - - The prerelease components or `null` if the version is not a prerelease.
+
+__Category__: [Version operations](#global-function-Version-operations-index)
+
+
+### `valid(version, options)` ⇒ `string` \| `null` ↱[source code](./src/semver-version-ops.mjs#L13) ⇧[global index](#global-function-index)
+
+Returns a parsed, normalized version string or null if the version is invalid.
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| `version` | `string` | The version to parse. |
+| `options` | `object` | The options to pass to the semver.valid function. |
+| `options.loose` | `boolean` | Allow non-conforming, but recognizable semver strings. |
+| `options.includePrerelease` | `boolean` | Whether to include prerelease versions. |
+
+**Returns**: `string` \| `null` - - The parsed, normalized version string or null if the version is invalid.
+
+__Category__: [Version operations](#global-function-Version-operations-index)
+
diff --git a/jsdoc.config.json b/jsdoc.config.json
new file mode 100644
index 0000000..ade88fc
--- /dev/null
+++ b/jsdoc.config.json
@@ -0,0 +1,17 @@
+{
+ "plugins": ["dmd-readme-api"],
+ "recurseDepth": 10,
+ "source": {
+ "includePattern": ".+\\.(c|m)?js(doc|x)?$",
+ "excludePattern": "((^|\\/|\\\\)_|.+\\.test\\.(c|m)?jsx?$)"
+ },
+ "sourceType": "module",
+ "tags": {
+ "allowUnknownTags": true,
+ "dictionaries": ["jsdoc","closure"]
+ },
+ "templates": {
+ "cleverLinks": true,
+ "monospaceLinks": true
+ }
+}
\ No newline at end of file
diff --git a/make/55-readme-md.mk b/make/55-readme-md.mk
new file mode 100644
index 0000000..da86b5a
--- /dev/null
+++ b/make/55-readme-md.mk
@@ -0,0 +1,15 @@
+README_MD:=README.md
+README_MD_SRC:=$(shell find $(SRC)/doc -name "*.md") $(SDLC_ALL_NON_TEST_JS_FILES_SRC)
+BUILD_TARGETS+=$(README_MD)
+
+$(README_MD): $(README_MD_SRC)
+ cp $(SRC)/doc/README.01.md $@
+ npx jsdoc2md \
+ --files 'src/**/*' \
+ --plugin dmd-readme-api \
+ --global-index-format grouped \
+ --name-format \
+ --configure jsdoc.config.json \
+ --no-cache \
+ >> $@
+ cat $(SRC)/doc/README.02.md >> $@
\ No newline at end of file
diff --git a/make/95-final-targets.mk b/make/95-final-targets.mk
index 66ccb79..eb14f4f 100644
--- a/make/95-final-targets.mk
+++ b/make/95-final-targets.mk
@@ -2,26 +2,27 @@
# to https://npmjs.com/package/@liquid-labs/sdlc-projects-workflow-node-build for
# further details
+.DEFAULT_GOAL:=all
+
.PRECIOUS: $(PRECIOUS_TARGETS)
build: $(BUILD_TARGETS)
+.PHONY+= build
-PHONY_TARGETS+=build
+all: build doc
+.PHONY+= all
-all: build
+doc: $(DOC_TARGETS)
+.PHONY+= doc
lint: $(LINT_TARGETS)
-
lint-fix: $(LINT_FIX_TARGETS)
-
-PHONY_TARGETS+=lint lint-fix
+.PHONY+=lint lint-fix
test: $(TEST_TARGETS)
-
-PHONY_TARGETS+= test
+.PHONY+= test
qa: test lint
+.PHONY+=qa
-PHONY_TARGETS+=qa
-
-.PHONY: $(PHONY_TARGETS)
+.PHONY: $(.PHONY)
diff --git a/package-lock.json b/package-lock.json
index 0043893..e2b5dd8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,12 +10,15 @@
"license": "UNLICENSED",
"dependencies": {
"http-errors": "^2.0.0",
- "semver": "^7.3.8"
+ "semver": "^7.0.0"
},
"devDependencies": {
+ "@liquid-labs/dmd": "^7.1.1",
+ "@liquid-labs/jsdoc-to-markdown": "^9.1.3",
"@liquid-labs/sdlc-resource-babel-and-rollup": "^1.0.0-alpha.5",
"@liquid-labs/sdlc-resource-eslint": "^1.0.0-alpha.2",
- "@liquid-labs/sdlc-resource-jest": "^1.0.0-alpha.5"
+ "@liquid-labs/sdlc-resource-jest": "^1.0.0-alpha.5",
+ "dmd-readme-api": "^1.0.0-beta.8"
},
"engines": {
"node": ">=18.0.0"
@@ -2844,6 +2847,78 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@jsdoc/salty": {
+ "version": "0.2.9",
+ "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.9.tgz",
+ "integrity": "sha512-yYxMVH7Dqw6nO0d5NIV8OQWnitU8k6vXH8NtgqAfIa/IUqRMxRv/NUJJ08VEKbAakwxlgBl5PJdrU0dMPStsnw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "lodash": "^4.17.21"
+ },
+ "engines": {
+ "node": ">=v12.0.0"
+ }
+ },
+ "node_modules/@liquid-labs/dmd": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/@liquid-labs/dmd/-/dmd-7.1.1.tgz",
+ "integrity": "sha512-J8CKJBwYtGDNwmbUENCamFw+H6OAaaYHIlBS0h2OBNSgECZXU2+hIF+STE2irJTO2nzmuc+De7es7/QcWID58w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-back": "^6.2.2",
+ "cache-point": "^3.0.0",
+ "common-sequence": "^3.0.0",
+ "file-set": "^5.2.2",
+ "handlebars": "^4.7.8",
+ "marked": "^4.3.0",
+ "regex-repo": "^5.0.1",
+ "walk-back": "^5.1.1"
+ },
+ "engines": {
+ "node": ">=12.17"
+ },
+ "peerDependencies": {
+ "@75lb/nature": "^0.1.10"
+ },
+ "peerDependenciesMeta": {
+ "@75lb/nature": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@liquid-labs/jsdoc-to-markdown": {
+ "version": "9.1.3",
+ "resolved": "https://registry.npmjs.org/@liquid-labs/jsdoc-to-markdown/-/jsdoc-to-markdown-9.1.3.tgz",
+ "integrity": "sha512-NjiqezNbmDLttbUkbJyoglA/Y5ZQrs1HuVBn98UYmuQ9zosb59W71QBoVdAL3kZEy6nLbK2Y80Q1EXGdVdyJMQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@liquid-labs/dmd": "^7.1.1",
+ "array-back": "^6.2.2",
+ "command-line-args": "^6.0.1",
+ "command-line-usage": "^7.0.3",
+ "config-master": "^3.1.0",
+ "jsdoc-api": "^9.3.5",
+ "jsdoc-parse": "^6.2.5",
+ "walk-back": "^5.1.1"
+ },
+ "bin": {
+ "jsdoc2md": "bin/cli.js"
+ },
+ "engines": {
+ "node": ">=12.17"
+ },
+ "peerDependencies": {
+ "@75lb/nature": "^0.1.10"
+ },
+ "peerDependenciesMeta": {
+ "@75lb/nature": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@liquid-labs/sdlc-resource-babel-and-rollup": {
"version": "1.0.0-alpha.5",
"resolved": "https://registry.npmjs.org/@liquid-labs/sdlc-resource-babel-and-rollup/-/sdlc-resource-babel-and-rollup-1.0.0-alpha.5.tgz",
@@ -3447,6 +3522,31 @@
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
"dev": true
},
+ "node_modules/@types/linkify-it": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
+ "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/markdown-it": {
+ "version": "14.1.2",
+ "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz",
+ "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/linkify-it": "^5",
+ "@types/mdurl": "^2"
+ }
+ },
+ "node_modules/@types/mdurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz",
+ "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/node": {
"version": "20.10.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.0.tgz",
@@ -3579,6 +3679,16 @@
"sprintf-js": "~1.0.2"
}
},
+ "node_modules/array-back": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz",
+ "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.17"
+ }
+ },
"node_modules/array-buffer-byte-length": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz",
@@ -3976,6 +4086,13 @@
"node": ">=8"
}
},
+ "node_modules/bluebird": {
+ "version": "3.7.2",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -3987,12 +4104,13 @@
}
},
"node_modules/braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "fill-range": "^7.0.1"
+ "fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
@@ -4067,6 +4185,27 @@
"semver": "^7.0.0"
}
},
+ "node_modules/cache-point": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/cache-point/-/cache-point-3.0.1.tgz",
+ "integrity": "sha512-itTIMLEKbh6Dw5DruXbxAgcyLnh/oPGVLBfTPqBOftASxHe8bAeXy7JkO4F0LvHqht7XqP5O/09h5UcHS2w0FA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-back": "^6.2.2"
+ },
+ "engines": {
+ "node": ">=12.17"
+ },
+ "peerDependencies": {
+ "@75lb/nature": "latest"
+ },
+ "peerDependenciesMeta": {
+ "@75lb/nature": {
+ "optional": true
+ }
+ }
+ },
"node_modules/call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
@@ -4127,6 +4266,19 @@
}
]
},
+ "node_modules/catharsis": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz",
+ "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "lodash": "^4.17.15"
+ },
+ "engines": {
+ "node": ">= 10"
+ }
+ },
"node_modules/chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
@@ -4141,6 +4293,98 @@
"node": ">=4"
}
},
+ "node_modules/chalk-template": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz",
+ "integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^4.1.2"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk-template?sponsor=1"
+ }
+ },
+ "node_modules/chalk-template/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/chalk-template/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/chalk-template/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/chalk-template/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/chalk-template/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/chalk-template/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/char-regex": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
@@ -4244,6 +4488,46 @@
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
"dev": true
},
+ "node_modules/command-line-args": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-6.0.1.tgz",
+ "integrity": "sha512-Jr3eByUjqyK0qd8W0SGFW1nZwqCaNCtbXjRo2cRJC1OYxWl3MZ5t1US3jq+cO4sPavqgw4l9BMGX0CBe+trepg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-back": "^6.2.2",
+ "find-replace": "^5.0.2",
+ "lodash.camelcase": "^4.3.0",
+ "typical": "^7.2.0"
+ },
+ "engines": {
+ "node": ">=12.20"
+ },
+ "peerDependencies": {
+ "@75lb/nature": "latest"
+ },
+ "peerDependenciesMeta": {
+ "@75lb/nature": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/command-line-usage": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.3.tgz",
+ "integrity": "sha512-PqMLy5+YGwhMh1wS04mVG44oqDsgyLRSKJBdOo1bnYhMKBW65gZF1dRp2OZRhiTjgUHljy99qkO7bsctLaw35Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-back": "^6.2.2",
+ "chalk-template": "^0.4.0",
+ "table-layout": "^4.1.0",
+ "typical": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=12.20.0"
+ }
+ },
"node_modules/commander": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
@@ -4259,6 +4543,16 @@
"integrity": "sha512-YeNK4tavZwtH7jEgK1ZINXzLKm6DZdEMfsaaieOsCAN0S8vsY7UeuO3Q7d/M018EFgE+IeUAuBOKkFccBZsUZA==",
"dev": true
},
+ "node_modules/common-sequence": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/common-sequence/-/common-sequence-3.0.0.tgz",
+ "integrity": "sha512-g/CgSYk93y+a1IKm50tKl7kaT/OjjTYVQlEbUlt/49ZLV1mcKpUU7iyDiqTAeLdb4QDtQfq3ako8y8v//fzrWQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.17"
+ }
+ },
"node_modules/commondir": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
@@ -4271,6 +4565,26 @@
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"dev": true
},
+ "node_modules/config-master": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/config-master/-/config-master-3.1.0.tgz",
+ "integrity": "sha512-n7LBL1zBzYdTpF1mx5DNcZnZn05CWIdsdvtPL4MosvqbBUK3Rq6VWEtGUuF3Y0s9/CIhMejezqlSkP6TnCJ/9g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "walk-back": "^2.0.1"
+ }
+ },
+ "node_modules/config-master/node_modules/walk-back": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-2.0.1.tgz",
+ "integrity": "sha512-Nb6GvBR8UWX1D+Le+xUq0+Q1kFmRBIWVrfLnQAOmcpEzA9oAxwJ9gIr36t9TWYfzvWRvuMtjHiVsJYEkXWaTAQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/convert-source-map": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
@@ -4395,6 +4709,16 @@
"node": ">= 8"
}
},
+ "node_modules/current-module-paths": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/current-module-paths/-/current-module-paths-1.1.2.tgz",
+ "integrity": "sha512-H4s4arcLx/ugbu1XkkgSvcUZax0L6tXUqnppGniQb8l5VjUKGHoayXE5RiriiPhYDd+kjZnaok1Uig13PKtKYQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.17"
+ }
+ },
"node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -4507,6 +4831,16 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
+ "node_modules/dmd-readme-api": {
+ "version": "1.0.0-beta.8",
+ "resolved": "https://registry.npmjs.org/dmd-readme-api/-/dmd-readme-api-1.0.0-beta.8.tgz",
+ "integrity": "sha512-KocOTjjhavStJ5efGIgCmrrAMm/vuVgeJXgF9r+VAlQXQ5tQligdvcJN28RYYeR9Kk0zqBBkMk4zUiBIzPJplg==",
+ "dev": true,
+ "license": "Apache 2.0",
+ "dependencies": {
+ "extract-topic": "^1.0.0-beta.6"
+ }
+ },
"node_modules/doctrine": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
@@ -4543,6 +4877,19 @@
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
+ "node_modules/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
"node_modules/error-ex": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
@@ -5393,12 +5740,39 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
+ "node_modules/extract-topic": {
+ "version": "1.0.0-beta.6",
+ "resolved": "https://registry.npmjs.org/extract-topic/-/extract-topic-1.0.0-beta.6.tgz",
+ "integrity": "sha512-ZvOzCjllNDigyhdX9s+CsChwfyOuk2TlvFmzWWNhwK131Y4dv9A9dhu3jfRln7d+Pgnm6kEL76/iM+PLtUn4ow==",
+ "dev": true,
+ "license": "UNLICENSED",
+ "dependencies": {
+ "he": "^1.2.0"
+ }
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
+ "node_modules/fast-glob": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
+ "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.8"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
@@ -5441,11 +5815,34 @@
"node": "^10.12.0 || >=12.0.0"
}
},
+ "node_modules/file-set": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/file-set/-/file-set-5.3.0.tgz",
+ "integrity": "sha512-FKCxdjLX0J6zqTWdT0RXIxNF/n7MyXXnsSUp0syLEOCKdexvPZ02lNNv2a+gpK9E3hzUYF3+eFZe32ci7goNUg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-back": "^6.2.2",
+ "fast-glob": "^3.3.2"
+ },
+ "engines": {
+ "node": ">=12.17"
+ },
+ "peerDependencies": {
+ "@75lb/nature": "latest"
+ },
+ "peerDependenciesMeta": {
+ "@75lb/nature": {
+ "optional": true
+ }
+ }
+ },
"node_modules/fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
},
@@ -5453,6 +5850,24 @@
"node": ">=8"
}
},
+ "node_modules/find-replace": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-5.0.2.tgz",
+ "integrity": "sha512-Y45BAiE3mz2QsrN2fb5QEtO4qb44NcS7en/0y9PEVsg351HsLeVclP8QPMH79Le9sH3rs5RSwJu99W0WPZO43Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ },
+ "peerDependencies": {
+ "@75lb/nature": "latest"
+ },
+ "peerDependenciesMeta": {
+ "@75lb/nature": {
+ "optional": true
+ }
+ }
+ },
"node_modules/find-root": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
@@ -5667,7 +6082,6 @@
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
- "optional": true,
"dependencies": {
"is-glob": "^4.0.1"
},
@@ -5723,6 +6137,28 @@
"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
"dev": true
},
+ "node_modules/handlebars": {
+ "version": "4.7.8",
+ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
+ "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "minimist": "^1.2.5",
+ "neo-async": "^2.6.2",
+ "source-map": "^0.6.1",
+ "wordwrap": "^1.0.0"
+ },
+ "bin": {
+ "handlebars": "bin/handlebars"
+ },
+ "engines": {
+ "node": ">=0.4.7"
+ },
+ "optionalDependencies": {
+ "uglify-js": "^3.1.4"
+ }
+ },
"node_modules/has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
@@ -5804,6 +6240,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/he": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "he": "bin/he"
+ }
+ },
"node_modules/html-escaper": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
@@ -6093,6 +6539,7 @@
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=0.12.0"
}
@@ -8004,6 +8451,111 @@
"js-yaml": "bin/js-yaml.js"
}
},
+ "node_modules/js2xmlparser": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz",
+ "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "xmlcreate": "^2.0.4"
+ }
+ },
+ "node_modules/jsdoc": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.5.tgz",
+ "integrity": "sha512-P4C6MWP9yIlMiK8nwoZvxN84vb6MsnXcHuy7XzVOvQoCizWX5JFCBsWIIWKXBltpoRZXddUOVQmCTOZt9yDj9g==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@babel/parser": "^7.20.15",
+ "@jsdoc/salty": "^0.2.1",
+ "@types/markdown-it": "^14.1.1",
+ "bluebird": "^3.7.2",
+ "catharsis": "^0.9.0",
+ "escape-string-regexp": "^2.0.0",
+ "js2xmlparser": "^4.0.2",
+ "klaw": "^3.0.0",
+ "markdown-it": "^14.1.0",
+ "markdown-it-anchor": "^8.6.7",
+ "marked": "^4.0.10",
+ "mkdirp": "^1.0.4",
+ "requizzle": "^0.2.3",
+ "strip-json-comments": "^3.1.0",
+ "underscore": "~1.13.2"
+ },
+ "bin": {
+ "jsdoc": "jsdoc.js"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/jsdoc-api": {
+ "version": "9.3.5",
+ "resolved": "https://registry.npmjs.org/jsdoc-api/-/jsdoc-api-9.3.5.tgz",
+ "integrity": "sha512-TQwh1jA8xtCkIbVwm/XA3vDRAa5JjydyKx1cC413Sh3WohDFxcMdwKSvn4LOsq2xWyAmOU/VnSChTQf6EF0R8g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-back": "^6.2.2",
+ "cache-point": "^3.0.1",
+ "current-module-paths": "^1.1.2",
+ "file-set": "^5.3.0",
+ "jsdoc": "^4.0.4",
+ "object-to-spawn-args": "^2.0.1",
+ "walk-back": "^5.1.1"
+ },
+ "engines": {
+ "node": ">=12.17"
+ },
+ "peerDependencies": {
+ "@75lb/nature": "latest"
+ },
+ "peerDependenciesMeta": {
+ "@75lb/nature": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/jsdoc-parse": {
+ "version": "6.2.5",
+ "resolved": "https://registry.npmjs.org/jsdoc-parse/-/jsdoc-parse-6.2.5.tgz",
+ "integrity": "sha512-8JaSNjPLr2IuEY4Das1KM6Z4oLHZYUnjRrr27hKSa78Cj0i5Lur3DzNnCkz+DfrKBDoljGMoWOiBVQbtUZJBPw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-back": "^6.2.2",
+ "find-replace": "^5.0.1",
+ "sort-array": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/jsdoc/node_modules/escape-string-regexp": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
+ "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jsdoc/node_modules/mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/jsesc": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
@@ -8046,6 +8598,16 @@
"node": ">=6"
}
},
+ "node_modules/klaw": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz",
+ "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.1.9"
+ }
+ },
"node_modules/kleur": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
@@ -8083,6 +8645,16 @@
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
"dev": true
},
+ "node_modules/linkify-it": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
+ "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "uc.micro": "^2.0.0"
+ }
+ },
"node_modules/locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
@@ -8101,6 +8673,13 @@
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
},
+ "node_modules/lodash.camelcase": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+ "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
@@ -8165,19 +8744,86 @@
"tmpl": "1.0.5"
}
},
+ "node_modules/markdown-it": {
+ "version": "14.1.0",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
+ "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1",
+ "entities": "^4.4.0",
+ "linkify-it": "^5.0.0",
+ "mdurl": "^2.0.0",
+ "punycode.js": "^2.3.1",
+ "uc.micro": "^2.1.0"
+ },
+ "bin": {
+ "markdown-it": "bin/markdown-it.mjs"
+ }
+ },
+ "node_modules/markdown-it-anchor": {
+ "version": "8.6.7",
+ "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz",
+ "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==",
+ "dev": true,
+ "license": "Unlicense",
+ "peerDependencies": {
+ "@types/markdown-it": "*",
+ "markdown-it": "*"
+ }
+ },
+ "node_modules/markdown-it/node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true,
+ "license": "Python-2.0"
+ },
+ "node_modules/marked": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz",
+ "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "marked": "bin/marked.js"
+ },
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/mdurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
+ "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
"dev": true
},
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
"node_modules/micromatch": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
- "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "braces": "^3.0.2",
+ "braces": "^3.0.3",
"picomatch": "^2.3.1"
},
"engines": {
@@ -8262,6 +8908,13 @@
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
"dev": true
},
+ "node_modules/neo-async": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
+ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/node-int64": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
@@ -8313,6 +8966,16 @@
"node": ">= 0.4"
}
},
+ "node_modules/object-to-spawn-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/object-to-spawn-args/-/object-to-spawn-args-2.0.1.tgz",
+ "integrity": "sha512-6FuKFQ39cOID+BMZ3QaphcC8Y4cw6LXBLyIgPU+OhIYwviJamPAn+4mITapnSBQrejB+NNp+FMskhD8Cq+Ys3w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
"node_modules/object.assign": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz",
@@ -8634,6 +9297,16 @@
"node": ">=6"
}
},
+ "node_modules/punycode.js": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
+ "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/pure-rand": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz",
@@ -8731,6 +9404,16 @@
"@babel/runtime": "^7.8.4"
}
},
+ "node_modules/regex-repo": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/regex-repo/-/regex-repo-5.2.0.tgz",
+ "integrity": "sha512-uctdIywmzsW9Rl64m53qI+UCzaQXQ7boasV/dJgIIdP8mkiS2MOMpfpViCHMZTIFeJohN0p5nYIAzJAeI0Bt5A==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "14.x || 16.x || >=18.0.0"
+ }
+ },
"node_modules/regexp.prototype.flags": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz",
@@ -8807,6 +9490,16 @@
"node": ">=0.10.0"
}
},
+ "node_modules/requizzle": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz",
+ "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "lodash": "^4.17.21"
+ }
+ },
"node_modules/resolve": {
"version": "1.22.6",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz",
@@ -9046,12 +9739,10 @@
}
},
"node_modules/semver": {
- "version": "7.5.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
- "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
+ "version": "7.7.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
+ "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
+ "license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
@@ -9059,22 +9750,6 @@
"node": ">=10"
}
},
- "node_modules/semver/node_modules/lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/semver/node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
- },
"node_modules/serialize-javascript": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz",
@@ -9165,6 +9840,28 @@
"integrity": "sha512-9LK+E7Hv5R9u4g4C3p+jjLstaLe11MDsL21UpYaCNmapvMkYhqCV4A/f/3gyH8QjMyh6l68q9xC85vihY9ahMQ==",
"dev": true
},
+ "node_modules/sort-array": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/sort-array/-/sort-array-5.1.1.tgz",
+ "integrity": "sha512-EltS7AIsNlAFIM9cayrgKrM6XP94ATWwXP4LCL4IQbvbYhELSt2hZTrixg+AaQwnWFs/JGJgqU3rxMcNNWxGAA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-back": "^6.2.2",
+ "typical": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=12.17"
+ },
+ "peerDependencies": {
+ "@75lb/nature": "^0.1.1"
+ },
+ "peerDependenciesMeta": {
+ "@75lb/nature": {
+ "optional": true
+ }
+ }
+ },
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -9416,6 +10113,20 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/table-layout": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-4.1.1.tgz",
+ "integrity": "sha512-iK5/YhZxq5GO5z8wb0bY1317uDF3Zjpha0QFFLA8/trAoiLbQD0HUbMesEaxyzUgDxi2QlcbM8IvqOlEjgoXBA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-back": "^6.2.2",
+ "wordwrapjs": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=12.17"
+ }
+ },
"node_modules/terser": {
"version": "5.21.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.21.0.tgz",
@@ -9492,6 +10203,7 @@
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
},
@@ -9638,6 +10350,37 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/typical": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmjs.org/typical/-/typical-7.3.0.tgz",
+ "integrity": "sha512-ya4mg/30vm+DOWfBg4YK3j2WD6TWtRkCbasOJr40CseYENzCUby/7rIvXA99JGsQHeNxLbnXdyLLxKSv3tauFw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.17"
+ }
+ },
+ "node_modules/uc.micro": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
+ "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/uglify-js": {
+ "version": "3.19.3",
+ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz",
+ "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "optional": true,
+ "bin": {
+ "uglifyjs": "bin/uglifyjs"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
"node_modules/unbox-primitive": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
@@ -9653,6 +10396,13 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/underscore": {
+ "version": "1.13.7",
+ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz",
+ "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
@@ -9752,6 +10502,16 @@
"node": ">=10.12.0"
}
},
+ "node_modules/walk-back": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-5.1.1.tgz",
+ "integrity": "sha512-e/FRLDVdZQWFrAzU6Hdvpm7D7m2ina833gIKLptQykRK49mmCYHLHq7UqjPDbxbKLZkTkW1rFqbengdE3sLfdw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.17"
+ }
+ },
"node_modules/walker": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz",
@@ -9811,6 +10571,23 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/wordwrap": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+ "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/wordwrapjs": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-5.1.1.tgz",
+ "integrity": "sha512-0yweIbkINJodk27gX9LBGMzyQdBDan3s/dEAiwBOj+Mf0PPyWL6/rikalkv8EeD0E8jm4o5RXEOrFTP3NXbhJg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.17"
+ }
+ },
"node_modules/wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
@@ -9880,6 +10657,13 @@
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
}
},
+ "node_modules/xmlcreate": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz",
+ "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
diff --git a/package.json b/package.json
index 80fe9ca..bd99db6 100644
--- a/package.json
+++ b/package.json
@@ -5,10 +5,11 @@
"main": "dist/semver-plus.js",
"scripts": {
"build": "make build",
+ "doc": "make doc",
"lint": "make lint",
"lint:fix": "make lint-fix",
"test": "make test",
- "preversion": "npm run qa",
+ "preversion": "npm run qa && npm run doc",
"prepack": "npm run build",
"qa": "make qa"
},
@@ -27,16 +28,19 @@
},
"homepage": "https://github.com/liquid-labs/semver-plus#readme",
"devDependencies": {
+ "@liquid-labs/dmd": "^7.1.1",
+ "@liquid-labs/jsdoc-to-markdown": "^9.1.3",
"@liquid-labs/sdlc-resource-babel-and-rollup": "^1.0.0-alpha.5",
"@liquid-labs/sdlc-resource-eslint": "^1.0.0-alpha.2",
- "@liquid-labs/sdlc-resource-jest": "^1.0.0-alpha.5"
+ "@liquid-labs/sdlc-resource-jest": "^1.0.0-alpha.5",
+ "dmd-readme-api": "^1.0.0-beta.8"
},
"liq": {
"packageType": "node|lib"
},
"dependencies": {
"http-errors": "^2.0.0",
- "semver": "^7.3.8"
+ "semver": "^7.0.0"
},
"_npm-check-plus": {
"depcheck": {
diff --git a/src/constants.mjs b/src/constants.mjs
index 94ff706..7b65167 100644
--- a/src/constants.mjs
+++ b/src/constants.mjs
@@ -1,5 +1,5 @@
export const xRangeRE =
// v single tuple v doublpe tuple v triple tuple v quad/pre-release tuple
// v if there's more than a single digit, it can't lead with a zero
- /^(?:[x*]|[1-9]?[0-9]+\.[x*]|(?:[1-9]?[0-9]+\.){2}[x*]|(?:[1-9]?[0-9]+\.){2}[1-9]?[0-9]+-(?:alpha|beta|rc)\.[x*])$/
-export const prereleaseXRangeRE = /^(?:[1-9]?[0-9]+\.){2}[1-9]?[0-9]+-(?:alpha|beta|rc)\.[x*]$/
+ /^(?:[Xx*]|[1-9]?[0-9]+\.[Xx*]|(?:[1-9]?[0-9]+\.){2}[Xx*]|(?:[1-9]?[0-9]+\.){2}[1-9]?[0-9]+-(?:alpha|beta|rc)\.[Xx*])$/
+export const prereleaseXRangeRE = /^(?:[1-9]?[0-9]+\.){2}[1-9]?[0-9]+-(?:alpha|beta|rc)\.[Xx*]$/
diff --git a/src/doc/README.01.md b/src/doc/README.01.md
new file mode 100644
index 0000000..3ac5dff
--- /dev/null
+++ b/src/doc/README.01.md
@@ -0,0 +1 @@
+# semver-plus
diff --git a/src/doc/README.02.md b/src/doc/README.02.md
new file mode 100644
index 0000000..e69de29
diff --git a/src/filter-valid-version-or-range.mjs b/src/filter-valid-version-or-range.mjs
deleted file mode 100644
index 6d31fa1..0000000
--- a/src/filter-valid-version-or-range.mjs
+++ /dev/null
@@ -1,6 +0,0 @@
-import { validVersionOrRange } from './valid-version-or-range'
-
-const filterValidVersionOrRange = (input = throw new Error("'input' is required."), options) =>
- input.filter((i) => validVersionOrRange(i, options))
-
-export { filterValidVersionOrRange }
diff --git a/src/index.js b/src/index.js
index 6468376..913a643 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,9 +1,11 @@
export * from './ext-constants'
-export * from './filter-valid-version-or-range'
+export * from './min-version'
+export * from './max-satisfying'
export * from './min-version'
export * from './next-version'
-export * from './prerelease'
+export * from './semver-comparison-ops'
+export * from './semver-range-ops'
+export * from './semver-version-ops'
export * from './upper-bound'
export * from './valid-version-or-range'
-export * from './version-compare'
export * from './x-sort'
diff --git a/src/lib/compare-helper.mjs b/src/lib/compare-helper.mjs
new file mode 100644
index 0000000..1300fe6
--- /dev/null
+++ b/src/lib/compare-helper.mjs
@@ -0,0 +1,16 @@
+const compareHelper = (versions, semverTest) => {
+ let currLead
+ for (let i = 0; i < versions.length; i += 1) {
+ const testVer = versions[i]
+ if (currLead === undefined) {
+ currLead = testVer
+ }
+ else if (semverTest(currLead, testVer)) {
+ currLead = testVer
+ }
+ }
+
+ return currLead
+}
+
+export { compareHelper }
diff --git a/src/lib/set-default-options.mjs b/src/lib/set-default-options.mjs
new file mode 100644
index 0000000..39804be
--- /dev/null
+++ b/src/lib/set-default-options.mjs
@@ -0,0 +1,12 @@
+const setDefaultOptions = (options = {}) => {
+ if (!('includePrerelease' in options)
+ && (process.env.SEMVER_PLUS_COMPAT === undefined
+ || process.env.SEMVER_PLUS_COMPAT.toLocaleLowerCase() === 'false'
+ || process.env.SEMVER_PLUS_COMPAT === '0')) {
+ options.includePrerelease = true
+ }
+
+ return options
+}
+
+export { setDefaultOptions }
diff --git a/src/max-satisfying.mjs b/src/max-satisfying.mjs
new file mode 100644
index 0000000..f1aa27a
--- /dev/null
+++ b/src/max-satisfying.mjs
@@ -0,0 +1,44 @@
+import semver from 'semver'
+
+import { rsort } from './semver-comparison-ops'
+import { satisfies } from './semver-range-ops'
+import { validVersionOrRange } from './valid-version-or-range'
+
+/**
+ * Returns the highest version in `versions` that satisfies the range, or null if no version satisfies the range. This
+ * implementation differs from the base `semver.maxSatisfying` in that it correctly handles the following case:
+ * `maxSatisfying(['1.0.0-alpha.0', '1.0.0'], '<1.0.0')` -> '1.0.0-alpha.0'. The base `semver.maxSatisfying` function
+ * returns `null` in this case. Note, support for this syntax is not comprehensive and more complicated expressions are
+ * likely to yield incorrect results.
+ * @param {string[]} versions - The versions to check.
+ * @param {string} range - The range to check.
+ * @param {object} options - The options to pass to the semver.maxSatisfying function.
+ * @param {boolean} options.compat - If true, then uses the base `semver.maxSatisfying` function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @param {boolean} options.includePrerelease - Include prerelease versions in the result. This is effectively implied
+ * if the range contains prerelease components.
+ * @param {boolean} options.throwIfInvalid - If true, throws an exception if any version or the range is invalid.
+ * @returns {string|null} - The highest version that satisfies the range, or null if no version satisfies the range.
+ * @category Range operations
+ * @function
+ */
+// export const maxSatisfying = semver.maxSatisfying
+export const maxSatisfying = (versions, range, options) => {
+ if (options?.throwIfInvalid === true) {
+ validVersionOrRange(versions, { ...options, disallowRanges : true })
+ validVersionOrRange([range], { ...options, disallowVersions : true })
+ }
+
+ if (options?.compat === true) {
+ return semver.maxSatisfying(versions, range, options)
+ }
+
+ versions = rsort(versions, options)
+
+ for (const version of versions) {
+ if (satisfies(version, range, options)) {
+ return version
+ }
+ }
+ return null
+}
diff --git a/src/min-version.mjs b/src/min-version.mjs
index 801f87d..fe576b4 100644
--- a/src/min-version.mjs
+++ b/src/min-version.mjs
@@ -2,20 +2,27 @@ import semver from 'semver'
import { prereleaseXRangeRE } from './constants'
-const minVersion = (range) => {
- // this has to come first because weirds, 'semver.validRange' recognizes 1.0.0-alpha.x (but not '.*'?!), but
- // 'semver.minVersion' does not return correct results
- if (range.match(prereleaseXRangeRE)) {
+/**
+ * Returns the lowest version that satisfies the range, or null if no version satisfies the range. This implementation
+ * differs from the base `semver.minVersion` in that it correctly handles simple prerelease x-ranges. E.g.,
+ * '1.0.0-alpha.x' -> '1.0.0-alpha.0'. To suppress this behavior, pass `options.compat = true`. Note, support for this
+ * syntax is not comprehensive and more complicated expressions are likely to yield incorrect results.
+ * @param {string} range - The range to check.
+ * @param {object} options - The options to pass to the semver.minVersion function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @param {boolean} options.includePrerelease - Whether to include prerelease versions.
+ * @param {boolean} options.compat - If true, prerelease ranges are treated the same as in the base semver package;
+ * e.g. `minVersion('1.0.0-alpha.x', { compat: true })` -> '1.0.0-alpha.x'.
+ * @returns {string|null} - The lowest version that satisfies the range, or null if no version satisfies the range.
+ * @category Range operations
+ */
+const minVersion = (range, options) => {
+ // we have to do this first, because semver does not recognize prerelease X-ranges ending with '*' (even though it
+ // does recognize these as valid ranges)
+ if (options?.compat !== true && range.match(prereleaseXRangeRE)) {
return range.slice(0, -1) + '0'
}
- else {
- const semverRange = semver.validRange(range)
- if (semverRange !== null) {
- return semver.minVersion(semverRange).version
- }
- }
- // else
- throw new Error(`Invaid range '${range}'.`)
+ return semver.minVersion(range, options)
}
export { minVersion }
diff --git a/src/next-version.mjs b/src/next-version.mjs
index f4db279..d579234 100644
--- a/src/next-version.mjs
+++ b/src/next-version.mjs
@@ -9,17 +9,16 @@ import {
} from './ext-constants'
/**
- * Given a current version, increment generates the next version string. This method follows the
- * [semver spec](https://semver.org) except that:
- * - `increment` 'prerelease' cannot be used with non-prerelease versions (results in execption)
- * - supports 'pretype' and specific pre-release sequence 'alpha' -> 'beta' -> 'rc' -> released
- *
- * #### Parameters
- * - `currVer`: the current version to increment.
- * - `increment`: what to inrement; may be: 'major', 'minor', 'patch', 'premajor', 'preminor', 'prepatch',
- * 'prerelease', or 'pretype'. The first seven are defined by the [semver spec](https://semver.org) and 'pretype'
- * means to increment the pre-release ID from 'alpha' -> 'beta' -> 'rc' -> none. Passing in a `currVer` with any
- * other prerelease ID with a 'pretype' increment will result in undefined results
+ * Given a current version generates the next version string accourding to `increment`. This method is similar to
+ * {@link inc} from the [base semver library](https://semver.org) with two differences.
+ * 1) It supports a specific pre-release sequence prototype -> 'alpha' -> 'beta' -> 'rc' -> released and the 'pretype'
+ * increment will advance the prerelease ID through these stages.
+ * 2) The 'prerelease' increment can only be used to advance the prerelease version number and does not function as
+ * 'prepatch' on a non-prerelease version.
+ * @param {string} currVer - The current version to increment.
+ * @param {string} increment - The increment to use.
+ * @returns {string} - The next version string.
+ * @category Version operations
*/
const nextVersion = (currVer, increment) => {
if (!semver.valid(currVer)) {
diff --git a/src/prerelease.mjs b/src/prerelease.mjs
deleted file mode 100644
index 2f8c86d..0000000
--- a/src/prerelease.mjs
+++ /dev/null
@@ -1,7 +0,0 @@
-import semver from 'semver'
-
-const prerelease = (version) => {
- return semver.prerelease(version)
-}
-
-export { prerelease }
diff --git a/src/semver-comparison-ops.mjs b/src/semver-comparison-ops.mjs
new file mode 100644
index 0000000..88244d4
--- /dev/null
+++ b/src/semver-comparison-ops.mjs
@@ -0,0 +1,170 @@
+import semver from 'semver'
+
+/**
+ * Returns `true` if `v1` is greater than `v2`, `false` otherwise.
+ * @param {string} v1 - The first version to compare.
+ * @param {string} v2 - The second version to compare.
+ * @param {object} options - The options to pass to the semver.gt function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {boolean} - `true` if `v1` is greater than `v2`, `false` otherwise.
+ * @category Comparison operations
+ * @function
+ */
+export const gt = semver.gt
+
+/**
+ * Returns `true` if `v1` is greater than or equal to `v2`, `false` otherwise.
+ * @param {string} v1 - The first version to compare.
+ * @param {string} v2 - The second version to compare.
+ * @param {object} options - The options to pass to the semver.gte function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {boolean} - `true` if `v1` is greater than or equal to `v2`, `false` otherwise.
+ * @category Comparison operations
+ * @function
+ */
+export const gte = semver.gte
+
+/**
+ * Returns `true` if `v1` is less than `v2`, `false` otherwise.
+ * @param {string} v1 - The first version to compare.
+ * @param {string} v2 - The second version to compare.
+ * @param {object} options - The options to pass to the semver.lt function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {boolean} - `true` if `v1` is less than `v2`, `false` otherwise.
+ * @category Comparison operations
+ * @function
+ */
+export const lt = semver.lt
+
+/**
+ * Returns `true` if `v1` is less than or equal to `v2`, `false` otherwise.
+ * @param {string} v1 - The first version to compare.
+ * @param {string} v2 - The second version to compare.
+ * @param {object} options - The options to pass to the semver.lte function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {boolean} - `true` if `v1` is less than or equal to `v2`, `false` otherwise.
+ * @category Comparison operations
+ * @function
+ */
+export const lte = semver.lte
+
+/**
+ * Returns `true` if `v1` is equal to `v2`, `false` otherwise.
+ * @param {string} v1 - The first version to compare.
+ * @param {string} v2 - The second version to compare.
+ * @param {object} options - The options to pass to the semver.eq function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {boolean} - `true` if `v1` is equal to `v2`, `false` otherwise.
+ * @category Comparison operations
+ * @function
+ */
+export const eq = semver.eq
+
+/**
+ * Returns `true` if `v1` is not equal to `v2`, `false` otherwise.
+ * @param {string} v1 - The first version to compare.
+ * @param {string} v2 - The second version to compare.
+ * @param {object} options - The options to pass to the semver.neq function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {boolean} - `true` if `v1` is not equal to `v2`, `false` otherwise.
+ * @category Comparison operations
+ * @function
+ */
+export const neq = semver.neq
+
+/**
+ * Returns a number indicating whether a version is greater than, equal to, or less than another version.
+ * @param {string} v1 - The first version to compare.
+ * @param {string} comparator - The comparator to use. May be '<', '<=', '>', '>=', '=', '==', '!=', '===', or '!=='.
+ * An exception is thrown if an invalid comparator is provided.
+ * @param {string} v2 - The second version to compare.
+ * @param {object} options - The options to pass to the semver.cmp function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {number} - A number indicating whether a version is greater than, equal to, or less than another version.
+ * @category Comparison operations
+ * @function
+ */
+export const cmp = semver.cmp
+
+/**
+ * Returns 0 if `v1 == v2`, 1 if `v1 > v2`, and -1 if `v1 < v2`. Will sort an array of versions in ascending order if
+ * passed to `Array.sort()`.
+ * @param {string} v1 - The first version to compare.
+ * @param {string} v2 - The second version to compare.
+ * @param {object} options - The options to pass to the semver.compare function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {number} - 0 if `v1 == v2`, 1 if `v1 > v2`, and -1 if `v1 < v2`.
+ * @category Comparison operations
+ * @function
+ */
+export const compare = semver.compare
+
+/**
+ * Same as {@link compare} except it compares build if two versions are otherwise equal.
+ * @param {string} v1 - The first version to compare.
+ * @param {string} v2 - The second version to compare.
+ * @param {object} options - The options to pass to the semver.compareBuild function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {number} - 0 if `v1 == v2`, 1 if `v1 > v2`, and -1 if `v1 < v2`.
+ * @category Comparison operations
+ * @function
+ */
+export const compareBuild = semver.compareBuild
+
+/**
+ * Reverse of {@link compare}.
+ * @param {string} v1 - The first version to compare.
+ * @param {string} v2 - The second version to compare.
+ * @param {object} options - The options to pass to the semver.rcompare function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {number} - 0 if `v1 == v2`, -1 if `v1 > v2`, and 1 if `v1 < v2`.
+ * @category Comparison operations
+ * @function
+ */
+export const rcompare = semver.rcompare
+
+/**
+ * Short for {@link compare} with `options.loose = true`.
+ * @param {string} v1 - The first version to compare.
+ * @param {string} v2 - The second version to compare.
+ * @returns {number} - 0 if `v1 == v2`, 1 if `v1 > v2`, and -1 if `v1 < v2`.
+ * @category Comparison operations
+ * @function
+ */
+export const compareLoose = semver.compareLoose
+
+/**
+ * Returns the difference between two versions. I.e., the most significant version component by which `v1` and `v2`
+ * differ.
+ * @param {string} v1 - The first version to compare.
+ * @param {string} v2 - The second version to compare.
+ * @param {object} options - The options to pass to the semver.diff function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {string|null} - `major`, 'minor', 'patch', 'prerelease', 'premajor', 'preminor', or 'prepatch' or null if
+ * the `v1` and `v2` are identical (disregarding build metadata).
+ * @category Comparison operations
+ * @function
+ */
+export const diff = semver.diff
+
+/**
+ * Sorts an array of versions in ascending order using {@link compareBuild}.
+ * @param {string[]} versions - The versions to sort.
+ * @param {object} options - The options to pass to the semver.sort function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {string[]} - The sorted versions.
+ * @category Comparison operations
+ * @function
+ */
+export const sort = semver.sort
+
+/**
+ * Sorts an array of versions in descending order using {@link compareBuild}.
+ * @param {string[]} versions - The versions to sort.
+ * @param {object} options - The options to pass to the semver.rsort function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {string[]} - The sorted versions.
+ * @category Comparison operations
+ * @function
+ */
+export const rsort = semver.rsort
diff --git a/src/semver-range-ops.mjs b/src/semver-range-ops.mjs
new file mode 100644
index 0000000..a55a9cd
--- /dev/null
+++ b/src/semver-range-ops.mjs
@@ -0,0 +1,117 @@
+import semver from 'semver'
+
+// note:
+// - `maxSatisfying` is overriden and defined in `max-satisfying.mjs`
+// - `minVersion` is overriden and defined in `min-version.mjs`
+
+/**
+ * Returns a parsed, normalized range string or null if the range is invalid.
+ * @param {string} range - The range to parse.
+ * @param {object} options - The options to pass to the semver.validRange function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {string|null} - The parsed, normalized range string or null if the range is invalid.
+ * @category Range operations
+ * @function
+ */
+export const validRange = semver.validRange
+
+/**
+ * Returns `true` if the version satisfies the range, `false` otherwise.
+ * @param {string} version - The version to check.
+ * @param {string} range - The range to check.
+ * @param {object} options - The options to pass to the semver.satisfies function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {boolean} - `true` if the version satisfies the range, `false` otherwise.
+ * @category Range operations
+ * @function
+ */
+export const satisfies = semver.satisfies
+
+/**
+ * Returns the lowest version in `versions` that satisfies the range, or null if no version satisfies the range.
+ * @param {string[]} versions - The versions to check.
+ * @param {string} range - The range to check.
+ * @param {object} options - The options to pass to the semver.minSatisfying function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {string|null} - The lowest version that satisfies the range, or null if no version satisfies the range.
+ * @category Range operations
+ * @function
+ */
+export const minSatisfying = semver.minSatisfying
+
+/**
+ * Returns `true` if `version` is greater than is greater than any version in `range`, `false` otherwise.
+ * @param {string} version - The version to check.
+ * @param {string} range - The range to check.
+ * @param {object} options - The options to pass to the semver.gtr function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {boolean} - `true` if `version` is greater than is greater than any version in `range`, `false` otherwise.
+ * @category Range operations
+ * @function
+ */
+export const gtr = semver.gtr
+
+/**
+ * Returns `true` if `version` is less than is less than any version in `range`, `false` otherwise.
+ * @param {string} version - The version to check.
+ * @param {string} range - The range to check.
+ * @param {object} options - The options to pass to the semver.ltr function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {boolean} - `true` if `version` is less than is less than any version in `range`, `false` otherwise.
+ * @category Range operations
+ * @function
+ */
+export const ltr = semver.ltr
+
+/**
+ * Returns `true` if `version` is outside of `range` in the indicated direction, `false` otherwise. `outside(v, r, '>)`
+ * is equivalent to `gtr(v, r)`.
+ * @param {string} version - The version to check.
+ * @param {string} range - The range to check.
+ * @param {string} direction - The direction to check. Must be '>' or '<'.
+ * @param {object} options - The options to pass to the semver.outside function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {boolean} - `true` if `version` is outside of `range` in the indicated direction, `false` otherwise.
+ * @category Range operations
+ * @function
+ */
+export const outside = semver.outside
+
+/**
+ * Returns `true` if any of the comparators in the range intersect with each other.
+ * @param {string} range - The first version range or comparator.
+ * @param {object} options - The options to pass to the semver.intersects function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {boolean} - `true` if any of the comparators in the range intersect with each other, `false` otherwise.
+ * @category Range operations
+ * @function
+ */
+export const intersects = semver.intersects
+
+/**
+ * Return a "simplified" range that matches the same items in the versions list as the range specified. Note that it
+ * does not guarantee that it would match the same versions in all cases, only for the set of versions provided. This
+ * is useful when generating ranges by joining together multiple versions with || programmatically, to provide the user
+ * with something a bit more ergonomic. If the provided range is shorter in string-length than the generated range,
+ * then that is returned.
+ * @param {string[]} versions - The versions to check.
+ * @param {string} range - The range to simplify.
+ * @param {object} options - The options to pass to the semver.simplifyRange function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {string} - The simplified range.
+ * @category Range operations
+ * @function
+ */
+export const simplifyRange = semver.simplifyRange
+
+/**
+ * Returns `true` if `subRange` is a subset of `superRange`, `false` otherwise.
+ * @param {string} subRange - The sub-range to check.
+ * @param {string} superRange - The super-range to check.
+ * @param {object} options - The options to pass to the semver.subset function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {boolean} - `true` if `subRange` is a subset of `superRange`, `false` otherwise.
+ * @category Range operations
+ * @function
+ */
+export const subset = semver.subset
diff --git a/src/semver-version-ops.mjs b/src/semver-version-ops.mjs
new file mode 100644
index 0000000..3d862a2
--- /dev/null
+++ b/src/semver-version-ops.mjs
@@ -0,0 +1,109 @@
+import semver from 'semver'
+
+/**
+ * Returns a parsed, normalized version string or null if the version is invalid.
+ * @param {string} version - The version to parse.
+ * @param {object} options - The options to pass to the semver.valid function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @param {boolean} options.includePrerelease - Whether to include prerelease versions.
+ * @returns {string|null} - The parsed, normalized version string or null if the version is invalid.
+ * @category Version operations
+ * @function
+ */
+export const valid = semver.valid
+
+/**
+ * Returns a new version string incremented by the specified part.
+ * @param {string} version - The version to increment.
+ * @param {string} increment - The increment to use.
+ * @param {object} options - The options to pass to the semver.inc function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @param {boolean} options.includePrerelease - Whether to include prerelease versions.
+ * @param {string} identifier - Used to specify the prerelease name for prerelease increments.
+ * @param {false|0|1} identifierBase - When incrementing to a new prerelease name, specifies the base number or
+ * `false` for no number.
+ * @returns {string} - The new version string.
+ * @category Version operations
+ * @function
+ */
+export const inc = semver.inc
+
+/**
+ * Returns an array of prerelease components or `null` if the version is not a prerelease. A 'component' is just a '.'
+ * separated string.
+ * @param {string} version - The version to parse.
+ * @param {object} options - The options to pass to the semver.inc function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {string[]|null} - The prerelease components or `null` if the version is not a prerelease.
+ * @category Version operations
+ * @function
+ */
+export const prerelease = semver.prerelease
+
+/**
+ * Returns the major version number.
+ * @param {string} version - The version to parse.
+ * @param {object} options - The options to pass to the semver.major function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {number} - The major version number.
+ * @category Version operations
+ * @function
+ */
+export const major = semver.major
+
+/**
+ * Returns the minor version number.
+ * @param {string} version - The version to parse.
+ * @param {object} options - The options to pass to the semver.minor function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {number} - The minor version number.
+ * @category Version operations
+ * @function
+ */
+export const minor = semver.minor
+
+/**
+ * Returns the patch version number.
+ * @param {string} version - The version to parse.
+ * @param {object} options - The options to pass to the semver.patch function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {number} - The patch version number.
+ * @category Version operations
+ * @function
+ */
+export const patch = semver.patch
+
+/**
+ * Attempts to parse and normalize a string as a semver string. An aliase for {@link valid}.
+ * @category Version operations
+ * @function
+ */
+export const parse = semver.parse
+
+/**
+ * Aggressively attempts to coerce a string into a valid semver string. Basically, starting from the left side of the
+ * string, it looks for a digit and then includes anything to the right of the digit that looks like part of a semver.
+ * So, 'Number 1!' -> '1.0.0', 'Upgrade 1.2 to 1.3' -> '1.2.0', etc.
+ * @param {string} version - The version to coerce.
+ * @param {object} options - The options to pass to the semver.coerce function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @param {boolean} options.includePrerelease - Unless true, prerelease tags (and build metadata) are stripped. If
+ * @param {boolean} options.rtl - Instead of searching for a digit from the left, start searching from the right.
+ * true, then they are preserved.
+ * @returns {string|null} - The coerced version string or null if the version is invalid.
+ * @category Version operations
+ * @function
+ */
+export const coerce = semver.coerce
+
+/**
+ * Returns a cleaned version string removing unecessary comparators and, if `options.loose` is true, fixing space
+ * issues. Only works for versions, not ranges.
+ * @param {string} version - The version to clean.
+ * @param {object} options - The options to pass to the semver.clean function.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @returns {string|null} - The cleaned version string or null if the version is invalid.
+ * @category Version operations
+ * @function
+ */
+export const clean = semver.clean
diff --git a/src/test/filter-valid-version-or-range.test.mjs b/src/test/filter-valid-version-or-range.test.mjs
deleted file mode 100644
index 80a5c4f..0000000
--- a/src/test/filter-valid-version-or-range.test.mjs
+++ /dev/null
@@ -1,11 +0,0 @@
-/* global describe expect test */
-import { filterValidVersionOrRange } from '../filter-valid-version-or-range'
-
-describe('filterValidVersionOrRange', () => {
- test.each([
- [
- ['1.0', '1.2.3', '2.3.9-alpha.12', '1.1.1-alpha.x', 'backlog', '1.2.x', '8.*', '*', '1.2.4.*', '^1.2.3'],
- ['1.2.3', '2.3.9-alpha.12', '1.1.1-alpha.x', '1.2.x', '8.*', '*']
- ]
- ])('%p => %p', (input, expected) => expect(filterValidVersionOrRange(input, { onlyXRange : true })).toEqual(expected))
-})
diff --git a/src/test/max-satisfying.test.mjs b/src/test/max-satisfying.test.mjs
new file mode 100644
index 0000000..b564266
--- /dev/null
+++ b/src/test/max-satisfying.test.mjs
@@ -0,0 +1,34 @@
+/* global describe expect test */
+import { maxSatisfying } from '../max-satisfying'
+
+describe('maxSatisfying', () => {
+ test.each([
+ [['1.0.0-alpha.0', '1.0.0-beta.0'], '<1.0.0-beta.0', undefined, '1.0.0-alpha.0'],
+ [['1.0.0-beta.0', '1.0.0-rc.0'], '>1.0.0-beta.0', undefined, '1.0.0-rc.0'],
+ [['1.0.0-alpha.0', '1.0.0'], '*', undefined, '1.0.0'],
+ [['1.0.0-beta.0', '1.0.0-rc.0', '1.0.0'], '<1.0.0', undefined, null],
+ [['1.0.0-alpha.2', '1.0.0-alpha.13'], '>1.0.0-alpha.0', undefined, '1.0.0-alpha.13'],
+ [['2.0.0-alpha.0', '1.0.0'], '*', undefined, '1.0.0'],
+ [[], '*', undefined, null],
+ // includePrerelease = true
+ [['1.0.0-alpha.0', '1.0.0-beta.0'], '<1.0.0-beta.0', { includePrerelease : true }, '1.0.0-alpha.0'],
+ [['1.0.0-beta.0', '1.0.0-rc.0'], '>1.0.0-beta.0', { includePrerelease : true }, '1.0.0-rc.0'],
+ [['1.0.0-alpha.0', '1.0.0'], '*', { includePrerelease : true }, '1.0.0'],
+ [['1.0.0-beta.0', '1.0.0-rc.0', '1.0.0'], '<1.0.0', { includePrerelease : true }, '1.0.0-rc.0'],
+ [['1.0.0-alpha.2', '1.0.0-alpha.13'], '>1.0.0-alpha.0', { includePrerelease : true }, '1.0.0-alpha.13'],
+ [['2.0.0-alpha.0', '1.0.0'], '*', { includePrerelease : true }, '2.0.0-alpha.0'],
+ [[], '*', { includePrerelease : true }, null],
+ // compat = true
+ [['1.0.0-alpha.0', '1.0.0-beta.0', '1.0.0-rc.0', '1.0.0'], '<1.0.0', { compat : true, includePrerelease : true }, '1.0.0-rc.0']
+ ])('versions %p, range %s, options %v -> %s',
+ (versions, range, options, expected) =>
+ expect(maxSatisfying(versions, range, options)?.toString() || null).toBe(expected))
+
+ test('invalid version raises exception',
+ () => expect(() => maxSatisfying(['1.0.0', 'not-a-valid-vesion'], '*', { throwIfInvalid : true })).toThrow())
+
+ /* test.each([
+ [['1.0.0', 'not-a-valid-vesion', 'abc'], '1.0.0']
+ ])("'ignoreNonVersions' filters non-version strings from the version list",
+ (versions, expected) => expect(maxSatisfying(versions, '*', { ignoreNonVersions : true })).toBe(expected)) */
+})
diff --git a/src/test/min-version.test.mjs b/src/test/min-version.test.mjs
index e993c56..5ba0455 100644
--- a/src/test/min-version.test.mjs
+++ b/src/test/min-version.test.mjs
@@ -1,20 +1,41 @@
/* global describe expect test */
+import semver from 'semver'
+
import { minVersion } from '../min-version'
-describe('minVersion', () => {
+describe('minVersionString', () => {
+ test('verify semver prerelease bug', () => {
+ // we want to make sure we have the actual semver and not our local, which may have wrapper logic to fix this
+ expect(semver.minVersion('1.0.0-alpha.x').toString()).toBe('1.0.0-alpha.x') // correct
+ expect(semver.minVersion('1.0.0-alpha.x', { includePrerelease : true }).toString()).toBe('1.0.0-alpha.x') // incorrect
+ })
+
test.each([
+ // X-ranges
['*', '0.0.0'],
['1.*', '1.0.0'],
['1.0.*', '1.0.0'],
- ['1.0.0-alpha.*', '1.0.0-alpha.0'],
- ['1.0.0-beta.*', '1.0.0-beta.0'],
- ['1.0.0-rc.*', '1.0.0-rc.0'],
['x', '0.0.0'],
['1.x', '1.0.0'],
['1.0.x', '1.0.0'],
+ ['X', '0.0.0'],
+ // prerelease X-ranges
['1.0.0-alpha.x', '1.0.0-alpha.0'],
['1.0.0-beta.x', '1.0.0-beta.0'],
['1.0.0-rc.x', '1.0.0-rc.0'],
- ['1.0.0 - 2', '1.0.0']
- ])('%s => %s', (input, expected) => expect(minVersion(input)).toBe(expected))
+ ['1.0.0-alpha.X', '1.0.0-alpha.0'],
+ ['1.0.0-alpha.*', '1.0.0-alpha.0'],
+ // hyphen ranges
+ ['1.0.0 - 2', '1.0.0'],
+ // tilde ranges
+ ['~1.2.3', '1.2.3'],
+ ['~1.2', '1.2.0'],
+ ['~1', '1.0.0'],
+ ['~1.2.3-alpha.2', '1.2.3-alpha.2'],
+ // caret ranges
+ ['^1.2.3', '1.2.3'],
+ ['^1.2', '1.2.0'],
+ ['^1', '1.0.0'],
+ ['^1.2.3-alpha.2', '1.2.3-alpha.2']
+ ])('%s => %s', (input, expected) => expect(minVersion(input)?.toString()).toBe(expected))
})
diff --git a/src/test/prerelease.test.mjs b/src/test/prerelease.test.mjs
index c1c99cc..235f32c 100644
--- a/src/test/prerelease.test.mjs
+++ b/src/test/prerelease.test.mjs
@@ -1,6 +1,6 @@
/* global describe expect test */
-import { prerelease } from '../prerelease'
+import { prerelease } from '../semver-version-ops'
describe('prerelease', () => {
test.each([
diff --git a/src/test/valid-version-or-range.test.mjs b/src/test/valid-version-or-range.test.mjs
index a2e254b..7c31537 100644
--- a/src/test/valid-version-or-range.test.mjs
+++ b/src/test/valid-version-or-range.test.mjs
@@ -3,11 +3,25 @@ import { validVersionOrRange } from '../valid-version-or-range'
describe('validVersionOrRange', () => {
test.each([
- ['1.0.0', undefined, true],
- ['1.0.0-alpha.0', undefined, true],
- ['1.0.0-alpha.1', undefined, true],
- ['1.0.0 - 2', undefined, true],
- ['1.0.x', { onlyXRange : true }, true],
- ['1.0.0-alpha.1', undefined, true]
+ ['1.0.0', undefined, '1.0.0'],
+ ['1.0.0-alpha.0', undefined, '1.0.0-alpha.0'],
+ ['1.0.0-alpha.1', undefined, '1.0.0-alpha.1'],
+ ['1.0.0 - 2', undefined, '>=1.0.0 <3.0.0-0'],
+ ['1.0.x', { onlyXRange : true }, '>=1.0.0 <1.1.0-0'],
+ ['not-a-valid-version', undefined, null],
+ ['not-a-valid-range', undefined, null],
+ // invalid versions and ranges
+ ['1.0.0', { disallowVersions : true }, null],
+ ['1.0.x', { disallowRanges : true }, null]
])('%s => %s', (input, options, expected) => expect(validVersionOrRange(input, options)).toBe(expected))
+
+ test.each([
+ ['not-a-valid-version', { throwIfInvalid : true }],
+ ['not-a-valid-range', { throwIfInvalid : true }],
+ // invalid versions and ranges
+ ['1.0.0', { disallowVersions : true, throwIfInvalid : true }],
+ ['1.0.x', { disallowRanges : true, throwIfInvalid : true }],
+ ['1.0.0', { disallowVersions : true, disallowRanges : true }]
+ ])('invalid %s (%o) raises exception', (input, options) =>
+ expect(() => validVersionOrRange(input, options)).toThrow())
})
diff --git a/src/test/version-compare.test.mjs b/src/test/version-compare.test.mjs
deleted file mode 100644
index d910663..0000000
--- a/src/test/version-compare.test.mjs
+++ /dev/null
@@ -1,45 +0,0 @@
-/* global describe expect test */
-
-import { maxVersion, minVersion } from '../version-compare'
-
-describe('maxVersion', () => {
- test.each([
- [['1.0.0-alpha.0', '1.0.0-beta.0'], '1.0.0-beta.0'],
- [['1.0.0-beta.0', '1.0.0-rc.0'], '1.0.0-rc.0'],
- [['1.0.0-alpha.0', '1.0.0'], '1.0.0'],
- [['1.0.0-alpha.0', '1.0.0-beta.0', '1.0.0-rc.0', '1.0.0'], '1.0.0'],
- [['1.0.0-alpha.2', '1.0.0-alpha.13'], '1.0.0-alpha.13'],
- [['2.0.0-alpha.0', '1.0.0'], '2.0.0-alpha.0']
- ])('versions %p -> %s', (versions, expected) => expect(maxVersion({ versions })).toBe(expected))
-
- test('[] => null', () => expect(maxVersion({ versions : [] })).toBe(null))
-
- test('mixed version types raises exception',
- () => expect(() => maxVersion({ versions : ['1.0.0', 'not-a-valid-vesion'] })).toThrow())
-
- test.each([
- [['1.0.0', 'not-a-valid-vesion', 'abc'], '1.0.0']
- ])("'ignoreNonVersions' filters non-version strings from the version list",
- (versions, expected) => expect(maxVersion({ ignoreNonVersions : true, versions })).toBe(expected))
-})
-
-describe('minVersion', () => {
- test.each([
- [['1.0.0-alpha.0', '1.0.0-beta.0'], '1.0.0-alpha.0'],
- [['1.0.0-beta.0', '1.0.0-rc.0'], '1.0.0-beta.0'],
- [['1.0.0-alpha.0', '1.0.0'], '1.0.0-alpha.0'],
- [['1.0.0-alpha.0', '1.0.0-beta.0', '1.0.0-rc.0', '1.0.0'], '1.0.0-alpha.0'],
- [['2.0.0-alpha.0', '1.0.0'], '1.0.0'],
- [['1.0.0-alpha.2', '1.0.0-alpha.13'], '1.0.0-alpha.2']
- ])('versions %p -> %s', (versions, expected) => expect(minVersion({ versions })).toBe(expected))
-
- test('[] => null', () => expect(minVersion({ versions : [] })).toBe(null))
-
- test('mixed version types raises exception',
- () => expect(() => minVersion({ versions : ['1.0.0', 'not-a-valid-vesion'] })).toThrow())
-
- test.each([
- [['1.0.0', 'not-a-valid-vesion', 'abc'], '1.0.0']
- ])("'ignoreNonVersions' filters non-version strings from the version list",
- (versions, expected) => expect(minVersion({ ignoreNonVersions : true, versions })).toBe(expected))
-})
diff --git a/src/upper-bound.mjs b/src/upper-bound.mjs
index 9b40d34..d7d7db9 100644
--- a/src/upper-bound.mjs
+++ b/src/upper-bound.mjs
@@ -6,6 +6,7 @@ import semver from 'semver'
* function where 'verision-0' least range above the given range.
* @param {string} range - The range to find the ceiling for.
* @returns {string} - Either '*', a specific version, or a '-0'.
+ * @category Range operations
*/
const upperBound = (range, { stripOperators = false } = {}) => {
const normalizedRange = semver.validRange(range)
diff --git a/src/valid-version-or-range.mjs b/src/valid-version-or-range.mjs
index 44b5a8b..563cbae 100644
--- a/src/valid-version-or-range.mjs
+++ b/src/valid-version-or-range.mjs
@@ -2,13 +2,60 @@ import semver from 'semver'
import { xRangeRE } from './constants'
+/**
+ * Validates a string to be a valid version or range. By default, an exception is raised unless `options.disallowVersions`
+ * is `true`, in which case it filters out invalid strings and returns a new array.
+ * @param {string} input - The string to validate.
+ * @param {object} options - The options to pass to the semver.valid function.
+ * @param {boolean} options.disallowRanges - Whether to disallow ranges.
+ * @param {boolean} options.disallowVersions - Whether to disallow versions and ranges which are valid versions.
+ * @param {boolean} options.includePrerelease - Whether to include prerelease versions.
+ * @param {boolean} options.loose - Allow non-conforming, but recognizable semver strings.
+ * @param {boolean} options.onlyXRange - Whether to only allow x-ranges. Note, even if this is `true`, and a valid
+ * x-range is presented, the returned string will still be normalized.
+ * @param {boolean} options.throwIfInvalid - If true, throws an exception if the string is invalid.
+ * @returns {string|null} - A normalized version or range string or `null` if the string is invalid (if
+ * `options.throwIfInvalid` is `true`, in which case an exception is thrown).
+ */
const validVersionOrRange = (input = throw new Error("'input' is required."), {
- dissallowRanges = false,
- dissallowVersions = false,
- onlyXRange = false
-} = {}) =>
- !!((dissallowVersions !== true && semver.valid(input))
- || (onlyXRange !== true && dissallowRanges !== true && semver.validRange(input))
- || (onlyXRange === true && input.match(xRangeRE)))
+ disallowRanges = false,
+ disallowVersions = false,
+ onlyXRange = false,
+ throwIfInvalid = false,
+ ...options
+} = {}) => {
+ if (disallowVersions === true && disallowRanges === true) {
+ throw new Error("'disallowVersions' and 'disallowRanges' cannot both be true.")
+ }
+ if (disallowRanges === true && onlyXRange === true) {
+ throw new Error("'disallowRanges' and 'onlyXRange' cannot both be true.")
+ }
+
+ let normalized = disallowRanges === true ? semver.valid(input, options) : semver.validRange(input, options)
+ // test for x-range specifically
+ if (normalized !== null && onlyXRange === true && input.match(xRangeRE) === null) {
+ if (throwIfInvalid === true) {
+ throw new Error(`'${input}' is a valid range, but an x-range is specifically expected.`)
+ }
+ normalized = null
+ }
+ // test for range exclusive of versions
+ if (disallowVersions === true && semver.valid(input, options) !== null) {
+ if (throwIfInvalid === true) {
+ throw new Error(`'${input}' is a valid version, and a non-version range is expected.`)
+ }
+ normalized = null
+ }
+ // throw an exception if the string is invalid and `options.throwIfInvalid` is `true`
+ if (normalized === null && throwIfInvalid === true) {
+ const msg = `'${input}' is not a valid `
+ + `${disallowVersions === true
+ ? 'range exclusive of versions'
+ : (disallowRanges === true ? 'version' : 'version or range')}.`
+ throw new Error(msg)
+ }
+
+ return normalized
+}
export { validVersionOrRange }
diff --git a/src/version-compare.mjs b/src/version-compare.mjs
deleted file mode 100644
index f60b6f8..0000000
--- a/src/version-compare.mjs
+++ /dev/null
@@ -1,57 +0,0 @@
-import semver from 'semver'
-
-const compareHelper = ({ semverTest, timeverTest, versions }) => {
- let currLead
- for (let i = 0; i < versions.length; i += 1) {
- const testVer = versions[i]
- if (currLead === undefined) {
- currLead = testVer
- }
- else if (semverTest(currLead, testVer)) {
- currLead = testVer
- }
- }
-
- return currLead
-}
-
-const maxVersion = ({ ignoreNonVersions, versions }) => {
- if (!versions || versions.length === 0) {
- return null
- }
-
- versions = filterValidVersions(versions, { ignoreNonVersions })
-
- return compareHelper({ semverTest : semver.lt, timeverTest : (a, b) => a.localeCompare(b) < 0, versions })
-}
-
-const minVersion = ({ ignoreNonVersions, versions }) => {
- if (!versions || versions.length === 0) {
- return null
- }
-
- versions = filterValidVersions(versions, { ignoreNonVersions })
-
- return compareHelper({ semverTest : semver.gt, timeverTest : (a, b) => a.localeCompare(b) > 0, versions })
-}
-
-const filterValidVersions = (versions, { ignoreNonVersions }) => {
- versions = versions.filter((version) => {
- const valid = semver.valid(version) !== null
-
- if (valid === false) {
- if (ignoreNonVersions === true) {
- return false
- }
- else {
- throw new Error(`'${version}' is not a valid semver.`)
- }
- }
-
- return true
- })
-
- return versions
-}
-
-export { maxVersion, minVersion }
diff --git a/src/x-sort.mjs b/src/x-sort.mjs
index 42a2989..8e71d8c 100644
--- a/src/x-sort.mjs
+++ b/src/x-sort.mjs
@@ -5,6 +5,9 @@ import { upperBound } from './upper-bound'
/**
* Ascend sorts a mix of semver versions and x-range specified ranges (e.g., 1.2.* or 1.2.x). The ranges are sorted according to their highest version; e.g., 1.3.34 < 1.3.*. (I believe it can accept caret ranges too, but I would need to review the spec.)
+ * @param {string[]} versionsAndRanges - The versions and ranges to sort.
+ * @returns {string[]} - The sorted versions and ranges.
+ * @category Comparison operations
*/
const xSort = (versionsAndRanges) => {
// TODO: to sort any range type, develop 'minOutOfRange' and use those to sort ranges