From 26a20cf4f3a71ccdd7c6abb06cffd4c12d08395e Mon Sep 17 00:00:00 2001 From: Melody Horn Date: Sat, 26 Mar 2022 19:57:57 -0600 Subject: parse schemas with knuffel --- src/lib.rs | 264 ++++++++++++++++- src/schema_schema.rs | 794 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1052 insertions(+), 6 deletions(-) create mode 100644 src/schema_schema.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 1b4a90c..7f0966b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,260 @@ -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - let result = 2 + 2; - assert_eq!(result, 4); +#[cfg(feature = "knuffel")] +use knuffel::Decode; + +pub trait BuildFromRef { + fn ref_to(query: impl Into) -> Self; +} + +#[derive(Debug, PartialEq, Eq, Default)] +#[cfg_attr(feature = "knuffel", derive(Decode))] +pub struct Schema { + #[cfg_attr(feature = "knuffel", knuffel(child))] + pub document: Document, +} + +#[derive(Debug, PartialEq, Eq, Default)] +#[cfg_attr(feature = "knuffel", derive(Decode))] +pub struct Document { + #[cfg_attr(feature = "knuffel", knuffel(child))] + pub info: Info, + #[cfg_attr(feature = "knuffel", knuffel(children(name = "node")))] + pub nodes: Vec, +} + +pub use info::Info; + +pub mod info { + use super::*; + + #[derive(Debug, PartialEq, Eq, Default)] + #[cfg_attr(feature = "knuffel", derive(Decode))] + pub struct Info { + #[cfg_attr(feature = "knuffel", knuffel(children(name = "title")))] + pub title: Vec, + #[cfg_attr(feature = "knuffel", knuffel(children(name = "description")))] + pub description: Vec, + #[cfg_attr(feature = "knuffel", knuffel(children(name = "author")))] + pub authors: Vec, + #[cfg_attr(feature = "knuffel", knuffel(children(name = "contributor")))] + pub contributors: Vec, + #[cfg_attr(feature = "knuffel", knuffel(children(name = "link")))] + pub links: Vec, + #[cfg_attr(feature = "knuffel", knuffel(children(name = "license")))] + pub licenses: Vec, + #[cfg_attr(feature = "knuffel", knuffel(child))] + pub published: Option, + #[cfg_attr(feature = "knuffel", knuffel(child))] + pub modified: Option, + } + + #[derive(Debug, PartialEq, Eq)] + #[cfg_attr(feature = "knuffel", derive(Decode))] + pub struct TextValue { + #[cfg_attr(feature = "knuffel", knuffel(argument))] + pub text: String, + #[cfg_attr(feature = "knuffel", knuffel(property))] + pub lang: Option, + } + + #[derive(Debug, PartialEq, Eq)] + #[cfg_attr(feature = "knuffel", derive(Decode))] + pub struct Person { + #[cfg_attr(feature = "knuffel", knuffel(argument))] + pub name: String, + #[cfg_attr(feature = "knuffel", knuffel(property))] + pub orcid: Option, + #[cfg_attr(feature = "knuffel", knuffel(children(name = "link")))] + pub links: Vec, + } + + #[derive(Debug, PartialEq, Eq)] + #[cfg_attr(feature = "knuffel", derive(Decode))] + pub struct Link { + #[cfg_attr(feature = "knuffel", knuffel(argument))] + pub iri: String, + #[cfg_attr(feature = "knuffel", knuffel(property))] + pub rel: Option, + #[cfg_attr(feature = "knuffel", knuffel(property))] + pub lang: Option, + } + + #[derive(Debug, PartialEq, Eq)] + #[cfg_attr(feature = "knuffel", derive(Decode))] + pub struct License { + #[cfg_attr(feature = "knuffel", knuffel(argument))] + pub name: String, + #[cfg_attr(feature = "knuffel", knuffel(property))] + pub spdx: Option, + #[cfg_attr(feature = "knuffel", knuffel(children(name = "link")))] + pub link: Vec, + } + + #[derive(Debug, PartialEq, Eq)] + #[cfg_attr(feature = "knuffel", derive(Decode))] + pub struct Date { + #[cfg_attr(feature = "knuffel", knuffel(argument))] + pub date: String, + #[cfg_attr(feature = "knuffel", knuffel(property))] + pub time: Option, + } +} + +pub use node::Node; + +pub mod node { + use super::*; + + #[derive(Debug, PartialEq, Eq, Default)] + #[cfg_attr(feature = "knuffel", derive(Decode))] + pub struct Node { + #[cfg_attr(feature = "knuffel", knuffel(argument))] + pub name: Option, + #[cfg_attr(feature = "knuffel", knuffel(property))] + pub id: Option, + #[cfg_attr(feature = "knuffel", knuffel(property))] + pub description: Option, + #[cfg_attr(feature = "knuffel", knuffel(property))] + pub ref_: Option, + #[cfg_attr(feature = "knuffel", knuffel(child, unwrap(argument)))] + pub min: Option, + #[cfg_attr(feature = "knuffel", knuffel(child, unwrap(argument)))] + pub max: Option, + #[cfg_attr(feature = "knuffel", knuffel(children(name = "prop")))] + pub props: Vec, + #[cfg_attr(feature = "knuffel", knuffel(children(name = "value")))] + pub values: Vec, + #[cfg_attr(feature = "knuffel", knuffel(children(name = "children")))] + pub children: Vec, + } + + impl BuildFromRef for Node { + fn ref_to(query: impl Into) -> Self { + Self { + ref_: Some(query.into()), + ..Self::default() + } + } + } + + #[derive(Debug, PartialEq, Eq, Default)] + #[cfg_attr(feature = "knuffel", derive(Decode))] + pub struct Prop { + #[cfg_attr(feature = "knuffel", knuffel(argument))] + pub key: Option, + #[cfg_attr(feature = "knuffel", knuffel(property))] + pub id: Option, + #[cfg_attr(feature = "knuffel", knuffel(property))] + pub description: Option, + #[cfg_attr(feature = "knuffel", knuffel(property))] + pub ref_: Option, + #[cfg_attr(feature = "knuffel", knuffel(child))] + pub required: bool, + #[cfg_attr(feature = "knuffel", knuffel(children))] + pub validations: Vec, + } + + impl BuildFromRef for Prop { + fn ref_to(query: impl Into) -> Self { + Self { + ref_: Some(query.into()), + ..Self::default() + } + } + } + + #[derive(Debug, PartialEq, Eq, Default)] + #[cfg_attr(feature = "knuffel", derive(Decode))] + pub struct Value { + #[cfg_attr(feature = "knuffel", knuffel(property))] + pub id: Option, + #[cfg_attr(feature = "knuffel", knuffel(property))] + pub description: Option, + #[cfg_attr(feature = "knuffel", knuffel(property))] + pub ref_: Option, + #[cfg_attr(feature = "knuffel", knuffel(child, unwrap(argument)))] + pub min: Option, + #[cfg_attr(feature = "knuffel", knuffel(child, unwrap(argument)))] + pub max: Option, + #[cfg_attr(feature = "knuffel", knuffel(children))] + pub validations: Vec, + } + + impl BuildFromRef for Value { + fn ref_to(query: impl Into) -> Self { + Self { + ref_: Some(query.into()), + ..Self::default() + } + } + } + + #[derive(Debug, PartialEq, Eq, Default)] + #[cfg_attr(feature = "knuffel", derive(Decode))] + pub struct Children { + #[cfg_attr(feature = "knuffel", knuffel(property))] + pub id: Option, + #[cfg_attr(feature = "knuffel", knuffel(property))] + pub description: Option, + #[cfg_attr(feature = "knuffel", knuffel(property))] + pub ref_: Option, + #[cfg_attr(feature = "knuffel", knuffel(children(name = "node")))] + pub nodes: Vec, + } + + impl BuildFromRef for Children { + fn ref_to(query: impl Into) -> Self { + Self { + ref_: Some(query.into()), + ..Self::default() + } + } + } + + pub use validation::Validation; + + pub mod validation { + #[cfg(feature = "knuffel")] + use knuffel::{Decode, DecodeScalar}; + + #[derive(Debug, PartialEq, Eq)] + #[cfg_attr(feature = "knuffel", derive(Decode))] + pub enum Validation { + Type(#[cfg_attr(feature = "knuffel", knuffel(argument))] String), + Enum(#[cfg_attr(feature = "knuffel", knuffel(arguments))] Vec), + Pattern(#[cfg_attr(feature = "knuffel", knuffel(argument))] String), + Format(#[cfg_attr(feature = "knuffel", knuffel(arguments))] Vec), + } + + #[derive(Debug, PartialEq, Eq)] + #[cfg_attr(feature = "knuffel", derive(DecodeScalar))] + pub enum Format { + DateTime, + Date, + Time, + Duration, + Decimal, + Currency, + Country2, + Country3, + CountrySubdivision, + Email, + IdnEmail, + Hostname, + IdnHostname, + Ipv4, + Ipv6, + Url, + UrlReference, + Irl, + IrlReference, + UrlTemplate, + Uuid, + Regex, + Base64, + KdlQuery, + } } } + +mod schema_schema; +pub use schema_schema::SCHEMA_SCHEMA; diff --git a/src/schema_schema.rs b/src/schema_schema.rs new file mode 100644 index 0000000..d548f5a --- /dev/null +++ b/src/schema_schema.rs @@ -0,0 +1,794 @@ +use lazy_static::lazy_static; + +use super::node::validation::*; +use super::node::*; +use super::*; + +lazy_static! { + pub static ref SCHEMA_SCHEMA: Schema = make_schema_schema(); +} + +fn s>(text: &str) -> T { + T::from(text.to_string()) +} + +fn ref_to_id(id: &str) -> T { + T::ref_to(format!(r#"[id="{}"]"#, id)) +} + +fn make_schema_schema() -> Schema { + Schema { + document: Document { + info: make_schema_info(), + nodes: vec![make_document_node()], + }, + } +} + +fn make_document_node() -> Node { + Node { + name: s("document"), + min: Some(1), + max: Some(1), + children: vec![Children { + id: s("node-children"), + nodes: vec![ + Node { + name: s("node-names"), + id: s("node-names-node"), + description: s( + "Validations to apply specifically to arbitrary node names", + ), + children: vec![ref_to_id("validations")], + ..Node::default() + }, + Node { + name: s("other-nodes-allowed"), + id: s("other-nodes-allowed-node"), + description: s("Whether to allow child nodes other than the ones explicitly listed. Defaults to 'false'."), + max: Some(1), + values: vec![Value { + min: Some(1), + max: Some(1), + validations: vec![Validation::Type(s("boolean"))], + ..Value::default() + }], + ..Node::default() + }, + Node { + name: s("tag-names"), + description: s("Validations to apply specifically to arbitrary type tag names"), + children: vec![ref_to_id("validations")], + ..Node::default() + }, + Node { + name: s("other-tags-allowed"), + description: s("Whether to allow child node tags other than the ones explicitly listed. Defaults to 'false'."), + max: Some(1), + values: vec![Value { + min: Some(1), + max: Some(1), + validations: vec![Validation::Type(s("boolean"))], + ..Value::default() + }], + ..Node::default() + }, + make_info_node(), + Node { + name: s("tag"), + id: s("tag-node"), + description: s("A tag belonging to a child node of `document` or another node."), + values: vec![Value { + description: s("The name of the tag. If a tag name is not supplied, the node rules apply to _all_ nodes belonging to the parent."), + max: Some(1), + validations: vec![Validation::Type(s("string"))], + ..Value::default() + }], + props: vec![ + Prop { + key: s("description"), + description: s("A description of this node's purpose."), + validations: vec![Validation::Type(s("string"))], + ..Prop::default() + }, + Prop { + key: s("id"), + description: s("A globally-unique ID for this node."), + validations: vec![Validation::Type(s("string"))], + ..Prop::default() + }, + Prop { + key: s("ref"), + description: s("A globally unique reference to another node."), + validations: vec![ + Validation::Type(s("string")), + Validation::Format(vec![Format::KdlQuery]), + ], + ..Prop::default() + } + ], + children: vec![Children { + nodes: vec![ + ref_to_id("node-names-node"), + ref_to_id("other-nodes-allowed-node"), + ref_to_id("node-node"), + ], + ..Children::default() + }], + ..Node::default() + }, + make_node_node(), + Node { + name: s("definitions"), + description: s("Definitions to reference in parts of the top-level nodes"), + children: vec![Children { + nodes: vec![ + ref_to_id("node-node"), + ref_to_id("value-node"), + ref_to_id("prop-node"), + ref_to_id("children-node"), + ref_to_id("tag-node"), + ], + ..Children::default() + }], + ..Node::default() + } + ], + ..Children::default() + }], + ..Node::default() + } +} + +fn make_node_node() -> Node { + Node { + name: s("node"), + id: s("node-node"), + description: s("A child node belonging either to `document` or to another `node`. Nodes may be anonymous."), + values: vec![Value { + description: s("The name of the node. If a node name is not supplied, the node rules apply to _all_ nodes belonging to the parent."), + max: Some(1), + validations: vec![Validation::Type(s("string"))], + ..Value::default() + }], + props: vec![ + Prop { + key: s("description"), + description: s("A description of this node's purpose."), + validations: vec![Validation::Type(s("string"))], + ..Prop::default() + }, + Prop { + key: s("id"), + description: s("A globally-unique ID for this node."), + validations: vec![Validation::Type(s("string"))], + ..Prop::default() + }, + Prop { + key: s("ref"), + description: s("A globally unique reference to another node."), + validations: vec![ + Validation::Type(s("string")), + Validation::Format(vec![Format::KdlQuery]), + ], + ..Prop::default() + } + ], + children: vec![Children { + nodes: vec![ + Node { + name: s("prop-names"), + description: s("Validations to apply specifically to arbitrary property names"), + children: vec![ref_to_id("validations")], + ..Node::default() + }, + Node { + name: s("other-props-allowed"), + description: s("Whether to allow properties other than the ones explicitly listed. Defaults to 'false'."), + max: Some(1), + values: vec![Value { + min: Some(1), + max: Some(1), + validations: vec![Validation::Type(s("boolean"))], + ..Value::default() + }], + ..Node::default() + }, + Node { + name: s("min"), + description: s("minimum number of instances of this node in its parent's children."), + max: Some(1), + values: vec![Value { + min: Some(1), + max: Some(1), + validations: vec![Validation::Type(s("number"))], + ..Value::default() + }], + ..Node::default() + }, + Node { + name: s("max"), + description: s("maximum number of instances of this node in its parent's children."), + max: Some(1), + values: vec![Value { + min: Some(1), + max: Some(1), + validations: vec![Validation::Type(s("number"))], + ..Value::default() + }], + ..Node::default() + }, + ref_to_id("value-tag-node"), + Node { + name: s("prop"), + id: s("prop-node"), + description: s("A node property key/value pair."), + values: vec![Value { + description: s("The property key."), + validations: vec![Validation::Type(s("string"))], + ..Value::default() + }], + props: vec![ + Prop { + key: s("id"), + description: s("A globally-unique ID of this property."), + validations: vec![Validation::Type(s("string"))], + ..Prop::default() + }, + Prop { + key: s("ref"), + description: s("A globally unique reference to another property node."), + validations: vec![ + Validation::Type(s("string")), + Validation::Format(vec![Format::KdlQuery]), + ], + ..Prop::default() + }, + Prop { + key: s("description"), + description: s("A description of this property's purpose."), + validations: vec![Validation::Type(s("string"))], + ..Prop::default() + }, + ], + children: vec![ + Children { + description: s("Property-specific validations."), + nodes: vec![Node { + name: s("required"), + description: s("Whether this property is required if its parent is present."), + max: Some(1), + values: vec![Value { + min: Some(1), + max: Some(1), + validations: vec![Validation::Type(s("boolean"))], + ..Value::default() + }], + ..Node::default() + }], + ..Children::default() + }, + make_validations_children() + ], + ..Node::default() + }, + Node { + name: s("value"), + id: s("value-node"), + description: s("one or more direct node values"), + props: vec![ + Prop { + key: s("id"), + description: s("A globally-unique ID of this value."), + validations: vec![Validation::Type(s("string"))], + ..Prop::default() + }, + Prop { + key: s("ref"), + description: s("A globally unique reference to another value node."), + validations: vec![ + Validation::Type(s("string")), + Validation::Format(vec![Format::KdlQuery]), + ], + ..Prop::default() + }, + Prop { + key: s("description"), + description: s("A description of this property's purpose."), // TODO report bug in original document + validations: vec![Validation::Type(s("string"))], + ..Prop::default() + }, + ], + children: vec![ + ref_to_id("validations"), + Children { + description: s("Node value-specific validations"), + nodes: vec![ + Node { + name: s("min"), + description: s("minimum number of values for this node."), + max: Some(1), + values: vec![Value { + min: Some(1), + max: Some(1), + validations: vec![Validation::Type(s("number"))], + ..Value::default() + }], + ..Node::default() + }, + Node { + name: s("max"), + description: s("maximum number of values for this node."), + max: Some(1), + values: vec![Value { + min: Some(1), + max: Some(1), + validations: vec![Validation::Type(s("number"))], + ..Value::default() + }], + ..Node::default() + }, + ], + ..Children::default() + } + ], + ..Node::default() + }, + Node { + name: s("children"), + id: s("children-node"), + props: vec![ + Prop { + key: s("id"), + description: s("A globally-unique ID of this children node."), + validations: vec![Validation::Type(s("string"))], + ..Prop::default() + }, + Prop { + key: s("ref"), + description: s("A globally unique reference to another children node."), + validations: vec![ + Validation::Type(s("string")), + Validation::Format(vec![Format::KdlQuery]), + ], + ..Prop::default() + }, + Prop { + key: s("description"), + description: s("A description of this these children's purpose."), // TODO report bug in original document + validations: vec![Validation::Type(s("string"))], + ..Prop::default() + }, + ], + children: vec![ref_to_id("node-children")], + ..Node::default() + } + ], + ..Children::default() + }], + ..Node::default() + } +} + +fn make_validations_children() -> Children { + Children { + id: s("validations"), + description: s("General value validations."), + nodes: vec![ + Node { + name: s("tag"), + id: s("value-tag-node"), + description: s("The tags associated with this value"), + max: Some(1), + children: vec![ref_to_id("validations")], + ..Node::default() + }, + Node { + name: s("type"), + description: s("The type for this prop's value."), + max: Some(1), + values: vec![Value { + min: Some(1), + validations: vec![Validation::Type(s("string"))], + ..Value::default() + }], + ..Node::default() + }, + Node { + name: s("enum"), + description: s("An enumeration of possible values"), + max: Some(1), + values: vec![Value { + description: s("Enumeration choices"), + min: Some(1), + ..Value::default() + }], + ..Node::default() + }, + Node { + name: s("pattern"), + description: s("PCRE (Regex) pattern or patterns to test prop values against."), + values: vec![Value { + min: Some(1), + validations: vec![Validation::Type(s("string"))], + ..Value::default() + }], + ..Node::default() + }, + Node { + name: s("min-length"), + description: s("Minimum length of prop value, if it's a string."), + max: Some(1), + values: vec![Value { + min: Some(1), + validations: vec![Validation::Type(s("number"))], + ..Value::default() + }], + ..Node::default() + }, + Node { + name: s("max-length"), + description: s("Maximum length of prop value, if it's a string."), + max: Some(1), + values: vec![Value { + min: Some(1), + validations: vec![Validation::Type(s("number"))], + ..Value::default() + }], + ..Node::default() + }, + Node { + name: s("format"), + description: s("Intended data format."), + max: Some(1), + values: vec![Value { + min: Some(1), + validations: vec![ + Validation::Type(s("string")), + Validation::Enum(vec![ + s("date-time"), + s("date"), + s("time"), + s("duration"), + s("decimal"), + s("currency"), + s("country-2"), + s("country-3"), + s("country-subdivision"), + s("email"), + s("idn-email"), + s("hostname"), + s("idn-hostname"), + s("ipv4"), + s("ipv6"), + s("url"), + s("url-reference"), + s("irl"), + s("irl-reference"), + s("url-template"), + s("regex"), + s("uuid"), + s("kdl-query"), + s("i8"), + s("i16"), + s("i32"), + s("i64"), + s("u8"), + s("u16"), + s("u32"), + s("u64"), + s("isize"), + s("usize"), + s("f32"), + s("f64"), + s("decimal64"), + s("decimal128"), + ]) + ], + ..Value::default() + }], + ..Node::default() + }, + Node { + name: s("%"), + description: s("Only used for numeric values. Constrains them to be multiples of the given number(s)"), + max: Some(1), + values: vec![Value { + min: Some(1), + validations: vec![Validation::Type(s("number"))], + ..Value::default() + }], + ..Node::default() + }, + Node { + name: s(">"), + description: s("Only used for numeric values. Constrains them to be greater than the given number(s)"), + max: Some(1), + values: vec![Value { + min: Some(1), + max: Some(1), + validations: vec![Validation::Type(s("number"))], + ..Value::default() + }], + ..Node::default() + }, + Node { + name: s(">="), + description: s("Only used for numeric values. Constrains them to be greater than or equal to the given number(s)"), + max: Some(1), + values: vec![Value { + min: Some(1), + max: Some(1), + validations: vec![Validation::Type(s("number"))], + ..Value::default() + }], + ..Node::default() + }, + Node { + name: s("<"), + description: s("Only used for numeric values. Constrains them to be less than the given number(s)"), + max: Some(1), + values: vec![Value { + min: Some(1), + max: Some(1), + validations: vec![Validation::Type(s("number"))], + ..Value::default() + }], + ..Node::default() + }, + Node { + name: s("<="), + description: s("Only used for numeric values. Constrains them to be less than or equal to the given number(s)"), + max: Some(1), + values: vec![Value { + min: Some(1), + max: Some(1), + validations: vec![Validation::Type(s("number"))], + ..Value::default() + }], + ..Node::default() + }, + ], + ..Children::default() + } +} + +fn make_info_node() -> Node { + Node { + name: s("info"), + description: s("A child node that describes the schema itself."), + children: vec![Children { + nodes: vec![ + Node { + name: s("title"), + description: s("The title of the schema or the format it describes"), + values: vec![Value { + description: s("The title text"), + min: Some(1), + max: Some(1), + validations: vec![Validation::Type(s("string"))], + ..Value::default() + }], + props: vec![Prop { + key: s("lang"), + id: s("info-lang"), + description: s("The language of the text"), + validations: vec![Validation::Type(s("string"))], + ..Prop::default() + }], + ..Node::default() + }, + Node { + name: s("description"), + description: s("A description of the schema or the format it describes"), + values: vec![Value { + description: s("The description text"), + min: Some(1), + max: Some(1), + validations: vec![Validation::Type(s("string"))], + ..Value::default() + }], + props: vec![ref_to_id("info-lang")], + ..Node::default() + }, + Node { + name: s("author"), + description: s("Author of the schema"), + values: vec![Value { + id: s("info-person-name"), + description: s("Person name"), + min: Some(1), + max: Some(1), + validations: vec![Validation::Type(s("string"))], + ..Value::default() + }], + props: vec![Prop { + key: s("orcid"), + id: s("info-orcid"), + description: s("The ORCID of the person"), + validations: vec![ + Validation::Type(s("string")), + Validation::Pattern(s(r"\d{4}-\d{4}-\d{4}-\d{4}")), + ], + ..Prop::default() + }], + children: vec![Children { + nodes: vec![ref_to_id("info-link")], + ..Children::default() + }], + ..Node::default() + }, + Node { + name: s("contributor"), + description: s("Contributor to the schema"), + values: vec![ref_to_id("info-person-name")], + props: vec![ref_to_id("info-orcid")], + ..Node::default() + }, + Node { + name: s("link"), + id: s("info-link"), + description: s("Links to itself, and to sources describing it"), + values: vec![Value { + description: s("A URL that the link points to"), + min: Some(1), + max: Some(1), + validations: vec![ + Validation::Type(s("string")), + Validation::Format(vec![Format::Url, Format::Irl]), + ], + ..Value::default() + }], + props: vec![ + Prop { + key: s("rel"), + description: s("The relation between the current entity and the URL"), + validations: vec![ + Validation::Type(s("string")), + Validation::Enum(vec![s("self"), s("documentation")]), + ], + ..Prop::default() + }, + ref_to_id("info-lang"), + ], + ..Node::default() + }, + Node { + name: s("license"), + description: s("The license(s) that the schema is licensed under"), + values: vec![Value { + description: s("Name of the used license"), + min: Some(1), + max: Some(1), + validations: vec![Validation::Type(s("string"))], + ..Value::default() + }], + props: vec![Prop { + key: s("spdx"), + description: s("An SPDX license identifier"), + validations: vec![Validation::Type(s("string"))], + ..Prop::default() + }], + children: vec![Children { + nodes: vec![ref_to_id("info-link")], + ..Children::default() + }], + ..Node::default() + }, + Node { + name: s("published"), + description: s("When the schema was published"), + values: vec![Value { + description: s("Publication date"), + min: Some(1), + max: Some(1), + validations: vec![ + Validation::Type(s("string")), + Validation::Format(vec![Format::Date]), + ], + ..Value::default() + }], + props: vec![Prop { + key: s("time"), + id: s("info-time"), + description: s("A time to accompany the date"), + validations: vec![ + Validation::Type(s("string")), + Validation::Format(vec![Format::Time]), + ], + ..Prop::default() + }], + ..Node::default() + }, + Node { + name: s("modified"), + description: s("When the schema was last modified"), + values: vec![Value { + description: s("Modification date"), + min: Some(1), + max: Some(1), + validations: vec![ + Validation::Type(s("string")), + Validation::Format(vec![Format::Date]), + ], + ..Value::default() + }], + props: vec![ref_to_id("info-time")], + ..Node::default() + }, + Node { + name: s("version"), + description: s("The version number of this version of the schema"), + values: vec![Value { + description: s("Semver version number"), + min: Some(1), + max: Some(1), + validations: vec![ + Validation::Type(s("string")), + Validation::Pattern(s( + r"^(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-]+)*))?$", + )), + ], + ..Value::default() + }], + ..Node::default() + }, + ], + ..Children::default() + }], + ..Node::default() + } +} + +fn make_schema_info() -> Info { + Info { + title: vec![info::TextValue { + text: s("KDL Schema"), + lang: s("en"), + }], + description: vec![info::TextValue { + text: s("KDL Schema KDL schema in KDL"), + lang: s("en"), + }], + authors: vec![info::Person { + name: s("Kat Marchán"), + orcid: None, + links: vec![info::Link { + iri: s("https://github.com/zkat"), + rel: s("self"), + lang: None, + }], + }], + contributors: vec![info::Person { + name: s("Lars Willighagen"), + orcid: None, + links: vec![info::Link { + iri: s("https://github.com/larsgw"), + rel: s("self"), + lang: None, + }], + }], + links: vec![info::Link { + iri: s("https://github.com/zkat/kdl"), + rel: s("documentation"), + lang: None, + }], + licenses: vec![info::License { + name: s("Creative Commons Attribution-ShareAlike 4.0 International License"), + spdx: s("CC-BY-SA-4.0"), + link: vec![info::Link { + iri: s("https://creativecommons.org/licenses/by-sa/4.0/"), + rel: None, + lang: s("en"), + }], + }], + published: Some(info::Date { + date: s("2021-08-31"), + time: None, + }), + modified: Some(info::Date { + date: s("2021-09-01"), + time: None, + }), + } +} -- cgit v1.2.3