toolkit for mdBook [mirror of my GitHub repo] docs.tonywu.dev/mdbookkit/
permalinks rust-analyzer mdbook
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor: support mdbook 0.4 and 0.5

Tony Wu 318ffa61 4e63a0f3

+74 -14
-1
Cargo.toml
··· 49 49 50 50 [workspace.metadata.bin] 51 51 mdbook = { version = "0.5.1" } 52 - mdbook-alerts = { version = "0.7.0" }
+2 -2
crates/mdbook-permalinks/src/main.rs
··· 521 521 let Program { command } = clap::Parser::parse(); 522 522 match command { 523 523 None => { 524 - let (ctx, book) = book_from_stdin().context("failed to parse book content")?; 525 - Permalinks.run(&ctx, book)?.to_stdout()?; 524 + let (ctx, book) = book_from_stdin().context("failed to read from mdbook")?; 525 + Permalinks.run(&ctx, book)?.to_stdout(&ctx)?; 526 526 Ok(()) 527 527 } 528 528 Some(Command::Supports { .. }) => Ok(()),
+3 -3
crates/mdbook-rustdoc-links/src/main.rs
··· 204 204 } 205 205 206 206 async fn mdbook() -> Result<()> { 207 - let (context, mut book) = book_from_stdin().context("failed to parse book content")?; 207 + let (ctx, mut book) = book_from_stdin().context("failed to read from mdbook")?; 208 208 209 - let config = config(&context).context("failed to read preprocessor config from book.toml")?; 209 + let config = config(&ctx).context("failed to read preprocessor config from book.toml")?; 210 210 211 211 let client = Environment::new(config) 212 212 .context("failed to initialize `mdbook-rustdoc-link`")? ··· 268 268 } 269 269 }); 270 270 271 - book.to_stdout()?; 271 + book.to_stdout(&ctx)?; 272 272 273 273 env.config.fail_on_warnings.check(status.level())?; 274 274
+69 -8
crates/mdbookkit/src/book.rs
··· 3 3 path::PathBuf, 4 4 }; 5 5 6 - use anyhow::{Context, Result}; 6 + use anyhow::{Context, Result, bail}; 7 7 use mdbook_markdown::pulldown_cmark::Options as MarkdownOptions; 8 8 use mdbook_preprocessor::{ 9 9 PreprocessorContext, ··· 11 11 config::{Config as MDBookConfig, HtmlConfig}, 12 12 }; 13 13 use serde::Deserialize; 14 + use serde_json::{Value, json}; 14 15 use tap::Pipe; 15 16 16 17 use crate::markdown::default_markdown_options; ··· 24 25 /// This uses [`serde_json::from_str`] whereas [`mdbook_preprocessor::parse_input`] uses 25 26 /// [`serde_json::from_reader`], which could be slow. 26 27 pub fn book_from_stdin() -> Result<(PreprocessorContext, Book)> { 27 - Ok(serde_json::from_str(&string_from_stdin()?)?) 28 + let input = string_from_stdin()?; 29 + match serde_json::from_str(&input) { 30 + Ok(book) => Ok(book), 31 + Err(err) => { 32 + if !err.is_data() { 33 + Err(err)? 34 + } else { 35 + patch_mdbook_input(input, err) 36 + } 37 + } 38 + } 28 39 } 29 40 30 41 pub trait BookConfigHelper { ··· 72 83 pub trait BookHelper { 73 84 fn iter_chapters(&self) -> impl Iterator<Item = (&PathBuf, &Chapter)>; 74 85 75 - fn to_stdout(&self) -> Result<()>; 86 + fn to_stdout(self, ctx: &PreprocessorContext) -> Result<()>; 76 87 } 77 88 78 89 impl BookHelper for Book { ··· 88 99 }) 89 100 } 90 101 91 - fn to_stdout(&self) -> Result<()> { 92 - serde_json::to_string(&self) 93 - .context("failed to serialize book") 94 - .and_then(|output| Ok(std::io::stdout().write_all(output.as_bytes())?)) 95 - .context("failed to write book to stdout") 102 + fn to_stdout(self, ctx: &PreprocessorContext) -> Result<()> { 103 + let output = if ctx.mdbook_version.starts_with("0.4.") { 104 + patch_mdbook_output_0_4(self)? 105 + } else { 106 + serde_json::to_string(&self).context("failed to serialize mdbook output")? 107 + }; 108 + std::io::stdout() 109 + .write_all(output.as_bytes()) 110 + .context("failed to write mdbook output") 111 + } 112 + } 113 + 114 + fn patch_mdbook_input( 115 + input: String, 116 + error: serde_json::Error, 117 + ) -> Result<(PreprocessorContext, Book)> { 118 + let (mut ctx, mut book): (Value, Value) = serde_json::from_str(&input)?; 119 + 120 + match ctx.get("mdbook_version") { 121 + Some(Value::String(version)) => { 122 + if !version.starts_with("0.4.") && !version.starts_with("0.5.") { 123 + bail!("unsupported mdbook version {version}; supported versions are 0.4, 0.5") 124 + } 125 + } 126 + _ => return Err(error)?, 127 + } 128 + 129 + // 0.4 -> 0.5 130 + if let Some(conf) = ctx 131 + .pointer_mut("/config/book") 132 + .and_then(|val| val.as_object_mut()) 133 + { 134 + conf.remove("multilingual"); 96 135 } 136 + 137 + // 0.4 -> 0.5 138 + if let Some(book) = book.as_object_mut() 139 + && let Some(sections) = book.remove("sections") 140 + { 141 + book.insert("items".into(), sections); 142 + } 143 + 144 + Ok(serde_json::from_value(json!([ctx, book]))?) 145 + } 146 + 147 + fn patch_mdbook_output_0_4(book: Book) -> Result<String> { 148 + let mut book = serde_json::to_value(book)?; 149 + 150 + if let Some(book) = book.as_object_mut() { 151 + if let Some(sections) = book.remove("items") { 152 + book.insert("sections".into(), sections); 153 + } 154 + book.insert("__non_exhaustive".into(), Value::Null); 155 + } 156 + 157 + Ok(serde_json::to_string(&book)?) 97 158 }