#html #html-macro #rsx #jsx #syn #proc-macro #macro

rstml

基于proc-macro::TokenStreams实现的XML格式(HTML、SVG、MathML)的Rust模板

5个不稳定版本

0.12.0 2024年7月28日
0.11.2 2023年8月14日
0.11.0 2023年7月18日
0.10.6 2023年5月17日
0.9.0 2023年5月12日

#20过程宏 中排名

Download history 7742/week @ 2024-05-04 8658/week @ 2024-05-11 8159/week @ 2024-05-18 9078/week @ 2024-05-25 9114/week @ 2024-06-01 6908/week @ 2024-06-08 7802/week @ 2024-06-15 8438/week @ 2024-06-22 7354/week @ 2024-06-29 8018/week @ 2024-07-06 11663/week @ 2024-07-13 11768/week @ 2024-07-20 13140/week @ 2024-07-27 11893/week @ 2024-08-03 12969/week @ 2024-08-10 10833/week @ 2024-08-17

每月下载量50,829
用于 199 个crate(直接使用19个)

MIT 许可证

150KB
3K SLoC

rstml

crates.io页面 docs.rs页面 codecov build 许可证: MIT 在proc-macro::TokenStreams之上实现XML格式(HTML、SVG、MathML)的Rust模板。类似于JSX,但针对Rust(通常称为RSX)。解析结果是一个嵌套的Node结构,类似于浏览器的DOM,节点名称和值是syn表达式,以支持构建过程宏。

原始syn-rsx仓库的分支。由于各种原因创建了它

  • 原始syn-rsx的所有者已故
  • 发布了Syn v2,syn-rsx需要迁移到新版本。
  • 关于无损解析的想法被忽视。
  • 未引用文本功能应得到发展。
  • 对可恢复解析和更好的IDE支持的兴趣。

查看comparsion获取更多详细信息。

use std::convert::TryFrom;

use eyre::bail;
use quote::quote;
use rstml::{
    node::{Node, NodeAttribute, NodeElement, NodeText},
    parse2,
};

// Create HTML `TokenStream`.
let tokens = quote! { <hello world>"hi"</hello> };

// Parse the tokens into a tree of `Node`s.
let nodes = parse2(tokens)?;

// Extract some specific nodes from the tree.
let Node::Element(element) = &nodes[0] else {
    bail!("element")
};
let NodeAttribute::Attribute(attribute) = &element.attributes()[0] else {
    bail!("attribute")
};
let Node::Text(text) = &element.children[0] else {
    bail!("text")
};

// Work with the nodes.
assert_eq!(element.name().to_string(), "hello");
assert_eq!(attribute.key.to_string(), "world");
assert_eq!(text.value_string(), "hi");

由 rstml 驱动

  • html-to-string-macro - rstml 的基本使用示例,它使用 format! 宏将 HTML 转换为字符串。
  • html-node - html-to-string 宏的更强大版本,将 HTML 表示转换为 Rust 类型,这些类型可用于运行时内省。每种类型都具有 DisplayDebug 实现因此可用于格式化打印 HTML 节点。
  • leptos - 网络应用程序框架。在 view/template 宏内部以及用于 hot-reload 功能中使用了 Rstml
  • leptosfmt - 为 leptos 提供的 rustfmt 工具包装器,可以在 view 宏内部格式化 HTML/XML 代码。
  • sauron - 用于构建客户端和/或服务器端网络应用程序的通用网络框架和库。

功能

  • 不具偏见

    每个标签或属性名称都是有效的

    <hello world />
    
  • 文本节点

    <div>"String literal"</div>
    
  • 未引用的文本节点

    未引用的文本支持有一些限制

    • 仅有效的 Rust TokenStream 可以作为未引用的文本(不支持单引号文本,没有未闭合的大括号等)
    • 未引用的文本并不总是可以节省空间。它使用 Span::source_textSpan::join 来检索有关空格的信息,并且并不总是可用。
    • 未引用文本附近的引用文本被视为不同的节点,因此库用户应决定何时保留引号。
    <div> Some string that is valid rust token stream </div>
    
  • 节点名称由破折号、冒号或双冒号分隔

    <tag-name some:attribute-key="value" />
    <tag::name attribute::key="value" />
    
  • 具有保留关键字的节点名称

    <input type="submit" />
    
  • 文档类型、注释和片段

    <!DOCTYPE html>
    <!-- "comment" -->
    <></>
    
  • 大括号块被解析为任意 Rust 代码

    <{ let block = "in node name position"; } />
    <div>{ let block = "in node position"; }</div>
    <div { let block = "in attribute position"; } />
    <div key={ let block = "in attribute value position"; } />
    
  • 属性值可以是任何有效的 syn 表达式,无需要求大括号

    <div key=some::value() />
    
  • 开箱即用的错误报告功能

    error: open tag has no corresponding close tag and is not self-closing
    --> examples/html-to-string-macro/tests/lib.rs:5:24
      |
    5 |     html_to_string! { <div> };
      |                        ^^^
    
  • 能够获取整个节点的范围

    这可以用于改进错误报告,例如。

    error: Invalid element
    --> examples/src/main.rs:14:13
       |
    14 | /             <div>
    15 | |                 "invalid node for some consumer specific reason"
    16 | |             </div>
       | |__________________^
       
    
  • 可恢复解析器

    可以解析包含多个错误的 HTML。因此,库用户会得到一个错误数组,可以报告,并得到已解析的节点树。

     <div hello={world.} /> <!-- dot after world is invalid syn expression -->
      <>
          <div>"1"</x> <!-- incorrect closed tag -->
          <div>"2"</div>
          <div>"3"</div>
          <div {"some-attribute-from-rust-block"}/>
      </>
    

    使用此功能,可以以 IDE 友好的方式编写宏。此宏将更快地工作(因为在不合法的语法中,它稍微更改输出,而不是完全删除它,因此 IDE 可以快速检查差异)。并且更频繁地提供完成(转到定义和其他语义相关功能)。

  • 自定义

    一个 ParserConfig 可用于自定义解析行为,因此如果您对解析有稍微不同的要求并且尚未可自定义,请随时打开一个问题或拉取请求以扩展配置。

    关于自定义的一个亮点是 transform_block 配置,它接收一个闭包,该闭包接收原始块内容作为 ParseStream,并让您可以选择将其转换为 TokenStream。这使得在块中拥有自定义语法成为可能。更多详细信息请参阅 #9

依赖关系

~0.3–0.8MB
~19K SLoC