1// Package fqname provides utilities for handling fully qualified identifiers in2// Gno. A fully qualified identifier typically includes a package path followed3// by a dot (.) and then the name of a variable, function, type, or other4// package-level declaration.5package fqname67import (8 "strings"9)1011// Parse splits a fully qualified identifier into its package path and name12// components. It handles cases with and without slashes in the package path.13//14// pkgpath, name := fqname.Parse("gno.land/p/nt/avl/v0.Tree")15// ufmt.Sprintf("Package: %s, Name: %s\n", id.Package, id.Name)16// // Output: Package: gno.land/p/nt/avl/v0, Name: Tree17func Parse(fqname string) (pkgpath, name string) {18 // Find the index of the last slash.19 lastSlashIndex := strings.LastIndex(fqname, "/")20 if lastSlashIndex == -1 {21 // No slash found, handle it as a simple package name with dot notation.22 dotIndex := strings.LastIndex(fqname, ".")23 if dotIndex == -1 {24 return fqname, ""25 }26 return fqname[:dotIndex], fqname[dotIndex+1:]27 }2829 // Get the part after the last slash.30 afterSlash := fqname[lastSlashIndex+1:]3132 // Check for a dot in the substring after the last slash.33 dotIndex := strings.Index(afterSlash, ".")34 if dotIndex == -1 {35 // No dot found after the last slash36 return fqname, ""37 }3839 // Split at the dot to separate the base and the suffix.40 base := fqname[:lastSlashIndex+1+dotIndex]41 suffix := afterSlash[dotIndex+1:]4243 return base, suffix44}4546// Construct a qualified identifier.47//48// fqName := fqname.Construct("gno.land/r/demo/foo20", "Token")49// fmt.Println("Fully Qualified Name:", fqName)50// // Output: gno.land/r/demo/foo20.Token51func Construct(pkgpath, name string) string {52 // TODO: ensure pkgpath is valid - and as such last part does not contain a dot.53 if name == "" {54 return pkgpath55 }56 return pkgpath + "." + name57}5859// RenderLink creates a formatted link for a fully qualified identifier.60// If the package path starts with "gno.land", it converts it to a markdown link.61// If the domain is different or missing, it returns the input as is.62func RenderLink(pkgPath, slug string) string {63 if strings.HasPrefix(pkgPath, "gno.land") {64 pkgLink := strings.TrimPrefix(pkgPath, "gno.land")65 if slug != "" {66 safeSlug := escapeMarkdown(slug)67 return "[" + pkgPath + "](" + pkgLink + ")." + safeSlug68 }6970 return "[" + pkgPath + "](" + pkgLink + ")"71 }7273 if slug != "" {74 safeSlug := escapeMarkdown(slug)75 return pkgPath + "." + safeSlug76 }7778 return pkgPath79}8081// escapeMarkdown escapes characters that could break markdown link syntax.82func escapeMarkdown(s string) string {83 r := strings.NewReplacer(84 "[", `\[`,85 "]", `\]`,86 "(", `\(`,87 ")", `\)`,88 )89 return r.Replace(s)90}91Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.