Documentation
¶
Index ¶
- Constants
- func Bind(target interface{}, data map[string]any, opts ...*Options) error
- func BindJSON(target interface{}, data []byte, opts ...*Options) error
- func BindJSONFile(target interface{}, path string, opts ...*Options) error
- func BindJSONReader(target interface{}, r io.Reader, opts ...*Options) error
- func BindYAML(target interface{}, data []byte, opts ...*Options) error
- func BindYAMLFile(target interface{}, path string, opts ...*Options) error
- func BindYAMLReader(target interface{}, r io.Reader, opts ...*Options) error
- func DecodeStrictJSON(data []byte) (map[string]any, error)
- func DecodeStrictYAML(data []byte) (map[string]any, error)
- func Inspect(source interface{}, opts ...*InspectOptions) (string, error)
- func Link(targets ...interface{}) error
- func Merge(target interface{}, data map[string]any, opts ...*Options) error
- func MergeJSON(target interface{}, data []byte, opts ...*Options) error
- func MergeJSONFile(target interface{}, path string, opts ...*Options) error
- func MergeJSONReader(target interface{}, r io.Reader, opts ...*Options) error
- func MergeYAML(target interface{}, data []byte, opts ...*Options) error
- func MergeYAMLFile(target interface{}, path string, opts ...*Options) error
- func MergeYAMLReader(target interface{}, r io.Reader, opts ...*Options) error
- func MustInspect(source interface{}, opts ...*InspectOptions) string
- func New[T any](data map[string]any, opts ...*Options) (*T, error)
- func NewJSON[T any](data []byte, opts ...*Options) (*T, error)
- func NewJSONFile[T any](path string, opts ...*Options) (*T, error)
- func NewJSONReader[T any](r io.Reader, opts ...*Options) (*T, error)
- func NewYAML[T any](data []byte, opts ...*Options) (*T, error)
- func NewYAMLFile[T any](path string, opts ...*Options) (*T, error)
- func NewYAMLReader[T any](r io.Reader, opts ...*Options) (*T, error)
- func Unbind(source interface{}, opts ...*Options) (map[string]any, error)
- func UnbindJSON(source interface{}, opts ...*Options) ([]byte, error)
- func UnbindJSONFile(source interface{}, path string, opts ...*Options) error
- func UnbindJSONL(source interface{}, opts ...*Options) ([]byte, error)
- func UnbindJSONLWriter(source interface{}, w io.Writer, opts ...*Options) error
- func UnbindJSONWriter(source interface{}, w io.Writer, opts ...*Options) error
- func UnbindYAML(source interface{}, opts ...*Options) ([]byte, error)
- func UnbindYAMLFile(source interface{}, path string, opts ...*Options) error
- func UnbindYAMLWriter(source interface{}, w io.Writer, opts ...*Options) error
- type BindingError
- type ConversionError
- type Converter
- type DdTag
- type Defaulter
- type DuplicateKeyError
- type Dynamic
- type FileError
- type FileOptions
- type Identifiable
- type IndexError
- type InspectOptions
- type KeyCollisionError
- type Linker
- type LinkerOptions
- type Marshaler
- type MultipleExtraFieldsError
- type Options
- type Pointer
- type PointerError
- type RequiredFieldError
- type TypeMismatchError
- type UnbindingError
- type UnknownFieldError
- type Unmarshaler
- type UnsupportedError
- type ValidationError
- type ValueMismatchError
Constants ¶
const ( TypeKey = "type" // discriminator key for Dynamic types RefKey = "$ref" // reference key for Pointer types )
Magic string constants for special keys to avoid typos
Variables ¶
This section is empty.
Functions ¶
func Bind ¶
Bind populates the exported fields of target (a pointer to a struct) from the given data map. Keys are matched using either a struct tag `dd:"name,+required"` (where name overrides the key and the optional "+required" flag enforces presence), `dd:",+nullable"` to treat an explicit null as absent, `dd:"-"` to skip a field, or, when no tag is provided, a best-effort snake_case conversion of the field name.
Use Bind when you need to control how the prototype object is allocated. Use New when you just want to allocate a new object to bind off the heap.
supported kinds:
- primitives: string, bool, all int/uint sizes, float32/64, time.Duration, time.Time (from RFC3339 strings with optional fractional seconds)
- pointers to the above
- structs and pointers to structs (recursively bound from map[string]any)
- slices of the above (slice items are bound from []interface{})
- maps with comparable key types and any supported value type (map keys from JSON/YAML are coerced from strings)
interface types are not supported and will return an error if encountered, except for fields of type Dynamic which are resolved using Options.DynamicBinders.
opts are optional; pass nil or omit to use defaults.
func BindJSONFile ¶ added in v0.3.6
BindJSONFile reads JSON from the specified file path and binds it to the target struct.
func BindJSONReader ¶ added in v0.3.6
BindJSONReader reads JSON from an io.Reader and binds it to the target struct.
func BindYAMLFile ¶ added in v0.3.6
BindYAMLFile reads YAML from the specified file path and binds it to the target struct.
func BindYAMLReader ¶ added in v0.3.6
BindYAMLReader reads YAML from an io.Reader and binds it to the target struct.
func DecodeStrictJSON ¶ added in v1.0.2
DecodeStrictJSON parses JSON bytes into a map[string]any tree under the strict acceptance rules: duplicate member names are rejected anywhere (JSON parsers legally disagree on which duplicate wins, so one document must not have two meanings), trailing data after the document is rejected, the top level must be an object, and numbers are preserved as json.Number rather than collapsing through float64.
the returned tree is the same shape the forgiving intake produces, so it can be inspected or normalized before binding with Bind(target, m, dd.Strict()). BindJSON with the Strict option uses this decoder automatically.
func DecodeStrictYAML ¶ added in v1.0.2
DecodeStrictYAML parses YAML bytes into a map[string]any tree under the strict acceptance rules: duplicate mapping keys are rejected, aliases and anchors are rejected, mapping keys must be plain strings, the document must be a single mapping, and numbers are preserved as json.Number carrying the authored lexeme where it is JSON-valid (a bare 5.00 stays "5.00").
scalars outside the JSON value model — timestamps, binary — are rejected; quote them to bind as strings. the returned tree is the same shape the forgiving intake produces. BindYAML with the Strict option uses this decoder automatically.
func Inspect ¶
func Inspect(source interface{}, opts ...*InspectOptions) (string, error)
Inspect returns a human-readable representation of a struct's resolved state. designed for configuration debugging and validation. secret fields marked with `dd:",+secret"` are hidden unless ShowSecrets is true.
the output format is a clean, indented pseudo-data structure optimized for readability rather than parseability.
supported types: - primitives: string, bool, all int/uint sizes, float32/64, time.Duration - pointers to the above (nil pointers shown as "<nil>") - structs and pointers to structs (recursively inspected) - slices of the above (shown as numbered lists) - Dynamic interface implementations (shown with their type) - Pointer[T] references (shown with resolved state)
opts are optional; pass nil or omit to use defaults.
func Link ¶
func Link(targets ...interface{}) error
Link resolves all pointer references in the target objects by building a registry of all Identifiable objects and then resolving Pointer fields to their target objects. objects are namespaced by their concrete type to prevent Id clashes between different types.
func Merge ¶
Merge populates the exported fields of an existing target struct from the given data map, preserving any existing field values that are not present in the data. This allows binding partial data to pre-initialized structs with default values. If Merge has to allocate a fresh struct instance and that type implements Defaulter, ApplyDefaults is called before incoming data is bound.
uses the same field mapping rules as Bind: struct tags, snake_case conversion, etc.
supported kinds are the same as Bind.
opts are optional; pass nil or omit to use defaults.
func MergeJSONFile ¶ added in v0.3.6
MergeJSONFile reads JSON from the specified file path and merges it with the target struct.
func MergeJSONReader ¶ added in v0.3.6
MergeJSONReader reads JSON from an io.Reader and merges it with the target struct.
func MergeYAMLFile ¶ added in v0.3.6
MergeYAMLFile reads YAML from the specified file path and merges it with the target struct.
func MergeYAMLReader ¶ added in v0.3.6
MergeYAMLReader reads YAML from an io.Reader and merges it with the target struct.
func MustInspect ¶
func MustInspect(source interface{}, opts ...*InspectOptions) string
MustInspect returns a human-readable representation of a struct's resolved state, panicking if an error occurs. see Inspect for full documentation.
func New ¶
New creates and populates a new instance of type T from the given data map. Unlike Bind, which requires a pre-allocated target pointer, New automatically allocates the object and returns a pointer to the populated struct.
Use Bind instead of New when you need to control where and how the target object is instantiated. New just allocates a fresh target off the heap.
Example usage:
type Person struct {
Name string
Age int
}
data := map[string]any{"name": "John", "age": 30}
person, err := New[Person](data)
if err != nil {
// handle error
}
// person is now *Person with Name="John" and Age=30
supported kinds and field mapping rules are the same as Bind.
opts are optional; pass nil or omit to use defaults.
func NewJSONFile ¶ added in v0.3.6
NewJSONFile reads JSON from the specified file path and returns a new instance of type T.
func NewJSONReader ¶ added in v0.3.6
NewJSONReader reads JSON from an io.Reader and returns a new instance of type T.
func NewYAMLFile ¶ added in v0.3.6
NewYAMLFile reads YAML from the specified file path and returns a new instance of type T.
func NewYAMLReader ¶ added in v0.3.6
NewYAMLReader reads YAML from an io.Reader and returns a new instance of type T.
func Unbind ¶
Unbind converts a struct (or pointer to struct) into a map[string]any honoring the same `dd` tags used by Bind: - `dd:"name"` overrides the key name - `dd:"-"` skips the field - `dd:",+omitempty"` omits the field if it has a zero value - when no tag is provided, the key defaults to snake_case of the field name
pointers to values: if nil, the key is omitted; otherwise the pointed value is emitted. slices, structs, maps, and nested pointers are handled recursively. time.Duration values are emitted as strings using Duration.String() (e.g., "30s"). time.Time values are emitted as RFC3339 strings, preserving fractional seconds when present (e.g., "2024-03-15T14:30:45.123Z"). map keys are converted to strings for JSON/YAML compatibility; two distinct keys that convert to the same string (an interface-keyed map holding both 1 and "1") are a KeyCollisionError, since such a map has no lossless serialized form. Interface fields are not supported, except for fields of type `Dynamic` (and slices of `Dynamic`), which are converted via their ToMap() method which now returns (map[string]any, error).
the returned map is a Go map and therefore unordered; deterministic, sorted-key output is a property of the serialized forms (UnbindJSON, UnbindYAML, and their writer/file variants), not of this return value. see those functions for the determinism guarantee.
opts are optional; pass nil or omit to use defaults.
func UnbindJSON ¶ added in v0.3.6
UnbindJSON converts a struct to indented JSON bytes.
output is deterministic: for a given input value the produced bytes are identical across runs, processes, and versions. all keys — struct field names and map keys alike — are emitted in sorted order (encoding/json sorts object keys lexicographically), and slice and array element order is preserved as-is. fields captured via `+extra` are interleaved in sorted order with the rest rather than appended at the end.
func UnbindJSONFile ¶ added in v0.3.6
UnbindJSONFile converts a struct to JSON and writes it to the specified file path. output is deterministic with sorted keys; see UnbindJSON.
func UnbindJSONL ¶ added in v1.0.4
UnbindJSONL converts a struct to a single JSONL record: compact JSON with no interior newlines, terminated by exactly one '\n'. one call yields one line, so writing successive records to the same destination produces a JSON Lines stream. the encoding is otherwise identical to UnbindJSON — same keys, same values, same escaping — only the whitespace differs.
output is deterministic with sorted keys; see UnbindJSON. reading a stream back needs no dedicated helper: split it on '\n' and hand each line to BindJSON or NewJSON.
func UnbindJSONLWriter ¶ added in v1.0.4
UnbindJSONLWriter converts a struct to a single JSONL record and writes it to an io.Writer. call it once per record against the same writer to produce a JSON Lines stream. output is deterministic with sorted keys; see UnbindJSONL.
func UnbindJSONWriter ¶ added in v0.3.6
UnbindJSONWriter converts a struct to JSON and writes it to an io.Writer. output is deterministic with sorted keys; see UnbindJSON.
func UnbindYAML ¶ added in v0.3.6
UnbindYAML converts a struct to YAML bytes.
output is deterministic: for a given input value the produced bytes are identical across runs, processes, and versions. all keys — struct field names and map keys alike — are emitted in sorted order (yaml.v3 sorts mapping keys), and slice and array element order is preserved as-is. fields captured via `+extra` are interleaved in sorted order with the rest rather than appended at the end.
func UnbindYAMLFile ¶ added in v0.3.6
UnbindYAMLFile converts a struct to YAML and writes it to the specified file path. output is deterministic with sorted keys; see UnbindYAML.
Types ¶
type BindingError ¶
BindingError represents struct field binding errors
func (*BindingError) Error ¶
func (e *BindingError) Error() string
func (*BindingError) Unwrap ¶
func (e *BindingError) Unwrap() error
type ConversionError ¶
ConversionError represents data conversion failures
func (*ConversionError) Error ¶
func (e *ConversionError) Error() string
func (*ConversionError) Unwrap ¶
func (e *ConversionError) Unwrap() error
type Converter ¶
type Converter interface {
// FromRaw converts a raw value (from the data map) to the target type.
// the input can be any type that appears in the data map (string, int, bool, etc.).
FromRaw(raw interface{}) (interface{}, error)
// ToRaw converts a typed value back to a raw value for serialization.
// the output should be a type that can be marshaled (string, int, bool, etc.).
ToRaw(value interface{}) (interface{}, error)
}
Converter defines a bidirectional type conversion interface for custom field types. it allows users to define how their custom types should be converted to/from the raw data.
type DdTag ¶
type DdTag struct {
Name string // external field name override, empty means use default
Required bool // true if field is required during binding
Secret bool // true if field contains sensitive data
Skip bool // true if field should be skipped entirely
MatchValue string // expected value that must match during binding, empty means no constraint
HasMatch bool // true if a match constraint is specified
Extra bool // true if field should capture unmatched keys
OmitEmpty bool // true if field should be omitted when zero during unbinding
Opaque bool // true if field captures its raw subtree uninterpreted
Nullable bool // true if an explicit null should bind as an absent field
}
DdTag holds the parsed values from a `dd` struct tag.
type Defaulter ¶ added in v0.3.13
type Defaulter interface {
ApplyDefaults()
}
Defaulter allows a type to initialize its own default values when Merge allocates a fresh instance before overlaying external data.
type DuplicateKeyError ¶ added in v1.0.2
DuplicateKeyError represents a duplicate member name rejected by strict intake — parsers legally disagree on which duplicate wins, so one document must not have two meanings.
func (*DuplicateKeyError) Error ¶ added in v1.0.2
func (e *DuplicateKeyError) Error() string
type Dynamic ¶
Dynamic fields can be used when the concrete type of a field is selected dynamically through the `type` data provided in the incoming `map` that will be passed to `Bind`. A polymorphic field type.
type FileError ¶
FileError represents file I/O operation errors
func (*FileError) IsNotFound ¶
IsNotFound checks if the FileError represents a file not found error.
type FileOptions ¶ added in v0.3.14
type FileOptions struct {
// Mode sets the file mode used when writing output. If nil, file helpers preserve an
// existing file's mode when possible and otherwise fall back to their default mode.
Mode *fs.FileMode
}
FileOptions configures file output behavior for file-oriented helpers.
type Identifiable ¶
type Identifiable interface {
GetId() string
}
Identifiable objects can participate in pointer references by providing a unique Id.
type IndexError ¶
IndexError represents errors with array/slice indexing
func (*IndexError) Error ¶
func (e *IndexError) Error() string
func (*IndexError) Unwrap ¶
func (e *IndexError) Unwrap() error
type InspectOptions ¶
type InspectOptions struct {
// MaxDepth limits recursion depth to prevent infinite loops.
MaxDepth int
// Indent sets the indentation string (defaults to " ").
Indent string
// ShowSecrets includes secret fields in output when true.
ShowSecrets bool
}
InspectOptions configures inspection behavior.
type KeyCollisionError ¶ added in v1.0.5
type KeyCollisionError struct {
Key string // the spelling the keys collide on
Keys []string // the colliding source keys with their go types, sorted
}
KeyCollisionError represents two distinct map keys that serialize to the same string spelling during unbinding. such a map has no lossless JSON or YAML form, and which entry survived would depend on go's randomized map iteration, so unbind refuses it rather than letting one entry silently win.
func (*KeyCollisionError) Error ¶ added in v1.0.5
func (e *KeyCollisionError) Error() string
type Linker ¶
type Linker struct {
// contains filtered or unexported fields
}
Linker encapsulates the linking process, providing enhanced state management and advanced features.
func NewLinker ¶
func NewLinker(opts ...LinkerOptions) *Linker
NewLinker creates a new Linker with optional options. If no options are provided, default options are used.
func (*Linker) ClearCache ¶
func (l *Linker) ClearCache()
ClearCache clears the internal registry cache if caching is enabled.
func (*Linker) Link ¶
Link resolves all pointer references in the target objects by building a registry of all Identifiable objects and then resolving Pointer fields to their target objects. objects are namespaced by their concrete type to prevent Id clashes between different types.
func (*Linker) Register ¶
Register performs phase 1 of linking: collecting all Identifiable objects. This can be used for multi-stage linking where you want to register objects from multiple sources before resolving references.
func (*Linker) ResolveReferences ¶
ResolveReferences performs phase 2 of linking: resolving all pointer references using the collected registry. This can be used after collecting from multiple sources.
type LinkerOptions ¶
type LinkerOptions struct {
// EnableCaching enables registry caching for repeated linking operations
EnableCaching bool
// AllowPartialResolution allows linking to succeed even if some references can't be resolved
AllowPartialResolution bool
}
LinkerOptions configures the behavior of a Linker instance.
type MultipleExtraFieldsError ¶ added in v0.3.8
type MultipleExtraFieldsError struct {
Path string
}
MultipleExtraFieldsError represents the error when a struct has more than one +extra field
func (*MultipleExtraFieldsError) Error ¶ added in v0.3.8
func (e *MultipleExtraFieldsError) Error() string
type Options ¶
type Options struct {
// DynamicBinders maps a discriminator string (found under the "type" key in the input map) to a function that
// consumes the full map and returns a concrete value implementing the Dynamic interface.
DynamicBinders map[string]func(map[string]any) (Dynamic, error)
// FieldDynamicBinders allows specifying binder sets per field path. The key is the structured path of the field as
// used internally by Bind, e.g.: "Root.Items" for a slice field, "Root.Nested.Field" for nested fields.
// any array indices in the path are ignored for matching purposes.
// when present for a field, this map takes precedence over DynamicBinders.
FieldDynamicBinders map[string]map[string]func(map[string]any) (Dynamic, error)
// Converters maps Go types to custom converters for type conversion.
// the key is the reflect.Type of the target field, and the value is a Converter
// that handles bidirectional conversion between raw data and the target type.
Converters map[reflect.Type]Converter
// File configures file I/O behavior for helpers such as UnbindJSONFile and UnbindYAMLFile.
File *FileOptions
// Strict enables strict acceptance mode: intake rejects duplicate keys
// and non-JSON scalars and preserves numbers as json.Number; binding
// rejects unknown input keys and refuses type coercion. see Strict() for
// the full behavior. the default (false) is dd's forgiving posture, which
// is unchanged.
Strict bool
}
Options configures binding behavior.
func Strict ¶ added in v1.0.2
func Strict() *Options
Strict returns Options enabling strict acceptance mode.
dd's default posture is forgiving — unknown keys are ignored, duplicate JSON keys resolve last-wins inside the parser, and values coerce across types ("5" becomes an int, 5 becomes a string). forgiving YAML retains yaml.v3's existing duplicate-key rejection. that is right for config files and local records. strict mode is the opposite posture, for data whose exact spelling is the contract (signed payloads, hash-pinned documents):
- intake (BindJSON/BindYAML and their reader/file variants) rejects duplicate keys, trailing data, YAML aliases, and non-JSON scalars, and preserves numbers as json.Number — see DecodeStrictJSON and DecodeStrictYAML, which are also usable directly when a tree needs inspection or normalization between intake and binding
- binding rejects input keys the target struct does not declare (unless the struct carries a +extra field, which captures them by declared intent) and refuses type coercion: a number arriving at a string field is an error, not a conversion; map keys must have string as their underlying type
- a field tagged +opaque (a map[string]any) accepts any members and captures the raw subtree uninterpreted — syntactic intake rules still apply inside it, binding rules do not
custom Converters, Dynamic binders, and UnmarshalDd implementations remain in effect under strict mode. strict intake checks the syntax before delegation, but the custom machinery owns what it accepts; a permissive Unmarshaler should not be used at an exact contract boundary. Merge does not support strict mode.
type Pointer ¶
type Pointer[T Identifiable] struct { Ref string `dd:"$ref"` Resolved T // internal resolved reference (exported for reflection) }
Pointer represents a reference to an object of type T that implements Identifiable. During binding, the reference is stored as a string. During linking, it's resolved to the actual object.
func (*Pointer[T]) IsResolved ¶
IsResolved returns true if the pointer has been resolved to an actual object.
type PointerError ¶
PointerError represents pointer resolution errors
func (*PointerError) Error ¶
func (e *PointerError) Error() string
func (*PointerError) Unwrap ¶
func (e *PointerError) Unwrap() error
type RequiredFieldError ¶
RequiredFieldError represents missing required field errors
func (*RequiredFieldError) Error ¶
func (e *RequiredFieldError) Error() string
type TypeMismatchError ¶
TypeMismatchError represents type conversion errors
func (*TypeMismatchError) Error ¶
func (e *TypeMismatchError) Error() string
type UnbindingError ¶
UnbindingError represents struct field unbinding errors
func (*UnbindingError) Error ¶
func (e *UnbindingError) Error() string
func (*UnbindingError) Unwrap ¶
func (e *UnbindingError) Unwrap() error
type UnknownFieldError ¶ added in v1.0.2
UnknownFieldError represents an input key the target struct does not declare, rejected under strict binding.
func (*UnknownFieldError) Error ¶ added in v1.0.2
func (e *UnknownFieldError) Error() string
type Unmarshaler ¶
Unmarshaler allows a type to define its own unmarshalling logic from a map[string]any.
type UnsupportedError ¶
UnsupportedError represents unsupported operation errors
func (*UnsupportedError) Error ¶
func (e *UnsupportedError) Error() string
type ValidationError ¶
ValidationError represents errors in input validation
func (*ValidationError) Error ¶
func (e *ValidationError) Error() string
type ValueMismatchError ¶
ValueMismatchError represents errors when a field value doesn't match the expected constraint
func (*ValueMismatchError) Error ¶
func (e *ValueMismatchError) Error() string
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
dd_01_hello_world
command
|
|
|
dd_02_struct_tags
command
|
|
|
dd_03_type_coercion
command
|
|
|
dd_04_io
command
|
|
|
dd_05_nested_structs
command
|
|
|
dd_06_validation
command
|
|
|
dd_07_converters
command
|
|
|
dd_08_marshalers
command
|
|
|
dd_09_dynamic_types
command
|
|
|
dd_10_field_binders
command
|
|
|
dd_11_pointers
command
|
|
|
dd_12_advanced_linking
command
|
|
|
dd_13_typed_maps
command
|
|
|
dd_14_extra_fields
command
|
|
|
dd_15_strict_mode
command
|