calver

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 24, 2026 License: MIT Imports: 5 Imported by: 0

README

calver

calver is a dependency-free Go library for parsing, rendering, and comparing Calendar Versioning values with explicit user-defined formats.

It supports Go 1.18 and later.

Status

The public API is intentionally format-aware: CalVer does not define a single grammar, modifier precedence, or universal ordering between week-based and month/day-based versions.

Installation

go get github.com/woozymasta/calver

Usage

Compile a layout once, then use it for parsing hot paths:

format, err := calver.Compile("release-<YYYY>.<0M>.<0D>-<MODIFIER>")
if err != nil {
  return err
}

version, ok := format.Parse("release-2026.07.24-rc.1")
if !ok {
  return errors.New("invalid version")
}

fmt.Println(version.Major())                   // 2026, true
fmt.Println(version.Series(calver.LevelMicro)) // release-2026.07.24

Construct values without accepting an external version string:

format := calver.MustCompile("<MAJOR>.<MINOR>.<MICRO>")
version, err := format.New(calver.Parts{Major: 1, Minor: 2, Micro: 3})
if err != nil {
  return err
}

next, err := version.BumpMinor() // 1.3.3; lower components are unchanged
if err != nil {
  return err
}

BumpMajor, BumpMinor, and BumpMicro only operate on their respective generic tokens. Calendar tokens are rejected to prevent accidental date arithmetic. HasLevel and Kind expose a format's component profile when calling code needs to distinguish generic versions from calendar values.

Supported tokens:

  • <YYYY>, <YY>, <0Y>, <MAJOR>
  • <MM>, <0M>, <MINOR>
  • <WW>, <0W>, <DD>, <0D>, <MICRO>
  • terminal <MODIFIER>

Literal < and > are escaped as << and >>. One token is allowed per logical level. Week formats cannot be combined with month or day tokens.

Comparison

Compare provides a deterministic structural order suitable for sorting. It compares numeric components numerically, opaque modifiers bytewise, then uses the rendered value as a stable tie-breaker.

Use CompatibleWith and CompareCalendar when calendar meaning matters. For example, 2026-07-24 and 2026.07.25 are compatible, while 2026-07-24 and 2026-W30 are not.

Modifier values intentionally have no SemVer semantics: there is no implicit "release is greater than prerelease" rule and rc.10 sorts before rc.2 under the default bytewise policy. Greater, GreaterOrEqual, Less, and LessOrEqual are convenience helpers with the same ordering semantics.

Performance

Format.Parse and Version.Compare are allocation-free for valid values. String returns the parsed input; use AppendTo when appending into a caller buffer.

For Semantic Versioning, use the companion WoozyMasta/semver library.

Documentation

Overview

Package calver parses, renders, and compares Calendar Versioning values.

Calendar Versioning defines common calendar components but does not define a universal version grammar or modifier precedence. This package therefore requires callers to compile an explicit Format before parsing values. A compiled Format is immutable and safe for concurrent use.

Parse with Format.Parse is allocation-free for valid input. Parsed Version values retain the input string, including a zero-copy Modifier slice when it is present. Keep this in mind when parsing small values from large buffers.

Compare provides a deterministic structural order for sorting arbitrary values. CompareCalendar is restricted to semantically compatible formats; it does not compare week-based values with month/day-based values.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrInvalidParts indicates Parts that do not match a Format's schema.
	ErrInvalidParts = errors.New("calver: invalid parts for format")
	// ErrUnsupportedBump indicates a bump requested for a calendar token.
	ErrUnsupportedBump = errors.New("calver: bump requires a generic numeric level")
	// ErrBumpOverflow indicates an attempt to increment math.MaxUint64.
	ErrBumpOverflow = errors.New("calver: bump overflows uint64")
)

Functions

This section is empty.

Types

type CompileError

type CompileError struct {
	Kind   ErrorKind
	Offset int
}

CompileError describes an invalid CalVer layout.

func (*CompileError) Error

func (e *CompileError) Error() string

Error implements error.

type ComponentKind

type ComponentKind uint8

ComponentKind identifies the calendar meaning of a format level.

const (
	// ComponentKindNone indicates an absent or invalid level.
	ComponentKindNone ComponentKind = iota
	// ComponentKindYear identifies YYYY, YY, or 0Y.
	ComponentKindYear
	// ComponentKindMajor identifies MAJOR.
	ComponentKindMajor
	// ComponentKindMonth identifies MM or 0M.
	ComponentKindMonth
	// ComponentKindMinor identifies MINOR.
	ComponentKindMinor
	// ComponentKindWeek identifies WW or 0W.
	ComponentKindWeek
	// ComponentKindDay identifies DD or 0D.
	ComponentKindDay
	// ComponentKindMicro identifies MICRO.
	ComponentKindMicro
	// ComponentKindModifier identifies MODIFIER.
	ComponentKindModifier
)

type ErrorKind

type ErrorKind string

ErrorKind identifies a format compilation or version parsing failure.

const (
	// ErrEmptyFormat indicates an empty layout.
	ErrEmptyFormat ErrorKind = "empty format"
	// ErrInvalidToken indicates an unknown or malformed token.
	ErrInvalidToken ErrorKind = "invalid token"
	// ErrInvalidEscape indicates an unescaped angle bracket in a layout.
	ErrInvalidEscape ErrorKind = "invalid escape"
	// ErrDuplicateLevel indicates more than one token for a logical level.
	ErrDuplicateLevel ErrorKind = "duplicate level"
	// ErrIncompatibleTokens indicates an invalid month/day/week combination.
	ErrIncompatibleTokens ErrorKind = "incompatible tokens"
	// ErrAmbiguousLayout indicates a variable-width token without a boundary.
	ErrAmbiguousLayout ErrorKind = "ambiguous layout"
	// ErrModifierPosition indicates a non-terminal modifier token.
	ErrModifierPosition ErrorKind = "modifier must be final"
	// ErrLiteralMismatch indicates that an input literal does not match.
	ErrLiteralMismatch ErrorKind = "literal mismatch"
	// ErrInvalidNumber indicates an invalid numeric component.
	ErrInvalidNumber ErrorKind = "invalid number"
	// ErrOverflow indicates a component that does not fit into uint64.
	ErrOverflow ErrorKind = "numeric overflow"
	// ErrOutOfRange indicates a calendar component outside its range.
	ErrOutOfRange ErrorKind = "value out of range"
	// ErrInvalidDate indicates an invalid Gregorian calendar date.
	ErrInvalidDate ErrorKind = "invalid date"
	// ErrEmptyModifier indicates an empty modifier component.
	ErrEmptyModifier ErrorKind = "empty modifier"
)

type Format

type Format struct {
	// contains filtered or unexported fields
}

Format is an immutable compiled CalVer layout.

The zero value is invalid. Obtain a Format with Compile or MustCompile.

func Compile

func Compile(layout string) (Format, error)

Compile compiles layout into an immutable Format.

Layout tokens are YYYY, YY, 0Y, MAJOR, MM, 0M, MINOR, WW, 0W, DD, 0D, MICRO, and MODIFIER, each enclosed in angle brackets. Literal '<' and '>' are escaped as '<<' and '>>'. MODIFIER is allowed only as the final token.

func MustCompile

func MustCompile(layout string) Format

MustCompile compiles layout and panics if it is invalid.

func (Format) HasLevel

func (f Format) HasLevel(level Level) bool

HasLevel reports whether f contains level.

func (Format) Kind

func (f Format) Kind(level Level) ComponentKind

Kind returns the calendar meaning of level in f.

func (Format) Layout

func (f Format) Layout() string

Layout returns the original layout. It returns an empty string for the zero Format.

func (Format) New

func (f Format) New(parts Parts) (Version, error)

New constructs and validates a Version from parts according to f.

func (Format) Parse

func (f Format) Parse(input string) (Version, bool)

Parse parses input according to f. It returns false for an invalid Format or an input that does not match the layout.

Example
package main

import (
	"fmt"

	"github.com/woozymasta/calver"
)

func main() {
	format := calver.MustCompile("release-<YYYY>.<0M>.<0D>-<MODIFIER>")
	version, ok := format.Parse("release-2026.07.24-rc.1")
	if !ok {
		return
	}

	major, _ := version.Major()
	fmt.Println(major)
	fmt.Println(version.Series(calver.LevelMicro))

}
Output:
2026
release-2026.07.24

func (Format) ParseStrict

func (f Format) ParseStrict(input string) (Version, error)

ParseStrict parses input according to f and returns a typed error on failure.

type Level

type Level uint8

Level identifies a CalVer logical component.

const (
	// LevelMajor identifies the first logical component.
	LevelMajor Level = iota
	// LevelMinor identifies the second logical component.
	LevelMinor
	// LevelMicro identifies the third logical component.
	LevelMicro
	// LevelModifier identifies the trailing modifier component.
	LevelModifier
)

type List

type List []Version

List is a sortable collection of Versions.

func (List) Len

func (list List) Len() int

Len implements sort.Interface.

func (List) Less

func (list List) Less(left, right int) bool

Less implements sort.Interface.

func (List) Sort

func (list List) Sort()

Sort sorts list in ascending structural order.

func (List) Swap

func (list List) Swap(left, right int)

Swap implements sort.Interface.

type ParseError

type ParseError struct {
	Kind   ErrorKind
	Offset int
}

ParseError describes an input rejected by a Format.

func (*ParseError) Error

func (e *ParseError) Error() string

Error implements error.

type Parts

type Parts struct {
	// Modifier is the opaque trailing component.
	Modifier string `json:"modifier,omitempty" yaml:"modifier,omitempty"`
	// Major is the first numeric component or full calendar year.
	Major uint64 `json:"major" yaml:"major"`
	// Minor is the second numeric component or calendar month.
	Minor uint64 `json:"minor" yaml:"minor"`
	// Micro is the third numeric component, day, or week.
	Micro uint64 `json:"micro" yaml:"micro"`
}

Parts contains normalized values used to construct a Version.

Major is a full calendar year for YYYY, YY, and 0Y formats. A Format defines which parts it consumes; non-zero values for absent numeric levels and a modifier that disagrees with the format return ErrInvalidParts.

type Version

type Version struct {
	// contains filtered or unexported fields
}

Version is an immutable parsed CalVer value.

func Parse

func Parse(layout, input string) (Version, bool)

Parse parses input with layout. It is a convenience wrapper for Compile(layout) followed by Format.Parse.

func ParseStrict

func ParseStrict(layout, input string) (Version, error)

ParseStrict parses input with layout and returns a typed error on failure.

func (Version) AppendTo

func (v Version) AppendTo(dst []byte) []byte

AppendTo appends v's rendered value to dst. Invalid versions leave dst unchanged.

func (Version) BumpMajor

func (v Version) BumpMajor() (Version, error)

BumpMajor returns v with its generic MAJOR component incremented. It does not reset lower components.

func (Version) BumpMicro

func (v Version) BumpMicro() (Version, error)

BumpMicro returns v with its generic MICRO component incremented.

func (Version) BumpMinor

func (v Version) BumpMinor() (Version, error)

BumpMinor returns v with its generic MINOR component incremented. It does not reset lower components.

func (Version) Compare

func (v Version) Compare(other Version) int

Compare returns a deterministic structural order between v and other.

Invalid values sort before valid values. Numeric components compare by value, absent components sort before present components, and modifiers compare bitwise. Equal components use String as a final tie-breaker.

func (Version) CompareCalendar

func (v Version) CompareCalendar(other Version) (order int, ok bool)

CompareCalendar compares v and other when their semantic profiles match. It returns ok=false for incompatible formats.

Example
package main

import (
	"fmt"

	"github.com/woozymasta/calver"
)

func main() {
	dash := calver.MustCompile("<YYYY>-<0M>-<0D>")
	dot := calver.MustCompile("<YYYY>.<0M>.<0D>")
	first, _ := dash.Parse("2026-07-24")
	second, _ := dot.Parse("2026.07.25")

	order, compatible := first.CompareCalendar(second)
	fmt.Println(compatible, order)

}
Output:
true -1

func (Version) CompatibleWith

func (v Version) CompatibleWith(other Version) bool

CompatibleWith reports whether v and other have matching calendar semantics. Layout literals and zero-padding do not affect compatibility.

func (Version) Equal

func (v Version) Equal(other Version) bool

Equal reports whether v and other have the same structural order.

func (Version) Format

func (v Version) Format() Format

Format returns the Format that parsed v. It returns the zero Format when v is invalid.

func (Version) Greater

func (v Version) Greater(other Version) bool

Greater reports whether v sorts after other according to Compare.

func (Version) GreaterOrEqual

func (v Version) GreaterOrEqual(other Version) bool

GreaterOrEqual reports whether v does not sort before other according to Compare.

func (Version) IsValid

func (v Version) IsValid() bool

IsValid reports whether v was successfully parsed.

func (Version) Less

func (v Version) Less(other Version) bool

Less reports whether v sorts before other according to Compare.

func (Version) LessOrEqual

func (v Version) LessOrEqual(other Version) bool

LessOrEqual reports whether v does not sort after other according to Compare.

func (Version) Major

func (v Version) Major() (uint64, bool)

Major returns the first logical component and whether it is present.

func (Version) MarshalJSON

func (v Version) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler.

func (Version) MarshalText

func (v Version) MarshalText() ([]byte, error)

MarshalText implements encoding.TextMarshaler.

func (Version) Max

func (v Version) Max(other Version) Version

Max returns the greater version according to Compare.

func (Version) Micro

func (v Version) Micro() (uint64, bool)

Micro returns the third logical component and whether it is present.

func (Version) Min

func (v Version) Min(other Version) Version

Min returns the smaller version according to Compare.

func (Version) Minor

func (v Version) Minor() (uint64, bool)

Minor returns the second logical component and whether it is present.

func (Version) Modifier

func (v Version) Modifier() string

Modifier returns the opaque trailing modifier. It returns an empty string when the format has no modifier token or v is invalid.

func (Version) Series

func (v Version) Series(level Level) string

Series returns v up to and including level. It returns the full version when v is invalid or the requested level is absent.

func (Version) String

func (v Version) String() string

String implements fmt.Stringer. It returns the original input for valid versions and an empty string for invalid versions.

func (*Version) UnmarshalJSON

func (v *Version) UnmarshalJSON(data []byte) error

UnmarshalJSON implements json.Unmarshaler. It leaves v unchanged on error.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL