comver

package module
v0.3.2 Latest Latest
Warning

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

Go to latest
Published: Oct 26, 2025 License: MIT Imports: 5 Imported by: 0

README

comver

Go Reference GitHub Release Test codecov Go Report Card License Hire Typist Tech

Package comver provides the ability to work with composer supported versions in Go.

Built with ♥ by Typist Tech


[!TIP] Hire Tang Rufus!

I am looking for my next role, freelance or full-time. If you find this tool useful, I can build you more weird stuff like this. Let's talk if you are hiring PHP / Ruby / Go developers.

Contact me at https://typist.tech/contact/


Usage

[!NOTE]

See full API documentation on pkg.go.dev.

Known Issues

[!CAUTION]

Due to implementation complexity, it only supports a subset of composer versioning. Refer to the version_test.go for examples.

For better compatibility, use composer-semver instead.

[!TIP] Hire Tang Rufus!

There is no need to understand any of these quirks. Let me handle them for you. I am seeking my next job, freelance or full-time.

If you are hiring PHP / Ruby / Go developers, contact me at https://typist.tech/contact/

Credits

comver is a Typist Tech project and maintained by Tang Rufus, freelance developer for hire.

Full list of contributors can be found here.

This project is a free software distributed under the terms of the MIT license. For the full license, see LICENSE.

Contribute

Feedbacks / bug reports / pull requests are welcome.

Documentation

Overview

Package comver provides the ability to work with composer supported versions in Go.

Due to implementation complexity, this package only supports a subset of composer versioning. Refer to the version_test.go for examples.

For better compatibility, use composer-semver instead.

Example (Version)
package main

import (
	"fmt"

	"github.com/typisttech/comver"
)

func main() {
	ss := []string{
		"1.2.3",
		"1.2",
		"1",

		"   1.0.0",
		"00.01.03.04",

		"2010-01-02.5",
		"2010-01-02",

		"v1.2.3.4-beta.5+foo",
		"v1.2.3.4.p5+foo",
		"v1.2.3",
		"v1.2.p5+foo",

		"not a version",
		"1.0.0-alpha.beta",
		"1.0.0-meh",
		"1.0.0.0.0",
		"20100102.0.3.4",
	}

	for _, s := range ss {
		v, err := comver.Parse(s)
		if err != nil {
			fmt.Printf("%-21q => %v\n", s, err)

			continue
		}

		fmt.Printf("%-21q => %v\n", s, v)
	}

}
Output:

"1.2.3"               => 1.2.3.0
"1.2"                 => 1.2.0.0
"1"                   => 1.0.0.0
"   1.0.0"            => 1.0.0.0
"00.01.03.04"         => 0.1.3.4
"2010-01-02.5"        => 2010.1.2.5
"2010-01-02"          => 2010.1.2.0
"v1.2.3.4-beta.5+foo" => 1.2.3.4-beta5
"v1.2.3.4.p5+foo"     => 1.2.3.4-patch5
"v1.2.3"              => 1.2.3.0
"v1.2.p5+foo"         => 1.2.0.0-patch5
"not a version"       => error parsing version string "not a version"
"1.0.0-alpha.beta"    => error parsing version string "1.0.0-alpha.beta"
"1.0.0-meh"           => error parsing version string "1.0.0-meh"
"1.0.0.0.0"           => error parsing version string "1.0.0.0.0"
"20100102.0.3.4"      => error parsing version string "20100102.0.3.4"

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CeilingFloorConstrainter added in v0.2.0

type CeilingFloorConstrainter interface {
	Constrainter
	// contains filtered or unexported methods
}

func And added in v0.2.0

And returns a CeilingFloorConstrainter instance representing the logical AND of the given Endless instances; or return an error if the given Endless instances could never be satisfied at the same time.

Example
package main

import (
	"fmt"

	"github.com/typisttech/comver"
)

func main() {
	a, _ := comver.And(
		comver.NewGreaterThanOrEqualTo(comver.MustParse("2")),
		comver.NewLessThan(comver.MustParse("3")),
	)

	fmt.Println(a)
}
Output:

>=2 <3
Example (ExactConstraint)
package main

import (
	"fmt"

	"github.com/typisttech/comver"
)

func main() {
	a, _ := comver.And(
		comver.NewGreaterThanOrEqualTo(comver.MustParse("2")),
		comver.NewLessThanOrEqualTo(comver.MustParse("2")),
	)

	fmt.Println(a)
}
Output:

2
Example (ImpossibleInterval)
package main

import (
	"fmt"

	"github.com/typisttech/comver"
)

func main() {
	_, err := comver.And(
		comver.NewGreaterThanOrEqualTo(comver.MustParse("3")),
		comver.NewLessThan(comver.MustParse("2")),
	)

	fmt.Println(err)
}
Output:

impossible interval
Example (MatchAll)
package main

import (
	"fmt"

	"github.com/typisttech/comver"
)

func main() {
	a, _ := comver.And(
		comver.NewGreaterThanOrEqualTo(comver.MustParse("2")),
		comver.NewLessThan(comver.MustParse("3")),
		comver.NewMatchAll(),
	)

	fmt.Println(a)
}
Output:

>=2 <3

func MustAnd added in v0.2.0

func MustAnd(es ...Endless) CeilingFloorConstrainter

MustAnd is like And but panics if an error occurs.

type Constrainter added in v0.2.0

type Constrainter interface {
	// Check reports whether a [Version] satisfies the constraint.
	Check(v Version) bool
	String() string
}

func Compact

func Compact(o Or) Constrainter

Compact returns a new Constrainter that is logically equivalent to the input Or. The returned Constrainter may or may be not be an Or instance. When it is, Compact tries to return the shortest Or possible.

Example
package main

import (
	"fmt"

	"github.com/typisttech/comver"
)

func main() {
	o := comver.Or{
		comver.MustAnd(
			comver.NewLessThan(comver.MustParse("2")),
			comver.NewGreaterThan(comver.MustParse("1")),
		),
		comver.MustAnd(
			comver.NewLessThan(comver.MustParse("5")),
			comver.NewGreaterThan(comver.MustParse("3")),
		),
		comver.MustAnd(
			comver.NewLessThan(comver.MustParse("6")),
			comver.NewGreaterThan(comver.MustParse("4")),
		),
	}

	c := comver.Compact(o)

	fmt.Println("Before:", o)
	fmt.Println("After:", c)

}
Output:

Before: >1 <2 || >3 <5 || >4 <6
After: >1 <2 || >3 <6
Example (Endless)
package main

import (
	"fmt"

	"github.com/typisttech/comver"
)

func main() {
	o := comver.Or{
		comver.MustAnd(
			comver.NewLessThan(comver.MustParse("5")),
			comver.NewGreaterThan(comver.MustParse("3")),
		),
		comver.NewGreaterThan(comver.MustParse("4")),
	}

	c := comver.Compact(o)

	fmt.Println("Before:", o)
	fmt.Println("After:", c)

}
Output:

Before: >3 <5 || >4
After: >3
Example (MatchAll)
package main

import (
	"fmt"

	"github.com/typisttech/comver"
)

func main() {
	o := comver.Or{
		comver.NewLessThan(comver.MustParse("3")),
		comver.NewGreaterThan(comver.MustParse("2")),
	}

	c := comver.Compact(o)

	fmt.Println("Before:", o)
	fmt.Println("After:", c)

}
Output:

Before: <3 || >2
After: *
Example (MatchAllTrumps)
package main

import (
	"fmt"

	"github.com/typisttech/comver"
)

func main() {
	o := comver.Or{
		comver.MustAnd(
			comver.NewLessThan(comver.MustParse("2")),
			comver.NewGreaterThan(comver.MustParse("1")),
		),
		comver.NewMatchAll(),
	}

	c := comver.Compact(o)

	fmt.Println("Before:", o)
	fmt.Println("After:", c)

}
Output:

Before: >1 <2 || *
After: *

type Endless added in v0.2.0

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

Endless represents a constraint that is either floor bounded, ceiling bounded, or match all. The zero value for Endless is a match all constraint which satisfied by any Version.

func NewGreaterThan added in v0.2.0

func NewGreaterThan(v Version) Endless

func NewGreaterThanOrEqualTo added in v0.2.0

func NewGreaterThanOrEqualTo(v Version) Endless

func NewLessThan added in v0.2.0

func NewLessThan(v Version) Endless

func NewLessThanOrEqualTo added in v0.2.0

func NewLessThanOrEqualTo(v Version) Endless

func NewMatchAll added in v0.3.0

func NewMatchAll() Endless

func (Endless) Check added in v0.2.0

func (b Endless) Check(v Version) bool

Check reports whether a Version satisfies the constraint.

func (Endless) String added in v0.2.0

func (b Endless) String() string

type ExactConstraint added in v0.2.0

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

func NewExactConstraint added in v0.2.0

func NewExactConstraint(v Version) ExactConstraint

func (ExactConstraint) Check added in v0.2.0

func (e ExactConstraint) Check(v Version) bool

Check reports whether a Version satisfies the constraint.

func (ExactConstraint) String added in v0.2.0

func (e ExactConstraint) String() string

type Or added in v0.2.0

Or represents a logical OR operation between multiple CeilingFloorConstrainter instances. The zero value for Or is a match none constraint which could never be satisfied.

func (Or) Check added in v0.2.0

func (o Or) Check(v Version) bool

Check reports whether a Version satisfies the constraint.

func (Or) String added in v0.2.0

func (o Or) String() string

type ParseError

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

func (ParseError) Error

func (e ParseError) Error() string

func (ParseError) Original

func (e ParseError) Original() string

func (ParseError) Unwrap

func (e ParseError) Unwrap() error

type Version

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

Version represents a single composer version. The zero value for Version is v0.0.0.0 with empty original string.

func MustParse added in v0.2.0

func MustParse(v string) Version

MustParse is like Parse but panics if the version string cannot be parsed.

func Parse added in v0.2.0

func Parse(v string) (Version, error)

Parse parses a given version string, attempts to coerce a version string into a Version object or return an error if unable to parse the version string.

If there is a leading v or a version listed without all parts (e.g. v1.2.p5+foo) it attempt to coerce it into a valid composer version (e.g. 1.2.0.0-patch5). In both cases a Version object is returned that can be sorted, compared, and used in constraints.

Due to implementation complexity, it only supports a subset of composer versioning. Refer to the version_test.go for examples.

Example
package main

import (
	"fmt"

	"github.com/typisttech/comver"
)

func main() {
	v, _ := comver.Parse("1.2.3")

	fmt.Println(v)
}
Output:

1.2.3.0
Example (Error)
package main

import (
	"fmt"

	"github.com/typisttech/comver"
)

func main() {
	_, err := comver.Parse("not a version")

	fmt.Println(err)
}
Output:

error parsing version string "not a version"
Example (Full)
package main

import (
	"fmt"

	"github.com/typisttech/comver"
)

func main() {
	v, _ := comver.Parse("1.2.3.4-beta.5+foo")

	fmt.Println(v)
}
Output:

1.2.3.4-beta5

func (Version) Compare

func (v Version) Compare(w Version) int

Compare returns an integer comparing two Version instances.

Pre-release versions are compared according to semantic version precedence. The result is 0 when v == w, -1 when v < w, or +1 when v > w.

Example
package main

import (
	"fmt"

	"github.com/typisttech/comver"
)

func main() {
	v1 := comver.MustParse("1")
	v2 := comver.MustParse("2")
	w2 := comver.MustParse("2")
	v3 := comver.MustParse("3")

	v2v1 := v2.Compare(v1)
	fmt.Println(v2v1)

	v2w2 := v2.Compare(w2)
	fmt.Println(v2w2)

	v2v3 := v2.Compare(v3)
	fmt.Println(v2v3)

}
Output:

1
0
-1
Example (Metadata)
package main

import (
	"fmt"

	"github.com/typisttech/comver"
)

func main() {
	foo := comver.MustParse("1.0.0+foo")
	bar := comver.MustParse("1.0.0+bar")

	got := foo.Compare(bar)

	fmt.Println(got)
}
Output:

0
Example (Patch)
package main

import (
	"fmt"

	"github.com/typisttech/comver"
)

func main() {
	v1 := comver.MustParse("1")
	v1p := comver.MustParse("1.patch")

	got := v1.Compare(v1p)

	fmt.Println(got)
}
Output:

-1
Example (PreRelease)
package main

import (
	"fmt"

	"github.com/typisttech/comver"
)

func main() {
	v1b5 := comver.MustParse("1.0.0-beta.5")
	v1b6 := comver.MustParse("1.0.0-beta.6")

	got := v1b5.Compare(v1b6)

	fmt.Println(got)
}
Output:

-1

func (Version) Original

func (v Version) Original() string

Original returns the original version string passed into Parse. Empty string is returned when Version is the zero value.

Example
package main

import (
	"fmt"

	"github.com/typisttech/comver"
)

func main() {
	ss := []string{
		"1",
		"1.2",
		"1.2.3",
		"1.2.3+foo",
		"1.2.3.4",
		"1.2.3.4.beta",
		"1.2.3.4-beta5",
		"1.2.3.4-beta5+foo",
		"1.b5+foo",
	}

	for _, s := range ss {
		v := comver.MustParse(s)
		got := v.Original()

		fmt.Printf("%-19q => %v\n", s, got)
	}

}
Output:

"1"                 => 1
"1.2"               => 1.2
"1.2.3"             => 1.2.3
"1.2.3+foo"         => 1.2.3+foo
"1.2.3.4"           => 1.2.3.4
"1.2.3.4.beta"      => 1.2.3.4.beta
"1.2.3.4-beta5"     => 1.2.3.4-beta5
"1.2.3.4-beta5+foo" => 1.2.3.4-beta5+foo
"1.b5+foo"          => 1.b5+foo

func (Version) Short

func (v Version) Short() string

Short returns the shortest string representation of the version.

Example
package main

import (
	"fmt"

	"github.com/typisttech/comver"
)

func main() {
	ss := []string{
		"1",
		"1.2",
		"1.2.3",
		"1.2.3+foo",
		"1.2.3.4",
		"1.2.3.4.beta",
		"1.2.3.4-beta5",
		"1.2.3.4-beta5+foo",
		"1.b5+foo",
	}

	for _, s := range ss {
		v := comver.MustParse(s)
		got := v.Short()

		fmt.Printf("%-19q => %v\n", s, got)
	}

}
Output:

"1"                 => 1
"1.2"               => 1.2
"1.2.3"             => 1.2.3
"1.2.3+foo"         => 1.2.3
"1.2.3.4"           => 1.2.3.4
"1.2.3.4.beta"      => 1.2.3.4-beta
"1.2.3.4-beta5"     => 1.2.3.4-beta5
"1.2.3.4-beta5+foo" => 1.2.3.4-beta5
"1.b5+foo"          => 1-beta5

func (Version) String

func (v Version) String() string

String returns the normalized string representation of the version.

Jump to

Keyboard shortcuts

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