Skip to content
Effect 4.0 is here. One ecosystem. Zero dependencies.

SemVer unstable

Immutable Semantic Versioning 2.0.0 values with strict parsing, canonical formatting, spec precedence ordering, and version bumps.

A SemVer has numeric major, minor, and patch components, optional pre-release identifiers, and optional build metadata. Structural equality and hashing include build metadata, while Order follows spec precedence and ignores it. Version ranges live in SemVerRange.

40 exports Since v4.0.6 Source

Comparisons

difference

unstable
Since v4.0.6

Classifies the change between two versions by release type.

Details

Follows node-semver's diff, so the result names the bump that produces the higher version from the lower one. Moving to a pre-release adds the pre prefix, and finalizing a pre-release reports the level it was released at: 1.0.0-1 to 1.0.0 is "major", 1.1.0-1 to 1.1.0 is "minor", and 1.2.3-1 to 1.2.3 is "patch". The result does not depend on argument order.

Gotchas

Returns None for versions with the same precedence, including versions that differ only in build metadata.

See

  • bump for applying a release type to a version

Signature

declare const difference: {
(that: SemVer): (self: SemVer) => Option<ReleaseType>;
(self: SemVer, that: SemVer): Option<ReleaseType>;
}

Example Classifying upgrades

import { Option, SemVer } from "effect"
SemVer.difference(SemVer.parseUnsafe("1.2.3"), SemVer.parseUnsafe("1.3.0")) // => Option.some("minor")
SemVer.difference(SemVer.parseUnsafe("1.2.3"), SemVer.parseUnsafe("2.0.0-rc.1")) // => Option.some("premajor")
SemVer.difference(SemVer.parseUnsafe("2.0.0-rc.1"), SemVer.parseUnsafe("2.0.0")) // => Option.some("major")
SemVer.difference(SemVer.parseUnsafe("1.2.3+a"), SemVer.parseUnsafe("1.2.3+b")) // => Option.none()

Constructors

fromInput

unstable
Since v4.0.6

Converts a version, version string, or version components into a SemVer.

Details

Versions are returned unchanged, strings are parsed like parse, and components are validated like make. Invalid input fails with SemVerError.

See

Signature

declare function fromInput(input: Input): Result<SemVer, SemVerError>

Example Accepting flexible version input

import { Result, SemVer } from "effect"
Result.map(SemVer.fromInput("1.2.3-rc.1"), SemVer.format) // => Result.succeed("1.2.3-rc.1")
Result.map(SemVer.fromInput({ major: 1, minor: 2, patch: 3 }), SemVer.format) // => Result.succeed("1.2.3")
Result.isFailure(SemVer.fromInput({ major: -1, minor: 0, patch: 0 })) // => true
Since v4.0.6

Converts a version, version string, or version components into a SemVer and throws SemVerError for invalid input.

See

Signature

declare function fromInputUnsafe(input: Input): SemVer

make

unstable
Since v4.0.6

Creates a version from its components and throws SemVerError for invalid components.

Details

Components must be non-negative safe integers. Identifiers must be non-empty and contain only ASCII alphanumerics and hyphens. Digit-only pre-release strings are normalized to numbers and must not have leading zeros.

A SemVer spreads into exactly these components, so make({ ...version, patch: version.patch + 1 }) derives a validated version from an existing one.

See

  • parse for decoding version strings

Signature

declare function make(components: Components): SemVer

Example Creating a pre-release version

import { SemVer } from "effect"
SemVer.format(SemVer.make({ major: 1, minor: 0, patch: 0, prerelease: ["beta", "2"] })) // => "1.0.0-beta.2"

parse

unstable
Since v4.0.6

Parses a strict Semantic Versioning 2.0.0 string.

Details

The input must match the spec grammar exactly. Leading zeros in numeric components or pre-release identifiers, empty identifiers, and numbers above Number.MAX_SAFE_INTEGER are rejected.

Gotchas

A v prefix, surrounding whitespace, and partial versions such as 1.2 are rejected because they are not semantic versions.

See

Signature

declare function parse(input: string): Result<SemVer, SemVerError>

Example Parsing version strings

import { Result, SemVer } from "effect"
Result.isSuccess(SemVer.parse("1.2.3-alpha.1+001")) // => true
Result.isFailure(SemVer.parse("v1.2.3")) // => true

parseUnsafe

unstable
Since v4.0.6

Parses a strict Semantic Versioning 2.0.0 string and throws SemVerError for invalid input.

See

  • parse for non-throwing parsing

Signature

declare function parseUnsafe(input: string): SemVer

Converting

format

unstable
Since v4.0.6

Formats a version as its canonical string, including pre-release identifiers and build metadata.

See

  • parse for the inverse operation

Signature

declare function format(self: SemVer): string

Errors

SemVerError

unstable
Since v4.0.6

Error raised for invalid version strings, ranges, or components.

See

Signature

declare class SemVerError extends YieldableError<this> & {
readonly _tag: "SemVerError";
} & Readonly<{
readonly input?: string;
readonly message: string;
}> {
constructor(args: {
readonly input?: string;
readonly message: string;
});
readonly "~effect/SemVer/SemVerError": "~effect/SemVer/SemVerError";
}

Guards

isSemVer

unstable
Since v4.0.6

Checks whether a value is a SemVer.

Signature

declare function isSemVer(u: unknown): u is SemVer
Since v4.0.6

Checks whether a value is a SemVerError.

Signature

declare function isSemVerError(u: unknown): u is SemVerError

Instances

Equivalence

unstable
Since v4.0.6

Provides structural equivalence for versions, including build metadata.

See

  • Order for precedence that ignores build metadata

Signature

declare const Equivalence: Equ.Equivalence<SemVer>

Order

unstable
Since v4.0.6

Orders versions by Semantic Versioning precedence.

Details

Major, minor, and patch are compared numerically. A pre-release has lower precedence than its release. Pre-release identifiers are compared left to right: numeric identifiers compare numerically and sort before alphanumeric identifiers, which compare in ASCII order. A longer list of otherwise equal identifiers has higher precedence.

Gotchas

Build metadata is ignored, so versions that differ only in build metadata compare as 0 even though they are not Equal.

See

  • Equivalence for structural equality including build metadata

Signature

declare const Order: order.Order<SemVer>

Example Sorting by precedence

import { Array, SemVer } from "effect"
const versions = ["1.0.0", "1.0.0-rc.1", "1.0.0-beta.11", "1.0.0-beta.2", "1.0.0-alpha"].map(SemVer.parseUnsafe)
Array.sort(versions, SemVer.Order).map(SemVer.format) // => ["1.0.0-alpha", "1.0.0-beta.2", "1.0.0-beta.11", "1.0.0-rc.1", "1.0.0"]

Models

Components

interface unstable
Since v4.0.6

The numeric components and identifiers of a version.

See

  • make for validating components into a version

Signature

interface Components {
readonly build?: readonly Array<string>;
readonly major: number;
readonly minor: number;
readonly patch: number;
readonly prerelease?: readonly Array<string | number>;
}

Input

type unstable
Since v4.0.6

Values accepted by fromInput: a version, a version string literal, or version components.

See

Signature

type Input = SemVer | VersionString | Components

ReleaseType

type unstable
Since v4.0.6

Names of version changes, matching npm's release types.

See

  • difference for classifying the change between two versions

Signature

type ReleaseType = "major" | "premajor" | "minor" | "preminor" | "patch" | "prepatch" | "prerelease"

SemVer

interface unstable
Since v4.0.6

Represents a semantic version.

Details

Pre-release identifiers are numbers when they consist only of digits and strings otherwise. Build metadata identifiers are always strings because they may contain leading zeros. Both arrays are empty when absent.

See

  • parse for decoding version strings
  • make for constructing versions from components

Signature

interface SemVer extends Pipeable, Equal, Inspectable {
readonly "~effect/SemVer": "~effect/SemVer";
readonly build: readonly Array<string>;
readonly major: number;
readonly minor: number;
readonly patch: number;
readonly prerelease: readonly Array<string | number>;
}

Example Reading version components

import { SemVer } from "effect"
const version = SemVer.parseUnsafe("1.2.3-rc.1+build.5")
version.minor // => 2
version.prerelease // => ["rc", 1]
version.build // => ["build", "5"]

VersionString

type unstable
Since v4.0.6

Version string literals accepted by fromInput.

Details

Requires three numeric components without signs or leading zeros, followed by an optional - pre-release and + build suffix. Component magnitudes (at most Number.MAX_SAFE_INTEGER) and identifiers are only validated at runtime.

See

  • parse for arbitrary strings

Signature

type VersionString = `${NumericComponent}.${NumericComponent}.${NumericComponent}${"" | `-${string}` | `+${string}`}`

Ordering

clamp

unstable
Since v4.0.6

Constrains a version's precedence to an inclusive range.

Signature

declare const clamp: {
(options: {
maximum: SemVer;
minimum: SemVer;
}): (self: SemVer) => SemVer;
(self: SemVer, options: {
maximum: SemVer;
minimum: SemVer;
}): SemVer;
}

max

unstable
Since v4.0.6

Returns the version with higher precedence, preferring the first on ties.

Signature

declare const max: {
(that: SemVer): (self: SemVer) => SemVer;
(self: SemVer, that: SemVer): SemVer;
}

min

unstable
Since v4.0.6

Returns the version with lower precedence, preferring the first on ties.

Signature

declare const min: {
(that: SemVer): (self: SemVer) => SemVer;
(self: SemVer, that: SemVer): SemVer;
}

Predicates

between

unstable
Since v4.0.6

Checks whether a version's precedence is within an inclusive range.

Signature

declare const between: {
(options: {
maximum: SemVer;
minimum: SemVer;
}): (self: SemVer) => boolean;
(self: SemVer, options: {
maximum: SemVer;
minimum: SemVer;
}): boolean;
}

equals

unstable
Since v4.0.6

Checks whether two versions are structurally equal, including build metadata.

Signature

declare const equals: {
(that: SemVer): (self: SemVer) => boolean;
(self: SemVer, that: SemVer): boolean;
}

hasBuild

unstable
Since v4.0.6

Checks whether a version has build metadata.

Details

Build metadata does not affect precedence, but it is part of structural equality.

Signature

declare function hasBuild(self: SemVer): boolean
Since v4.0.6

Checks whether the first version has higher precedence than the second.

Signature

declare const isGreaterThan: {
(that: SemVer): (self: SemVer) => boolean;
(self: SemVer, that: SemVer): boolean;
}

Checks whether the first version has higher or equal precedence than the second.

Signature

declare const isGreaterThanOrEqualTo: {
(that: SemVer): (self: SemVer) => boolean;
(self: SemVer, that: SemVer): boolean;
}
Since v4.0.6

Checks whether a version is in initial development, meaning its major version is 0.

Details

The SemVer spec treats 0.y.z as initial development where anything may change at any time and the public API should not be considered stable.

Signature

declare function isInitialDevelopment(self: SemVer): boolean

isLessThan

unstable
Since v4.0.6

Checks whether the first version has lower precedence than the second.

Signature

declare const isLessThan: {
(that: SemVer): (self: SemVer) => boolean;
(self: SemVer, that: SemVer): boolean;
}
Since v4.0.6

Checks whether the first version has lower or equal precedence than the second.

Signature

declare const isLessThanOrEqualTo: {
(that: SemVer): (self: SemVer) => boolean;
(self: SemVer, that: SemVer): boolean;
}
Since v4.0.6

Checks whether a version has pre-release identifiers.

Signature

declare function isPrerelease(self: SemVer): boolean

Transforming

bump

unstable
Since v4.0.6

Bumps a version by release type.

When to use

Use when the release type is data, such as a CLI argument, configuration, or the result of difference.

Details

Dispatches to bumpMajor, bumpMinor, bumpPatch, bumpPremajor, bumpPreminor, bumpPrepatch, or bumpPrerelease, with the same semantics.

Gotchas

The pre-release identifier is ignored for "major", "minor", and "patch".

Signature

declare const bump: {
(releaseType: ReleaseType, identifier?: string): (self: SemVer) => SemVer;
(self: SemVer, releaseType: ReleaseType, identifier?: string): SemVer;
}

Example Bumping by a release type from input

import { SemVer } from "effect"
const version = SemVer.parseUnsafe("1.2.3")
SemVer.format(SemVer.bump(version, "minor")) // => "1.3.0"
SemVer.format(SemVer.bump(version, "premajor", "rc")) // => "2.0.0-rc.0"

Example Defining custom bump rules

import { SemVer } from "effect"
// Always increment patch, even for pre-releases, and keep build metadata
const customBump = (version: SemVer.SemVer, releaseType: SemVer.ReleaseType): SemVer.SemVer =>
releaseType === "patch"
? SemVer.make({ ...version, patch: version.patch + 1, prerelease: [] })
: SemVer.withBuild(SemVer.bump(version, releaseType), version.build)
SemVer.format(customBump(SemVer.parseUnsafe("1.2.3-rc.1+b"), "patch")) // => "1.2.4+b"
SemVer.format(customBump(SemVer.parseUnsafe("1.2.3-rc.1+b"), "minor")) // => "1.3.0+b"

bumpMajor

unstable
Since v4.0.6

Returns the next major release.

Details

Returns the smallest major release with higher precedence, so a pre-release of a major version, such as 2.0.0-rc.1, becomes 2.0.0. Pre-release identifiers and build metadata are removed.

Signature

declare function bumpMajor(self: SemVer): SemVer

Example Bumping major versions

import { SemVer } from "effect"
SemVer.format(SemVer.bumpMajor(SemVer.parseUnsafe("1.2.3"))) // => "2.0.0"
SemVer.format(SemVer.bumpMajor(SemVer.parseUnsafe("2.0.0-rc.1"))) // => "2.0.0"
SemVer.format(SemVer.bumpMajor(SemVer.parseUnsafe("2.1.0-rc.1"))) // => "3.0.0"

bumpMinor

unstable
Since v4.0.6

Returns the next minor release.

Details

Returns the smallest minor release with higher precedence, so a pre-release of a minor version, such as 1.3.0-rc.1, becomes 1.3.0. Pre-release identifiers and build metadata are removed.

Signature

declare function bumpMinor(self: SemVer): SemVer

bumpPatch

unstable
Since v4.0.6

Returns the next patch release.

Details

Returns the smallest patch release with higher precedence, so a pre-release such as 1.2.3-rc.1 becomes 1.2.3. Pre-release identifiers and build metadata are removed.

Signature

declare function bumpPatch(self: SemVer): SemVer
Since v4.0.6

Returns the first pre-release of the next major version.

Details

Increments major, resets minor and patch, and starts the pre-release at [identifier, 0], or [0] without an identifier. Build metadata is removed.

Signature

declare const bumpPremajor: {
(identifier?: string): (self: SemVer) => SemVer;
(self: SemVer, identifier?: string): SemVer;
}
Since v4.0.6

Returns the first pre-release of the next minor version.

Details

Increments minor, resets patch, and starts the pre-release at [identifier, 0], or [0] without an identifier. Build metadata is removed.

Signature

declare const bumpPreminor: {
(identifier?: string): (self: SemVer) => SemVer;
(self: SemVer, identifier?: string): SemVer;
}
Since v4.0.6

Returns the first pre-release of the next patch version.

Details

Increments patch and starts the pre-release at [identifier, 0], or [0] without an identifier. Build metadata is removed.

Signature

declare const bumpPrepatch: {
(identifier?: string): (self: SemVer) => SemVer;
(self: SemVer, identifier?: string): SemVer;
}
Since v4.0.6

Returns the next pre-release.

Details

  • A release starts the pre-release of the next patch, like bumpPrepatch.
  • An identifier that differs from the first pre-release identifier restarts the pre-release at [identifier, 0].
  • Otherwise the right-most numeric identifier is incremented, or 0 is appended when there is none.

Build metadata is removed.

Gotchas

Switching to an identifier that sorts lower, such as from beta to alpha, returns a version with lower precedence.

Signature

declare const bumpPrerelease: {
(identifier?: string): (self: SemVer) => SemVer;
(self: SemVer, identifier?: string): SemVer;
}

Example Advancing pre-releases

import { SemVer } from "effect"
SemVer.format(SemVer.bumpPrerelease(SemVer.parseUnsafe("1.2.3"), "alpha")) // => "1.2.4-alpha.0"
SemVer.format(SemVer.bumpPrerelease(SemVer.parseUnsafe("1.2.4-alpha.0"))) // => "1.2.4-alpha.1"
SemVer.format(SemVer.bumpPrerelease(SemVer.parseUnsafe("1.2.4-alpha.1"), "beta")) // => "1.2.4-beta.0"

release

unstable
Since v4.0.6

Removes pre-release identifiers and build metadata from a version.

Signature

declare function release(self: SemVer): SemVer

Example Finalizing a release candidate

import { SemVer } from "effect"
SemVer.format(SemVer.release(SemVer.parseUnsafe("2.0.0-rc.3+sha.5114f85"))) // => "2.0.0"

withBuild

unstable
Since v4.0.6

Replaces the build metadata of a version and throws SemVerError for invalid identifiers.

Details

An empty array removes the build metadata. Pre-release identifiers are preserved.

Signature

declare const withBuild: {
(build: readonly Array<string>): (self: SemVer) => SemVer;
(self: SemVer, build: readonly Array<string>): SemVer;
}
Since v4.0.6

Replaces the pre-release identifiers of a version and throws SemVerError for invalid identifiers.

Details

Digit-only strings are normalized to numbers. An empty array removes the pre-release. Build metadata is preserved.

Signature

declare const withPrerelease: {
(prerelease: readonly Array<string | number>): (self: SemVer) => SemVer;
(self: SemVer, prerelease: readonly Array<string | number>): SemVer;
}