brunoborges / toml-schema

MIT License
61 stars 2 forks source link

The TOML Schema Definition

A TOML Schema is a set of TOML-based constructs that define the structure, the names, and the types of configuration data on a TOML file.

The TOML Schema is used to validate the input of a TOML file during parsing to:

  1. Eliminate or reduce misconfiguration that could potentially damage if only validated during production evaluation,
  2. Be leveraged by editors and other tools to provide and enrich auto-completion and code hints for validation on the fly.

The schema format follows the TOML specification, meaning that a TOML Schema is in itself a valid TOML document.

First Glance

TOML example

Let's look at the TOML example displayed on the front page of toml.io:

# This is a TOML document

title = "TOML Example"

[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00

[database]
enabled = true
ports = [ 8000, 8001, 8002 ]
data = [ ["delta", "phi"], [3.14] ]
temp_targets = { cpu = 79.5, case = 72.0 }

[servers]

[servers.alpha]
ip = "10.0.0.1"
role = "frontend"

[servers.beta]
ip = "10.0.0.2"
role = "backend"

TOML Schema example

Example of a TOML Schema that validates the TOML document above:

# This is a TOML Schema document
[toml-schema]
version = "1"

[types.serverType]
type="table"

    [types.serverType.ip]
    type="string"
    pattern="^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$"
    [types.serverType.role]
    type="string"

[elements.title]
type="string"

[elements.owner]
type="table"
    [elements.owner.name]
    type="string"
    [elements.owner.dob]
    type="local-date"

[elements.database]
type="table"

    [elements.database.enabled]
    type = "boolean"
    [elements.database.ports]
    type = "array"
    arraytype = "integer"
    [elements.database.data]
    type = "array"
    arraytype = "array"
    [elements.database.temp_targets]
    type = "table"

[elements.servers]
type="collection"
typeof = "types.serverType"
minlength = 1

Schema Structure Reference

A TOML Schema file has the following structure:

# Metadata
[toml-schema]

# Types
[types]

# Elements
[elements]

Top-level Structure Conditions

IMPORTANT: No other top-level table or key-value pair may appear on a TOML Schema document.

Metadata Table - [toml-schema]

This table is reserved for metadata regarding the TOML Schema itself.

[toml-schema]
version = "1.0"
# custom = "value" # *NOT allowed

[toml-schema.meta]
<any> = <value> # allowed
...

[toml-schema.meta.subtable] # allowed

# [toml-schema.custom] # *NOT allowed
...

Supported Properties

Elements table - [elements]

The elements table defines the overall structure and properties of the TOML document. Elements follow the same structure and rules of Types, specified below, except that elements cannot reference other elements. To reuse conditions and structures, [types] must be defined and referenced back from the [elements] table.

Types table - [types]

The [types] table is for use when there is a need for custom, reusable types of structure or properties. A type is referenced in an element by the property typeof.

[types]

[types.<typename>]
type = "<simple-type> | array | table | collection"
typeof = "<full-name-of-a-defined-type>"
arraytype = "<simple-type>"
allowedvalues = [ <array-with-enumeration-of-allowed-values> ]
pattern = "<string-regex-for-string-validation>"
optional = true|false
min = <any>
max = <any>
minlength = <integer>
maxlength = <integer>

Simple Types - <simple-type>

List of considered simple types:

Allowed Values for Simple Types - allowedvalues

allowedvalues provides a mechanism to set an enumeration of allowed values to be used in any given simple type.

Example:

[types.colorType]
type="string"
allowedvalues=[ "red", "black", "blue" ]

Minimum Value / Maximum Value - min and max

This property may only be used when defining a value range for the following types:

Length - minlength and maxlength

This property may only be used when defining the allowed length of a string, an array, or a collection.

Conditions on any

No min/max condition may be applied to type any. The parser must show an error if this happens.

Block Types

(*) The schema also explicitly defines two types:

  1. The implicit TOML type table for specifying child elements associated to the parent.
  2. A type for a collection of elements, collection.

For simplicity, there is no definition of inline table since these are just tables that can be expressed inlined in a TOML document.

Tables

A table may have a set of properties, or none at all. If a table has a definition of properties, then the parser must validate the input and the input must match exactly the rules of the table and its children.

If a property of type table has no defined property and/or structure, the parser must not validate its input. This is useful for representing custom JSON data payloads.

Arrays

Arrays can be defined by mixing the following properties:

Example for schema definition:

[elements.colors]
type="array"
arraytype="string"

Example of TOML file:

colors=[ "red", "yellow", "green" ]
Observations on Conditions to Arrays

The minvalue and maxvalue conditions are used to set a valid range of values, and it may be applied only to properties where arraytype is one of the following: integer, float, and the four available date and/or time types. Both properties are inclusive.

Dates and Times are naturally sorted by past, present, future, meaning that the first element is in the past, and the furthest element is in the future.

allowedvalues does not have to be naturally sorted, but the lowest value must match minvalue if it is available. The highest/furthest value must match maxvalue if it is available.

If allowedvalues does not match the conditions of minlength, maxlength, minvalue and maxvalue, the parser must throw an error indicating that the TOML Schema is malformed.

If arraytype is not defined, then the type of array elements is any, and any data type can be used and mixed together.

If type is array and arraytype is of type array, then automatically any data type can be used and mixed together.

Collection of Elements for Dynamic Keys

One can set an element of type collection for when there is a need to have multiple children with dymamic, user-provided keys or table headers.

A collection is also a table and, therefore, it may have nested, schema-restricted key-value pairs of simple types.

A collection requires a type definition of the child elements. Each child must be given a unique key in the TOML document.

The types allowed in a collection may be defined with only one of the following attributes:

Example: The below example shows a table servers that is a collection. Each server must be given a key, and follow the defined structure of types.serverType. A server may also have a DNS table with user-provided key names.

TOML:

[servers]
group = "group1"

    [servers.alpha]
    name = "Alpha DC0"
    address = "dc0.alpha"

        [servers.alpha.dnstable]
        cloudflare = "1.1.1.1"
        google1 = "4.4.4.4"
        google2 = "8.8.8.8"
        internal = "mydns.intranet"

    [servers.beta]
    name = "Beta DC0"
    address = "dc0.beta"

TOML Schema:

[types]

    [types.dnsType]
    type = "string"
    pattern = "<ip-regex-pattern>"

    [types.hostnameType]
    type = "string"
    pattern = "<valid-hostname-regex-pattern>"

    [types.serverType]
    type = "table"

        [types.serverType.name]
        type = "string"

        [types.serverType.address]
        type = "string"

        [types.serverType.dnstable]
        type = "collection"
        anyof = [ "types.dnsType", "types.hostnameType" ]

[elements]

    [elements.servers]
    type = "collection"
    typeof = "types.serverType"

        [elements.servers.group]
        type = "string"

A collection may be represented as subtables of a common table in a TOML document.

Type Reference

A type may be referenced to inherit the defined rules existent in given type. Both type and element may reference a type.

[types]

    [types.nameType]
    type="string"
    pattern="[a-zA-Z]"

    [types.serverType.name]
    typeof = "types.nameType"

[elements]

    [elements.datacenter]
    type="table"

        [elements.datacenter.name]
        typeof="types.nameType"

        [elements.datacenter.servers]
        type = "collection"
        typeof = "types.serverType"

Optionality - optional

Properties may be defined as optional in the schema. By default, optional equals false, and the structure is required.

Parsers must only skip a structure validation if the structure is optinal in the TOML Schema and does not exist in the TOML document. For any other condition, the parser must validate the input against the schema.

Pattern - pattern

This property is only used for validating string input. Parsers must validate the input with the provided regular expression.

Parsers must support Perl/PCRE syntax. Parsers may support more extensions and other syntaxes.

Parsers

It is NOT the goal of a TOML Schema to ever modify the data output of a TOML object during parsing.

A parser that validates a TOML document against a TOML Schema must produce the exact same TOML data object as a parser that does not validate.

Filename Extension

TOML Schema files should use the extension .tosd.

MIME Types

When transferring TOML Schema files over the internet, the appropriate MIME types are:

TOML Reference of a TOML Schema

A TOML file must have this indication at the top, to reference which schema file to use for validation:

[toml-schema]
version = "1"
location = "<uri>"

Where <uri> can be a remote URL (e.g. https) or a local file.

Only simple built-in types are allowed.

Discussion

If you want to share your thoughts on this proposal, please go to the General Discussion.

Existing TOML Schema Proposal

There is an ongoing effort to bring Schema support for TOML under the PR 116. I found that proposal to be extensively detailed and well constructed, but I believe this simpler proposal to be more realistic.

Contributors

Thanks to my friends!