Documentation
¶
Overview ¶
Package schema provides support for Tony Schema, a schema system for describing and validating Tony format documents.
Overview ¶
Tony Schema is similar to JSON Schema but designed to be simpler, more lightweight, and more readable. Schemas describe constraints and information about documents in the Tony format, enabling:
- Precise modeling of data structures
- Document validation
- Documentation and communication between stakeholders
- Automation and code generation
Core Concepts ¶
## Schema Documents
A schema document consists of:
- Context: Execution context (match, patch, eval, etc.) that defines which tags are available
- Signature: How the schema can be referenced (name and optional parameters)
- Define: Value definitions (like JSON Schema $defs)
- Accept: What documents this schema accepts (validation constraints)
- Tags: Custom tags that this schema introduces
Example schema:
context: tony-format/context/match
signature:
name: user-schema
define:
user:
name: !irtype ""
email: !irtype ""
age: .[number]
accept:
.[user]
## Contexts
Contexts define execution environments and which tags are available. Built-in contexts include:
- match: For validation/matching operations (!or, !and, !not, !type, etc.)
- patch: For data transformation operations (!nullify, !insert, !delete, etc.)
- eval: For evaluation operations (!eval, !exec, !file, etc.)
- diff: For diff operations (!strdiff, !arraydiff)
Contexts use JSON-LD style naming with short names (e.g., "match") and full URIs (e.g., "tony-format/context/match").
## Tags
Tags are operations or type markers that work within specific contexts. Tags appear on IR nodes using the `!tagName` syntax:
- Schema references: `!person` references a schema named "person"
- Type markers: `!irtype` marks built-in types
- Operations: `!or`, `!and`, `!nullify` invoke operations
Tags can be composed: `!all.has-path "foo"` means "all items have path foo".
## Schema References
Schemas can reference other schemas using `!schema(name)` or `!from(schema-name, def-name)`:
- `!schema example` - references schema named "example" in current context
- `!schema tony-format/schema/base` - references schema by full URI
- `!from(base-schema, number)` - references definition "number" from "base-schema"
Usage ¶
## Parsing a Schema
import (
"github.com/signadot/tony-format/go-tony/parse"
"github.com/signadot/tony-format/go-tony/schema"
)
// Parse a Tony document into IR
node, err := parse.Parse(schemaBytes)
if err != nil {
return err
}
// Parse the schema from IR
schema, err := schema.ParseSchema(node)
if err != nil {
return err
}
## Using Schema Registry
import (
"github.com/signadot/tony-format/go-tony/schema"
)
// Create a context registry
ctxRegistry := schema.NewContextRegistry()
// Create a schema registry
schemaRegistry := schema.NewSchemaRegistry(ctxRegistry)
// Register a schema
err := schemaRegistry.RegisterSchema(mySchema)
if err != nil {
return err
}
// Resolve a schema reference
ref := &schema.SchemaReference{Name: "user-schema"}
resolved, err := schemaRegistry.ResolveSchema(ref)
if err != nil {
return err
}
## Validating Documents
Validation is currently not fully implemented. The Schema.Validate() method exists but returns an error indicating validation is not yet implemented.
When implemented, validation will check documents against the schema's `accept` clause using match operations.
Related Packages ¶
- github.com/signadot/tony-format/go-tony/ir - Intermediate representation
- github.com/signadot/tony-format/go-tony/mergeop - Match and patch operations
- github.com/signadot/tony-format/go-tony/parse - Parsing Tony format
Index ¶
- Constants
- func All() map[string]*Schema
- func ParseFromRefFromTag(tag string) (string, string, []string, error)
- func ParseSchemaRefFromTag(tag string) (string, error)
- func Register(s *Schema) error
- func ResolveDefinitionName(schema *Schema, name string) (*ir.Node, error)
- func ValidateCycles(schema *Schema) error
- type Arg
- type Context
- type ContextRegistry
- func (r *ContextRegistry) AllContexts() []*Context
- func (r *ContextRegistry) GetContext(uri string) (*Context, bool)
- func (r *ContextRegistry) GetTagContexts(tagName string) []*Context
- func (r *ContextRegistry) RegisterContext(ctx *Context) error
- func (r *ContextRegistry) ResolveContext(name string) (*Context, error)
- type FromReference
- type Schema
- type SchemaReference
- type SchemaRegistry
- func (r *SchemaRegistry) AllSchemas() []*Schema
- func (r *SchemaRegistry) GetSchema(name string) (*Schema, bool)
- func (r *SchemaRegistry) RegisterSchema(schema *Schema) error
- func (r *SchemaRegistry) ResolveDefinition(ref *FromReference) (*ir.Node, error)
- func (r *SchemaRegistry) ResolveSchema(ref *SchemaReference) (*Schema, error)
- type Signature
- type TagDefinition
Constants ¶
const ( TonyFormatContextURI = "tony-format/context" TonyFormatSchemaURI = "tony-format/schema" )
Variables ¶
This section is empty.
Functions ¶
func ParseFromRefFromTag ¶
ParseFromRefFromTag parses schema-name (possibly parameterized), def-name from !from(schema-name(...),def-name) tag string (no spaces in tag) Returns the schema name, definition name, and schema arguments (if the schema is parameterized)
func ParseSchemaRefFromTag ¶
ParseSchemaRefFromTag parses X from !schema(X) tag string Returns the first argument from the !schema tag
func ResolveDefinitionName ¶
ResolveDefinitionName resolves a definition name within a schema's Define map.
This function takes just the definition name (e.g., "number", "int"), not the full .[name] syntax that appears in Tony schema files. When processing schema definitions that contain .[name] references, extract the name first, then call this function.
The .[name] syntax in Tony schemas works with expr-lang eval, where the schema's Define map acts as the environment. When a schema definition contains ".[number]", it evaluates to the definition node stored in schema.Define["number"].
Example usage:
// In a Tony schema file:
define:
number: !irtype 1
int: !and
- .[number] # This references the "number" definition above
- int: !not null
// When processing the "int" definition, extract the name from ".[number]":
refTag := ".[number]" // As it appears in the schema
name := eval.GetRaw(refTag) // Extracts "number" from ".[number]"
defNode, err := ResolveDefinitionName(schema, name) // Looks up "number"
Note: This function only resolves definitions within the same schema. For cross-schema references (using !from), use SchemaRegistry.ResolveDefinition.
func ValidateCycles ¶
ValidateCycles validates that all cycles in schema definitions have escape hatches
Types ¶
type Context ¶
type Context struct {
// OutIn maps URI to short names (which short names belong to this URI)
OutIn map[string]map[string]bool
// InOut maps short name to URI
InOut map[string]string
// URI is the primary/long name for this context (e.g., "tony-format/context/match")
// If not set, will be inferred from OutIn
URI string
// ShortName is the short name for this context (e.g., "match")
ShortName string
// Tags defines which tags are available in this context
// Map of tag name -> TagDefinition
Tags map[string]*TagDefinition
// Extends lists URIs of parent contexts (for inheritance/composition)
Extends []string
}
func DefaultContext ¶
func DefaultContext() *Context
func (*Context) FromIR ¶
FromIR creates a Context from an IR node representing a JSON-LD style context The node can be:
- A string (URI)
- An object mapping terms to URIs (e.g., {"match": "tony-format/context/match"})
- An array of contexts
Ensures InOut and OutIn are always consistent: OutIn[uri][short] == true iff InOut[short] == uri
type ContextRegistry ¶
type ContextRegistry struct {
// contains filtered or unexported fields
}
ContextRegistry manages all known execution contexts
func NewContextRegistry ¶
func NewContextRegistry() *ContextRegistry
NewContextRegistry creates a new context registry with built-in contexts
func (*ContextRegistry) AllContexts ¶
func (r *ContextRegistry) AllContexts() []*Context
AllContexts returns all registered contexts
func (*ContextRegistry) GetContext ¶
func (r *ContextRegistry) GetContext(uri string) (*Context, bool)
GetContext returns a context by URI (must be exact match)
func (*ContextRegistry) GetTagContexts ¶
func (r *ContextRegistry) GetTagContexts(tagName string) []*Context
GetTagContexts returns all contexts that have a given tag
func (*ContextRegistry) RegisterContext ¶
func (r *ContextRegistry) RegisterContext(ctx *Context) error
RegisterContext registers a context
func (*ContextRegistry) ResolveContext ¶
func (r *ContextRegistry) ResolveContext(name string) (*Context, error)
ResolveContext resolves a context by URI or short name
type FromReference ¶
type FromReference struct {
// SchemaName is the name of the schema containing the definition
SchemaName string
// DefName is the name of the definition within that schema
DefName string
// SchemaArgs are schema arguments (for parameterized schemas)
SchemaArgs []*ir.Node
}
FromReference represents a reference to a definition in another schema
func ParseFromReference ¶
func ParseFromReference(node *ir.Node) (*FromReference, error)
ParseFromReference parses a from reference from an IR node with a !from(schema-name,def-name, ...) tag (no spaces in tag) Examples:
- !from(base-schema,number) -> FromReference{SchemaName: "base-schema", DefName: "number"}
- !from(param-schema(1,2),def-name) -> FromReference with schema args
type Schema ¶
type Schema struct {
// The context in which this schema lives (handles @context and with)
Context *Context
// Signature defines how the schema can be referenced
Signature *Signature `tony:"signature"`
// Tags defines tags that this schema introduces
// Map of tag name -> TagDefinition
//
// When reading: If signature.name exists, a tag with that name is automatically
// added to Tags (if not already present) for programmatic access. Writers don't
// need to duplicate signature.name in the tags field.
//
// When encoding: Tags matching signature.name with no additional fields
// (only Name set, no Contexts/SchemaRef/Description) are elided to avoid duplication.
Tags map[string]*TagDefinition `tony:"tags"`
// Define provides a place for value definitions, like json-schema $defs
Define map[string]*ir.Node `tony:"define"`
// Accept defines what documents this schema accepts
Accept *ir.Node `tony:"accept"`
}
Schema represents a Tony schema document
func ParseSchema ¶
ParseSchema parses a schema from an IR node
type SchemaReference ¶
type SchemaReference struct {
// Name is the schema name (from signature.name)
Name string
// URI is the fully qualified schema URI (optional, for cross-context refs)
URI string
// Args are schema arguments (for parameterized schemas)
Args []*ir.Node
}
SchemaReference represents a reference to another schema
func ParseSchemaReference ¶
func ParseSchemaReference(node *ir.Node) (*SchemaReference, error)
ParseSchemaReference parses a schema reference from an IR node with a !schema(X) tag Examples:
- !schema(example) -> SchemaReference{Name: "example"}
- !schema(tony-format/schema/base) -> SchemaReference{URI: "tony-format/schema/base"}
- !schema(p(1,2,3)) -> SchemaReference{Name: "p", Args: ["1", "2", "3"]}
type SchemaRegistry ¶
type SchemaRegistry struct {
// contains filtered or unexported fields
}
SchemaRegistry manages all known schemas
func NewSchemaRegistry ¶
func NewSchemaRegistry(contextRegistry *ContextRegistry) *SchemaRegistry
NewSchemaRegistry creates a new schema registry
func (*SchemaRegistry) AllSchemas ¶
func (r *SchemaRegistry) AllSchemas() []*Schema
AllSchemas returns all registered schemas
func (*SchemaRegistry) GetSchema ¶
func (r *SchemaRegistry) GetSchema(name string) (*Schema, bool)
GetSchema returns a schema by name
func (*SchemaRegistry) RegisterSchema ¶
func (r *SchemaRegistry) RegisterSchema(schema *Schema) error
RegisterSchema registers a schema
func (*SchemaRegistry) ResolveDefinition ¶
func (r *SchemaRegistry) ResolveDefinition(ref *FromReference) (*ir.Node, error)
ResolveDefinition resolves a FromReference to get the actual definition node from another schema Example: ResolveDefinition(&FromReference{SchemaName: "base-schema", DefName: "number"}) returns the definition node for "number" from the "base-schema" schema
func (*SchemaRegistry) ResolveSchema ¶
func (r *SchemaRegistry) ResolveSchema(ref *SchemaReference) (*Schema, error)
ResolveSchema resolves a schema by reference
type Signature ¶
type Signature struct {
// Name is the schema name, so we can use '!name' to refer to this
Name string `tony:"name"`
// Args are the schema arguments (for parameterized schemas)
Args []Arg `tony:"args"`
}
Signature defines how a schema can be referenced
type TagDefinition ¶
type TagDefinition struct {
// Name is the tag name (e.g., "or", "and")
Name string
// Contexts lists which contexts this tag belongs to (URIs)
Contexts []string
// SchemaRef optionally references a schema that defines this tag's behavior
// Empty if no schema defines it (built-in tag)
SchemaRef string
// Description of what this tag does
Description string
}
TagDefinition describes a tag and its behavior