PathrockNetwork Gno Explorer
HomeBlocksTransactionsTokensRealmsPackagesValidatorsAnalytics

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/r/moul/x/daily/semverdemo/v0

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
v0
Namespace
moul / x / daily / semverdemo
Files
3 (README)(gnomod.toml)
Exported functions
2
Module
gno.land/r/moul/x/daily/semverdemo/v0
gno
0.9

Files (3)

  • README.mdmarkdown
  • gnomod.tomltoml
  • semverdemo.gnogno
semverdemo.gnogno
1// Package semverdemo is a small on-chain demo of the semantic-versioning2// parser/comparator provided by the3// [p/moul/x/daily/semver](/p/moul/x/daily/semver/v0) library.4//5// It holds the realm state the pure library deliberately does not: a6// "submitted versions" board (an avl tree of version string -> submitter7// address) that anyone can post to with [Submit], plus a gnoweb [Render] view8// that lists them in SemVer precedence order and compares arbitrary pairs. All9// parsing and comparison math lives in the library; this realm is just the10// on-chain wiring and the view.11package semverdemo1213import (14	"sort"15	"strconv"16	"strings"1718	"chain"19	"chain/runtime/unsafe"2021	"gno.land/p/moul/x/daily/semver/v0"22	"gno.land/p/nt/avl/v0"23)2425// submitted holds versions users have posted on-chain: version string -> submitter.26var submitted = avl.NewTree()2728// Submit stores a valid version on-chain, tagged with the caller's address, so29// Render("/sorted") can list everyone's submissions in precedence order. It30// validates the input with [semver.Parse] and panics on anything malformed.31func Submit(cur realm, version string) {32	if _, err := semver.Parse(version); err != nil {33		panic("invalid semantic version: " + version)34	}35	who := unsafe.PreviousRealm().Address()36	submitted.Set(version, who.String())37	chain.Emit("VersionSubmitted", "version", version, "by", who.String())38}3940// ---- Render ----------------------------------------------------------------4142func Render(path string) string {43	path = strings.TrimPrefix(path, "/")44	switch {45	case path == "":46		return renderHome()47	case path == "sorted":48		return renderSorted()49	default:50		parts := strings.SplitN(path, "/", 2)51		if len(parts) != 2 {52			return renderHome()53		}54		return renderCompare(parts[0], parts[1])55	}56}5758func renderHome() string {59	var b strings.Builder60	b.WriteString("# semver — Semantic Versioning on-chain\n\n")61	b.WriteString("Demo of the [`p/moul/x/daily/semver`](/p/moul/x/daily/semver/v0) ")62	b.WriteString("library — a port of `golang.org/x/mod/semver`. Parse ")63	b.WriteString("`vMAJOR.MINOR.PATCH[-prerelease][+build]` and compare with ")64	b.WriteString("SemVer 2.0.0 precedence.\n\n")6566	b.WriteString("## Examples\n\n")67	b.WriteString("| a | rel | b | note |\n|---|:---:|---|---|\n")68	examples := [][2]string{69		{"1.2.3", "1.2.10"},70		{"1.0.0-alpha", "1.0.0"},71		{"1.0.0-alpha.1", "1.0.0-alpha.beta"},72		{"1.0.0-rc.1", "1.0.0"},73		{"2.0.0", "2.0.0+build.5"},74	}75	notes := []string{76		"numeric patch, not lexical",77		"pre-release < release",78		"numeric id < alphanumeric id",79		"release candidate < final",80		"build metadata ignored",81	}82	for i, ex := range examples {83		b.WriteString("| `" + ex[0] + "` | " + relSym(semver.Compare(ex[0], ex[1])) +84			" | `" + ex[1] + "` | " + notes[i] + " |\n")85	}8687	b.WriteString("\n## Try it\n\n")88	b.WriteString("- Compare two versions: [`/1.2.3/1.2.10`](/r/moul/x/daily/semverdemo/v0:1.2.3/1.2.10)\n")89	b.WriteString("- Submitted list: [`/sorted`](/r/moul/x/daily/semverdemo/v0:sorted)\n")90	b.WriteString("- Submit on-chain: `Submit(\"v1.4.2\")`\n")91	return b.String()92}9394func renderCompare(a, b string) string {95	var sb strings.Builder96	sb.WriteString("# Compare\n\n")97	sb.WriteString(describe("A", a))98	sb.WriteString(describe("B", b))99100	_, ea := semver.Parse(a)101	_, eb := semver.Parse(b)102	if ea != nil || eb != nil {103		sb.WriteString("\n> One or both inputs are not valid semver.\n")104		return sb.String()105	}106	c := semver.Compare(a, b)107	sb.WriteString("\n## Result\n\n")108	sb.WriteString("`" + a + "` **" + word(c) + "** `" + b + "`  ")109	sb.WriteString("→ `Compare = " + strconv.Itoa(c) + "`\n")110	return sb.String()111}112113func describe(label, s string) string {114	v, err := semver.Parse(s)115	if err != nil {116		return "## " + label + ": `" + s + "`\n\n> invalid\n\n"117	}118	pre := "—"119	if len(v.Pre) > 0 {120		pre = "`" + strings.Join(v.Pre, ".") + "`"121	}122	build := "—"123	if v.Build != "" {124		build = "`" + v.Build + "`"125	}126	return "## " + label + ": `" + v.Canonical() + "`\n\n" +127		"| major | minor | patch | pre | build |\n|---|---|---|---|---|\n" +128		"| " + strconv.Itoa(v.Major) + " | " + strconv.Itoa(v.Minor) + " | " + strconv.Itoa(v.Patch) +129		" | " + pre + " | " + build + " |\n\n"130}131132func renderSorted() string {133	var es []entry134	// Capture the submitter straight from Iterate's callback value, avoiding a135	// separate avl.Get whose arity differs across gno versions.136	submitted.Iterate("", "", func(key string, value any) bool {137		if v, err := semver.Parse(key); err == nil {138			who, _ := value.(string)139			es = append(es, entry{v: v, who: who})140		}141		return false142	})143	if len(es) == 0 {144		return "# Submitted versions\n\n_None yet._ Call `Submit(\"v1.0.0\")` to add one.\n"145	}146	sort.Stable(byPrecedence(es))147148	var b strings.Builder149	b.WriteString("# Submitted versions (lowest → highest)\n\n")150	b.WriteString("| # | version | submitter |\n|---|---|---|\n")151	for i, e := range es {152		b.WriteString("| " + strconv.Itoa(i+1) + " | `" + e.v.Canonical() + "` | `" + e.who + "` |\n")153	}154	return b.String()155}156157// entry pairs a parsed version with the address that submitted it.158type entry struct {159	v   semver.Version160	who string161}162163// byPrecedence sorts entries ascending. `sort` on-chain has no Slice helper,164// so we implement sort.Interface; ordering defers to semver.Compare on the165// original strings.166type byPrecedence []entry167168func (p byPrecedence) Len() int { return len(p) }169func (p byPrecedence) Less(i, j int) bool {170	return semver.Compare(p[i].v.Orig, p[j].v.Orig) < 0171}172func (p byPrecedence) Swap(i, j int) { p[i], p[j] = p[j], p[i] }173174func relSym(c int) string {175	switch {176	case c < 0:177		return "&lt;"178	case c > 0:179		return "&gt;"180	}181	return "="182}183184func word(c int) string {185	switch {186	case c < 0:187		return "<"188	case c > 0:189		return ">"190	}191	return "=="192}193

Functions

  • Render(path string) string

  • Submit(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, version string)

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

Rendered

RenderedRawgnoweb ↗

vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.