logo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//! `kdl` is a "document-oriented" parser and API for the [KDL Document
//! Language](https://kdl.dev), a node-based, human-friendly configuration and
//! serialization format. Unlike serde-based implementations, this crate
//! preserves formatting when editing, as well as when inserting or changing
//! values with custom formatting. This is most 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.
//!
//! If you don't care about formatting or programmatic manipulation, you might
//! check out [`knuffel`](https://crates.io/crates/knuffel) or
//! [`kaydle`](https://crates.io/crates/kaydle) instead for serde (or
//! serde-like) parsing.
//!
//! ## 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.
//!
//! ## Error Reporting
//!
//! [`KdlError`] implements [`miette::Diagnostic`] and can be used to display
//! detailed, pretty-printed diagnostic messages when using [`miette::Result`]
//! and the `"fancy"` feature flag for `miette`:
//!
//! ```toml
//! # Cargo.toml
//! [dependencies]
//! miette = { version = "x.y.z", features = ["fancy"] }
//! ```
//!
//! ```no_run
//! fn main() -> miette::Result<()> {
//!     "foo 1.".parse::<kdl::KdlDocument>()?;
//!     Ok(())
//! }
//! ```
//!
//! This will display a message like:
//! ```text
//! Error:
//!   × Expected valid value.
//!    ╭────
//!  1 │ foo 1.
//!    ·     ─┬
//!    ·      ╰── invalid float
//!    ╰────
//!   help: Floating point numbers must be base 10, and have numbers after the decimal point.
//! ```
//!
//! ## Quirks
//!
//! ### Properties
//!
//! Multiple properties with the same name are allowed, and all duplicated
//! **will be preserved**, meaning those documents will correctly round-trip.
//! When using `node.get()`/`node["key"]` & company, the _last_ property with
//! that name's value will be returned.
//!
//! ### Numbers
//!
//! KDL itself does not specify a particular representation for numbers and
//! accepts just about anything valid, no matter how large and how small. This
//! means a few things:
//!
//! * Numbers without a decimal point are interpreted as [`u64`].
//! * Numbers with a decimal point are interpreted as [`f64`].
//! * Floating point numbers that evaluate to [`f64::INFINITY`] or
//!   [`f64::NEG_INFINITY`] or NaN will be represented as such in the values,
//!   instead of the original numbers.
//! * A similar restriction applies to overflowed [`u64`] values.
//! * The original _representation_ of these numbers will be preserved, unless
//!   you [`KdlDocument::fmt`] in which case the original representation will be
//!   thrown away and the actual value will be used when serializing.
//!
//! ## 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_favicon_url = "https://kdl.dev/favicon.ico")]
#![doc(html_logo_url = "https://kdl.dev/logo.svg")]

pub use document::*;
pub use entry::*;
pub use error::*;
pub use identifier::*;
pub use node::*;
pub use value::*;

mod document;
mod entry;
mod error;
mod fmt;
mod identifier;
mod node;
mod nom_compat;
mod parser;
mod value;