KDL schema spec (#104)

Fixes: https://github.com/kdl-org/kdl/issues/83
This commit is contained in:
Kat Marchán 2021-08-31 12:03:27 -07:00 committed by GitHub
parent 9e35601c91
commit d87979f175
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 379 additions and 0 deletions

161
SCHEMA-SPEC.md Normal file
View File

@ -0,0 +1,161 @@
# KDL Schema Specification
The KDL Schema specification describes a schema language for use with KDL,
written in KDL itself. A schema language allows users to describe and
constrain the allowed semantics of a KDL document. This can be used for many
purposes: documentation for users, automated verification, or even automated
generation of bindings!
## The Formal Schema
For the full KDL Schema schema itself, see
[examples/kdl-schema.kdl](./examples/kdl-schema.kdl).
## Definition
### `document` node
This is the toplevel node in a KDL Schema. It is required, and there must be
exactly one, at the very toplevel of a document.
#### Values
None.
#### Properties
* `description` (optional): An informational description of the purpose of this schema.
* `schema-url` (optional): A URL where someone may go to find more information about this schema. It is not meant for mechanical processing.
#### Children
* [`node`](#node-node) - zero or more toplevel nodes for the KDL document this schema describes.
* `node-names` (optional): [Validations](#validation-nodes) to apply to the _names_ of child nodes.
* `other-nodes-allowed` (optional): Whether to allow nodes other than the ones explicitly listed here. Defaults to `false`.
### `node` node
The `node` node describes node instances in a document. These may either be at
the toplevel of the document, or they may be nested inside a children block in
another node.
#### Values
* Node name (optional) - A string name for the node. If present, the node's rules/validations will apply only to children with this node name. Otherwise, the rules will apply to _all_ child nodes, regardless of whether they're named or not.
#### Properties
* `description` (optional): An informational description of the purpose of this node.
* `id` (optional): A globally unique identifier for this node.
* `ref` (optional): A globally unique reference to another node's ID. If present, all properties, values, and children defined in the target node will be copied to this node, replacing any conflicts.
#### Children
* `min` (optional): Minimum number of this kind of node (or any node, if the name is missing) allowed in the parent's children block.
* `max` (optional): Maximum number of this kind of node (or any node, if the name is missing) allowed in the parent's children block.
* `prop-names` (optional): [Validations](#validation-nodes) to apply to the _names_ of properties.
* `other-props-allowed` (optional): Whether to allow props other than the ones explicitly listed here. Defaults to `false`.
* [`prop`](#prop-node) - zero or more properties for this node.
* [`value`](#value-node) - zero or more values for this node.
* [`children`](#children-node) - zero or more children for this node.
### `prop` node
Represents a property of a node, which is a key/value pair in KDL.
#### Values
* `key` (optional) - String key for the property. If this value is missing, the `prop` node's attributes will apply to all properties of its parent.
#### Properties
* `description` (optional): An informational description of the purpose of this property.
* `id` (optional): A globally unique identifier for this property.
* `ref` (optional): A globally unique reference to another property's ID. If present, all properties defined in the target property will be copied to this property, replacing any conflicts.
#### Children
* `required` (optional): A boolean value indicating whether this property is required.
* Any [validation node](#validation-nodes).
### `value` node
Used to describe one or more values for a KDL node.
#### Values
None.
#### Properties
* `description` (optional): An informational description of the purpose of this value.
* `id` (optional): A globally unique identifier for this value.
* `ref` (optional): A globally unique reference to another value's ID. If present, all values defined in the target value will be copied to this value, replacing any conflicts.
#### Children
* `min` (optional): Minimum number of values allowed.
* `max` (optional): Maximum number of values allowed.
* Any [validation node](#validation-nodes).
### `children` node
Denotes KDL node children.
#### Values
None.
#### Properties
* `description` (optional): An informational description of the purpose of this children block.
* `id` (optional): A globally unique identifier for this children block.
* `ref` (optional): A globally unique reference to another children block's ID. If present, all children defined in the target children block will be copied to this children block, replacing any conflicts.
#### Children
* [`node`](#node-node) - zero or more child nodes.
* `node-names` (optional): [Validations](#validation-nodes) to apply to the _names_ of child nodes.
* `other-nodes-allowed` (optional): Whether to allow nodes other than the ones explicitly listed here. Defaults to `false`.
### Validation Nodes
The following nodes are shared validations between props and values, and can
be used as children to either definition. They are also used to verify node
and property names when the `node-names` or `prop-names` options are activated.
#### Generic validations
* `type`: A string denoting the type of the property value.
* `enum`: A specific list of allowed values for this property. May be heterogenous as long as it agrees with the `type`, if specified.
#### String validations
* `pattern`: Regex pattern or patterns to test prop values against. Specific regex syntax may be implementation-dependent.
* `min-length`: Minimum length, if a string.
* `max-length`: Maximum length, if a string.
* `format`: Intended data format, if the value is a string. Possible values are:
* `date-time`: ISO8601 date/time format.
* `time`: "Time" section of ISO8601.
* `date`: "Date" section of ISO8601.
* `email`: RFC5302 email address.
* `idn-email`: RFC6531 internationalized email address.
* `hostname`: RFC1132 internet hostname.
* `idn-hostname`: RFC5890 internationalized internet hostname.
* `ipv4`: RFC2673 dotted-quad IPv4 address.
* `ipv6`: RFC2373 IPv6 address.
* `uri`: RFC3986 URI.
* `uri-reference`: RFC3986 URI Reference.
* `iri`: RFC3987 Internationalized Resource Identifier.
* `iri-reference`: RFC3987 Internationalized Resource Identifier Reference.
* `uri-template`: RFC6570 URI Template.
* `uuid`: RFC4122 UUID.
* `regex`: Regular expression. Specific patterns may be implementation-dependent.
#### Number validations
* `%`: Only used for numeric values. Constrains them to be multiples of the given number(s).
* `>`: Greater than.
* `>=`: Greater than or equal to.
* `<`: Less than.
* `<=`: Less than or equal to.

218
examples/kdl-schema.kdl Normal file
View File

@ -0,0 +1,218 @@
document description="KDL Schema KDL schema in KDL" schema-url="https://github.com/zkat/kdl" {
node "document" {
min 1
max 1
prop "schema-url" description="URL where you can find this schema. Informational only." {
type "url"
}
prop "description" description="General purpose and description for this document schema." {
type "string"
}
children id="node-children" {
node "node-names" description="Validations to apply specifically to arbitrary node names" {
children ref="#validations"
}
node "other-nodes-allowed" description="Whether to allow child nodes other than the ones explicitly listed. Defaults to 'false'." {
max 1
value {
min 1
max 1
type "boolean"
}
}
node "node" description="A child node belonging either to `document` or to another `node`. Nodes may be anonymous." {
value description="The name of the node. If a node name is not supplied, the node rules apply to _all_ nodes belonging to the parent." {
type "string"
max 1
}
prop "description" description="A description of this node's purpose." {
type "string"
}
prop "id" description="A globally-unique ID for this node." {
type "string"
}
prop "ref" description="A globally unique reference to another node." {
type "string"
}
children {
node "prop-names" description="Validations to apply specifically to arbitrary property names" {
children ref="#validations"
}
node "other-props-allowed" description="Whether to allow properties other than the ones explicitly listed. Defaults to 'false'." {
max 1
value {
min 1
max 1
type "boolean"
}
}
node "min" description="minimum number of instances of this node in its parent's children." {
max 1
value {
min 1
max 1
type "number"
}
}
node "max" description="maximum number of instances of this node in its parent's children." {
max 1
value {
min 1
max 1
type "number"
}
}
node "prop" description="A node property key/value pair." {
value description="The property key." {
type "string"
}
prop "id" description="A globally-unique ID of this property." {
type "string"
}
prop "ref" description="A globally unique reference to another property node." {
type "string"
}
prop "description" description="A description of this property's purpose." {
type "string"
}
children description="Property-specific validations." {
node "required" description="Whether this property is required if its parent is present." {
max 1
value {
min 1
max 1
type "boolean"
}
}
}
children id="validations" description="General value validations." {
node "type" description="The type for this prop's value." {
max 1
value {
min 1
type "string"
}
}
node "enum" description="An enumeration of possible values" {
max 1
value description="Enumeration choices" {
min 1
}
}
node "pattern" description="PCRE (Regex) pattern or patterns to test prop values against." {
value {
min 1
type "string"
}
}
node "min-length" description="Minimum length of prop value, if it's a string." {
max 1
value {
min 1
type "number"
}
}
node "max-length" description="Maximum length of prop value, if it's a string." {
max 1
value {
min 1
type "number"
}
}
node "format" description="Intended data format, if the value is a string." {
max 1
value {
min 1
type "string"
// https://json-schema.org/understanding-json-schema/reference/string.html#format
enum "date-time" "date" "time" "email" "idn-email" "hostname" "idn-hostname" "ipv4" "ipv6" "uri" "uri-reference" "iri", "iri-reference" "uri-template" "regex" "uuid"
}
}
node "%" description="Only used for numeric values. Constrains them to be multiples of the given number(s)" {
max 1
value {
min 1
type "number"
}
}
node ">" description="Only used for numeric values. Constrains them to be greater than the given number(s)" {
max 1
value {
min 1
max 1
type "number"
}
}
node ">=" description="Only used for numeric values. Constrains them to be greater than or equal to the given number(s)" {
max 1
value {
min 1
max 1
type "number"
}
}
node "<" description="Only used for numeric values. Constrains them to be less than the given number(s)" {
max 1
value {
min 1
max 1
type "number"
}
}
node "<=" description="Only used for numeric values. Constrains them to be less than or equal to the given number(s)" {
max 1
value {
min 1
max 1
type "number"
}
}
}
}
node "value" description="one or more direct node values" {
prop "id" description="A globally-unique ID of this value." {
type "string"
}
prop "ref" description="A globally unique reference to another value node." {
type "string"
}
prop "description" description="A description of this property's purpose." {
type "string"
}
children ref="#validations"
children description="Node value-specific validations" {
node "min" description="minimum number of values for this node." {
max 1
value {
min 1
max 1
type "number"
}
}
node "max" description="maximum number of values for this node." {
max 1
value {
min 1
max 1
type "number"
}
}
}
}
node "children" {
prop "id" description="A globally-unique ID of this children node." {
type "string"
}
prop "ref" description="A globally unique reference to another children node." {
type "string"
}
prop "description" description="A description of this these children's purpose." {
type "string"
}
children ref="#node-children"
}
}
}
}
}
}