util

package
v0.3.0-alpha.1 Latest Latest
Warning

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

Go to latest
Published: Aug 26, 2026 License: MIT Imports: 19 Imported by: 2

README

util

Small, generic helpers shared across gokit — collections, pointers, string casing and sanitization, secret redaction, environment access, hashing, byte/duration formatting, and templates. It is the scoped foundation owner for helpers too small for their own package; reach for the standard library (slices, maps, cmp) or a dedicated owner (fs, codec) first.

Install

go get github.com/kbukum/gokit

Quick Start

package main

import (
    "fmt"
    "github.com/kbukum/gokit/util"
)

func main() {
    // Pointer helpers
    name := util.Ptr("hello")
    fmt.Println(util.Deref(name)) // "hello"

    // Slice utilities
    nums := []int{1, 2, 3, 2, 1}
    unique := util.Unique(nums)                                     // [1, 2, 3]
    even := util.Filter(nums, func(n int) bool { return n%2 == 0 }) // [2, 2]

    // String sanitization and casing
    safe := util.IsSafeString("SELECT * FROM users") // false
    snake := util.ToSnakeCase("camelCaseString") // "camel_case_string"

    // Human-readable sizes and durations
    fmt.Println(util.FormatBytes(1536)) // "1.5 KiB"

    // Environment access with a typed fallback
    debug := util.GetEnvBool("DEBUG", false)
    _ = debug
}

Key Types & Functions

Name Description
Ptr[T]() / Deref[T]() Pointer creation and safe dereference
Contains[T]() / Filter[T]() / Map[T,U]() / Unique[T]() Generic slice operations
Chunk[T]() / Partition[T]() / GroupBy[T,K]() / IndexBy[T,K]() Slice partitioning and indexing
Keys[K,V]() / Values[K,V]() / DeepMerge() / Coalesce[T]() Map utilities and first-non-zero
ToSnakeCase() / ToKebabCase() / ToCamelCase() String casing
Truncate() / TruncateEllipsis() Byte-bounded, rune-safe truncation
SanitizeString() / SanitizeEnvValue() / IsSafeString() Input sanitization and SQL/XSS detection
SecretString / SecretKeyMatcher / MaskSecret() In-memory secret redaction (crypto lives in encryption)
GetEnv() / GetEnvOr() / GetEnvBool() / GetEnvParsed[T]() Environment variable access
ContentHasher / Sha256Hex() / HashHex() / Sha256Reader() Content hashing
FormatBytes() / ParseBytes() / ParseSize() Human-readable byte sizes
FormatDuration() / ParseDuration() / TimeIt[T]() Duration formatting and timing
Clock / NewFakeClock() Injectable clock for deterministic tests
GlobMatch() / NewGlob() / HasWildcard() Glob pattern matching
Nearest() / NearestWithin() / ResolveUnique[T]() Fuzzy suggestion and unique resolution
ParseTemplate[P]() / ParseDynamicTemplate() Placeholder template parsing

⬅ Back to main README

Documentation

Overview

Package util provides small, generic helpers shared across gokit — the scoped foundation owner for capabilities too small to deserve their own package, never a dumping ground. Prefer the modern standard library (slices, maps, cmp) first and a dedicated owner (fs for filesystem, codec for formats) where one exists.

The helpers group by concern:

  • Collections: Contains, Filter, Map, Unique, Chunk, Partition, GroupBy, IndexBy, Keys, Values, Coalesce, DeepMerge, and uniqueness checks.
  • Pointers: Ptr and Deref.
  • Strings: casing (ToSnakeCase, ToKebabCase, ToCamelCase), Truncate/TruncateEllipsis, glob matching (GlobMatch, NewGlob), and fuzzy lookup (Nearest, ResolveUnique).
  • Sanitization: SanitizeString, SanitizeEnvValue, and IsSafeString boundary checks.
  • Secrets: SecretString and SecretKeyMatcher for in-memory redaction, plus MaskSecret. Cryptography stays in the encryption and security packages.
  • Environment: GetEnv, GetEnvOr, GetEnvBool, and typed GetEnvParsed.
  • Hashing: ContentHasher and the Sha256Hex/HashHex/Sha256Reader helpers.
  • Sizes and time: FormatBytes/ParseBytes, FormatDuration/ParseDuration, TimeIt, and the injectable Clock (with FakeClock for deterministic tests).
  • Templates: ParseTemplate and ParseDynamicTemplate for placeholder substitution.

Index

Constants

View Source
const DefaultSuggestionDistance = 2

DefaultSuggestionDistance is the default maximum edit distance for a suggestion to be offered. Two catches single transpositions, one insertion plus one deletion, and most realistic typos while rejecting unrelated tokens.

Variables

View Source
var DefaultSecretKeyNames = []string{
	"password",
	"passwd",
	"pwd",
	"token",
	"secret",
	"credential",
	"credentials",
	"apikey",
	"api_key",
	"auth",
	"authorization",
	"auth_token",
	"access_token",
	"refresh_token",
	"client_secret",
}

DefaultSecretKeyNames are the key names SecretKeyMatcher treats as secret-bearing by default. They cover the common credential and token spellings seen in config keys and CLI flags.

Functions

func Chunk

func Chunk[T any](items []T, size int) [][]T

Chunk splits items into consecutive chunks of at most size elements. A size of zero or less returns nil.

func Coalesce

func Coalesce[T comparable](values ...T) T

Coalesce returns the first non-zero value, or the zero value if all are zero.

func ConstantTimeEqual

func ConstantTimeEqual(left, right []byte) bool

ConstantTimeEqual reports whether two byte slices are equal, comparing in constant time to avoid a timing side channel. Length is not secret: a length mismatch returns false quickly, so prefer fixed-length encodings for sensitive tokens.

func Contains

func Contains[T comparable](slice []T, val T) bool

Contains checks if a slice contains a value.

func CopyDir

func CopyDir(src, dst string) error

CopyDir recursively copies a directory tree from src to dst. It preserves file permissions, modification times, and symlinks. dst must not be inside src; passing an overlapping dst returns an error.

func CopyFile

func CopyFile(src, dst string) error

CopyFile copies a single file from src to dst, preserving permissions and modification times. Both src and dst are resolved through symlinks (os.Stat / os.Open follow symlinks), so if src is a symlink its target's content is copied; if dst is an existing symlink the link target is overwritten. Use CopyDir to copy directory trees (symlinks inside are recreated as symlinks, not followed). Parent directories of dst are created as needed.

func DeepMerge

func DeepMerge(base, override map[string]any) map[string]any

DeepMerge recursively merges override into base, treating both as decoded JSON/YAML documents. When both values for a key are map[string]any they are merged recursively; otherwise the override value replaces the base. Neither input is mutated.

The map[string]any type is a deliberate, documented opaque-value exception to the no-any rule: the function operates on genuinely heterogeneous document trees whose leaf values cannot be given a closed type.

func Deref

func Deref[T any](p *T) T

Deref returns the value pointed to by p, or the zero value if p is nil.

func DirExists

func DirExists(path string) bool

DirExists reports whether path exists and is a directory.

func ElapsedMillis

func ElapsedMillis(start, end uint64) uint64

ElapsedMillis returns the non-negative elapsed milliseconds between two monotonic millisecond readings, saturating at zero when end precedes start.

func EnsureDir

func EnsureDir(path string) error

EnsureDir creates a directory and all parents if they don't exist.

func EnsureUniqueBy

func EnsureUniqueBy[T any, K comparable](items []T, key func(T) K) error

EnsureUniqueBy returns a *DuplicateKeyError for the first duplicated key, or nil when every item's key is unique.

func FileExists

func FileExists(path string) bool

FileExists reports whether path exists and is a regular file.

func Filter

func Filter[T any](slice []T, predicate func(T) bool) []T

Filter returns a new slice containing only elements that satisfy the predicate.

func FindDuplicatesBy

func FindDuplicatesBy[T any, K comparable](items []T, key func(T) K) []K

FindDuplicatesBy returns the keys that occur more than once, in first-seen order.

func FormatBytes

func FormatBytes(bytes uint64) string

FormatBytes renders a byte count using binary (1024-based) units, choosing the largest unit for which the value is at least one and trimming trailing zeros.

FormatBytes(1536) == "1.5 KiB"
FormatBytes(1048576) == "1 MiB"

func FormatDuration

func FormatDuration(d time.Duration) string

FormatDuration renders d as a human-readable string, choosing the largest unit for which the value reads naturally: hours and minutes with two decimals, seconds with two decimals down to one second, then integer milliseconds, microseconds ("μs"), or nanoseconds.

FormatDuration(5 * time.Second) == "5.00s"
FormatDuration(152 * time.Millisecond) == "152ms"

func GetEnv

func GetEnv(key string) (string, bool)

GetEnv reads a string environment variable, returning ("", false) when it is unset.

func GetEnvBool

func GetEnvBool(key string, fallback bool) bool

GetEnvBool reads a boolean environment variable, recognizing "true", "1", "yes", and "on" as true and "false", "0", "no", and "off" as false (case-insensitively, trimmed). It returns fallback when the variable is unset or unrecognized.

func GetEnvNonEmpty

func GetEnvNonEmpty(key string) (string, bool)

GetEnvNonEmpty reads a string environment variable, treating an empty value as unset.

func GetEnvOr

func GetEnvOr(key, fallback string) string

GetEnvOr reads a string environment variable, returning fallback when it is unset.

func GetEnvParsed

func GetEnvParsed[T any](key string, parse func(string) (T, error)) (T, bool)

GetEnvParsed reads an environment variable and parses it with parse, returning (zero, false) when the variable is unset or parsing fails.

func GlobMatch

func GlobMatch(pattern, text string) bool

GlobMatch reports whether pattern matches text, treating '*' and '?' as wildcards.

'*' matches any run of characters (including none) and '?' matches exactly one character; every other character matches itself. Matching is rune-oriented and case-sensitive, with no path or separator semantics, so it composes over identifiers, names, or topic segments. The two-pointer algorithm uses constant backtracking state (worst case O(len(pattern)*len(text)), never exponential).

func GroupBy

func GroupBy[T any, K comparable](items []T, key func(T) K) map[K][]T

GroupBy groups items into slices keyed by the key function, preserving order.

func HasWildcard

func HasWildcard(pattern string) bool

HasWildcard reports whether pattern contains any wildcard metacharacter ('*' or '?').

func HashHex

func HashHex(bytes []byte) string

HashHex returns the lowercase-hex BLAKE3 content digest of a single byte slice.

func IndexBy

func IndexBy[T any, K comparable](items []T, key func(T) K) map[K]T

IndexBy indexes items by the key function. On duplicate keys the last item wins.

func IsSafeString

func IsSafeString(s string) bool

IsSafeString checks whether s passes basic input validation. It is NOT a security boundary — use parameterized queries for SQL and proper encoding for HTML output. This only catches the most obvious injection patterns and is intended as an additional defense-in-depth signal, not a primary safeguard.

func Keys

func Keys[K comparable, V any](m map[K]V) []K

Keys returns the keys of a map.

func Map

func Map[T, U any](slice []T, transform func(T) U) []U

Map transforms a slice using the given function.

func MaskSecret

func MaskSecret(s string, visiblePrefix int) string

MaskSecret hides sensitive parts of a string for safe display in logs. If the string is shorter than visiblePrefix, it is fully masked.

func Nearest

func Nearest(input string, candidates []string) (string, bool)

Nearest returns the candidate nearest to input within DefaultSuggestionDistance, or "" and false when none is close enough.

Nearest("fmt", []string{"format", "test", "lint"}) == ("format", true)

func NearestWithin

func NearestWithin(input string, candidates []string, maxDistance int) (string, bool)

NearestWithin returns the candidate nearest to input within maxDistance edits.

Matching is case-insensitive. A candidate qualifies either by an Optimal String Alignment (restricted Damerau-Levenshtein) distance within maxDistance — counting an adjacent transposition as a single edit — or, as a fallback, by being an abbreviation of input (input of at least two characters is a subsequence of a candidate no more than four times its length, e.g. "fmt" → "format"). Ties break toward a candidate sharing input's leading character, then lexicographically, so the result is deterministic regardless of iteration order.

func ParseBytes

func ParseBytes(input string) (uint64, error)

ParseBytes parses a human byte size into a raw byte count. It accepts an optional decimal magnitude followed by an optional unit; a bare number is bytes. Units are binary (1024-based) and case-insensitive, accepting the full forms (KiB, MiB, GiB, TiB, PiB), the ambiguous decimal-looking spellings (KB, MB, …), and the short aliases (k, ki, m, mi, g, gi, t, ti, p, pi, b). Whitespace between the number and unit is optional.

ParseBytes("1.5 KiB") == (1536, nil)
ParseBytes("10mb") == (10485760, nil)

func ParseDuration

func ParseDuration(s string) (time.Duration, bool)

ParseDuration parses a duration string such as "5s", "10m", or "1.5h" into a time.Duration. Parsing is case-insensitive, allows optional whitespace before the unit, and treats a unit-less value as seconds. Recognized units are ns, us/μs, ms, s, m/min, h/hr, and d/day. It returns (0, false) on an unknown unit, a negative or malformed magnitude, or overflow.

ParseDuration("5") == (5*time.Second, true)
ParseDuration("10m") == (10*time.Minute, true)

func ParseSize

func ParseSize(s string, defaultBytes int64) int64

ParseSize parses a human-readable size string (e.g. "10MB", "512KB", "2GB") into bytes. Returns defaultBytes if the string cannot be parsed.

func Partition

func Partition[T any](items []T, pred func(T) bool) (matched, rest []T)

Partition splits items into those satisfying pred and the rest, preserving order.

func Ptr

func Ptr[T any](v T) *T

Ptr returns a pointer to the given value.

func ReadFileString

func ReadFileString(path string) (string, error)

ReadFileString reads a file and returns its content as a string.

func RemoveAll

func RemoveAll(path string) error

RemoveAll removes path and any children. It does not return an error if path doesn't exist.

func ResolveUnique

func ResolveUnique[T any](input string, candidates []T, keyOf func(T) string) (match T, found bool, err error)

ResolveUnique resolves input to the unique candidate whose key equals it.

keyOf projects each candidate to the string compared against input. Comparison is exact and case-sensitive. It returns (candidate, true, nil) when exactly one candidate matches, (zero, false, nil) when none do, and (zero, false, *Ambiguity) when two or more share the key. Callers wanting fuzzy resolution use Nearest.

func SanitizeEnvValue

func SanitizeEnvValue(s string) string

SanitizeEnvValue cleans an environment variable value by removing surrounding quotes and trimming whitespace.

func SanitizeString

func SanitizeString(s string) string

SanitizeString trims whitespace and removes control characters from s.

func Sha256Hex

func Sha256Hex(bytes []byte) string

Sha256Hex returns the lowercase-hex SHA-256 digest of a byte slice. SHA-256 is for wire-format and interop use cases only; prefer HashHex (BLAKE3) for internal identity.

func Sha256Reader

func Sha256Reader(reader io.Reader) (string, error)

Sha256Reader computes the lowercase-hex SHA-256 digest of a stream, reading in bounded chunks so large inputs never need to be fully resident in memory.

func TimeIt

func TimeIt[T any](fn func() T) (T, time.Duration)

TimeIt runs fn and returns its result alongside the wall-clock time it took.

func ToCamelCase

func ToCamelCase(s string) string

ToCamelCase converts a string to camelCase, treating '_', '-', and ' ' as word boundaries and lowercasing the leading character.

ToCamelCase("snake_case_string") == "snakeCaseString"
ToCamelCase("Kebab-Case-String") == "kebabCaseString"

func ToKebabCase

func ToKebabCase(s string) string

ToKebabCase converts a string to kebab-case, collapsing runs of separators and inserting hyphens before interior uppercase letters.

ToKebabCase("camelCaseString") == "camel-case-string"

func ToSnakeCase

func ToSnakeCase(s string) string

ToSnakeCase converts a string to snake_case, collapsing runs of separators and inserting underscores before interior uppercase letters.

ToSnakeCase("camelCaseString") == "camel_case_string"
ToSnakeCase("Kebab-Case-String") == "kebab_case_string"

func Truncate

func Truncate(s string, maxBytes int) string

Truncate returns a UTF-8-safe prefix of s sized for TruncateEllipsis. When truncation is needed the prefix is at most maxBytes-3 bytes, reserving space for the ellipsis TruncateEllipsis appends. A rune is never split.

Truncate("hello world", 8) == "hello"
Truncate("hello", 10) == "hello"

func TruncateEllipsis

func TruncateEllipsis(s string, maxBytes int) string

TruncateEllipsis truncates s to at most maxBytes bytes, appending "..." when truncation occurs and maxBytes > 3. For smaller limits the result is maxBytes dots, because there is no room for the full ellipsis.

TruncateEllipsis("hello world", 8) == "hello..."

func Unique

func Unique[T comparable](slice []T) []T

Unique returns a slice with duplicate values removed, preserving order.

func Values

func Values[K comparable, V any](m map[K]V) []V

Values returns the values of a map.

func WriteFile

func WriteFile(path string, data []byte) error

WriteFile writes content to path, creating parent directories as needed. Uses 0o644 permissions for the file.

Types

type Ambiguity

type Ambiguity[T any] struct {
	// Input is the shorthand that matched more than one candidate.
	Input string
	// Matches are every candidate whose key equalled Input, in encounter order.
	Matches []T
}

Ambiguity carries the candidates a shorthand matched when more than one qualified.

func (*Ambiguity[T]) Error

func (a *Ambiguity[T]) Error() string

Error implements error, rendering an actionable "did you mean one of …?" message.

type Clock

type Clock interface {
	Now() time.Time
}

Clock abstracts time for deterministic testing.

type ContentHasher

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

ContentHasher is an incremental content hasher producing a stable lowercase-hex digest, backed by BLAKE3. Feed bytes with Update (raw) or UpdateFramed (domain-separated), then read the digest with FinalizeHex. Finalizing does not consume the hasher, so it may be reused. BLAKE3 is the canonical content hash for cache keys, change detection, and deduplication; the digest identity matches the rskit and pykit content hashers.

func NewContentHasher

func NewContentHasher() *ContentHasher

NewContentHasher creates an empty content hasher.

func (*ContentHasher) FinalizeHex

func (h *ContentHasher) FinalizeHex() string

FinalizeHex renders the current digest as a 64-character lowercase hex string. It does not consume the hasher: further updates may follow and produce a new digest.

func (*ContentHasher) Update

func (h *ContentHasher) Update(bytes []byte) *ContentHasher

Update folds bytes into the digest verbatim, without framing, returning the hasher for chaining.

func (*ContentHasher) UpdateFramed

func (h *ContentHasher) UpdateFramed(label, value []byte) *ContentHasher

UpdateFramed folds a labeled value into the digest with unambiguous framing. Each of label and value is folded length-prefixed (its length as a little-endian uint64, then its bytes), so field boundaries stay unambiguous even when inputs contain arbitrary bytes; independently folded fields cannot alias one another. Returns the hasher for chaining.

type DuplicateKeyError

type DuplicateKeyError[K comparable] struct {
	Key K
}

DuplicateKeyError reports the first duplicated key found by EnsureUniqueBy.

func (*DuplicateKeyError[K]) Error

func (e *DuplicateKeyError[K]) Error() string

type DynamicTemplate

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

DynamicTemplate is a parsed "{{var}}" template with an open set of named variables resolved at render time. Unlike Template, whose placeholders are a fixed typed set known at compile time, a DynamicTemplate carries data-driven variable names looked up against a caller-supplied function. Parsing is lenient: names may be padded with whitespace ("{{ name }}" equals "{{name}}"), and any run that is not a well-formed placeholder is preserved verbatim. Use it for prompt-style templates.

func ParseDynamicTemplate

func ParseDynamicTemplate(template string) DynamicTemplate

ParseDynamicTemplate parses template. Parsing never fails: malformed "{{"/"}}" runs and invalid names are kept as literal text.

func (DynamicTemplate) Render

func (t DynamicTemplate) Render(lookup func(name string) (string, bool)) (string, error)

Render resolves each variable through lookup, which returns the value and whether it was found. A variable with no value yields a TemplateError of kind TemplateErrorMissingVariable.

func (DynamicTemplate) Variables

func (t DynamicTemplate) Variables() []string

Variables returns the sorted, de-duplicated set of variable names the template references.

type FakeClock

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

FakeClock is a deterministic clock for tests.

func NewFakeClock

func NewFakeClock(initial time.Time) *FakeClock

NewFakeClock creates a FakeClock starting at the given time. If zero, defaults to 2024-01-01T00:00:00Z.

func (*FakeClock) Advance

func (c *FakeClock) Advance(d time.Duration)

Advance moves the clock forward by d.

func (*FakeClock) Now

func (c *FakeClock) Now() time.Time

Now returns the fake clock's current time.

func (*FakeClock) Set

func (c *FakeClock) Set(t time.Time)

Set sets the clock to an absolute time.

type Glob

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

Glob is a compiled glob pattern that can be matched against many candidates. A wildcard pattern is parsed once; a plain literal keeps no parsed form and compares directly. Matching semantics are identical to GlobMatch.

func NewGlob

func NewGlob(pattern string) Glob

NewGlob compiles pattern into a reusable matcher.

func (Glob) IsLiteral

func (g Glob) IsLiteral() bool

IsLiteral reports whether the pattern is a plain literal with no wildcards.

func (Glob) Matches

func (g Glob) Matches(text string) bool

Matches reports whether the pattern matches text.

func (Glob) Pattern

func (g Glob) Pattern() string

Pattern returns the source pattern string.

type Placeholder

type Placeholder interface {
	comparable
	Token() string
}

Placeholder is a typed template token. Implementations are comparable and expose their user-facing token name (without braces) via Token.

type SecretKeyMatcher

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

SecretKeyMatcher decides whether a config key or flag name commonly carries a secret value, so callers can redact it. Names are normalized (leading dashes trimmed, '-' folded to '_', lowercased) and a key matches when it equals a configured name or ends with "_<name>" — so "db_password" matches while "author" does not.

func DefaultSecretKeyMatcher

func DefaultSecretKeyMatcher() SecretKeyMatcher

DefaultSecretKeyMatcher returns a matcher seeded with DefaultSecretKeyNames.

func NewSecretKeyMatcher

func NewSecretKeyMatcher(names []string) SecretKeyMatcher

NewSecretKeyMatcher builds a matcher from the given secret-bearing names, applying the same normalization used at match time and dropping empties.

func (SecretKeyMatcher) IsSecretKey

func (m SecretKeyMatcher) IsSecretKey(name string) bool

IsSecretKey reports whether name should be treated as secret-bearing.

func (SecretKeyMatcher) WithName

func (m SecretKeyMatcher) WithName(name string) SecretKeyMatcher

WithName returns a matcher extended with one more secret-bearing name.

func (SecretKeyMatcher) WithNames

func (m SecretKeyMatcher) WithNames(names []string) SecretKeyMatcher

WithNames returns a matcher extended with several secret-bearing names.

type SecretString

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

SecretString wraps a string so it does not leak through logging, formatting, or JSON serialization. The plaintext is reachable only through Expose, marshals as the mask "***", and unmarshals from plaintext so a SecretString can be populated from config. Go provides no guaranteed in-memory zeroization, so unlike the rskit counterpart the backing bytes are not scrubbed on drop; treat process memory as a separate trust boundary.

func NewSecretString

func NewSecretString(plaintext string) SecretString

NewSecretString wraps plaintext in a SecretString.

func (SecretString) Equal

func (s SecretString) Equal(other SecretString) bool

Equal compares two secrets in constant time, avoiding a timing side channel.

func (SecretString) Expose

func (s SecretString) Expose() string

Expose returns the plaintext value. Call it only where the secret is genuinely needed.

func (SecretString) GoString

func (s SecretString) GoString() string

GoString masks the value in %#v / Go-syntax formatting.

func (SecretString) IsEmpty

func (s SecretString) IsEmpty() bool

IsEmpty reports whether the underlying value is empty.

func (SecretString) Len

func (s SecretString) Len() int

Len returns the length of the underlying value in bytes.

func (SecretString) MarshalJSON

func (s SecretString) MarshalJSON() ([]byte, error)

MarshalJSON emits the mask for a non-empty secret and an empty string otherwise, so the plaintext never reaches a serialized config dump.

func (SecretString) String

func (s SecretString) String() string

String renders the mask for a non-empty secret and an empty string otherwise, so a SecretString is safe to interpolate into logs.

func (*SecretString) UnmarshalJSON

func (s *SecretString) UnmarshalJSON(data []byte) error

UnmarshalJSON reads a plaintext string into the secret.

type SystemClock

type SystemClock struct{}

SystemClock returns real wall-clock time.

func (SystemClock) Now

func (SystemClock) Now() time.Time

Now returns the current UTC time.

type Template

type Template[P Placeholder] struct {
	// contains filtered or unexported fields
}

Template is a parsed template string validated against a fixed, typed set of placeholders known at compile time. Unknown placeholders are rejected at parse time, so rendering only ever sees tokens the caller declared.

func ParseTemplate

func ParseTemplate[P Placeholder](value string, placeholders []P) (Template[P], error)

ParseTemplate parses value against the allowed placeholders, rejecting unknown or malformed placeholders and unmatched braces.

func (Template[P]) Contains

func (t Template[P]) Contains(placeholder P) bool

Contains reports whether the template references placeholder.

func (Template[P]) Parts

func (t Template[P]) Parts() []TemplatePart[P]

Parts returns the parsed template parts in source order.

func (Template[P]) RenderWith

func (t Template[P]) RenderWith(render func(P) (string, error)) (string, error)

RenderWith renders the template, resolving each placeholder through render. A render error is wrapped as a TemplateError of kind TemplateErrorRender.

type TemplateError

type TemplateError struct {
	// Kind is the failure category.
	Kind TemplateErrorKind
	// Detail is the offending template, placeholder, or variable name.
	Detail string
}

TemplateError describes a template parse or render failure. It is comparable, so callers can match a specific failure with ==.

func (TemplateError) Error

func (e TemplateError) Error() string

Error implements error with a message matching the failure kind.

type TemplateErrorKind

type TemplateErrorKind int

TemplateErrorKind classifies a TemplateError.

const (
	// TemplateErrorUnclosedPlaceholder marks a placeholder missing its closing brace.
	TemplateErrorUnclosedPlaceholder TemplateErrorKind = iota
	// TemplateErrorUnmatchedClosingBrace marks a stray closing brace with no opener.
	TemplateErrorUnmatchedClosingBrace
	// TemplateErrorEmptyPlaceholder marks a placeholder with an empty name.
	TemplateErrorEmptyPlaceholder
	// TemplateErrorUnknownPlaceholder marks a placeholder not in the typed set.
	TemplateErrorUnknownPlaceholder
	// TemplateErrorRender marks a failure returned by a render callback.
	TemplateErrorRender
	// TemplateErrorMissingVariable marks a dynamic variable with no value.
	TemplateErrorMissingVariable
)

type TemplatePart

type TemplatePart[P Placeholder] struct {
	Kind        TemplatePartKind
	Literal     string
	Placeholder P
}

TemplatePart is one parsed part of a typed Template: either literal text or a placeholder. When Kind is TemplatePartLiteral, Literal holds the text; when it is TemplatePartPlaceholder, Placeholder holds the token.

type TemplatePartKind

type TemplatePartKind int

TemplatePartKind distinguishes a literal template part from a placeholder part.

const (
	// TemplatePartLiteral is verbatim text.
	TemplatePartLiteral TemplatePartKind = iota
	// TemplatePartPlaceholder is a resolved placeholder token.
	TemplatePartPlaceholder
)

Jump to

Keyboard shortcuts

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