From d87979f175f00d357fa9582f1298ed5937224daa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kat=20March=C3=A1n?= Date: Tue, 31 Aug 2021 12:03:27 -0700 Subject: [PATCH] KDL schema spec (#104) Fixes: https://github.com/kdl-org/kdl/issues/83 --- SCHEMA-SPEC.md | 161 +++++++++++++++++++++++++++++ examples/kdl-schema.kdl | 218 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 379 insertions(+) create mode 100644 SCHEMA-SPEC.md create mode 100644 examples/kdl-schema.kdl diff --git a/SCHEMA-SPEC.md b/SCHEMA-SPEC.md new file mode 100644 index 0000000..d891ffa --- /dev/null +++ b/SCHEMA-SPEC.md @@ -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. diff --git a/examples/kdl-schema.kdl b/examples/kdl-schema.kdl new file mode 100644 index 0000000..e6c8b59 --- /dev/null +++ b/examples/kdl-schema.kdl @@ -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" + } + } + } + } + } +}