dotprop

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Jul 18, 2026 License: MIT Imports: 2 Imported by: 0

Documentation

Overview

Package dotprop provides get/set/has/delete access to nested map[string]any structures using dotted path strings, mirroring the behavior of the npm "dot-prop" library, using only the Go standard library. It exposes four functions — Get, Has, Set, and Delete — that address a value deep inside a tree of maps and slices by a single string path such as "a.b.c" rather than by a chain of hand-written map lookups and type assertions.

This is the utility you want when working with dynamically shaped data: configuration loaded from JSON or YAML, a decoded request body, or any map[string]any whose structure is known by path rather than by a Go type. It lets a caller read config.Get(cfg, "server.tls.enabled") or set a deeply nested default without first checking that every intermediate map exists, which keeps option-merging and template-context code short and free of nil-map panics.

A path is split on unescaped dots into segments. A literal dot inside a key can be escaped with a backslash, so the Go string "a\\.b" (the path a\.b) refers to the single key "a.b" rather than to a nested a then b; a backslash itself is escaped the same way, and a trailing backslash is kept literally. At each step the resolver looks at the current node: if it is a map[string]any the segment is used as a string key, and if it is a []any the segment is parsed as a base-ten index into the slice. Numeric segments therefore index slices only when the current value actually is a slice; against a map the same digits are an ordinary string key.

The four operations have well-defined behavior on the awkward inputs. Get returns (value, true) when the whole path resolves and (nil, false) otherwise — including a missing key, an out-of-range or negative slice index, a non-numeric index into a slice, or an attempt to descend into a scalar leaf — and Has is simply Get with the value discarded. Set creates intermediate map[string]any nodes as needed and overwrites any non-map value that sits in the way of the path, then returns obj so calls can be chained; it does not create slice nodes. Delete removes the addressed key and reports whether something was actually removed. A nil obj or an empty path is a no-op: Get and Has report absence, Set returns obj unchanged, and Delete returns false.

Parity with the Node original covers the core get/set/has/delete surface and the dot-with-backslash-escape path grammar. The deliberate differences are idiomatic and reflect Go's type system: values are map[string]any and []any instead of arbitrary JavaScript objects, Get returns the Go-style (value, ok) pair rather than an optional-or-default, array indices only apply to real []any slices, and this port does not implement dot-prop's default-value argument or its escaping of bracket-style paths — paths are dot-and-backslash only.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Delete

func Delete(obj map[string]any, path string) bool

Delete removes the value at the given dotted path. It returns true if a value was present and removed, false otherwise.

func Get

func Get(obj map[string]any, path string) (any, bool)

Get retrieves the value at the given dotted path. It returns the value and true when the path resolves, or nil and false otherwise. Numeric segments index into []any slices; all other segments are map keys.

Example

ExampleGet reads a value from deep inside a tree of maps by a single dotted path. The path "a.b.c" is split on dots and each segment is used as a map key, descending one level at a time. Get returns the value and true when the whole path resolves, or nil and false otherwise, so a caller can address nested config without hand-written lookups and type assertions.

package main

import (
	"fmt"

	"github.com/malcolmston/express/dotprop"
)

func main() {
	obj := map[string]any{
		"a": map[string]any{
			"b": map[string]any{"c": 42},
		},
	}
	value, ok := dotprop.Get(obj, "a.b.c")
	fmt.Println(value, ok)
}
Output:
42 true

func Has

func Has(obj map[string]any, path string) bool

Has reports whether the given dotted path resolves to a value in obj.

Example

ExampleHas reports whether a dotted path resolves to a value, without returning the value itself. It is simply Get with the value discarded. Here a present path reports true and a missing sibling reports false, which is handy for feature-flag or optional-config checks.

package main

import (
	"fmt"

	"github.com/malcolmston/express/dotprop"
)

func main() {
	obj := map[string]any{"a": map[string]any{"b": 1}}
	fmt.Println(dotprop.Has(obj, "a.b"))
	fmt.Println(dotprop.Has(obj, "a.c"))
}
Output:
true
false

func Set

func Set(obj map[string]any, path string, value any) map[string]any

Set assigns value at the given dotted path, creating intermediate map[string]any nodes as needed. It returns obj to allow chaining. If obj is nil or path is empty, obj is returned unchanged. Existing non-map intermediate values along the path are overwritten with new maps.

Example

ExampleSet assigns a value at a dotted path, creating intermediate maps as needed. Starting from an empty map, setting "server.port" builds the nested "server" map automatically. Set returns the same top-level map so calls can be chained, and reading the value back confirms it was stored at the nested location.

package main

import (
	"fmt"

	"github.com/malcolmston/express/dotprop"
)

func main() {
	obj := map[string]any{}
	dotprop.Set(obj, "server.port", 8080)

	value, ok := dotprop.Get(obj, "server.port")
	fmt.Println(value, ok)
}
Output:
8080 true

Types

This section is empty.

Jump to

Keyboard shortcuts

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