mirror of https://github.com/kdl-org/kdl-rs.git
chore: clean up and docs
This commit is contained in:
parent
a1555949ed
commit
fc1d0fd24b
|
|
@ -9,3 +9,9 @@ workspace=false
|
|||
install_crate="cargo-release"
|
||||
command = "cargo"
|
||||
args = ["release", "--workspace", "${@}"]
|
||||
|
||||
[tasks.readme]
|
||||
workspace=false
|
||||
install_crate="cargo-readme"
|
||||
command = "cargo"
|
||||
args = ["readme", "-o", "README.md"]
|
||||
|
|
|
|||
60
README.md
60
README.md
|
|
@ -1,7 +1,9 @@
|
|||
# `kdl`
|
||||
|
||||
`kdl` is a "document-oriented" parser and API. That means that, unlike
|
||||
serde-based implementations, it's meant to preserve formatting when editing,
|
||||
as well as inserting values with custom formatting. This is useful when
|
||||
working with human-maintained KDL files.
|
||||
serde-based implementations, it's meant to preserve formatting when
|
||||
editing, as well as inserting values with custom formatting. This is
|
||||
useful when working with human-maintained KDL files.
|
||||
|
||||
You can think of this crate as
|
||||
[`toml_edit`](https://crates.io/crates/toml_edit), but for KDL.
|
||||
|
|
@ -11,18 +13,58 @@ You can think of this crate as
|
|||
```rust
|
||||
use kdl::KdlDocument;
|
||||
|
||||
let doc: KdlDocument = r#"
|
||||
let doc_str = r#"
|
||||
hello 1 2 3
|
||||
|
||||
world prop="value" {
|
||||
child 1
|
||||
child 2
|
||||
}
|
||||
"#.parse().expect("failed to parse KDL");
|
||||
"#;
|
||||
|
||||
assert_eq!(doc.get_args("hello"), vec![&1.into(), &2.into(), &3.into()]);
|
||||
assert_eq!(doc.get("world").map(|node| &node["prop"]), Some(&"value".into()));
|
||||
let doc: KdlDocument = doc_str.parse().expect("failed to parse KDL");
|
||||
|
||||
assert_eq!(
|
||||
doc.get_args("hello"),
|
||||
vec![&1.into(), &2.into(), &3.into()]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
doc.get("world").map(|node| &node["prop"]),
|
||||
Some(&"value".into())
|
||||
);
|
||||
|
||||
// Documents fully roundtrip:
|
||||
assert_eq!(doc.to_string(), doc_str);
|
||||
```
|
||||
|
||||
## License
|
||||
### Controlling Formatting
|
||||
|
||||
The code in this repository is covered by [the Apache-2.0 License](LICENSE.md).
|
||||
By default, everything is created with default formatting. You can parse
|
||||
items manually to provide custom representations, comments, etc:
|
||||
|
||||
```rust
|
||||
let node_str = r#"
|
||||
// indented comment
|
||||
"formatted" 1 /* comment */ \
|
||||
2;
|
||||
"#;
|
||||
|
||||
let mut doc = kdl::KdlDocument::new();
|
||||
doc.nodes_mut().push(node_str.parse().unwrap());
|
||||
|
||||
assert_eq!(&doc.to_string(), node_str);
|
||||
```
|
||||
|
||||
[`KdlDocument`], [`KdlNode`], [`KdlEntry`], and [`KdlIdentifier`] can all
|
||||
be parsed and managed this way.
|
||||
|
||||
### License
|
||||
|
||||
The code in this repository is covered by [the Apache-2.0
|
||||
License](LICENSE.md).
|
||||
|
||||
[`KdlDocument`]: https://docs.rs/kdl/3.0.1-alpha.0/kdl/struct.KdlDocument.html
|
||||
[`KdlNode`]: https://docs.rs/kdl/3.0.1-alpha.0/kdl/struct.KdlNode.html
|
||||
[`KdlEntry`]: https://docs.rs/kdl/3.0.1-alpha.0/kdl/struct.KdlEntry.html
|
||||
[`KdlIdentifier`]: https://docs.rs/kdl/3.0.1-alpha.0/kdl/struct.KdlIdentifier.html
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
# `{{crate}}`
|
||||
|
||||
{{readme}}
|
||||
|
||||
[`KdlDocument`]: https://docs.rs/kdl/{{version}}/kdl/struct.KdlDocument.html
|
||||
[`KdlNode`]: https://docs.rs/kdl/{{version}}/kdl/struct.KdlNode.html
|
||||
[`KdlEntry`]: https://docs.rs/kdl/{{version}}/kdl/struct.KdlEntry.html
|
||||
[`KdlIdentifier`]: https://docs.rs/kdl/{{version}}/kdl/struct.KdlIdentifier.html
|
||||
|
|
@ -8,6 +8,14 @@ use crate::{parser, KdlError, KdlNode, KdlValue};
|
|||
/// This type is also used to manage a [`KdlNode`]'s [`Children
|
||||
/// Block`](https://github.com/kdl-org/kdl/blob/main/SPEC.md#children-block),
|
||||
/// when present.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// The easiest way to create a `KdlDocument` is to parse it:
|
||||
/// ```rust
|
||||
/// # use kdl::KdlDocument;
|
||||
/// let kdl: KdlDocument = "foo 1 2 3\nbar 4 5 6".parse().expect("parse failed");
|
||||
/// ```
|
||||
#[derive(Debug, Default, Clone, PartialEq)]
|
||||
pub struct KdlDocument {
|
||||
pub(crate) leading: Option<String>,
|
||||
|
|
@ -88,6 +96,9 @@ impl KdlDocument {
|
|||
.collect()
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the first argument (value) of the first
|
||||
/// child node with a matching name. This is a shorthand utility for cases
|
||||
/// where a document is being used as a key/value store.
|
||||
pub fn get_arg_mut(&mut self, name: &str) -> Option<&mut KdlValue> {
|
||||
self.get_mut(name)
|
||||
.and_then(|node| node.get_mut(0))
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ impl KdlEntry {
|
|||
}
|
||||
}
|
||||
|
||||
/// Gets a reference to this entry's name, if it's a property entry.
|
||||
pub fn name(&self) -> Option<&KdlIdentifier> {
|
||||
self.name.as_ref()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,12 +15,14 @@ use {
|
|||
#[error("{kind}")]
|
||||
pub struct KdlError {
|
||||
#[source_code]
|
||||
/// Source string for the KDL document that failed to parse.
|
||||
pub input: String,
|
||||
|
||||
/// Offset in chars of the error.
|
||||
#[label = "here"]
|
||||
pub offset: usize,
|
||||
|
||||
/// Specific error kind for this parser error.
|
||||
pub kind: KdlErrorKind,
|
||||
}
|
||||
|
||||
|
|
@ -29,18 +31,24 @@ pub struct KdlError {
|
|||
pub enum KdlErrorKind {
|
||||
#[error(transparent)]
|
||||
#[diagnostic(code(kdl::parse_int))]
|
||||
/// An error occurred while parsing an integer.
|
||||
ParseIntError(ParseIntError),
|
||||
|
||||
#[error(transparent)]
|
||||
#[diagnostic(code(kdl::parse_float))]
|
||||
/// An error occurred while parsing a floating point number.
|
||||
ParseFloatError(ParseFloatError),
|
||||
|
||||
#[error("Expected {0}.")]
|
||||
#[diagnostic(code(kdl::parse_component))]
|
||||
/// Generic parsing error. The given context string denotes the component
|
||||
/// that failed to parse.
|
||||
Context(&'static str),
|
||||
|
||||
#[error("An unspecified error occurred.")]
|
||||
#[diagnostic(code(kdl::other))]
|
||||
/// Generic unspecified error. If this is returned, the call site should
|
||||
/// be annotated with context, if possible.
|
||||
Other,
|
||||
}
|
||||
|
||||
|
|
|
|||
96
src/lib.rs
96
src/lib.rs
|
|
@ -1,32 +1,72 @@
|
|||
//! `kdl` is a "document-oriented" parser and API. That means that, unlike
|
||||
//! serde-based implementations, it's meant to preserve formatting when
|
||||
//! editing, as well as inserting values with custom formatting. This is
|
||||
//! useful when working with human-maintained KDL files.
|
||||
//!
|
||||
//! You can think of this crate as
|
||||
//! [`toml_edit`](https://crates.io/crates/toml_edit), but for KDL.
|
||||
//!
|
||||
//! ## Example
|
||||
//!
|
||||
//! ```rust
|
||||
//! use kdl::KdlDocument;
|
||||
//!
|
||||
//! let doc_str = r#"
|
||||
//! hello 1 2 3
|
||||
//!
|
||||
//! world prop="value" {
|
||||
//! child 1
|
||||
//! child 2
|
||||
//! }
|
||||
//! "#;
|
||||
//!
|
||||
//! let doc: KdlDocument = doc_str.parse().expect("failed to parse KDL");
|
||||
//!
|
||||
//! assert_eq!(
|
||||
//! doc.get_args("hello"),
|
||||
//! vec![&1.into(), &2.into(), &3.into()]
|
||||
//! );
|
||||
//!
|
||||
//! assert_eq!(
|
||||
//! doc.get("world").map(|node| &node["prop"]),
|
||||
//! Some(&"value".into())
|
||||
//! );
|
||||
//!
|
||||
//! // Documents fully roundtrip:
|
||||
//! assert_eq!(doc.to_string(), doc_str);
|
||||
//! ```
|
||||
//!
|
||||
//! ## Controlling Formatting
|
||||
//!
|
||||
//! By default, everything is created with default formatting. You can parse
|
||||
//! items manually to provide custom representations, comments, etc:
|
||||
//!
|
||||
//! ```rust
|
||||
//! let node_str = r#"
|
||||
//! // indented comment
|
||||
//! "formatted" 1 /* comment */ \
|
||||
//! 2;
|
||||
//! "#;
|
||||
//!
|
||||
//! let mut doc = kdl::KdlDocument::new();
|
||||
//! doc.nodes_mut().push(node_str.parse().unwrap());
|
||||
//!
|
||||
//! assert_eq!(&doc.to_string(), node_str);
|
||||
//! ```
|
||||
//!
|
||||
//! [`KdlDocument`], [`KdlNode`], [`KdlEntry`], and [`KdlIdentifier`] can all
|
||||
//! be parsed and managed this way.
|
||||
//!
|
||||
//! ## License
|
||||
//!
|
||||
//! The code in this repository is covered by [the Apache-2.0
|
||||
//! License](LICENSE.md).
|
||||
|
||||
#![deny(missing_debug_implementations, nonstandard_style)]
|
||||
#![warn(missing_docs, unreachable_pub, rust_2018_idioms, unreachable_pub)]
|
||||
#![cfg_attr(test, deny(warnings))]
|
||||
#![doc(html_logo_url = "https://kdl.dev/logo.svg")]
|
||||
/// `kdl` is a "document-oriented" parser and API. That means that, unlike
|
||||
/// serde-based implementations, it's meant to preserve formatting when editing,
|
||||
/// as well as inserting values with custom formatting. This is useful when
|
||||
/// working with human-maintained KDL files.
|
||||
///
|
||||
/// You can think of this crate as
|
||||
/// [`toml_edit`](https://crates.io/crates/toml_edit), but for KDL.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use kdl::KdlDocument;
|
||||
///
|
||||
/// let doc: KdlDocument = r#"
|
||||
/// hello 1 2 3
|
||||
/// world prop="value" {
|
||||
/// child 1
|
||||
/// child 2
|
||||
/// }
|
||||
/// "#.parse().expect("failed to parse KDL");
|
||||
///
|
||||
/// assert_eq!(doc.get_args("hello"), vec![&1.into(), &2.into(), &3.into()]);
|
||||
/// assert_eq!(doc.get("world").map(|node| &node["prop"]), Some(&"value".into()));
|
||||
/// ```
|
||||
///
|
||||
/// ## License
|
||||
///
|
||||
/// The code in this repository is covered by [the Apache-2.0 License](LICENSE.md).
|
||||
|
||||
pub use document::*;
|
||||
pub use entry::*;
|
||||
pub use error::*;
|
||||
|
|
|
|||
|
|
@ -50,16 +50,17 @@ impl KdlNode {
|
|||
self.name = name.into();
|
||||
}
|
||||
|
||||
/// Gets the node's type, if any.
|
||||
/// Gets the node's type identifier, if any.
|
||||
pub fn ty(&self) -> Option<&KdlIdentifier> {
|
||||
self.ty.as_ref()
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the node's type.
|
||||
/// Gets a mutable reference to the node's type identifier.
|
||||
pub fn ty_mut(&mut self) -> &mut Option<KdlIdentifier> {
|
||||
&mut self.ty
|
||||
}
|
||||
|
||||
/// Sets the node's type identifier.
|
||||
pub fn set_ty(&mut self, ty: impl Into<KdlIdentifier>) {
|
||||
self.ty = Some(ty.into());
|
||||
}
|
||||
|
|
@ -334,7 +335,9 @@ impl KdlNode {
|
|||
/// Represents a [`KdlNode`]'s entry key.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum NodeKey {
|
||||
/// Key for a node property entry.
|
||||
Key(KdlIdentifier),
|
||||
/// Index for a node argument entry (positional value).
|
||||
Index(usize),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use nom::error::{ErrorKind, ParseError};
|
||||
use nom::{Err, IResult, Parser};
|
||||
|
||||
pub fn many0<I, O, E, F>(mut f: F) -> impl FnMut(I) -> IResult<I, Vec<O>, E>
|
||||
pub(crate) fn many0<I, O, E, F>(mut f: F) -> impl FnMut(I) -> IResult<I, Vec<O>, E>
|
||||
where
|
||||
I: Clone + PartialEq,
|
||||
F: Parser<I, O, E>,
|
||||
|
|
@ -26,7 +26,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub fn many1<I, O, E, F>(mut f: F) -> impl FnMut(I) -> IResult<I, Vec<O>, E>
|
||||
pub(crate) fn many1<I, O, E, F>(mut f: F) -> impl FnMut(I) -> IResult<I, Vec<O>, E>
|
||||
where
|
||||
I: Clone + PartialEq,
|
||||
F: Parser<I, O, E>,
|
||||
|
|
@ -58,7 +58,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub fn many_till<I, O, P, E, F, G>(
|
||||
pub(crate) fn many_till<I, O, P, E, F, G>(
|
||||
mut f: F,
|
||||
mut g: G,
|
||||
) -> impl FnMut(I) -> IResult<I, (Vec<O>, P), E>
|
||||
|
|
|
|||
Loading…
Reference in New Issue