mirror of
https://github.com/hanzoai/o11y-foundry.git
synced 2026-10-30 18:26:45 +00:00
98 lines
3.3 KiB
Go
98 lines
3.3 KiB
Go
package domain
|
|
|
|
import (
|
|
"github.com/hanzoai/o11y-foundry/internal/errors"
|
|
"github.com/tidwall/gjson"
|
|
)
|
|
|
|
var (
|
|
FormatYAML = Format{s: "yaml", new: func(c []byte, p string) (Material, error) { return NewYAMLMaterial(c, p) }}
|
|
FormatJSON = Format{s: "json", new: func(c []byte, p string) (Material, error) { return NewJSONMaterial(c, p) }}
|
|
FormatINI = Format{s: "ini", new: func(c []byte, p string) (Material, error) { return NewINIMaterial(c, p) }}
|
|
FormatText = Format{s: "text", new: func(c []byte, p string) (Material, error) { return NewBlobMaterial(c, p), nil }}
|
|
)
|
|
|
|
// Format identifies the syntax of a Material's contents and carries the
|
|
// constructor that wraps a rendered byte stream in the matching concrete
|
|
// Material type. To register a new format, add a single entry above with its
|
|
// New* constructor — Template.Render picks it up automatically.
|
|
type Format struct {
|
|
s string
|
|
new func(contents []byte, path string) (Material, error)
|
|
}
|
|
|
|
func (f Format) String() string {
|
|
return f.s
|
|
}
|
|
|
|
// NewMaterial wraps contents in the concrete Material type for this format.
|
|
func (f Format) NewMaterial(contents []byte, path string) (Material, error) {
|
|
if f.new == nil {
|
|
return nil, errors.Newf(errors.TypeUnsupported, "failed to create material for path %q: unsupported format %q", path, f.s)
|
|
}
|
|
return f.new(contents, path)
|
|
}
|
|
|
|
// Material is a unit of output that Foundry produces. It carries the path it
|
|
// should be written to and the bytes to write there.
|
|
type Material interface {
|
|
Path() string
|
|
|
|
// FmtContents returns the bytes in their human-readable, on-disk form. This
|
|
// is the form Foundry writes out, distinct from the canonical form used for
|
|
// traversal and patching.
|
|
FmtContents() []byte
|
|
}
|
|
|
|
// StructuredMaterial is a Material whose contents are structured data with a
|
|
// navigable shape, supporting in-place reads and patches against a canonical
|
|
// representation.
|
|
type StructuredMaterial interface {
|
|
Material
|
|
|
|
// JSONContents returns the canonical JSON form used for traversal and
|
|
// patching. JSON is the contract: callers (e.g. jsonpatch) operate on it
|
|
// directly.
|
|
JSONContents() []byte
|
|
|
|
// HasMultipleDocuments reports whether the material groups multiple
|
|
// top-level documents under one path (currently only multi-document YAML).
|
|
// Callers use this to choose between scalar and array traversal of
|
|
// JSONContents.
|
|
HasMultipleDocuments() bool
|
|
|
|
CloneWithJSONContents(contents []byte) StructuredMaterial
|
|
|
|
// GetBytes returns the value at the given path as bytes. The path uses
|
|
// gjson dotted-key syntax (e.g. "service.name", "service.names.0"), not
|
|
// JSON Pointer.
|
|
GetBytes(path string) ([]byte, error)
|
|
|
|
// GetStringSlice returns the slice at the given path as strings. See
|
|
// GetBytes for path syntax.
|
|
GetStringSlice(path string) ([]string, error)
|
|
}
|
|
|
|
func getBytes(contents []byte, path string) ([]byte, error) {
|
|
result := gjson.GetBytes(contents, path)
|
|
if !result.Exists() {
|
|
return nil, errors.Newf(errors.TypeNotFound, "path %q does not exist", path)
|
|
}
|
|
|
|
return []byte(result.String()), nil
|
|
}
|
|
|
|
func getStringSlice(contents []byte, path string) ([]string, error) {
|
|
result := gjson.GetBytes(contents, path)
|
|
if !result.Exists() {
|
|
return nil, errors.Newf(errors.TypeNotFound, "path %q does not exist", path)
|
|
}
|
|
|
|
var items []string
|
|
for _, item := range result.Array() {
|
|
items = append(items, item.String())
|
|
}
|
|
|
|
return items, nil
|
|
}
|