schema

package
v0.0.12 Latest Latest
Warning

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

Go to latest
Published: Dec 12, 2025 License: Apache-2.0 Imports: 8 Imported by: 0

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.

  • 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

View Source
const (
	TonyFormatContextURI = "tony-format/context"
	TonyFormatSchemaURI  = "tony-format/schema"
)

Variables

This section is empty.

Functions

func All

func All() map[string]*Schema

All returns all registered schemas

func ParseFromRefFromTag

func ParseFromRefFromTag(tag string) (string, string, []string, error)

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

func ParseSchemaRefFromTag(tag string) (string, error)

ParseSchemaRefFromTag parses X from !schema(X) tag string Returns the first argument from the !schema tag

func Register

func Register(s *Schema) error

Register registers a schema in the global registry

func ResolveDefinitionName

func ResolveDefinitionName(schema *Schema, name string) (*ir.Node, error)

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

func ValidateCycles(schema *Schema) error

ValidateCycles validates that all cycles in schema definitions have escape hatches

Types

type Arg

type Arg struct {
	Name  string
	Match *ir.Node
}

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

func (c *Context) FromIR(node *ir.Node) error

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

func (*Context) ToIR

func (c *Context) ToIR() (*ir.Node, error)

ToIR converts a Context to an IR node representing a JSON-LD style context Returns an object mapping terms to URIs (e.g., {"match": "tony-format/context/match"}) If there's only one URI with no terms, returns a string URI Returns an error if InOut and OutIn are inconsistent

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 Lookup

func Lookup(name string) *Schema

Lookup looks up a schema by name

func ParseSchema

func ParseSchema(node *ir.Node) (*Schema, error)

ParseSchema parses a schema from an IR node

func (*Schema) ToIR

func (s *Schema) ToIR() (*ir.Node, error)

ToIR converts a Schema to an IR node Elides tags that match signature.name and have no additional fields (auto-injected tags)

func (*Schema) Validate

func (s *Schema) Validate(doc *ir.Node) error

Validate validates a document against this schema

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

Jump to

Keyboard shortcuts

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