PathrockNetwork Gno Explorer
HomeBlocksTransactionsRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/p/moul/x/daily/semver/v0

Package
Open in gnoweb ↗

Overview

Kind
Pure package
Name
v0
Namespace
moul / x / daily / semver
Files
3 (README)(gnomod.toml)
Exported functions
n/a — not supported for pure packages by the node (vm/qfuncs)
Module
gno.land/p/moul/x/daily/semver/v0
gno
0.9

Files (3)

  • README.mdmarkdown
  • gnomod.tomltoml
  • semver.gnogno
semver.gnogno
1// Package semver is an on-chain port of the core of golang.org/x/mod/semver2// (and the spirit of github.com/Masterminds/semver): parse "vMAJOR.MINOR.PATCH3// [-prerelease][+build]" strings and compare them with correct Semantic4// Versioning 2.0.0 precedence. Pure and deterministic — no time, randomness,5// goroutines, or I/O.6//7// This package holds only the pure parsing/comparison API. For a live,8// stateful gnoweb demo that imports it and keeps an on-chain "submitted9// versions" board, see10// [r/moul/x/daily/semverdemo](/r/moul/x/daily/semverdemo/v0).11package semver1213import (14	"errors"15	"strings"16)1718// Version is a parsed semantic version. Build metadata is retained for display19// but, per the spec, is ignored when comparing precedence.20type Version struct {21	Major, Minor, Patch int22	Pre                 []string // pre-release identifiers (dot-separated)23	Build               string   // build metadata (after '+')24	Orig                string   // original input25}2627var errBadVersion = errors.New("invalid semantic version")2829// Parse reads "vMAJOR.MINOR.PATCH[-prerelease][+build]". The leading 'v' is30// optional. Numeric fields must be non-empty digit runs without leading zeros.31func Parse(s string) (Version, error) {32	v := Version{Orig: s}33	body := strings.TrimPrefix(s, "v")3435	if i := strings.IndexByte(body, '+'); i >= 0 {36		v.Build = body[i+1:]37		body = body[:i]38		if v.Build == "" {39			return Version{}, errBadVersion40		}41	}42	if i := strings.IndexByte(body, '-'); i >= 0 {43		pre := body[i+1:]44		body = body[:i]45		v.Pre = strings.Split(pre, ".")46		for _, id := range v.Pre {47			if !validPreIdent(id) {48				return Version{}, errBadVersion49			}50		}51	}5253	parts := strings.Split(body, ".")54	if len(parts) != 3 {55		return Version{}, errBadVersion56	}57	nums := [3]int{}58	for i, p := range parts {59		n, ok := parseNum(p)60		if !ok {61			return Version{}, errBadVersion62		}63		nums[i] = n64	}65	v.Major, v.Minor, v.Patch = nums[0], nums[1], nums[2]66	return v, nil67}6869// Compare returns -1, 0, or +1 as a < b, a == b, or a > b under semver70// precedence. Unparseable inputs sort after everything valid (and equal to71// each other), so Compare never panics.72func Compare(a, b string) int {73	va, ea := Parse(a)74	vb, eb := Parse(b)75	switch {76	case ea != nil && eb != nil:77		return 078	case ea != nil:79		return 180	case eb != nil:81		return -182	}83	return va.compare(vb)84}8586func (v Version) compare(o Version) int {87	if c := cmpInt(v.Major, o.Major); c != 0 {88		return c89	}90	if c := cmpInt(v.Minor, o.Minor); c != 0 {91		return c92	}93	if c := cmpInt(v.Patch, o.Patch); c != 0 {94		return c95	}96	return comparePre(v.Pre, o.Pre)97}9899// comparePre implements SemVer §11: a version WITH a pre-release has lower100// precedence than the same version WITHOUT one.101func comparePre(a, b []string) int {102	if len(a) == 0 && len(b) == 0 {103		return 0104	}105	if len(a) == 0 { // a is a release, b is a pre-release106		return 1107	}108	if len(b) == 0 {109		return -1110	}111	for i := 0; i < len(a) && i < len(b); i++ {112		if c := compareIdent(a[i], b[i]); c != 0 {113			return c114		}115	}116	return cmpInt(len(a), len(b))117}118119// compareIdent: numeric identifiers compare numerically and always rank below120// alphanumeric ones; alphanumerics compare in ASCII order.121func compareIdent(a, b string) int {122	an, aNum := parseNum(a)123	bn, bNum := parseNum(b)124	switch {125	case aNum && bNum:126		return cmpInt(an, bn)127	case aNum:128		return -1129	case bNum:130		return 1131	}132	return strings.Compare(a, b)133}134135func cmpInt(a, b int) int {136	switch {137	case a < b:138		return -1139	case a > b:140		return 1141	}142	return 0143}144145// parseNum accepts a non-empty run of ASCII digits with no leading zero (except146// "0" itself), returning the value and whether it qualified.147func parseNum(s string) (int, bool) {148	if s == "" {149		return 0, false150	}151	if len(s) > 1 && s[0] == '0' {152		return 0, false153	}154	n := 0155	for i := 0; i < len(s); i++ {156		c := s[i]157		if c < '0' || c > '9' {158			return 0, false159		}160		n = n*10 + int(c-'0')161	}162	return n, true163}164165// validPreIdent allows [0-9A-Za-z-] and rejects empty identifiers.166func validPreIdent(s string) bool {167	if s == "" {168		return false169	}170	for i := 0; i < len(s); i++ {171		c := s[i]172		ok := (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||173			(c >= 'A' && c <= 'Z') || c == '-'174		if !ok {175			return false176		}177	}178	return true179}180181// Canonical renders the parsed version back to a canonical string.182func (v Version) Canonical() string {183	s := ufmt(v.Major) + "." + ufmt(v.Minor) + "." + ufmt(v.Patch)184	if len(v.Pre) > 0 {185		s += "-" + strings.Join(v.Pre, ".")186	}187	if v.Build != "" {188		s += "+" + v.Build189	}190	return s191}192193func ufmt(n int) string {194	if n == 0 {195		return "0"196	}197	var b []byte198	for n > 0 {199		b = append([]byte{byte('0' + n%10)}, b...)200		n /= 10201	}202	return string(b)203}204

Functions

not supported for pure packages by the node (vm/qfuncs)

Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.