yggdrasil/api/posts/
roundtrip.rs1use crate::api::error::ApiError;
4use leptos::prelude::*;
5
6#[cfg(feature = "server")]
7use super::helpers::get_current_admin_user;
8#[cfg(feature = "server")]
9use crate::api::error::AppError;
10
11#[server(CheckMarkdownRoundtrip, endpoint = "check_markdown_roundtrip", input = leptos::server_fn::codec::Json)]
13pub async fn check_markdown_roundtrip(
14 original: String,
15 roundtrip: String,
16) -> Result<bool, ApiError> {
17 let _user = get_current_admin_user().await?;
18 #[cfg(feature = "server")]
19 {
20 let same = tokio::task::spawn_blocking(move || renders_identically(&original, &roundtrip))
21 .await
22 .map_err(|_| AppError::Internal("Markdown 渲染任务失败"))?;
23 Ok(same)
24 }
25 #[cfg(not(feature = "server"))]
26 {
27 Ok(false)
28 }
29}
30
31#[cfg(feature = "server")]
32fn renders_identically(original: &str, roundtrip: &str) -> bool {
33 use crate::api::markdown::render_markdown_enhanced as render;
34 render(original).html == render(roundtrip).html
35}
36
37#[cfg(all(test, feature = "server"))]
38mod tests {
39 use super::renders_identically;
40
41 #[test]
42 fn alert_marker_escaped_by_editor_is_lossy() {
43 assert!(!renders_identically("> [!NOTE]\n> x", "> \\[!NOTE\\]\n> x"));
44 }
45
46 #[test]
47 fn table_column_padding_is_not_lossy() {
48 assert!(renders_identically(
49 "| a | b |\n| --- | --- |\n| 1 | 2 |",
50 "| a | b |\n| --- | --- |\n| 1 | 2 |"
51 ));
52 }
53
54 #[test]
55 fn escaped_intraword_delimiters_are_not_lossy() {
56 assert!(renders_identically("H~2~O 与 x^2^", "H\\~2\\~O 与 x^2\\^"));
57 }
58}