5个稳定版本

3.2.0 2023年4月15日
3.0.0 2023年3月14日
2.0.0 2022年3月31日
1.1.0 2022年2月8日
1.0.0 2022年2月7日

#578解析器实现

Download history 450/week @ 2024-03-14 540/week @ 2024-03-21 620/week @ 2024-03-28 432/week @ 2024-04-04 462/week @ 2024-04-11 897/week @ 2024-04-18 524/week @ 2024-04-25 381/week @ 2024-05-02 306/week @ 2024-05-09 386/week @ 2024-05-16 365/week @ 2024-05-23 357/week @ 2024-05-30 294/week @ 2024-06-06 387/week @ 2024-06-13 429/week @ 2024-06-20 408/week @ 2024-06-27

1,619 每月下载量
用于 9 个crate(8个直接)

MIT/Apache

135KB
3.5K SLoC

一个具有出色错误报告和方便的 derive 宏的 KDL 文件格式解析器。

关于KDL

为了向您介绍 KDL 格式的背景,这里有一个小示例

foo 1 key="val" "three" {
    bar
    (role)baz 1 2
}

以下是根据 规范 和本指南描述的所有数据的注释

foo 1 "three" key="val" {                           ╮
─┬─ ┬ ───┬─── ────┬────                             │
 │  │    │        ╰───── property (can be multiple) │
 │  │    │                                          │
 │  ╰────┴────────────── arguments                  │
 │                                                  │
 └── node name                                      ├─ node "foo", with
                                                    │  "bar" and "baz"
    bar                                             │  being children
    (role)baz 1 2                                   │
     ──┬─                                           │
       └────── type name for node named "baz"       │
}                                                   ╯

(注意,属性的顺序并不重要,以及与参数相关的属性的顺序,所以我将参数移动到交叉较少的箭头处)

用法

此库最常用的用法是使用 derive 和 [parse] 函数

#[derive(knuffel::Decode)]
enum TopLevelNode {
    Route(Route),
    Plugin(Plugin),
}

#[derive(knuffel::Decode)]
struct Route {
    #[knuffel(argument)]
    path: String,
    #[knuffel(children(name="route"))]
    subroutes: Vec<Route>,
}

#[derive(knuffel::Decode)]
struct Plugin {
    #[knuffel(argument)]
    name: String,
    #[knuffel(property)]
    url: String,
}

# fn main() -> miette::Result<()> {
let config = knuffel::parse::<Vec<TopLevelNode>>("example.kdl", r#"
    route "/api" {
        route "/api/v1"
    }
    plugin "http" url="https://example.org/http"
"#)?;
# Ok(())
# }

它解析为枚举 TopLevelNode 的节点向量,但如果没有声明属性和参数,也可以使用某些节点作为文档的根

#[derive(knuffel::Decode)]
struct Document {
    #[knuffel(child, unwrap(argument))]
    version: Option<String>,
    #[knuffel(children(name="route"))]
    routes: Vec<Route>,
    #[knuffel(children(name="plugin"))]
    plugins: Vec<Plugin>,
}

let config = parse::<Document>("example.kdl", r#"
    version "2.0"
    route "/api" {
        route "/api/v1"
    }
    plugin "http" url="https://example.org/http"
"#)?;

有关允许的属性和解析模式的完整参考,请参阅 DecodeDecodeScalar 的描述

错误

此crate发布了漂亮的错误,如下所示


Screenshot of error. Here is how narratable printer would print the error:
Error: single char expected after `Alt+`
Diagnostic severity: error
\
Begin snippet for test.kdl starting at line 17, column 1
\
snippet line 17:     }
snippet line 18:     key "Alt+" mode="normal" {
label starting at line 18, column 10: invalid value
snippet line 19:         move-focus "left"

要使它们正常工作,必须在最终应用的 Cargo.toml 中启用 miette 的 "fancy" 功能

[dependencies]
miette = { version="4.3.0", features=["fancy"] }

然后,应将解析器返回的错误转换为 miette::Report 并使用调试处理程序打印。最手动的方法是

# #[derive(knuffel::Decode, Debug)]
# struct Config {}
# let file_name = "1.kdl";
# let text = "";
let config = match knuffel::parse::<Config>(file_name, text) {
    Ok(config) => config,
    Err(e) => {
         println!("{:?}", miette::Report::new(e));
         std::process::exit(1);
    }
};

但通常返回 miette::Result 的函数就足够了

# use std::fs;
# #[derive(knuffel::Decode)]
# struct Config {}
use miette::{IntoDiagnostic, Context};

fn parse_config(path: &str) -> miette::Result<Config> {
    let text = fs::read_to_string(path).into_diagnostic()
        .wrap_err_with(|| format!("cannot read {:?}", path))?;
    Ok(knuffel::parse(path, &text)?)
}
fn main() -> miette::Result<()> {
    let config = parse_config("my.kdl")?;
    # Ok(())
}

有关配置错误输出的其他方法的说明,请参阅 miette 指南

名称

KDL 发音为 cuddle。"Knuffel" 在荷兰语中与 cuddle 的意思相同。

许可协议

根据以下任一协议许可

贡献

除非您明确声明,否则根据Apache-2.0许可证定义,您有意提交用于工作内容的任何贡献,应作为上述双重许可,不附加任何额外条款或条件。

依赖项

~4MB
~63K SLoC