# SemVer API

Version parsing, validation, comparison, version requirement matching, and
bumping helpers live under `ptool.semver` and `p.semver`.

## ptool.semver.parse

> `v0.1.0` - Introduced.

`ptool.semver.parse(version)` parses a version string and returns a `Version`
object.

- `version` (string, required): A semantic version string, optionally prefixed
  with `v`.

Example:

```lua
local v = ptool.semver.parse("v1.2.3-alpha.1+build.9")
print(v.major, v.minor, v.patch)
print(v.pre, v.build)
print(tostring(v))
```

## ptool.semver.is_valid

> `v0.1.0` - Introduced.

`ptool.semver.is_valid(version)` checks whether a version string is valid.

- `version` (string, required): A semantic version string.
- Returns: `boolean`.

```lua
print(ptool.semver.is_valid("1.2.3")) -- true
print(ptool.semver.is_valid("x.y.z")) -- false
```

## ptool.semver.parse_req

> `v0.7.0` - Introduced.

`ptool.semver.parse_req(req)` parses a Cargo-style semantic version requirement
string and returns a `VersionReq` object.

- `req` (string, required): A version requirement string.
- Returns: `VersionReq`.

Supported examples include `^1.2.3`, `~1.2.3`, `>=1.2.3, <2.0.0`, `1.*`, and
`1.2.*`. Version components inside a requirement may also use an optional `v`
prefix, such as `>= v0.6.0, < 0.7.0`.

```lua
local req = ptool.semver.parse_req(">= v0.6.0, < 0.7.0")
print(tostring(req)) -- >=0.6.0, <0.7.0
```

## ptool.semver.is_valid_req

> `v0.7.0` - Introduced.

`ptool.semver.is_valid_req(req)` checks whether a version requirement string is
valid.

- `req` (string, required): A version requirement string.
- Returns: `boolean`.

```lua
print(ptool.semver.is_valid_req("^1.2.3")) -- true
print(ptool.semver.is_valid_req(">= 1.2.3, <")) -- false
```

## ptool.semver.compare

> `v0.1.0` - Introduced.

`ptool.semver.compare(a, b)` compares two versions.

- `a` / `b` (string|Version, required): A version string or a `Version` object.
- Returns: `-1 | 0 | 1`.

```lua
print(ptool.semver.compare("1.2.3", "1.2.4")) -- -1
```

## ptool.semver.matches

> `v0.7.0` - Introduced.

`ptool.semver.matches(req, version)` checks whether a version satisfies a
version requirement.

- `req` (string|VersionReq, required): A version requirement string or a
  `VersionReq` object.
- `version` (string|Version, required): A version string or a `Version` object.
- Returns: `boolean`.

```lua
local req = ptool.semver.parse_req("^0.6.0")
print(ptool.semver.matches(req, "0.6.3")) -- true
print(ptool.semver.matches(">=0.6.0, <0.7.0", "0.7.0")) -- false
```

## ptool.semver.bump

> `v0.1.0` - Introduced.

`ptool.semver.bump(v, op[, channel])` returns a new version object after
applying the bump.

- `v` (string|Version, required): The original version.
- `op` (string, required): One of `major`, `minor`, `patch`, `release`,
  `alpha`, `beta`, `rc`, `prepatch`, `preminor`, or `premajor`.
- `channel` (string, optional): Supported only for `prepatch`, `preminor`, and
  `premajor`. Must be one of `alpha`, `beta`, or `rc`. Defaults to `alpha`.
- Returns: `Version`.

```lua
local v = ptool.semver.bump("1.2.3", "alpha")
print(tostring(v)) -- 1.2.4-alpha.1

local next_minor_rc = ptool.semver.bump("1.2.3", "preminor", "rc")
print(tostring(next_minor_rc)) -- 1.3.0-rc.1

local stable = ptool.semver.bump("1.2.4-rc.2", "release")
print(tostring(stable)) -- 1.2.4
```

## Version

> `v0.1.0` - Introduced.

`Version` represents a parsed semantic version returned by
`ptool.semver.parse(...)` or `ptool.semver.bump(...)`.

It is implemented as a Lua userdata.

Fields and methods:

- Fields:
  - `major` (integer)
  - `minor` (integer)
  - `patch` (integer)
  - `pre` (string|nil)
  - `build` (string|nil)
- Methods:
  - `v:compare(other)` -> `-1|0|1`
  - `v:bump(op[, channel])` -> `Version`
  - `v:to_string()` -> `string`
- Metamethods:
  - `tostring(v)` is available.
  - `==`, `<`, and `<=` comparisons are supported.

### compare

Canonical API name: `ptool.semver.Version:compare`.

`v:compare(other)` compares the current version with `other`.

- `other` (string|Version, required): A version string or another `Version`
  object.
- Returns: `-1 | 0 | 1`.

### bump

Canonical API name: `ptool.semver.Version:bump`.

`v:bump(op[, channel])` returns a new `Version` object after applying the bump.

- `op` (string, required): One of `major`, `minor`, `patch`, `release`,
  `alpha`, `beta`, `rc`, `prepatch`, `preminor`, or `premajor`.
- `channel` (string, optional): Supported only for `prepatch`, `preminor`, and
  `premajor`. Must be one of `alpha`, `beta`, or `rc`. Defaults to `alpha`.
- Returns: `Version`.

### to_string

Canonical API name: `ptool.semver.Version:to_string`.

`v:to_string()` returns the canonical string form of the version.

- Returns: `string`.

## VersionReq

> `v0.7.0` - Introduced.

`VersionReq` represents a parsed semantic version requirement returned by
`ptool.semver.parse_req(...)`.

It is implemented as a Lua userdata.

Methods:

- `req:matches(version)` -> `boolean`
- `req:to_string()` -> `string`

Metamethods:

- `tostring(req)` is available.

### matches

Canonical API name: `ptool.semver.VersionReq:matches`.

`req:matches(version)` checks whether `version` satisfies the current version
requirement.

- `version` (string|Version, required): A version string or a `Version` object.
- Returns: `boolean`.

### to_string

Canonical API name: `ptool.semver.VersionReq:to_string`.

`req:to_string()` returns the canonical string form of the version
requirement.

- Returns: `string`.

Prerelease bump rules:

- Bumping a stable version to `alpha`, `beta`, or `rc` first increments the
  patch version, then enters the target channel starting from `.1`.
- `prepatch`, `preminor`, and `premajor` start a fresh prerelease from the next
  patch, minor, or major version respectively, such as
  `1.2.3 -> 1.3.0-rc.1` with `preminor` + `rc`.
- Bumping within the same channel increments the sequence number, such as
  `alpha.1 -> alpha.2`.
- `release` removes prerelease and build metadata while keeping the same
  `major.minor.patch` values, such as `1.2.3-rc.2 -> 1.2.3`.
- Channel promotion is allowed (`alpha -> beta -> rc`), but channel downgrade is
  not (for example, `rc -> beta` raises an error).
