From 94190697d8ad676f9b879dcc90f8eb03266c3ef8 Mon Sep 17 00:00:00 2001 From: jam1garner <8260240+jam1garner@users.noreply.github.com> Date: Sat, 8 May 2021 17:31:58 -0400 Subject: [PATCH] feat(docs): Add documentation for the entire crate (#16) --- src/error.rs | 10 +++++++ src/lib.rs | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/node.rs | 48 +++++++++++++++++++++++++++++- src/parser.rs | 8 +++-- 4 files changed, 144 insertions(+), 4 deletions(-) diff --git a/src/error.rs b/src/error.rs index 8995395..ad765eb 100644 --- a/src/error.rs +++ b/src/error.rs @@ -3,6 +3,14 @@ use std::num::{ParseFloatError, ParseIntError}; use nom::error::{ContextError, ErrorKind, FromExternalError, ParseError}; use thiserror::Error; + +#[cfg(doc)] +use { + crate::KdlNode, + std::convert::{TryFrom, TryInto}, +}; + +/// An error that occurs when parsing a KDL document. #[derive(Debug, Clone, Eq, PartialEq, Error)] #[error("Error parsing document at line {line} column {column}. {kind}")] pub struct KdlError { @@ -16,6 +24,7 @@ pub struct KdlError { pub kind: KdlErrorKind, } +/// A type reprenting additional information specific to the type of error being returned. #[derive(Debug, Clone, Eq, PartialEq, Error)] pub enum KdlErrorKind { #[error(transparent)] @@ -28,6 +37,7 @@ pub enum KdlErrorKind { Other, } +/// Coversion errors for converting [`KdlNode`] to another type via [`TryFrom`] or [`TryInto`]. #[derive(Debug, Clone, Eq, PartialEq, Error)] #[error("Failed to convert from KdlNodeValue::{variant} to {expected}.")] pub struct TryFromKdlNodeValueError { diff --git a/src/lib.rs b/src/lib.rs index e472be5..584717e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,63 @@ +#![doc(html_logo_url = "https://kdl.dev/logo.svg")] +//! KDL is a document language with xml-like semantics that looks like you're invoking a bunch of +//! CLI commands! It's meant to be used both as a serialization format and a configuration language, +//! much like JSON, YAML, or XML. +//! +//! There's a [living specification], as well as [various implementations]. You can also check out the +//! [language FAQ] to answer all your burning questions! +//! +//! This crate is the official/reference implementation of the KDL document language. +//! +//! [living specification]: https://github.com/kdl-org/kdl/blob/main/SPEC.md +//! [various implementations]: https://kdl.dev/#implementations +//! [language FAQ]: https://kdl.dev/#faq +//! +//! ## License +//! +//! The code in this crate is covered by the [Parity License], a strong copyleft license. That +//! means that you can only use this project if you're working on an open source-licensed product +//! (MIT/Apache projects are ok!) +//! +//! [Parity License]: https://github.com/kdl-org/kdl-rs/blob/main/LICENSE.md +//! +//! ## Example KDL File +//! +//! ```text +//! author "Alex Monad" email="alex@example.com" active=true +//! +//! contents { +//! section "First section" { +//! paragraph "This is the first paragraph" +//! paragraph "This is the second paragraph" +//! } +//! } +//! +//! // unicode! comments! +//! π 3.14159 +//! ``` +//! +//! ## Basic Library Example +//! +//! ``` +//! use kdl::{KdlNode, KdlValue}; +//! use std::collections::HashMap; +//! +//! assert_eq!( +//! kdl::parse_document("node 1 key=true").unwrap(), +//! vec![ +//! KdlNode { +//! name: String::from("node"), +//! values: vec![KdlValue::Int(1)], +//! properties: { +//! let mut temp = HashMap::new(); +//! temp.insert(String::from("key"), KdlValue::Boolean(true)); +//! temp +//! }, +//! children: vec![], +//! } +//! ] +//! ) +//! ``` use nom::combinator::all_consuming; use nom::Finish; @@ -8,6 +68,28 @@ mod error; mod node; mod parser; +/// Parse a KDL document from a string into a list of [`KdlNode`]s. +/// +/// ``` +/// use kdl::{KdlNode, KdlValue}; +/// use std::collections::HashMap; +/// +/// assert_eq!( +/// kdl::parse_document("node 1 key=true").unwrap(), +/// vec![ +/// KdlNode { +/// name: String::from("node"), +/// values: vec![KdlValue::Int(1)], +/// properties: { +/// let mut temp = HashMap::new(); +/// temp.insert(String::from("key"), KdlValue::Boolean(true)); +/// temp +/// }, +/// children: vec![], +/// } +/// ] +/// ) +/// ``` pub fn parse_document(input: I) -> Result, KdlError> where I: AsRef, diff --git a/src/node.rs b/src/node.rs index ff49d9b..b390880 100644 --- a/src/node.rs +++ b/src/node.rs @@ -2,7 +2,52 @@ use std::{collections::HashMap, convert::TryFrom, fmt}; use crate::TryFromKdlNodeValueError; -#[derive(Debug, Clone, PartialEq)] +/// A node representing the smallest unit of a KDL document. +/// +/// The anatomy of a node: +/// ```text +/// name "value" property_key="property value" { +/// child +/// } +/// ``` +/// +/// ## Example +/// +/// ``` +/// use kdl::{KdlNode, KdlValue}; +/// use std::collections::HashMap; +/// +/// const DOCUMENT: &str = r#" +/// name "value" property_key="property value" { +/// child +/// } +/// "#; +/// +/// assert_eq!( +/// kdl::parse_document(DOCUMENT).unwrap(), +/// vec![ +/// KdlNode { +/// name: String::from("name"), +/// values: vec![KdlValue::String("value".into())], +/// properties: { +/// let mut temp = HashMap::new(); +/// temp.insert( +/// String::from("property_key"), +/// KdlValue::String("property value".into()) +/// ); +/// temp +/// }, +/// children: vec![ +/// KdlNode { +/// name: String::from("child"), +/// ..Default::default() +/// } +/// ], +/// } +/// ] +/// ) +/// ``` +#[derive(Default, Debug, Clone, PartialEq)] pub struct KdlNode { pub name: String, pub values: Vec, @@ -10,6 +55,7 @@ pub struct KdlNode { pub children: Vec, } +/// A value present in either a node's values or in a node's properties. #[derive(Debug, Clone, PartialEq)] pub enum KdlValue { Int(i64), diff --git a/src/parser.rs b/src/parser.rs index e53efc2..79d1269 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -18,7 +18,7 @@ use crate::node::{KdlNode, KdlValue}; pub(crate) fn nodes(input: &str) -> IResult<&str, Vec, KdlParseError<&str>> { let (input, _) = many0(linespace)(input)?; let (input, nodes) = map(many0(terminated(node, many0(linespace))), |nodes| { - nodes.into_iter().filter_map(|node| node).collect() + nodes.into_iter().flatten().collect() })(input)?; let (input, _) = many0(linespace)(input)?; Ok((input, nodes)) @@ -84,7 +84,7 @@ pub(crate) fn node(input: &str) -> IResult<&str, Option, KdlParseError< } else { let (values, properties): (Vec, Vec) = args .into_iter() - .filter_map(|n| n) + .flatten() .partition(|arg| matches!(arg, NodeArg::Value(_))); Ok(( input, @@ -308,7 +308,9 @@ fn integer(input: &str) -> IResult<&str, i64, KdlParseError<&str>> { map_res( recognize(many1(terminated(one_of("0123456789"), many0(char('_'))))), move |out: &str| { - i64::from_str_radix(&str::replace(&out, "_", ""), 10).map(move |x| x * mult) + str::replace(&out, "_", "") + .parse::() + .map(move |x| x * mult) }, )(input) }