# `A2UICore.SemVer`
[🔗](https://github.com/a2ui-elixir/a2ui/blob/v0.1.1/umbrella/apps/a2ui_core/lib/a2ui_core/sem_ver.ex#L1)

Semantic Versioning 2.0.0 parsing and comparison.

Mirrors `a2ui-core`'s `common/semver.py` semantics (upstream reference),
extended with Elixir-idiomatic `{:ok, _}`/`:error` returns and tuples.

## Normalization

* `v1_0` / `V1_0` / `1.0` / `1.0.0` / `v1_0_0` are all equivalent to
  each other and normalize to `1.0` (patch omitted when `0`).
* Pre-release (`-beta.1`) and build (`+meta`) suffixes survive the
  normalization and are included in the canonical form when present.

## Comparison

Full SemVer 2.0.0 precedence rules:
`1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta <
1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0`. Build metadata is
ignored.

# `t`
*since 0.1.0* 

```elixir
@type t() :: %A2UICore.SemVer{
  build: [String.t()],
  major: non_neg_integer(),
  minor: non_neg_integer(),
  patch: non_neg_integer(),
  prerelease: [String.t()]
}
```

# `at_least`
*since 0.1.0* 

```elixir
@spec at_least(t() | String.t() | nil, t() | String.t()) :: boolean()
```

Whether `version` is parseable and at least `minimum` (both may be
`t:A2UICore.SemVer.t/0` or strings).

## Examples

    iex> A2UICore.SemVer.at_least("v1.0", "v0.9")
    true
    iex> A2UICore.SemVer.at_least(nil, "v1.0")
    false

# `compare`
*since 0.1.0* 

```elixir
@spec compare(t() | String.t() | nil, t() | String.t() | nil) :: integer()
```

Compares two versions per SemVer 2.0.0 section 11 precedence rules.

Returns a negative integer, zero, or a positive integer for
`<`, `==`, `>` relationships. `nil` or unparseable compares as
smaller than anything that parses.

# `normalize`
*since 0.1.0* 

```elixir
@spec normalize(term()) :: String.t()
```

Strips a leading `v`/`V` and replaces underscores in the release core
with dots, preserving any `-prerelease`/`+build` tail. `"v1_0"` →
`"1.0"`.

# `parse`
*since 0.1.0* 

```elixir
@spec parse(term()) :: {:ok, t()} | :error
```

Parses a version string as SemVer 2.0.0. Returns `{:ok, version}` or
`:error`.

## Examples

    iex> {:ok, v} = A2UICore.SemVer.parse("v1.0")
    iex> {v.major, v.minor, v.patch}
    {1, 0, 0}
    iex> A2UICore.SemVer.parse("not_a_version")
    :error

    iex> A2UICore.SemVer.parse("1")
    :error

# `to_canonical`
*since 0.1.0* 

```elixir
@spec to_canonical(t() | String.t() | nil) :: String.t() | nil
```

Canonical text form per upstream rule: `major.minor` when patch is `0`
and no prerelease/build, otherwise full `major.minor.patch[-pre][+build]`.

Semantics copied from upstream `to_canonical_version/1`: input that is not
parseable returns `nil`.

# `to_semver`
*since 0.1.0* 

```elixir
@spec to_semver(t() | String.t() | nil) :: {:ok, t()} | :error
```

A shorthand for `parse/1` that also accepts an already-parsed
`t:A2UICore.SemVer.t/0`.

Returns `{:ok, t}` or `:error`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
