sadl

package module
v1.4.1 Latest Latest
Warning

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

Go to latest
Published: Feb 3, 2021 License: Apache-2.0 Imports: 18 Imported by: 3

README

SADL - Simple API Description Language

SADL is a general high level API description language that defines its own schema language as well as operation and resource descriptions, optimized for simplicity and speed.

Base Types

  • Bool - Either true or false
  • Int8 - an 8 bit signed integer
  • Int16 - a 16 bit signed integer
  • Int32 - a 32 bit signed integer
  • Int64 - a 64 bit signed integer
  • Float32 - single precision IEEE 754 floating point number
  • Float64 - double precision IEEE 754 floating point number
  • Decimal - An arbitrary precision decimal number. Represented as a string in JSON to avoid implementation-specific precision issues (i.e. "3.141592653589793238462643383279502884197169399375105819")
  • Bytes - a sequence of 8 bit bytes
  • String - A sequence of Unicode characters.
  • Timestamp - An instant in time, formatted as string per RFC 3339 in JSON (i.e. "2019-02-04T01:05:16.565Z")
  • UnitValue<Decimal,String> - A tuple of numeric value and String or Enum units the value is measured in. Expressed as a string in JSON (i.e. "100.00 USD")
  • UUID - a Universally Unique Identifier RFC 4122, represented as a string in JSON (i.e. "1ce437b0-1dd2-11b2-81ef-003ee1be85f9")
  • Array - an ordered collections of values
  • Map<String,Any> - an unordered mapping of keys to values type.
  • Struct - an ordered collection of named fields, each with its own type.
  • Enum - a set of symbols
  • Union<typename,...> - a tagged union of types. Expressed as a JSON object with optional keys for each variant.
  • Any - any of the above types

Example Schemas

TBD. For now, see some examples in the examples directory. Or take a file in a know format and just parse it to output the SADL representation of it.

Usage

To get SADL and shoiw basic usage:

go get github.com/boynton/sadl/...
$(GOPATH)/bin/sadl

In general, it takes an arbitrary input file, parses it, and outputs with a generator, which defaults to SADL itself.

To just parse, show errors, and output the JSON representation of the resulting model:

$(GOPATH)/bin/sadl foo.sadl

To generate Java code:

$(GOPATH)/bin/sadl -g java foo.sadl

There are a variety of options possible to place in the config file (use the -help option to see the list for each generator). An example config file might look like this:

java:
   domain: "boynton.com"

graphql:
   custom-scalars:
      UUID: UUID
      Timestamp: Timestamp
      Decimal: Decimal
      Int64: Long

The pom option creates a Maven pom.xml file with dependencies to build the resulting code, and the server option produces example JAX-RS server code (using Jersey, Jackson, and Jetty), useful as a quick ready-to-build project creation tool.

To generate Go code:

$(GOPATH)/bin/sadl2go
usage: sadl2go -dir outdir -package go_package_name -runtime some_model.sadl

The runtime option (which defaults to false) causes the generated code to use this repo's runtime library code for types like Decimal and Timestamp. By default such code is generated in your package along with the modeled types.

Notes

SADL is inspired by RDL, but is not compatible with it.

SADL is designed for prototyping and experimentation.

Documentation

Overview

Decimal is a big.Float equivalent that marshals to/from JSON.

Index

Constants

View Source
const BLACK = "\033[0;0m"
View Source
const BLUE = "\033[94m"
View Source
const DecimalPrecision = uint(250)

we establish this "reasonable" max precision

View Source
const GREEN = "\033[92m"
View Source
const Length = 36
View Source
const RED = "\033[0;31m"
View Source
const RFC3339Milli = "%d-%02d-%02dT%02d:%02d:%02d.%03dZ"
View Source
const Version = "1.4"
View Source
const YELLOW = "\033[0;33m"

Variables

View Source
var BaseTypes = []string{
	"Bool",
	"Int8",
	"Int16",
	"Int32",
	"Int64",
	"Float32",
	"Float64",
	"Decimal",
	"Bytes",
	"String",
	"Timestamp",
	"UnitValue",
	"UUID",
	"Array",
	"Map",
	"Struct",
	"Enum",
	"Union",
	"Any",
}
View Source
var Verbose bool

Functions

func AsArray

func AsArray(v interface{}) []interface{}

func AsBool

func AsBool(v interface{}) bool

func AsFloat64

func AsFloat64(v interface{}) float64

func AsInt

func AsInt(v interface{}) int

func AsInt64

func AsInt64(v interface{}) int64

func AsMap

func AsMap(v interface{}) map[string]interface{}

func AsString

func AsString(v interface{}) string

func AsStringArray

func AsStringArray(v interface{}) []string

func BaseFileName

func BaseFileName(path string) string

func Capitalize

func Capitalize(s string) string

func DataToFile

func DataToFile(data *Data, path string) error

func Debug

func Debug(args ...interface{})

func DecompileSadl

func DecompileSadl(model *Model) string

func Equivalent

func Equivalent(obj1 interface{}, obj2 interface{}) bool

func FormatComment

func FormatComment(indent, prefix, comment string, maxcol int, extraPad bool) string

func FormattedAnnotation

func FormattedAnnotation(filename string, source string, prefix string, msg string, tok *Token, color string, contextSize int) string

func Get

func Get(m map[string]interface{}, key string) interface{}

func GetArray

func GetArray(m map[string]interface{}, key string) []interface{}

func GetBool

func GetBool(m map[string]interface{}, key string) bool

func GetInt

func GetInt(m map[string]interface{}, key string) int

func GetInt64

func GetInt64(m map[string]interface{}, key string) int64

func GetMap

func GetMap(m map[string]interface{}, key string) map[string]interface{}

func GetString

func GetString(m map[string]interface{}, key string) string

func GetStringArray

func GetStringArray(m map[string]interface{}, key string) []string

func IsDigit

func IsDigit(ch rune) bool

func IsLetter

func IsLetter(ch rune) bool

func IsLowercaseLetter

func IsLowercaseLetter(ch rune) bool

func IsSymbol

func IsSymbol(s string) bool

func IsSymbolChar

func IsSymbolChar(ch rune, first bool) bool

func IsUppercaseLetter

func IsUppercaseLetter(ch rune) bool

func IsValidFile

func IsValidFile(path string) bool

func IsWhitespace

func IsWhitespace(ch rune) bool

func Kind

func Kind(v interface{}) string

func Pretty

func Pretty(obj interface{}) string

func ToString

func ToString(obj interface{}) string

func Uncapitalize

func Uncapitalize(s string) string

Types

type ActionDef

type ActionDef struct {
	Name        string            `json:"name,omitempty"`
	Comment     string            `json:"comment,omitempty"`
	Annotations map[string]string `json:"annotations,omitempty"`
	Input       string            `json:"input,omitempty"`
	Output      string            `json:"output,omitempty"`
	Exceptions  []string          `json:"exceptions,omitempty"`
}

type Data

type Data struct {
	// contains filtered or unexported fields
}

func DataFromFile

func DataFromFile(path string) (*Data, error)

func DataFromJsonString

func DataFromJsonString(raw string) (*Data, error)

func NewData

func NewData() *Data

func (*Data) AsMap

func (data *Data) AsMap() map[string]interface{}

func (*Data) Get

func (data *Data) Get(keys ...string) interface{}

func (*Data) GetArray

func (data *Data) GetArray(keys ...string) []interface{}

func (*Data) GetBool

func (data *Data) GetBool(keys ...string) bool

func (*Data) GetData

func (data *Data) GetData(keys ...string) *Data

func (*Data) GetDecimal

func (data *Data) GetDecimal(keys ...string) *Decimal

func (*Data) GetInt

func (data *Data) GetInt(keys ...string) int

func (*Data) GetMap

func (data *Data) GetMap(keys ...string) map[string]interface{}

func (*Data) GetString

func (data *Data) GetString(keys ...string) string

func (*Data) Has

func (data *Data) Has(keys ...string) bool

func (Data) MarshalJSON

func (d Data) MarshalJSON() ([]byte, error)

func (*Data) Put

func (data *Data) Put(key string, value interface{})

func (*Data) String

func (data *Data) String() string

func (*Data) UnmarshalJSON

func (d *Data) UnmarshalJSON(b []byte) error

type Decimal

type Decimal struct {
	big.Float
}

func AsDecimal

func AsDecimal(v interface{}) *Decimal

func DecimalValue

func DecimalValue(val *Decimal, defval interface{}) *Decimal

func GetDecimal

func GetDecimal(m map[string]interface{}, key string) *Decimal

func NewDecimal

func NewDecimal(val float64) *Decimal

func ParseDecimal

func ParseDecimal(text string) (*Decimal, error)

func (*Decimal) AsBigFloat

func (d *Decimal) AsBigFloat() *big.Float

func (*Decimal) AsFloat64

func (d *Decimal) AsFloat64() float64

func (*Decimal) AsInt32

func (d *Decimal) AsInt32() int32

func (*Decimal) AsInt64

func (d *Decimal) AsInt64() int64

func (Decimal) MarshalJSON

func (d Decimal) MarshalJSON() ([]byte, error)

Encode as a JSON number. The JSON spec allows for arbitrary precision, so this is the correct thing to do.

func (*Decimal) String

func (d *Decimal) String() string

func (*Decimal) UnmarshalJSON

func (d *Decimal) UnmarshalJSON(b []byte) error

type EnumElementDef

type EnumElementDef struct {
	Symbol      string            `json:"symbol"`
	Comment     string            `json:"comment,omitempty"`
	Annotations map[string]string `json:"annotations,omitempty"`
}

type ExampleDef

type ExampleDef struct {
	Target      string            `json:"target"`
	Name        string            `json:"name,omitempty"`
	Example     interface{}       `json:"example,omitempty"`
	Comment     string            `json:"comment,omitempty"`
	Annotations map[string]string `json:"annotations,omitempty"`
}

type Extension

type Extension interface {
	Name() string
	Result() interface{}
	Parse(p *Parser) error
	Validate(p *Parser) error
}

type Generator

type Generator struct {
	Config *Data
	OutDir string
	Err    error
	// contains filtered or unexported fields
}

func (*Generator) Begin

func (gen *Generator) Begin()

func (*Generator) Capitalize

func (gen *Generator) Capitalize(s string) string

func (*Generator) Emit

func (gen *Generator) Emit(s string)

func (*Generator) EmitTemplate

func (gen *Generator) EmitTemplate(name string, tmplSource string, data interface{}, funcMap template.FuncMap)

func (*Generator) End

func (gen *Generator) End() string

func (*Generator) FileExists

func (gen *Generator) FileExists(path string) bool

func (*Generator) FormatComment

func (gen *Generator) FormatComment(indent, comment string, maxcol int, extraPad bool) string

func (*Generator) GetConfigBool

func (gen *Generator) GetConfigBool(k string, defaultValue bool) bool

func (*Generator) GetConfigInt

func (gen *Generator) GetConfigInt(k string, defaultValue int) int

func (*Generator) GetConfigString

func (gen *Generator) GetConfigString(k string, defaultValue string) string

func (*Generator) Uncapitalize

func (gen *Generator) Uncapitalize(s string) string

func (*Generator) WriteFile

func (gen *Generator) WriteFile(path string, content string)

type HttpDef

type HttpDef struct {
	Name        string               `json:"name,omitempty"`
	Resource    string               `json:"resource,omitempty"`
	Comment     string               `json:"comment,omitempty"`
	Annotations map[string]string    `json:"annotations,omitempty"`
	Method      string               `json:"method"`
	Path        string               `json:"path"`
	Inputs      []*HttpParamSpec     `json:"inputs,omitempty"`
	Expected    *HttpExpectedSpec    `json:"expected,omitempty"`
	Exceptions  []*HttpExceptionSpec `json:"exceptions,omitempty"`
}

type HttpExceptionSpec

type HttpExceptionSpec struct {
	Type        string            `json:"type"`
	Status      int32             `json:"status"`
	Comment     string            `json:"comment,omitempty"`
	Annotations map[string]string `json:"annotations,omitempty"`
}

type HttpExpectedSpec

type HttpExpectedSpec struct {
	Outputs     []*HttpParamSpec  `json:"outputs,omitempty"`
	Status      int32             `json:"status"`
	Comment     string            `json:"comment,omitempty"`
	Annotations map[string]string `json:"annotations,omitempty"`
}

type HttpParamSpec

type HttpParamSpec struct {
	Header string `json:"header,omitempty"`
	Query  string `json:"query,omitempty"`
	Path   bool   `json:"path,omitempty"`
	StructFieldDef
}

type Model

type Model struct {
	Schema
	Extensions map[string]interface{} `json:"extensions,omitempty"`
	// contains filtered or unexported fields
}

func LoadModel

func LoadModel(path string) (*Model, error)

func NewModel

func NewModel(schema *Schema) (*Model, error)

func ParseSadlFile

func ParseSadlFile(path string, conf *Data, extensions ...Extension) (*Model, error)

import "github.com/boynton/sadl" ... model, err := sadl.ParseFile("/some/path")

func ParseSadlString

func ParseSadlString(src string, conf *Data, extensions ...Extension) (*Model, error)

import "github.com/boynton/sadl" ... model, err := sadl.ParseString("...")

func (*Model) ConvertInlineEnums

func (model *Model) ConvertInlineEnums() error

for every typedef and action parameter that has an inline enum def, create a toplevel enum def and refer to it instead. This reduces duplicate definitions. This produces an error if name conflicts cannot be resolved.

func (*Model) EquivalentTypes

func (model *Model) EquivalentTypes(ts1, ts2 *TypeSpec) bool

func (*Model) EquivalentTypesByName

func (model *Model) EquivalentTypesByName(tname1, tname2 string) bool

func (*Model) FindExampleType

func (model *Model) FindExampleType(ex *ExampleDef) (*TypeSpec, error)

func (*Model) FindHttp

func (model *Model) FindHttp(name string) *HttpDef

func (*Model) FindType

func (model *Model) FindType(name string) *TypeDef

func (*Model) IsNumericType

func (model *Model) IsNumericType(td *TypeSpec) bool

func (*Model) IsStructField

func (model *Model) IsStructField(ts *TypeSpec, name string) bool

func (*Model) Validate

func (model *Model) Validate(context string, typename string, value interface{}) error

func (*Model) ValidateAgainstTypeSpec

func (model *Model) ValidateAgainstTypeSpec(context string, td *TypeSpec, value interface{}) error

func (*Model) ValidateArray

func (model *Model) ValidateArray(context string, td *TypeSpec, value interface{}) error

func (*Model) ValidateBool

func (model *Model) ValidateBool(context string, td *TypeSpec, value interface{}) error

func (*Model) ValidateEnum

func (model *Model) ValidateEnum(context string, td *TypeSpec, value interface{}) error

func (*Model) ValidateMap

func (model *Model) ValidateMap(context string, td *TypeSpec, value interface{}) error

func (*Model) ValidateNumber

func (model *Model) ValidateNumber(context string, td *TypeSpec, value interface{}) error

func (*Model) ValidateString

func (model *Model) ValidateString(context string, td *TypeSpec, val interface{}) error

func (*Model) ValidateStruct

func (model *Model) ValidateStruct(context string, td *TypeSpec, value interface{}) error

func (*Model) ValidateTimestamp

func (model *Model) ValidateTimestamp(tname string, td *TypeSpec, val interface{}) error

func (*Model) ValidateUUID

func (model *Model) ValidateUUID(context string, td *TypeSpec, value interface{}) error

func (*Model) ValidateUnitValue

func (model *Model) ValidateUnitValue(context string, td *TypeSpec, value interface{}) error

type Options

type Options struct {
	Required    bool
	Default     interface{}
	Pattern     string
	Values      []string
	MinSize     *int64
	MaxSize     *int64
	Min         *Decimal
	Max         *Decimal
	Action      string
	Resource    string
	Header      string
	Reference   string
	Name        string
	Annotations map[string]string
}

type Parser

type Parser struct {
	// contains filtered or unexported fields
}

func (*Parser) CurrentComment

func (p *Parser) CurrentComment() string

func (*Parser) EndOfFileError

func (p *Parser) EndOfFileError() error

func (*Parser) EndOfStatement

func (p *Parser) EndOfStatement(comment string) (string, error)

func (*Parser) Error

func (p *Parser) Error(msg string) error

func (*Parser) ExpectCompoundIdentifier

func (p *Parser) ExpectCompoundIdentifier() (string, error)

func (*Parser) ExpectIdentifier

func (p *Parser) ExpectIdentifier() (string, error)

func (*Parser) ExpectString

func (p *Parser) ExpectString() (string, error)

func (*Parser) GetToken

func (p *Parser) GetToken() *Token

func (*Parser) IsBlockDone

func (p *Parser) IsBlockDone(comment string) (bool, string, error)

func (*Parser) MergeComment

func (p *Parser) MergeComment(comment1 string, comment2 string) string

func (*Parser) Model

func (p *Parser) Model() *Model

func (*Parser) Parse

func (p *Parser) Parse(extensions []Extension) (*Model, error)

func (*Parser) ParseNoValidate

func (p *Parser) ParseNoValidate(extensions []Extension) error

func (*Parser) ParseOptions

func (p *Parser) ParseOptions(typeName string, acceptable []string) (*Options, error)

func (*Parser) ParseTrailingComment

func (p *Parser) ParseTrailingComment(comment string) string

func (*Parser) ParseTypeSpec

func (p *Parser) ParseTypeSpec(comment string) (*TypeSpec, *Options, string, error)

func (*Parser) ParseTypeSpecElements

func (p *Parser) ParseTypeSpecElements() (string, []string, []*StructFieldDef, []*EnumElementDef, *Options, string, error)

func (*Parser) Source

func (p *Parser) Source() string

func (*Parser) SyntaxError

func (p *Parser) SyntaxError() error

func (*Parser) UngetToken

func (p *Parser) UngetToken()

func (*Parser) Validate

func (p *Parser) Validate() (*Model, error)

type SadlGenerator

type SadlGenerator struct {
	Generator
	Model *Model
}

func NewGenerator

func NewGenerator(model *Model, outdir string) *SadlGenerator

func (*SadlGenerator) CreateSadlSource

func (g *SadlGenerator) CreateSadlSource()

func (*SadlGenerator) Generate

func (g *SadlGenerator) Generate() string

type Scanner

type Scanner struct {
	// contains filtered or unexported fields
}

func NewScanner

func NewScanner(r io.Reader) *Scanner

func (*Scanner) Scan

func (s *Scanner) Scan() Token

type Schema

type Schema struct {
	Sadl        string            `json:"sadl"`
	Name        string            `json:"name"`
	Namespace   string            `json:"namespace,omitempty"`
	Version     string            `json:"version,omitempty"`
	Comment     string            `json:"comment,omitempty"`
	Types       []*TypeDef        `json:"types,omitempty"`
	Examples    []*ExampleDef     `json:"examples,omitempty"`
	Actions     []*ActionDef      `json:"actions,omitempty"`
	Http        []*HttpDef        `json:"http,omitempty"`
	Base        string            `json:"base,omitempty"`
	Annotations map[string]string `json:"annotations,omitempty"`
}

type StructFieldDef

type StructFieldDef struct {
	Name        string            `json:"name"`
	Comment     string            `json:"comment,omitempty"`
	Annotations map[string]string `json:"annotations,omitempty"`
	Required    bool              `json:"required,omitempty"`
	Default     interface{}       `json:"default,omitempty"`
	TypeSpec
}

type Timestamp

type Timestamp struct {
	time.Time
}

func ParseTimestamp

func ParseTimestamp(s string) (Timestamp, error)

func (Timestamp) MarshalJSON

func (ts Timestamp) MarshalJSON() ([]byte, error)

func (Timestamp) String

func (ts Timestamp) String() string

func (*Timestamp) UnmarshalJSON

func (ts *Timestamp) UnmarshalJSON(b []byte) error

type Token

type Token struct {
	Type  TokenType
	Text  string
	Line  int
	Start int
}

func (Token) IsNumeric

func (tok Token) IsNumeric() bool

func (Token) IsText

func (tok Token) IsText() bool

func (Token) String

func (tok Token) String() string

type TokenType

type TokenType int
const (
	UNDEFINED TokenType = iota
	EOF
	LINE_COMMENT
	BLOCK_COMMENT
	SYMBOL
	NUMBER
	STRING
	COLON
	SEMICOLON
	COMMA
	AT
	DOT
	EQUALS
	DOLLAR
	QUOTE
	SLASH
	QUESTION
	OPEN_BRACE
	CLOSE_BRACE
	OPEN_BRACKET
	CLOSE_BRACKET
	OPEN_PAREN
	CLOSE_PAREN
	OPEN_ANGLE
	CLOSE_ANGLE
	NEWLINE
	HASH
	AMPERSAND
	STAR
	BACKQUOTE
	TILDE
	BANG
)

func (TokenType) String

func (tokenType TokenType) String() string

type TypeDef

type TypeDef struct {
	Name        string            `json:"name"`
	Comment     string            `json:"comment,omitempty"`
	Annotations map[string]string `json:"annotations,omitempty"`
	TypeSpec
}

type TypeSpec

type TypeSpec struct {
	Type      string             `json:"type"`
	Pattern   string             `json:"pattern,omitempty"`
	Values    []string           `json:"values,omitempty"`
	MinSize   *int64             `json:"minSize,omitempty"`
	MaxSize   *int64             `json:"maxSize,omitempty"`
	Fields    []*StructFieldDef  `json:"fields,omitempty"`
	Elements  []*EnumElementDef  `json:"elements,omitempty"`
	Min       *Decimal           `json:"min,string,omitempty"`
	Max       *Decimal           `json:"max,string,omitempty"`
	Items     string             `json:"items,omitempty"`
	Keys      string             `json:"keys,omitempty"`
	Variants  []*UnionVariantDef `json:"variants,omitempty"` //FIXME: a variant element, so comments/annotations can be attached
	Unit      string             `json:"unit,omitempty"`
	Value     string             `json:"value,omitempty"`
	Reference string             `json:"reference,omitempty"`
}

type UUID

type UUID string

func ParseUUID

func ParseUUID(text string) UUID

func (*UUID) UnmarshalJSON

func (u *UUID) UnmarshalJSON(b []byte) error

type UnionVariantDef

type UnionVariantDef struct {
	Name        string            `json:"name"`
	Comment     string            `json:"comment,omitempty"`
	Annotations map[string]string `json:"annotations,omitempty"`
	TypeSpec
}

type UnitValue

type UnitValue struct {
	Value *Decimal
	Unit  string
}

func NewUnitValue

func NewUnitValue(value float64, unit string) *UnitValue

func ParseUnitValue

func ParseUnitValue(repr string) (*UnitValue, error)

func (*UnitValue) MarshalJSON

func (q *UnitValue) MarshalJSON() ([]byte, error)

func (*UnitValue) String

func (q *UnitValue) String() string

func (*UnitValue) UnmarshalJSON

func (q *UnitValue) UnmarshalJSON(b []byte) error

Directories

Path Synopsis
cmd
sadl command

Jump to

Keyboard shortcuts

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