mirror of https://github.com/kdl-org/kdl.git
Merge b6d5eb2739 into b8570137b6
This commit is contained in:
commit
06dfc692fb
|
|
@ -1,17 +1,16 @@
|
||||||
# KDL Schema Specification
|
# KDL Schema Language Specification
|
||||||
|
|
||||||
The KDL Schema specification describes a schema language for use with KDL,
|
The KDL Schema Language specification describes a schema language for use with
|
||||||
written in KDL itself. A schema language allows users to describe and
|
KDL. A schema language allows users to describe and constrain the allowed
|
||||||
constrain the allowed semantics of a KDL document. This can be used for many
|
semantics of a document. This can be used for many purposes: documentation for
|
||||||
purposes: documentation for users, automated verification, or even automated
|
users, automated verification, or even automated generation of bindings!
|
||||||
generation of bindings!
|
|
||||||
|
|
||||||
This document describes KDL Schema version `1.0.0`. It was released on September 11, 2021.
|
This document describes KDL Schema version `2.0.0`. It is unreleased.
|
||||||
|
|
||||||
## The Formal Schema
|
## The Formal Schema
|
||||||
|
|
||||||
For the full KDL Schema schema itself, see
|
For the full KDL Schema Language schema itself, see
|
||||||
[examples/kdl-schema.kdl](./examples/kdl-schema.kdl).
|
[schema/ksl-schema.kdl](./schema/ksl-schema.kdl).
|
||||||
|
|
||||||
## Definition
|
## Definition
|
||||||
|
|
||||||
|
|
@ -39,6 +38,14 @@ None.
|
||||||
* `tag-names` (optional): [Validations](#validation-nodes) to apply to the _names_ of tags of child nodes.
|
* `tag-names` (optional): [Validations](#validation-nodes) to apply to the _names_ of tags of child nodes.
|
||||||
* `other-tags-allowed` (optional): Whether to allow node tags other than the ones explicitly listed here. Defaults to `#false`.
|
* `other-tags-allowed` (optional): Whether to allow node tags other than the ones explicitly listed here. Defaults to `#false`.
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
|
```kdl
|
||||||
|
document {
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### `info` node
|
### `info` node
|
||||||
|
|
||||||
The `info` node describes the schema itself.
|
The `info` node describes the schema itself.
|
||||||
|
|
|
||||||
|
|
@ -1,376 +0,0 @@
|
||||||
document {
|
|
||||||
info {
|
|
||||||
title "KDL Schema" lang=en
|
|
||||||
description "KDL Schema KDL schema in KDL" lang=en
|
|
||||||
author "Kat Marchán" {
|
|
||||||
link "https://github.com/zkat" rel=self
|
|
||||||
}
|
|
||||||
contributor "Lars Willighagen" {
|
|
||||||
link "https://github.com/larsgw" rel=self
|
|
||||||
}
|
|
||||||
link "https://github.com/zkat/kdl" rel=documentation
|
|
||||||
license "Creative Commons Attribution-ShareAlike 4.0 International License" spdx=CC-BY-SA-4.0 {
|
|
||||||
link "https://creativecommons.org/licenses/by-sa/4.0/" lang=en
|
|
||||||
}
|
|
||||||
published "2021-08-31"
|
|
||||||
modified "2021-09-01"
|
|
||||||
}
|
|
||||||
node document {
|
|
||||||
min 1
|
|
||||||
max 1
|
|
||||||
children id=node-children {
|
|
||||||
node node-names id=node-names-node description="Validations to apply specifically to arbitrary node names" {
|
|
||||||
children ref=#"[id="validations"]"#
|
|
||||||
}
|
|
||||||
node other-nodes-allowed id=other-nodes-allowed-node 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 tag-names description="Validations to apply specifically to arbitrary type tag names" {
|
|
||||||
children ref=#"[id="validations"]"#
|
|
||||||
}
|
|
||||||
node other-tags-allowed description="Whether to allow child node tags other than the ones explicitly listed. Defaults to '#false'." {
|
|
||||||
max 1
|
|
||||||
value {
|
|
||||||
min 1
|
|
||||||
max 1
|
|
||||||
type boolean
|
|
||||||
}
|
|
||||||
}
|
|
||||||
node info description="A child node that describes the schema itself." {
|
|
||||||
children {
|
|
||||||
node title description="The title of the schema or the format it describes" {
|
|
||||||
value description="The title text" {
|
|
||||||
type string
|
|
||||||
min 1
|
|
||||||
max 1
|
|
||||||
}
|
|
||||||
prop lang id=info-lang description="The language of the text" {
|
|
||||||
type string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
node description description="A description of the schema or the format it describes" {
|
|
||||||
value description="The description text" {
|
|
||||||
type string
|
|
||||||
min 1
|
|
||||||
max 1
|
|
||||||
}
|
|
||||||
prop ref=#"[id="info-lang"]"#
|
|
||||||
}
|
|
||||||
node author description="Author of the schema" {
|
|
||||||
value id=info-person-name description="Person name" {
|
|
||||||
type string
|
|
||||||
min 1
|
|
||||||
max 1
|
|
||||||
}
|
|
||||||
prop orcid id=info-orcid description="The ORCID of the person" {
|
|
||||||
type string
|
|
||||||
pattern #"\d{4}-\d{4}-\d{4}-\d{4}"#
|
|
||||||
}
|
|
||||||
children {
|
|
||||||
node ref=#"[id="info-link"]"#
|
|
||||||
}
|
|
||||||
}
|
|
||||||
node contributor description="Contributor to the schema" {
|
|
||||||
value ref=#"[id="info-person-name"]"#
|
|
||||||
prop ref=#"[id="info-orcid"]"#
|
|
||||||
children {
|
|
||||||
node ref=#"[id="info-link"]"#
|
|
||||||
}
|
|
||||||
}
|
|
||||||
node link id=info-link description="Links to itself, and to sources describing it" {
|
|
||||||
value description="A URL that the link points to" {
|
|
||||||
type string
|
|
||||||
format url irl
|
|
||||||
min 1
|
|
||||||
max 1
|
|
||||||
}
|
|
||||||
prop rel description="The relation between the current entity and the URL" {
|
|
||||||
type string
|
|
||||||
enum self documentation
|
|
||||||
}
|
|
||||||
prop ref=#"[id="info-lang"]"#
|
|
||||||
}
|
|
||||||
node license description="The license(s) that the schema is licensed under" {
|
|
||||||
value description="Name of the used license" {
|
|
||||||
type string
|
|
||||||
min 1
|
|
||||||
max 1
|
|
||||||
}
|
|
||||||
prop spdx description="An SPDX license identifier" {
|
|
||||||
type string
|
|
||||||
}
|
|
||||||
children {
|
|
||||||
node ref=#"[id="info-link"]"#
|
|
||||||
}
|
|
||||||
}
|
|
||||||
node published description="When the schema was published" {
|
|
||||||
value description="Publication date" {
|
|
||||||
type string
|
|
||||||
format date
|
|
||||||
min 1
|
|
||||||
max 1
|
|
||||||
}
|
|
||||||
prop time id=info-time description="A time to accompany the date" {
|
|
||||||
type string
|
|
||||||
format time
|
|
||||||
}
|
|
||||||
}
|
|
||||||
node modified description="When the schema was last modified" {
|
|
||||||
value description="Modification date" {
|
|
||||||
type string
|
|
||||||
format date
|
|
||||||
min 1
|
|
||||||
max 1
|
|
||||||
}
|
|
||||||
prop ref=#"[id="info-time"]"#
|
|
||||||
}
|
|
||||||
node version description="The version number of this version of the schema" {
|
|
||||||
value description="Semver version number" {
|
|
||||||
type string
|
|
||||||
pattern #"^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$"#
|
|
||||||
min 1
|
|
||||||
max 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
node tag id=tag-node description="A tag belonging to a child node of `document` or another node." {
|
|
||||||
value description="The name of the tag. If a tag 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
|
|
||||||
format kdl-query
|
|
||||||
}
|
|
||||||
children {
|
|
||||||
node ref=#"[id="node-names-node"]"#
|
|
||||||
node ref=#"[id="other-nodes-allowed-node"]"#
|
|
||||||
node ref=#"[id="node-node"]"#
|
|
||||||
}
|
|
||||||
}
|
|
||||||
node node id=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
|
|
||||||
format kdl-query
|
|
||||||
}
|
|
||||||
children {
|
|
||||||
node prop-names description="Validations to apply specifically to arbitrary property names" {
|
|
||||||
children ref=#"[id="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 ref=#"[id="value-tag-node"]"#
|
|
||||||
node prop id="prop-node" 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
|
|
||||||
format kdl-query
|
|
||||||
}
|
|
||||||
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 tag id=value-tag-node description="The tags associated with this value" {
|
|
||||||
max 1
|
|
||||||
children ref=#"[id="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." {
|
|
||||||
max 1
|
|
||||||
value {
|
|
||||||
min 1
|
|
||||||
type string
|
|
||||||
// https://json-schema.org/understanding-json-schema/reference/string.html#format
|
|
||||||
enum date-time date time duration decimal currency country-2 country-3 country-subdivision email idn-email hostname idn-hostname ipv4 ipv6 url url-reference irl irl-reference url-template regex uuid kdl-query i8 i16 i32 i64 u8 u16 u32 u64 isize usize f32 f64 decimal64 decimal128
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 id=value-node 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
|
|
||||||
format kdl-query
|
|
||||||
}
|
|
||||||
prop description description="A description of this property's purpose." {
|
|
||||||
type string
|
|
||||||
}
|
|
||||||
children ref=#"[id="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 id=children-node {
|
|
||||||
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
|
|
||||||
format kdl-query
|
|
||||||
}
|
|
||||||
prop description description="A description of this these children's purpose." {
|
|
||||||
type string
|
|
||||||
}
|
|
||||||
children ref=#"[id="node-children"]"#
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
node definitions description="Definitions to reference in parts of the top-level nodes" {
|
|
||||||
children {
|
|
||||||
node ref=#"[id="node-node"]"#
|
|
||||||
node ref=#"[id="value-node"]"#
|
|
||||||
node ref=#"[id="prop-node"]"#
|
|
||||||
node ref=#"[id="children-node"]"#
|
|
||||||
node ref=#"[id="tag-node"]"#
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,172 @@
|
||||||
|
@kdl:schema "https://github.com/kdl-org/kdl/blob/main/schema/kdl-schema.kdl"
|
||||||
|
|
||||||
|
metadata {
|
||||||
|
// TODO: update this link when we're ready to release something.
|
||||||
|
link "https://github.com/kdl-org/kdl/blob/main/schema/cargo.kdl" rel=self
|
||||||
|
title "Cargo Schema" lang=en
|
||||||
|
description "KDL-based translation of the Cargo.toml schema." lang=en
|
||||||
|
author "Kat Marchán" {
|
||||||
|
link "https://github.com/zkat" rel=self
|
||||||
|
}
|
||||||
|
link "https://github.com/kdl-org/kdl" rel=documentation
|
||||||
|
link "https://doc.rust-lang.org/cargo/reference/manifest.html" rel=documentation
|
||||||
|
license "Creative Commons Attribution-ShareAlike 4.0 International License" spdx=CC-BY-SA-4.0 {
|
||||||
|
link "https://creativecommons.org/licenses/by-sa/4.0/" lang=en
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
children {
|
||||||
|
node package title="Describes a package" {
|
||||||
|
children {
|
||||||
|
node name title="The name of the package" {
|
||||||
|
required
|
||||||
|
arg {
|
||||||
|
type string
|
||||||
|
pattern #"^[a-zA-Z0-0\-_]+$"#
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node version title="The version of the package." {
|
||||||
|
arg {
|
||||||
|
type string
|
||||||
|
// From https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
|
||||||
|
pattern #"^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$"#
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node authors title="The authors of the package." {
|
||||||
|
repeatable
|
||||||
|
args {
|
||||||
|
distinct
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
children {
|
||||||
|
node - {
|
||||||
|
repeatable
|
||||||
|
arg title="Name" {
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
prop email title="Email address" {
|
||||||
|
type string
|
||||||
|
format email
|
||||||
|
}
|
||||||
|
prop about title="Brief note about author (role, etc)" {
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node edition title="The Rust edition." {
|
||||||
|
arg {
|
||||||
|
type string
|
||||||
|
enum "2015" "2018" "2021" "2024"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node rust-version title="The minimal supported Rust version." {
|
||||||
|
arg {
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node description title="A description of the package." {
|
||||||
|
arg {
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node documentation title="URL of the package documentation." {
|
||||||
|
arg {
|
||||||
|
type string
|
||||||
|
format url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node readme title="Path to the package’s README file." {
|
||||||
|
arg {
|
||||||
|
type string #boolean
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node homepage title="URL of the package homepage." {
|
||||||
|
arg {
|
||||||
|
type string
|
||||||
|
format url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node repository title="URL of the package source repository." {
|
||||||
|
arg {
|
||||||
|
type string
|
||||||
|
format url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node license title="The package license." {
|
||||||
|
arg {
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node license-file title="Path to the text of the license." {
|
||||||
|
arg {
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node keywords title="Keywords for the package." {
|
||||||
|
args {
|
||||||
|
type string
|
||||||
|
// No pattern because keyword restrictions are only on
|
||||||
|
// crates.io
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node categories title="Categories of the package." {
|
||||||
|
args {
|
||||||
|
type string
|
||||||
|
// No pattern because category restrictions are only on
|
||||||
|
// crates.io
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node workspace title="Path to the workspace for the package." {
|
||||||
|
arg {
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node build title="Path to the package build script." {
|
||||||
|
arg {
|
||||||
|
type string boolean
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node links title="Name of the native library the package links with." {
|
||||||
|
arg {
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node exclude title="Files to exclude when publishing." {
|
||||||
|
args {
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node include title="Files to include when publishing." {
|
||||||
|
args {
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node publish title="Can be used to prevent publishing the package." {
|
||||||
|
// TODO: This is a good example of where we might need smarter
|
||||||
|
// comstraints ("either a single boolean, or 1+ strings")
|
||||||
|
args {
|
||||||
|
type string boolean
|
||||||
|
}
|
||||||
|
]
|
||||||
|
node metadata title="Extra settings for external tools." {
|
||||||
|
repeat
|
||||||
|
args
|
||||||
|
props {
|
||||||
|
allow-others
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node default-run title="The default binary to run by cargo run." {
|
||||||
|
arg {
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node no-autolib title="Disables library auto discovery."
|
||||||
|
node no-autobins title="Disables binary auto discovery."
|
||||||
|
node no-autoexamples title="Disables example auto discovery."
|
||||||
|
node no-autotests title="Disables test auto discovery."
|
||||||
|
node no-autobenches title="Disables bench auto discovery."
|
||||||
|
node resolver title="Sets the dependency resolver to use."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,951 @@
|
||||||
|
// TODO:
|
||||||
|
// * dependentRequired
|
||||||
|
// * dependentSchema
|
||||||
|
// * if-then-else
|
||||||
|
// * composition (anyOf, allOf, oneOf, not, etc: https://json-schema.org/understanding-json-schema/reference/combining)
|
||||||
|
// * something like `xsd:group` for the above, instead? Including `xsd:sequence` stuff.
|
||||||
|
// * something to configure LSP semanticTokens with
|
||||||
|
|
||||||
|
@ksl:schema "https://github.com/kdl-org/kdl/blob/main/examples/ksl-schema.kdl"
|
||||||
|
|
||||||
|
metadata {
|
||||||
|
// TODO: update this link when we're ready to release something.
|
||||||
|
id "https://github.com/kdl-org/kdl/blob/main/examples/ksl-schema.kdl"
|
||||||
|
title "KDL Schema"
|
||||||
|
description "KDL Schema schema using KDL Schema"
|
||||||
|
author "Kat Marchán" {
|
||||||
|
link "https://github.com/zkat"
|
||||||
|
}
|
||||||
|
contributor "Lars Willighagen" {
|
||||||
|
link "https://github.com/larsgw"
|
||||||
|
}
|
||||||
|
link "https://github.com/kdl-org/kdl" rel=documentation
|
||||||
|
license "Creative Commons Attribution-ShareAlike 4.0 International License" spdx=CC-BY-SA-4.0 {
|
||||||
|
link "https://creativecommons.org/licenses/by-sa/4.0/"
|
||||||
|
}
|
||||||
|
published "2021-08-31"
|
||||||
|
modified "2021-09-01"
|
||||||
|
}
|
||||||
|
|
||||||
|
document {
|
||||||
|
node example about="""
|
||||||
|
An example document validated by this schema
|
||||||
|
|
||||||
|
The `example` node is completely inert. It SHOULD contain an
|
||||||
|
illustrative example of a document that would be valid if checked
|
||||||
|
against this schema.
|
||||||
|
""" {
|
||||||
|
repeatable
|
||||||
|
ref about-mixin
|
||||||
|
arg about="""
|
||||||
|
Example filename
|
||||||
|
|
||||||
|
A descriptive filename that this example document might have, e.g. `mylang-schema.kdl`.
|
||||||
|
""" {
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node metadata about="""
|
||||||
|
Schema metadata
|
||||||
|
|
||||||
|
Contains metadata about the schema itself.
|
||||||
|
""" {
|
||||||
|
required
|
||||||
|
children {
|
||||||
|
node id about="""
|
||||||
|
Schema identifier
|
||||||
|
|
||||||
|
The unique identifier for this schema. MUST be a valid URL/IRL.
|
||||||
|
When parsing a schema, implementations SHOULD NOT attempt to
|
||||||
|
visit the URL itself, as it is not necessary for it to be valid.
|
||||||
|
Parsers verifying against a schema MAY look at the given URL for
|
||||||
|
a document if they don't already have a valid copy.
|
||||||
|
""" {
|
||||||
|
arg {
|
||||||
|
type string
|
||||||
|
format url irl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node title about="""
|
||||||
|
Schema title
|
||||||
|
|
||||||
|
The title of the schema or the format it describes.
|
||||||
|
""" {
|
||||||
|
arg about="The title text" {
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node description about="""
|
||||||
|
Schema description
|
||||||
|
|
||||||
|
A description of the schema or the format it validates, which
|
||||||
|
may include its purposes, its usage, and even examples.
|
||||||
|
""" {
|
||||||
|
arg about="Description text" {
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node author about="""
|
||||||
|
Schema author
|
||||||
|
|
||||||
|
An author for the schema.
|
||||||
|
""" {
|
||||||
|
ref person-mixin
|
||||||
|
repeatable
|
||||||
|
}
|
||||||
|
node contributor about="""
|
||||||
|
Schema contributor
|
||||||
|
|
||||||
|
A contributor to the schema might not be considered an author.
|
||||||
|
""" {
|
||||||
|
ref person-mixin
|
||||||
|
repeatable
|
||||||
|
}
|
||||||
|
node link about="""
|
||||||
|
External link
|
||||||
|
|
||||||
|
Link to an external resource of some sort, such as the
|
||||||
|
containing item itself (`rel=self`, the default) or
|
||||||
|
documentation (`rel=documentation`). Implementations MAY visit
|
||||||
|
the URL, but MUST NOT assume it is valid.
|
||||||
|
""" {
|
||||||
|
ref link-mixin
|
||||||
|
repeatable
|
||||||
|
arg about="Link URL\n\nA URL that the link points to." {
|
||||||
|
type string
|
||||||
|
format url irl
|
||||||
|
}
|
||||||
|
prop rel about="Link relationship\n\nThe relation between the current entity and the URL." {
|
||||||
|
type string
|
||||||
|
enum self documentation disallow-others=#false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node license about="""
|
||||||
|
Schema license
|
||||||
|
|
||||||
|
The license(s) that the schema is licensed under.
|
||||||
|
""" {
|
||||||
|
repeatable
|
||||||
|
arg description="Name of the used license" {
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
prop spdx description="An SPDX license identifier" {
|
||||||
|
type string
|
||||||
|
// TODO: validation?
|
||||||
|
}
|
||||||
|
prop path about="Path to a local license file" {
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
prop url about="URL to an externally-stored license" {
|
||||||
|
type string
|
||||||
|
format url url-reference irl irl-reference
|
||||||
|
}
|
||||||
|
children {
|
||||||
|
node link about="Link to license" {
|
||||||
|
ref link-mixin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node published about="""
|
||||||
|
Schema publication date
|
||||||
|
|
||||||
|
Date or data+time when the schema was published.
|
||||||
|
""" {
|
||||||
|
arg about="Publication date" {
|
||||||
|
type string
|
||||||
|
format date date-time
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node modified about="""
|
||||||
|
Schema modification date
|
||||||
|
|
||||||
|
When the schema was modified. If used multiple times, the most
|
||||||
|
recent date will be considered 'latest'.
|
||||||
|
""" {
|
||||||
|
repeatable
|
||||||
|
args about="Modification date" {
|
||||||
|
type string
|
||||||
|
format date date-time
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node version about="""
|
||||||
|
Schema semver version
|
||||||
|
|
||||||
|
The version number of this version of the schema, in semver
|
||||||
|
format.
|
||||||
|
""" {
|
||||||
|
arg about="Semver version number" {
|
||||||
|
type string
|
||||||
|
// https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string.
|
||||||
|
pattern #"^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$"#
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node definitions about="""
|
||||||
|
Inert validation definitions
|
||||||
|
|
||||||
|
An optional set of definitions that may be referenced elsewhere in the
|
||||||
|
schema. They will be inert (that is, not directly apply to the document)
|
||||||
|
unless referenced by another node inside `document`.
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
node document {
|
||||||
|
ref children-node
|
||||||
|
node @ksl:schema about="""
|
||||||
|
Schema reference
|
||||||
|
|
||||||
|
Reference(s) for the schema(s) describing this document. They
|
||||||
|
MUST be properly-formatted URLs. Implementations MAY attempt to
|
||||||
|
visit them, but MUST NOT assume they are valid.
|
||||||
|
|
||||||
|
If multiple URLs are provided, or if multiple `@ksl:schema`
|
||||||
|
nodes are present, ALL schemas MUST successfully validate in
|
||||||
|
order for the document to validate, unless `warn-only` is
|
||||||
|
`#true`.
|
||||||
|
|
||||||
|
In such a case, implementations SHOULD warn that validation has
|
||||||
|
failed and report which schema failed to pass--they SHOULD
|
||||||
|
include more details about what the specific failure was, but
|
||||||
|
MAY simply indicate that certain schema(s) failed to validate.
|
||||||
|
""" {
|
||||||
|
repeatable
|
||||||
|
prop warn-only about="Validation failures should ONLY be warnings." {
|
||||||
|
type boolean
|
||||||
|
default #false
|
||||||
|
}
|
||||||
|
// TODO(@zkat): is this the best way to do it?
|
||||||
|
one-of {
|
||||||
|
arg {
|
||||||
|
type string
|
||||||
|
format url url-reference irl irl-reference
|
||||||
|
}
|
||||||
|
arg about="Disallow the `@ksl:schema` node altogether" {
|
||||||
|
enum #false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
children {
|
||||||
|
node children about="""
|
||||||
|
Node children
|
||||||
|
|
||||||
|
Validations and definitions used for all nodes in this scope.
|
||||||
|
Children are only allowed on nodes (or the toplevel document) if
|
||||||
|
at least one `children` node is present in their definitions.
|
||||||
|
""" {
|
||||||
|
children {
|
||||||
|
node min about="""
|
||||||
|
Minimum number of children
|
||||||
|
""" {
|
||||||
|
arg {
|
||||||
|
type integer
|
||||||
|
default 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node max about="""
|
||||||
|
Maximum number of children
|
||||||
|
""" {
|
||||||
|
arg {
|
||||||
|
type integer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node names about="""
|
||||||
|
Child node name validations
|
||||||
|
|
||||||
|
String validations to apply to all node names in this scope.
|
||||||
|
""" {
|
||||||
|
ref string-validations
|
||||||
|
ref about-mixin
|
||||||
|
repeatable
|
||||||
|
}
|
||||||
|
node disallow-others about="""
|
||||||
|
Disallow other children
|
||||||
|
|
||||||
|
If present/`#true`, blocks child nodes in this scope
|
||||||
|
other than the ones explicitly listed and those allowed
|
||||||
|
by `names`.
|
||||||
|
""" {
|
||||||
|
arg {
|
||||||
|
type boolean
|
||||||
|
default #false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node disallow about="""
|
||||||
|
Disallows matching nodes
|
||||||
|
|
||||||
|
Node specifications under this node will be matched
|
||||||
|
against children and fail validation if a child matches.
|
||||||
|
""" {
|
||||||
|
children {
|
||||||
|
ref node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node node about="""
|
||||||
|
A KDL node
|
||||||
|
|
||||||
|
Declares a KDL node belonging either to the top-level
|
||||||
|
document or to another `node`'s children.
|
||||||
|
""" {
|
||||||
|
ref about-mixin
|
||||||
|
repeatable
|
||||||
|
arg about="Node name\n\nThe name of the node." {
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
prop id about="Node identifier\n\nA schema-unique ID/anchor for this node." {
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
children {
|
||||||
|
node ref about="""
|
||||||
|
A reference to a node defined elsewhere.
|
||||||
|
|
||||||
|
Each `ref` child will be interpreted in order of
|
||||||
|
appearance. Any overlapping definitions will replace
|
||||||
|
preceding instances, with each subsequent `ref`
|
||||||
|
replacing any duplicate node components.
|
||||||
|
|
||||||
|
The replacement rules are as follows, and apply recursively:
|
||||||
|
* node properties MUST by replaced by key.
|
||||||
|
* node arguments MUST be replaced by order of appearance.
|
||||||
|
* `prop` definitions MUST be replaced by key (their first argument)
|
||||||
|
* `arg` definitions MUST be replaced based on _order of
|
||||||
|
appearance_. That is, the first `arg` in ref `B` till be
|
||||||
|
merged into the first `arg` in preceding ref `A`.
|
||||||
|
* For all other components:
|
||||||
|
* If the definition specified is marked as
|
||||||
|
`repeatable`, then all definitions using that node
|
||||||
|
will be concatenated, with later `ref`s
|
||||||
|
concatenating definitions after the previous `ref`'s
|
||||||
|
definitions.
|
||||||
|
* If the definition is NOT marked as `repeatable`,
|
||||||
|
it will be replaced by subsequent `ref`s.
|
||||||
|
|
||||||
|
Once all `ref` children are resolved, the containing
|
||||||
|
node's own items will override anything defined by
|
||||||
|
`ref`s, using the same rules as above (essentially, the
|
||||||
|
current node is treated as a 'final `ref`').
|
||||||
|
|
||||||
|
If both an ID argument and a `path` are provided,
|
||||||
|
the ID will take precedence and, if not found, fall
|
||||||
|
back to the path. For `id` and `path` children,
|
||||||
|
precedence is in order of appearance, regardless of
|
||||||
|
whether the child is an `id` or a `path`.
|
||||||
|
|
||||||
|
If no items resolve into a valid ref, validation
|
||||||
|
MUST error, unless the ref is configured as
|
||||||
|
`optional`, in which case validation MAY warn, but
|
||||||
|
MUST NOT fail.
|
||||||
|
""" {
|
||||||
|
repeatable
|
||||||
|
arg about="KPath-based reference to another node" {
|
||||||
|
type string
|
||||||
|
format kpath
|
||||||
|
}
|
||||||
|
prop base about="""
|
||||||
|
Base schema
|
||||||
|
|
||||||
|
The schema to resolve references against. If not
|
||||||
|
provided, the base schema SHALL be the one
|
||||||
|
defined in `metadata > id` for the current
|
||||||
|
schema.
|
||||||
|
|
||||||
|
Relative schema references SHALL be resolved
|
||||||
|
against `metadata > id`.
|
||||||
|
""" {
|
||||||
|
type string
|
||||||
|
format url-reference irl-reference
|
||||||
|
}
|
||||||
|
children {
|
||||||
|
node path about="KPath-based reference to another node." {
|
||||||
|
repeatable
|
||||||
|
arg {
|
||||||
|
type string
|
||||||
|
format kpath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node undefine about="Undefine a node with this name" {
|
||||||
|
arg {
|
||||||
|
optional
|
||||||
|
type boolean
|
||||||
|
default #true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node required about="""
|
||||||
|
Node is required
|
||||||
|
|
||||||
|
By default, all declared child nodes are
|
||||||
|
optional. Including this option will require
|
||||||
|
that this node always appear in its parent's
|
||||||
|
children block.
|
||||||
|
""" {
|
||||||
|
arg {
|
||||||
|
type boolean
|
||||||
|
default #true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node repeatable about="""
|
||||||
|
Node is repeatable
|
||||||
|
|
||||||
|
By default, each node in a `children` block may
|
||||||
|
only appear once in its scope. When this option
|
||||||
|
is present, the node will be allowed to have
|
||||||
|
multiple instances within the same scope.
|
||||||
|
""" {
|
||||||
|
prop min about="""
|
||||||
|
Minimum node count
|
||||||
|
|
||||||
|
Minimum number of repeated instances of this
|
||||||
|
node that must appear in the same scope.
|
||||||
|
""" {
|
||||||
|
arg {
|
||||||
|
gte 0
|
||||||
|
type integer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prop max about="""
|
||||||
|
Maximum node count
|
||||||
|
|
||||||
|
Maximum numbers of repeated instances of
|
||||||
|
this node that may appear in the same scope.
|
||||||
|
""" {
|
||||||
|
arg {
|
||||||
|
gte 0
|
||||||
|
type integer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node deprecated about="""
|
||||||
|
Mark node as deprecated
|
||||||
|
|
||||||
|
When present, this node will be considered a
|
||||||
|
deprecated part of the API. You may optionally
|
||||||
|
supply a message, and/or a reference to a node
|
||||||
|
that should be used instead.
|
||||||
|
""" {
|
||||||
|
arg {
|
||||||
|
optional
|
||||||
|
type boolean
|
||||||
|
default #true
|
||||||
|
}
|
||||||
|
prop message about="""
|
||||||
|
Deprecation message
|
||||||
|
|
||||||
|
A helpful deprecation message that may
|
||||||
|
explain why the node was deprecated and
|
||||||
|
other information, such as when the node
|
||||||
|
will be removed altogether. Users SHOULD use
|
||||||
|
`by=` and `by-kpath` to specify what node
|
||||||
|
this will be replaced with instead of
|
||||||
|
including it in the `message` itself.
|
||||||
|
""" {
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
prop by about="Deprecated by this node `id`" {
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
prop by-kpath about="Deprecated by this node KPath" {
|
||||||
|
type string
|
||||||
|
format kpath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node annotations about="""
|
||||||
|
Node type annotations
|
||||||
|
|
||||||
|
Validations to apply specifically to arbitrary
|
||||||
|
node type annotation names.
|
||||||
|
""" {
|
||||||
|
ref about-mixin
|
||||||
|
ref string-validations
|
||||||
|
repeatable
|
||||||
|
}
|
||||||
|
node prop about="""
|
||||||
|
Node property
|
||||||
|
|
||||||
|
A node property key/value pair. Properties
|
||||||
|
declared with `prop` are always optional, unless
|
||||||
|
marked as `required` or included in
|
||||||
|
`props:required`.
|
||||||
|
""" {
|
||||||
|
ref about-mixin
|
||||||
|
ref value-validations
|
||||||
|
repeatable
|
||||||
|
arg about="The property key" {
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
children about="Property-specific validations" {
|
||||||
|
node required about="Whether this property is required in the node." {
|
||||||
|
arg {
|
||||||
|
optional
|
||||||
|
type boolean
|
||||||
|
default #true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node props about="""
|
||||||
|
General property validations
|
||||||
|
|
||||||
|
Validations to apply to all properties of this
|
||||||
|
node.
|
||||||
|
""" {
|
||||||
|
ref about-mixin
|
||||||
|
ref value-validations
|
||||||
|
children {
|
||||||
|
node names about="Validations to apply to all property names." {
|
||||||
|
ref string-validations
|
||||||
|
repeatable
|
||||||
|
}
|
||||||
|
node min about="""
|
||||||
|
Minimum property count
|
||||||
|
|
||||||
|
Minimum number of properties this node
|
||||||
|
must have.
|
||||||
|
""" {
|
||||||
|
arg {
|
||||||
|
gte 0
|
||||||
|
type integer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node max about="""
|
||||||
|
Maximum property count
|
||||||
|
|
||||||
|
Maximum number of properties this node
|
||||||
|
may have.
|
||||||
|
""" {
|
||||||
|
arg {
|
||||||
|
gte 0
|
||||||
|
type integer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node required about="""
|
||||||
|
List of required props
|
||||||
|
|
||||||
|
List of property names that must be
|
||||||
|
present on the node. Individual `prop`
|
||||||
|
nodes may specify additional required
|
||||||
|
properties beyond those specified in
|
||||||
|
this list. Properties listed here which
|
||||||
|
already have a `prop` node marked as
|
||||||
|
`required` are allowed, but are
|
||||||
|
redundant.
|
||||||
|
""" {
|
||||||
|
args {
|
||||||
|
min 1
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node disallow-others about="""
|
||||||
|
Disallow other properties
|
||||||
|
|
||||||
|
If present, block properties that don't
|
||||||
|
match this validator.
|
||||||
|
""" {
|
||||||
|
arg {
|
||||||
|
type boolean
|
||||||
|
default #true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node arg about="""
|
||||||
|
Defines an individual, ordered argument
|
||||||
|
|
||||||
|
Each nth instance of this node will specify
|
||||||
|
validations for the corresponding nth instance
|
||||||
|
of the arg. Every specified `arg` is required,
|
||||||
|
in the given order, unless marked as `optional`.
|
||||||
|
""" {
|
||||||
|
ref about-mixin
|
||||||
|
ref value-validations
|
||||||
|
repeatable
|
||||||
|
children {
|
||||||
|
node optional about="""
|
||||||
|
Argument is not required
|
||||||
|
|
||||||
|
Specified `arg`s are required by
|
||||||
|
default.
|
||||||
|
|
||||||
|
`optional` only applies to *presence*:
|
||||||
|
an existing argument in an optional
|
||||||
|
`arg` \"slot\" that fails validation
|
||||||
|
will fail normally, even though it is
|
||||||
|
optional. As such, `optional` is only
|
||||||
|
really useful if it is on the last
|
||||||
|
`arg`, or is only followed by optional
|
||||||
|
`arg`s.
|
||||||
|
""" {
|
||||||
|
arg {
|
||||||
|
type boolean
|
||||||
|
default #true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: add a feature that will let us specify that `args`
|
||||||
|
// MUST be after any existing `arg` nodes in the current
|
||||||
|
// scope. i.e. you can't do `node x { args; arg }`
|
||||||
|
node args about="""
|
||||||
|
Validations for all args
|
||||||
|
|
||||||
|
Specifies validations for all arguments. Can be
|
||||||
|
used in conjunction with `arg`. If this node is
|
||||||
|
not present, and if there are no `arg` nodes, no
|
||||||
|
arguments will be allowed on the node at all
|
||||||
|
""" {
|
||||||
|
ref about-mixin
|
||||||
|
ref value-validation
|
||||||
|
children {
|
||||||
|
// TODO: opportunity for mutual requirements here
|
||||||
|
node min about="""
|
||||||
|
Minimum argument count
|
||||||
|
|
||||||
|
Minimum number of arguments that must be
|
||||||
|
present in a node. Must be less than or
|
||||||
|
equal to `max`, if the latter is
|
||||||
|
present.
|
||||||
|
""" {
|
||||||
|
arg {
|
||||||
|
gte 0
|
||||||
|
type integer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node max about="""
|
||||||
|
Maximum argument count
|
||||||
|
|
||||||
|
Maximum number of arguments that may be
|
||||||
|
present in a node. Must be greater than or
|
||||||
|
equal to `max`, if the latter is present.
|
||||||
|
""" {
|
||||||
|
arg {
|
||||||
|
gte 0
|
||||||
|
type integer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node distinct about="""
|
||||||
|
All arguments must be distinct
|
||||||
|
|
||||||
|
If present, all of this node's arguments
|
||||||
|
need to be distinct values.
|
||||||
|
""" {
|
||||||
|
arg {
|
||||||
|
type boolean
|
||||||
|
default #true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node children {
|
||||||
|
ref children
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
definitions {
|
||||||
|
node link-mixin about="""
|
||||||
|
External link
|
||||||
|
|
||||||
|
Link to an external resource of some sort, such as the schema
|
||||||
|
itself (`rel=self`) or documentation (`rel=documentation`).
|
||||||
|
Implementations MAY visit the URL, but MUST NOT assume it is
|
||||||
|
valid.
|
||||||
|
""" {
|
||||||
|
repeatable
|
||||||
|
arg about="Link URL\n\nA URL that the link points to." {
|
||||||
|
type string
|
||||||
|
format url irl
|
||||||
|
}
|
||||||
|
prop rel about="Link relationship\n\nThe relation between the current entity and the URL." {
|
||||||
|
type string
|
||||||
|
default self
|
||||||
|
enum self documentation disallow-others=#false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node person-mixin {
|
||||||
|
arg description="Person name" {
|
||||||
|
optional
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
prop orcid description="The ORCID of the person" {
|
||||||
|
type string
|
||||||
|
pattern #"\d{4}-\d{4}-\d{4}-\d{4}"#
|
||||||
|
}
|
||||||
|
children {
|
||||||
|
node link {
|
||||||
|
ref metadata-link
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node lang-mixin {
|
||||||
|
prop lang about="""
|
||||||
|
Content language
|
||||||
|
|
||||||
|
The (human) language of the text.
|
||||||
|
""" {
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node string-validations about="String-related validations" {
|
||||||
|
ref shared-validations
|
||||||
|
children {
|
||||||
|
node pattern about="""
|
||||||
|
Regex-based validations
|
||||||
|
|
||||||
|
Tests string values against a regular expression and passes if
|
||||||
|
the regular expression matches.
|
||||||
|
|
||||||
|
Implementations SHOULD use an EcmaScript-compatible regex engine. If they choose not to, this SHOULD be clearly documented.
|
||||||
|
""" {
|
||||||
|
args {
|
||||||
|
min 1
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node min-length about="""
|
||||||
|
Minimum string length
|
||||||
|
|
||||||
|
Minimum length of the value, if it's a string.
|
||||||
|
""" {
|
||||||
|
arg {
|
||||||
|
gte 0
|
||||||
|
type integer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node max-length about="""
|
||||||
|
Maximum string length
|
||||||
|
|
||||||
|
Maximum length of the value, if it's a string.
|
||||||
|
""" {
|
||||||
|
arg {
|
||||||
|
gte 0
|
||||||
|
type integer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node format about="""
|
||||||
|
Specifies the format of the value
|
||||||
|
|
||||||
|
Any supported type annotation from the KDL spec may be
|
||||||
|
specified. It is up to implementations whether they validate
|
||||||
|
this node. They SHOULD document the ones they support, if any.
|
||||||
|
|
||||||
|
Any format that the implementation supports MUST be compliant
|
||||||
|
with the specified reserved format in the KDL spec, and only
|
||||||
|
apply it to the specified data types (e.g. `u8` can only apply
|
||||||
|
to items of type `integer`, not to `string` or `number`). If the
|
||||||
|
checked value is not of an applicable type, the implementation
|
||||||
|
MUST skip applying this to the given type. It MAY choose to warn
|
||||||
|
about skipping the format check.
|
||||||
|
|
||||||
|
If a value specifies multiple `type`s, any `format`s are checked
|
||||||
|
as usual against the matrix of compatible `type`/`format`
|
||||||
|
values.
|
||||||
|
|
||||||
|
Implementations MAY choose either error or simply warn about
|
||||||
|
format violations. They SHOULD document the behavior, and MAY
|
||||||
|
provide configuration for it.
|
||||||
|
"""
|
||||||
|
repeatable
|
||||||
|
args {
|
||||||
|
min 1
|
||||||
|
type string
|
||||||
|
// https://json-schema.org/understanding-json-schema/reference/string.html#format
|
||||||
|
// TODO: Make sure this is up to date with the types listed in the spec.
|
||||||
|
enum disallow-others=#false \
|
||||||
|
// String validations
|
||||||
|
date-time date time duration decimal currency country-2 \
|
||||||
|
country- country-subdivision email idn-email hostname \
|
||||||
|
idn-hostname ipv4 ipv6 url url-reference irl \
|
||||||
|
irl-reference url-template regex uuid kpath \
|
||||||
|
|
||||||
|
// Number validations
|
||||||
|
i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 isize usize f32 \
|
||||||
|
f64 decimal64 decimal128
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node media-type about="""
|
||||||
|
MIME type
|
||||||
|
|
||||||
|
MIME type of string value. May be applied to 'deserialized' data
|
||||||
|
if value format is base64/base85 or some other stringly binary
|
||||||
|
encoding.
|
||||||
|
""" {
|
||||||
|
repeatable
|
||||||
|
args {
|
||||||
|
min 1
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Number-specific validations
|
||||||
|
node number-validations {
|
||||||
|
ref shared-validations
|
||||||
|
children {
|
||||||
|
node div about="
|
||||||
|
Divisible by
|
||||||
|
|
||||||
|
Constrains them to be multiples of the given number(s). Only
|
||||||
|
used for numeric values. If multiple numbers are given, _any_
|
||||||
|
match will pass. In order to say something like `divisible by 3
|
||||||
|
AND by 4`, use multiple `div` nodes: `div 3; div 4`.
|
||||||
|
""" {
|
||||||
|
repeatable
|
||||||
|
args {
|
||||||
|
min 1
|
||||||
|
type number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node gt about="""
|
||||||
|
Greater than
|
||||||
|
|
||||||
|
Only used for numeric values. Constrains them to be greater than
|
||||||
|
the given number.
|
||||||
|
""" {
|
||||||
|
arg {
|
||||||
|
type number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node gte about="""
|
||||||
|
Greater than or equal to
|
||||||
|
|
||||||
|
Only used for numeric values. Constrains them to be greater than
|
||||||
|
or equal to the given number.
|
||||||
|
""" {
|
||||||
|
arg {
|
||||||
|
type number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node lt about="""
|
||||||
|
Less than
|
||||||
|
|
||||||
|
Only used for numeric values. Constrains them to be less than
|
||||||
|
the given number.
|
||||||
|
""" {
|
||||||
|
arg {
|
||||||
|
type number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node lte about="""
|
||||||
|
Less than or equal to
|
||||||
|
|
||||||
|
Only used for numeric values. Constrains them to be less than or
|
||||||
|
equal to the given number
|
||||||
|
""" {
|
||||||
|
arg {
|
||||||
|
type number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Validations shared across all types.
|
||||||
|
node shared-validations {
|
||||||
|
children {
|
||||||
|
node type about="The type for this value\n\nMultiple arguments signify a sum type." {
|
||||||
|
repeatable
|
||||||
|
args {
|
||||||
|
min 1
|
||||||
|
type string
|
||||||
|
enum string boolean number integer #null
|
||||||
|
distinct
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: establish equality expectations.
|
||||||
|
node enum about="""
|
||||||
|
Enumeration of values
|
||||||
|
|
||||||
|
An enumeration of possible values
|
||||||
|
""" {
|
||||||
|
repeatable
|
||||||
|
args about="Enumeration choices" {
|
||||||
|
min 1
|
||||||
|
}
|
||||||
|
prop disallow-others about="""
|
||||||
|
Disallow other choices
|
||||||
|
|
||||||
|
Whether other values than those explicitly enumerated
|
||||||
|
may be provided, so long as they pass other validations
|
||||||
|
in the node.
|
||||||
|
|
||||||
|
While apparently redundant, this option may be useful in
|
||||||
|
cases where there's a set of suggested values, but
|
||||||
|
others are acceptable. This information can then be used
|
||||||
|
by tooling to e.g. suggest completion items.
|
||||||
|
""" {
|
||||||
|
type boolean
|
||||||
|
default #true
|
||||||
|
}
|
||||||
|
children {
|
||||||
|
node - about="Enumeration choice" {
|
||||||
|
ref about-mixin
|
||||||
|
arg about="Enum value"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// General value validations
|
||||||
|
node value-validations {
|
||||||
|
ref string-validations number-validations
|
||||||
|
children {
|
||||||
|
node annotations about="""
|
||||||
|
Validates value type annotations
|
||||||
|
|
||||||
|
String validations for the type annotations that can be applied
|
||||||
|
to this value.
|
||||||
|
""" {
|
||||||
|
ref string-validations
|
||||||
|
}
|
||||||
|
node default about="""
|
||||||
|
Default value
|
||||||
|
|
||||||
|
Sets a default value when optional. That is, it requires
|
||||||
|
`optional` for `arg` nodes, and doesn't do anything useful if a
|
||||||
|
`prop` is marked `required`, though it is not invalid to do so.
|
||||||
|
""" {
|
||||||
|
arg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node about-mixin {
|
||||||
|
prop about about="""
|
||||||
|
Description for this component.
|
||||||
|
|
||||||
|
By convention, the format of this value is intended to be similar to
|
||||||
|
git's commit message system: The first line is treated as a short
|
||||||
|
descriptor/summary, and any lines underneath it are treated as the
|
||||||
|
longer-form documentation. As such, the first line SHOULD be up to
|
||||||
|
50 characters in length.
|
||||||
|
|
||||||
|
Tooling SHOULD only display some or all of the first line in user
|
||||||
|
interfaces that call for terseness, and they SHOULD display both the
|
||||||
|
short descriptor and the longer explanation.
|
||||||
|
""" {
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
children {
|
||||||
|
node about about="""
|
||||||
|
Description for this component.
|
||||||
|
|
||||||
|
By convention, the format of this value is intended to be similar to
|
||||||
|
git's commit message system: The first line is treated as a short
|
||||||
|
descriptor/summary, and any lines underneath it are treated as the
|
||||||
|
longer-form documentation. Tooling SHOULD only display some or all
|
||||||
|
of the first line in user interfaces that call for terseness, and
|
||||||
|
they SHOULD display both the short descriptor and the longer
|
||||||
|
explanation
|
||||||
|
|
||||||
|
If both an `about` property and an `about` child node are
|
||||||
|
present in a definition, the child node's value MUST take
|
||||||
|
precedence.
|
||||||
|
""" {
|
||||||
|
arg {
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
// schema for a hypothetical package.kdl based on NPM's package.json.
|
||||||
|
// It takes some liberties to make the format feel more "cuddly", rather than
|
||||||
|
// trying to map the package.json structure 1:1.
|
||||||
|
// Derived from https://github.com/SchemaStore/schemastore/blob/master/src/schemas/json/package.json
|
||||||
|
|
||||||
|
@ksl:schema "https://github.com/kdl-org/kdl/blob/main/examples/ksl-schema.kdl"
|
||||||
|
|
||||||
|
example "package.kdl" {
|
||||||
|
name "@bgotink/kdl"
|
||||||
|
version "0.3.1"
|
||||||
|
author "Bram Gotink" url="https://github.com/bgotink"
|
||||||
|
license MIT
|
||||||
|
repository "https://github.com/bgotink/kdl" type=git
|
||||||
|
homepage "https://github.bram.dev/kdl/"
|
||||||
|
description "Modification-friendly KDL parser and serializer."
|
||||||
|
keywords kdl parser serializer
|
||||||
|
type module
|
||||||
|
private
|
||||||
|
no-side-effects
|
||||||
|
package-manager yarn@4.0.2
|
||||||
|
exports {
|
||||||
|
"." "./src/index.js"
|
||||||
|
"./json" "./src/json.js"
|
||||||
|
"./v1-compat" "./src/v1-compat.js"
|
||||||
|
"./dessert" "./src/dessert.js"
|
||||||
|
"./package.json" "/package.json"
|
||||||
|
}
|
||||||
|
imports { "#v1" "@bgotink/kdl-v1" }
|
||||||
|
scripts {
|
||||||
|
postinstall "is-ci || husky"
|
||||||
|
build "node scripts/build.js"
|
||||||
|
test "uvu test"
|
||||||
|
bench "node scripts/bench.js"
|
||||||
|
book "scripts/book.sh"
|
||||||
|
}
|
||||||
|
dev-dependencies {
|
||||||
|
"@bgotink/kdl-v1" "=0.1.7" package="@bgotink/kdl" workspace="./legacy"
|
||||||
|
"@types/benchmark" ^2.1.5
|
||||||
|
"@types/node" ^22
|
||||||
|
benchmark ^2.1.4
|
||||||
|
esbuild ^0.24.2
|
||||||
|
express-check-in ^0.2.0
|
||||||
|
husky "=9.1.7-dotconfig.0.1.0" package="@dot-config/husky"
|
||||||
|
is-ci ^3.0.1
|
||||||
|
kdljs ^0.2.0
|
||||||
|
marked ^14.1.2
|
||||||
|
prettier "=3.4.2-dotconfig.0.1.0" package="@dot-config/prettier"
|
||||||
|
typedoc ^0.27.6
|
||||||
|
typedoc-plugin-markdown ^4.3.3
|
||||||
|
typescript ~5.6.2
|
||||||
|
uvu ^0.5.6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata {
|
||||||
|
// TODO: update this link when we're ready to release something.
|
||||||
|
id "https://github.com/kdl-org/kdl/blob/main/schema/package.kdl"
|
||||||
|
title "NPM package.kdl schema" lang=en
|
||||||
|
description "KDL-based translation of the package.json schema." lang=en
|
||||||
|
author "Kat Marchán" {
|
||||||
|
link "https://github.com/zkat" rel=self
|
||||||
|
}
|
||||||
|
link "https://github.com/kdl-org/kdl" rel=documentation
|
||||||
|
link "https://docs.npmjs.com/cli/v11/configuring-npm/package-json" rel=documentation
|
||||||
|
license "Creative Commons Attribution-ShareAlike 4.0 International License" spdx=CC-BY-SA-4.0 {
|
||||||
|
link "https://creativecommons.org/licenses/by-sa/4.0/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document {
|
||||||
|
node dependencies
|
||||||
|
}
|
||||||
|
|
||||||
|
definitions {
|
||||||
|
node person about="""
|
||||||
|
A person
|
||||||
|
|
||||||
|
Someone who has been involved in creating and maintaining this package.
|
||||||
|
""" {
|
||||||
|
arg about="Person name" {
|
||||||
|
type string
|
||||||
|
}
|
||||||
|
prop email about="Person's email address" {
|
||||||
|
type string
|
||||||
|
format email
|
||||||
|
}
|
||||||
|
prop url about="URL related to this person" {
|
||||||
|
type string
|
||||||
|
format url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node dependency-block {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue