mirror of https://github.com/kdl-org/kdl.git
new schema format/spec
This commit is contained in:
parent
ebf9ef7649
commit
ec62d768c6
393
SCHEMA-SPEC.md
393
SCHEMA-SPEC.md
|
|
@ -1,347 +1,208 @@
|
|||
# KDL Schema Specification
|
||||
# KDL Schema Language 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 KDL Schema Language specification describes a schema language for use with
|
||||
KDL. A schema language allows users to describe and constrain the allowed
|
||||
semantics of a document. This can be used for many purposes: documentation for
|
||||
users, automated verification, or even automated 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
|
||||
[examples/kdl-schema.kdl](./examples/kdl-schema.kdl).
|
||||
For the full KDL Schema Language schema itself, see
|
||||
[schema/kdl-schema.kdl](./schema/kdl-schema.kdl).
|
||||
|
||||
## Definition
|
||||
# Definitions
|
||||
|
||||
### `document` node
|
||||
There are four "toplevel" nodes in the KDL Schema Language. Each is defined below, along with the children they may have:
|
||||
|
||||
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.
|
||||
- [`metadata`](#metadata): General metadata about the schema itself
|
||||
- [`example`](#example): An example document that's considered to be valid according to this schema
|
||||
- [`definitions`](#definitions): An inert set of [shared node definitions](#shared-definitions) that may be references/mixed-in into the "true" definitions in the `document` node
|
||||
- [`document`](#document): The main schema definition itself
|
||||
|
||||
#### Values
|
||||
## `metadata`
|
||||
|
||||
None.
|
||||
**Schema metadata**
|
||||
|
||||
#### Properties
|
||||
Contains metadata about the schema itself.
|
||||
|
||||
None.
|
||||
- **required**
|
||||
|
||||
#### Children
|
||||
### Children
|
||||
|
||||
* [`info`](#info-node) - one info node for that describes the schema itself.
|
||||
* [`node`](#node-node) - zero or more toplevel nodes for the KDL document this schema describes.
|
||||
* [`definitions`](#definitions-node) (optional): Definitions of nodes, values, props, and children block to reference in the toplevel 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`.
|
||||
* [`tag`](#tag-node) - zero or more toplevel tags for nodes in the KDL document that this schema describes.
|
||||
* `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`.
|
||||
#### `id`
|
||||
|
||||
### `info` node
|
||||
**Schema identifier**
|
||||
|
||||
The `info` node describes the schema itself.
|
||||
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.
|
||||
|
||||
#### Values
|
||||
- **arg:** URL/IRL identifier.
|
||||
- **type:** `string`
|
||||
- **format:** `url`, `irl`
|
||||
|
||||
None.
|
||||
#### `title`
|
||||
|
||||
#### Properties
|
||||
|
||||
None.
|
||||
|
||||
#### Children
|
||||
|
||||
* [`title`](#title-node) (optional): zero or more titles
|
||||
* [`description`](#description-node) (optional): zero or more descriptions
|
||||
* [`author`](#author-and-contributor-nodes) (optional): zero or more authors
|
||||
* [`contributor`](#author-and-contributor-nodes) (optional): zero or more contributors
|
||||
* [`link`](#link-node) (optional): zero or more URLs
|
||||
* [`license`](#license-node) (optional): zero or more licenses
|
||||
* [`published`](#published-and-modified-nodes) (optional): a publication date
|
||||
* [`modified`](#published-and-modified-nodes) (optional): a modification date
|
||||
* [`version`](#version-node) (optional): a [SemVer](https://semver.org/) version number
|
||||
|
||||
### `title` node
|
||||
**Schema title**
|
||||
|
||||
The title of the schema or the format it describes.
|
||||
|
||||
#### Values
|
||||
- **arg:** The title text.
|
||||
- **type:** `string`
|
||||
|
||||
* Title
|
||||
#### `description`
|
||||
|
||||
#### Properties
|
||||
**Schema description**
|
||||
|
||||
* `lang` (optional): An IETF BCP 47 language tag
|
||||
A description of the schema or the format it validates, which may include its purposes, its usage, and even examples.
|
||||
|
||||
### `description` node
|
||||
- **arg:** Description text.
|
||||
- **type:** `string`
|
||||
|
||||
A description of the schema or the format it describes.
|
||||
#### `author`
|
||||
|
||||
#### Values
|
||||
**Schema author**
|
||||
|
||||
* Description
|
||||
An author for the schema.
|
||||
|
||||
#### Properties
|
||||
- **repeatable**
|
||||
- [Person](#person-mixin)
|
||||
|
||||
* `lang` (optional): An IETF BCP 47 language tag
|
||||
#### `contributor`
|
||||
|
||||
### `author` and `contributor` nodes
|
||||
**Schema author**
|
||||
|
||||
Author(s) of the schema.
|
||||
A contributor to the schema, who might not be considered an author, per-se.
|
||||
|
||||
#### Values
|
||||
- **repeatable**
|
||||
- [Person](#person-mixin)
|
||||
|
||||
* Author name
|
||||
#### `link`
|
||||
|
||||
#### Properties
|
||||
A link related to this schema.
|
||||
|
||||
* `orcid` (optional): The [ORCID](https://orcid.org/) of the author.
|
||||
- **repeatable**
|
||||
- [Link](#link-mixin)
|
||||
|
||||
#### Children
|
||||
#### `license`
|
||||
|
||||
* [`link`](#link-node) (optional): zero or more URLs
|
||||
**Schema license**
|
||||
|
||||
### `link` node
|
||||
The license(s) that the schema is licensed under. At least one of `spdx`, `path`, or `url` props must be provided.
|
||||
|
||||
Links to the schema itself, and to sources about the schema.
|
||||
- **repeatable**
|
||||
- **prop `spdx`:** An SPDX license identifier
|
||||
- **type:** `string`
|
||||
- **prop `path`:** Path to a local license file. Relative paths MAY be interpreted in any way the program chooses, or MAY be ignored
|
||||
- **type:** `string`
|
||||
- **prop `link`:** URL/IRL to an externally-stored license
|
||||
- **type:** `string`
|
||||
- **format:** `url`, `url-reference`, `irl`, `irl-reference`
|
||||
|
||||
#### Values
|
||||
#### `published`
|
||||
|
||||
* URI/IRI - A URI/IRI that the link points to
|
||||
**Schema publication date**
|
||||
|
||||
#### Properties
|
||||
Date or datetime when the schema was published.
|
||||
|
||||
* `rel`: what the link is for (`self` or `documentation`)
|
||||
* `lang` (optional): An IETF BCP 47 language tag
|
||||
- **arg:** Publication date
|
||||
- **required**
|
||||
- **type:** `string`
|
||||
- **format:** `date`, `date-time`
|
||||
|
||||
### `license` node
|
||||
#### `modified`
|
||||
|
||||
The license(s) that the schema is licensed under.
|
||||
Schema modification date
|
||||
|
||||
#### Values
|
||||
When the schema was modified. If used multiple times, the most recent date will be considered 'latest'.
|
||||
|
||||
* License name - Name of the used license
|
||||
- **repeatable**
|
||||
- **arg:** Modification date
|
||||
- **type:** `string`
|
||||
- **format:** `date`, `date-time`
|
||||
|
||||
#### Properties
|
||||
#### `version`
|
||||
|
||||
* `spdx` (optional): an [SPDX license identifier](https://spdx.dev/ids/)
|
||||
Schema semver version
|
||||
|
||||
#### Children
|
||||
The version number of this version of the schema, in semver format.
|
||||
|
||||
* [`link`](#link-node): one or more URLs
|
||||
<hr />
|
||||
|
||||
### `published` and `modified` nodes
|
||||
## `example`
|
||||
|
||||
When the schema was published or last modified respectively.
|
||||
An example document validated by this schema
|
||||
|
||||
#### Values
|
||||
The `example` node is completely inert. It SHOULD contain an illustrative example of a document that would be valid if checked against this schema.
|
||||
|
||||
* Publication or modification date - As a ISO8601 date
|
||||
- **repeatable**
|
||||
- [About](#about-mixin)
|
||||
|
||||
#### Properties
|
||||
<hr />
|
||||
|
||||
* `time` (optional): an ISO8601 Time to accompany the date
|
||||
<hr />
|
||||
|
||||
### `version` nodes
|
||||
# Shared definitions
|
||||
|
||||
The version number of this version of the schema.
|
||||
<a name="person-mixin"></a>
|
||||
|
||||
#### Values
|
||||
## Person
|
||||
|
||||
* Version - Semver version specification
|
||||
Shared definition for what makes a "person".
|
||||
|
||||
### `node` node
|
||||
- **arg:** Person name
|
||||
- **type:** `string`
|
||||
- **prop `orcid`:** The ORCID of the person
|
||||
- **type:** `string`
|
||||
|
||||
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.
|
||||
### Children
|
||||
|
||||
#### Values
|
||||
#### `link`
|
||||
|
||||
* 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.
|
||||
Link connected to this resource. Use `mailto:` for emails.
|
||||
|
||||
#### Properties
|
||||
- **repeatable**
|
||||
- [Link](#link-mixin)
|
||||
|
||||
* `description` (optional): An informational description of the purpose of this node.
|
||||
* `id` (optional): A globally unique identifier for this node.
|
||||
* `ref` (optional): A [KDL Query](./QUERY-SPEC.md) string relative to the root of the document. If present, all properties, values, and children defined in the target node will be copied to this node, replacing any conflicts.
|
||||
<a name="link-mixin"></a>
|
||||
## Link
|
||||
|
||||
#### Children
|
||||
External link
|
||||
|
||||
* `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`.
|
||||
* `tag`: [Validations](#validation-nodes) to apply to the tag of the node.
|
||||
* [`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.
|
||||
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.
|
||||
|
||||
### `tag` node
|
||||
- **arg:** Link connected to this resource. Use `mailto:` for emails.
|
||||
- **type:** `string`
|
||||
- **format:** `url`, `irl`
|
||||
- **prop `rel`:** The relationship between the current entity and the URL/IRL.
|
||||
- **type:** `string`
|
||||
- **default:** `self`
|
||||
- **enum:** (non-exhaustive)
|
||||
- `self`
|
||||
- `documentation`
|
||||
- `contact`
|
||||
- `organization`
|
||||
|
||||
The `tag` describes the tags allowed in a children block or toplevel document.
|
||||
<a name="about-mixin"></a>
|
||||
## About
|
||||
|
||||
#### Values
|
||||
**Description for this component**
|
||||
|
||||
* Tag name (optional) - A tag for the node. If present, the node's rules/validations will apply only to children with this tag. Otherwise, the rules will apply to _all_ child nodes with tags.
|
||||
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.
|
||||
|
||||
#### Properties
|
||||
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 when expanding it.
|
||||
|
||||
* `description` (optional): An informational description of the purpose of this node.
|
||||
* `id` (optional): A globally unique identifier for this node.
|
||||
* `ref` (optional): A [KDL Query](./QUERY-SPEC.md) string relative to the root of the document. If present, all properties, values, and children defined in the target node will be copied to this node, replacing any conflicts.
|
||||
`about` can be provided either as a prop or a child.
|
||||
|
||||
#### Children
|
||||
- **prop `about`:** Description for this component
|
||||
**type:** `string`
|
||||
|
||||
* [`node`](#node-node) - zero or more toplevel nodes that this tag is allowed to be on.
|
||||
* `node-names` (optional): [Validations](#validation-nodes) to apply to the _names_ of nodes with this tag.
|
||||
* `other-nodes-allowed` (optional): Whether to allow nodes other than the ones explicitly listed here. Defaults to `false`.
|
||||
### Children
|
||||
|
||||
### `prop` node
|
||||
#### `about`
|
||||
|
||||
Represents a property of a node, which is a key/value pair in KDL.
|
||||
Description for this component
|
||||
|
||||
#### 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 [KDL Query](./QUERY-SPEC.md) string relative to the root of the document. 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 [KDL Query](./QUERY-SPEC.md) string relative to the root of the document. 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 [KDL Query](./QUERY-SPEC.md) string relative to the root of the document. 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
|
||||
|
||||
* `tag`: [Validations](#validation-nodes) to apply to the tag of the value.
|
||||
* `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. Reserved values are:
|
||||
* `date-time`: ISO8601 date/time format.
|
||||
* `time`: "Time" section of ISO8601.
|
||||
* `date`: "Date" section of ISO8601.
|
||||
* `duration`: ISO8601 duration format.
|
||||
* `decimal`: IEEE 754-2008 decimal string format.
|
||||
* `currency`: ISO 4217 currency code.
|
||||
* `country-2`: ISO 3166-1 alpha-2 country code.
|
||||
* `country-3`: ISO 3166-1 alpha-3 country code.
|
||||
* `country-subdivision`: ISO 3166-2 country subdivision code.
|
||||
* `email`: RFC5302 email address.
|
||||
* `idn-email`: RFC6531 internationalized email address.
|
||||
* `hostname`: RFC1123 internet hostname.
|
||||
* `idn-hostname`: RFC5890 internationalized internet hostname.
|
||||
* `ipv4`: RFC2673 dotted-quad IPv4 address.
|
||||
* `ipv6`: RFC2373 IPv6 address.
|
||||
* `url`: RFC3986 URI.
|
||||
* `url-reference`: RFC3986 URI Reference.
|
||||
* `irl`: RFC3987 Internationalized Resource Identifier.
|
||||
* `irl-reference`: RFC3987 Internationalized Resource Identifier Reference.
|
||||
* `url-template`: RFC6570 URI Template.
|
||||
* `uuid`: RFC4122 UUID.
|
||||
* `regex`: Regular expression. Specific patterns may be implementation-dependent.
|
||||
* `base64`: A Base64-encoded string, denoting arbitrary binary data.
|
||||
* `kdl-query`: A [KDL Query](./QUERY-SPEC.md) string.
|
||||
|
||||
#### 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.
|
||||
* `format`: Intended data format for numeric values. Reserved values are:
|
||||
* `i8`: 8-bit signed integer
|
||||
* `i16`: 16-bit signed integer
|
||||
* `i32`: 32-bit signed integer
|
||||
* `i64`: 64-bit signed integer
|
||||
* `i128`: 128-bit signed integer
|
||||
* `u8`: 8-bit unsigned integer
|
||||
* `u16`: 16-bit unsigned integer
|
||||
* `u32`: 32-bit unsigned integer
|
||||
* `u64`: 64-bit unsigned integer
|
||||
* `u128`: 128-bit unsigned integer
|
||||
* `isize`: Platform-dependent signed integer
|
||||
* `usize`: Platform-dependent unsigned integer
|
||||
* `f32`: IEEE 754 single (32-bit) precision floating point number
|
||||
* `f64`: IEEE 754 double (64-bit) precision floating point number
|
||||
* `decimal64`: IEEE 754-2008 64-bit decimal floating point number
|
||||
* `decimal128`: IEEE 754-2008 128-bit decimal floating point number
|
||||
|
||||
### `definitions` node
|
||||
|
||||
Definitions to reference in parts of the top-level `node`s.
|
||||
|
||||
#### Values
|
||||
|
||||
None.
|
||||
|
||||
#### Properties
|
||||
|
||||
None.
|
||||
|
||||
#### Children
|
||||
|
||||
* [`node`](#node-node) - zero or more node definitions.
|
||||
* [`tag`](#tag-node) - zero or more toplevel tags for nodes in the KDL document that this schema describes.
|
||||
* [`prop`](#prop-node) - zero or more property definitions.
|
||||
* [`value`](#value-node) - zero or more value definitions.
|
||||
* [`children`](#children-node) - zero or more definitions of children blocks.
|
||||
- **arg:** Description for this component
|
||||
- **required**
|
||||
- **type:** `string`
|
||||
|
|
|
|||
|
|
@ -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,937 @@
|
|||
@kdl:schema "https://github.com/kdl-org/kdl/blob/main/examples/kdl-schema.kdl"
|
||||
|
||||
metadata {
|
||||
// TODO: update this link when we're ready to release something.
|
||||
id "https://github.com/kdl-org/kdl/blob/main/examples/kdl-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
|
||||
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
|
||||
}
|
||||
}
|
||||
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 @kdl: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 `@dsl: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 `@kdl: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
|
||||
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 value about="""
|
||||
Defines a new value type
|
||||
|
||||
Value definitions let you treat shared value validations as discrete validations. Unlike `ref`s, this makes it possible to use these validations with
|
||||
"""
|
||||
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 type-annotations about="""
|
||||
Node type annotations
|
||||
|
||||
Validations to apply specifically to arbitrary
|
||||
node type annotation names.
|
||||
""" {
|
||||
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.
|
||||
""" {
|
||||
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 type-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