summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Milligan <tom.milligan@uipath.com>2023-07-22 11:01:27 +0100
committerTom Milligan <tom.milligan@uipath.com>2023-07-22 11:32:40 +0100
commitde539cd0fdb8fcbef3b0ec81b3cf333853ae8f60 (patch)
treeca7bc2aa65397d076f7c523318f1437f8a52bccd
parent4842daea1c0f1624344fe55c5d906ccd72345203 (diff)
internal: split up lib.rs
-rw-r--r--src/book_config.rs119
-rw-r--r--src/lib.rs1264
-rw-r--r--src/parse.rs86
-rw-r--r--src/types.rs6
4 files changed, 208 insertions, 1267 deletions
diff --git a/src/book_config.rs b/src/book_config.rs
new file mode 100644
index 0000000..2ec2263
--- /dev/null
+++ b/src/book_config.rs
@@ -0,0 +1,119 @@
+use anyhow::{anyhow, Context, Result};
+use mdbook::preprocess::PreprocessorContext;
+use std::str::FromStr;
+
+use crate::types::AdmonitionDefaults;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub(crate) enum RenderMode {
+ Preserve,
+ Strip,
+ Html,
+}
+
+impl FromStr for RenderMode {
+ type Err = ();
+
+ fn from_str(string: &str) -> Result<Self, ()> {
+ match string {
+ "preserve" => Ok(Self::Preserve),
+ "strip" => Ok(Self::Strip),
+ "html" => Ok(Self::Html),
+ _ => Err(()),
+ }
+ }
+}
+
+impl RenderMode {
+ pub(crate) fn from_context(
+ context: &PreprocessorContext,
+ renderer: &str,
+ default: Self,
+ ) -> Result<Self> {
+ let key = format!("preprocessor.admonish.renderer.{renderer}.render_mode");
+ let value = context.config.get(&key);
+
+ // If no key set, return default
+ let value = if let Some(value) = value {
+ value
+ } else {
+ return Ok(default);
+ };
+
+ // Othersise, parse value
+ let value = value
+ .as_str()
+ .with_context(|| format!("Invalid value for {key}: {value:?}"))?;
+
+ RenderMode::from_str(value).map_err(|_| anyhow!("Invalid value for {key}: {value}"))
+ }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub(crate) enum OnFailure {
+ Bail,
+ Continue,
+}
+
+impl Default for OnFailure {
+ fn default() -> Self {
+ Self::Continue
+ }
+}
+
+impl FromStr for OnFailure {
+ type Err = ();
+
+ fn from_str(string: &str) -> Result<Self, ()> {
+ match string {
+ "bail" => Ok(Self::Bail),
+ "continue" => Ok(Self::Continue),
+ _ => Ok(Self::Continue),
+ }
+ }
+}
+
+impl OnFailure {
+ pub(crate) fn from_context(context: &PreprocessorContext) -> Self {
+ context
+ .config
+ .get("preprocessor.admonish.on_failure")
+ .and_then(|value| value.as_str())
+ .map(|value| OnFailure::from_str(value).unwrap_or_default())
+ .unwrap_or_default()
+ }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub(crate) enum Renderer {
+ Html,
+ Test,
+}
+
+impl FromStr for Renderer {
+ type Err = ();
+
+ fn from_str(string: &str) -> Result<Self, ()> {
+ match string {
+ "html" => Ok(Self::Html),
+ "test" => Ok(Self::Test),
+ _ => Err(()),
+ }
+ }
+}
+
+impl AdmonitionDefaults {
+ pub(crate) fn from_context(ctx: &PreprocessorContext) -> Result<Self> {
+ const KEY: &str = "preprocessor.admonish.default";
+ let table = ctx.config.get(KEY);
+
+ Ok(if let Some(table) = table {
+ table
+ .to_owned()
+ .try_into()
+ .with_context(|| "{KEY} could not be parsed from book.toml")?
+ } else {
+ Default::default()
+ })
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 063c9b1..d26be04 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,1264 +1,10 @@
-use anyhow::{anyhow, Context, Result};
-use mdbook::{
- book::{Book, BookItem},
- errors::Result as MdbookResult,
- preprocess::{Preprocessor, PreprocessorContext},
- utils::unique_id_from_content,
-};
-use pulldown_cmark::{CodeBlockKind::*, Event, Options, Parser, Tag};
-use std::{borrow::Cow, str::FromStr};
-
+mod book_config;
mod config;
+mod markdown;
mod parse;
+mod preprocessor;
+mod render;
mod resolve;
mod types;
-use crate::{
- resolve::AdmonitionMeta,
- types::{AdmonitionDefaults, Directive},
-};
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-enum RenderTextMode {
- Strip,
- Html,
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-enum RenderMode {
- Preserve,
- Strip,
- Html,
-}
-
-impl FromStr for RenderMode {
- type Err = ();
-
- fn from_str(string: &str) -> Result<Self, ()> {
- match string {
- "preserve" => Ok(Self::Preserve),
- "strip" => Ok(Self::Strip),
- _ => Err(()),
- }
- }
-}
-
-fn test_render_mode(context: &PreprocessorContext) -> Result<RenderMode> {
- const TOML_KEY: &str = "preprocessor.admonish.renderer.test.render_mode";
- let value = context.config.get(TOML_KEY);
-
- // If no key set, return default
- let value = if let Some(value) = value {
- value
- } else {
- return Ok(RenderMode::Preserve);
- };
-
- // Othersise, parse value
- let value = value
- .as_str()
- .with_context(|| format!("Invalid value for {TOML_KEY}: {value:?}"))?;
-
- RenderMode::from_str(value).map_err(|_| anyhow!("Invalid value for {TOML_KEY}: {value}"))
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-enum OnFailure {
- Bail,
- Continue,
-}
-
-impl Default for OnFailure {
- fn default() -> Self {
- Self::Continue
- }
-}
-
-impl FromStr for OnFailure {
- type Err = ();
-
- fn from_str(string: &str) -> Result<Self, ()> {
- match string {
- "bail" => Ok(Self::Bail),
- "continue" => Ok(Self::Continue),
- _ => Ok(Self::Continue),
- }
- }
-}
-
-impl OnFailure {
- fn from_context(context: &PreprocessorContext) -> Self {
- context
- .config
- .get("preprocessor.admonish.on_failure")
- .and_then(|value| value.as_str())
- .map(|value| OnFailure::from_str(value).unwrap_or_default())
- .unwrap_or_default()
- }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-enum Renderer {
- Html,
- Test,
-}
-
-impl FromStr for Renderer {
- type Err = ();
-
- fn from_str(string: &str) -> Result<Self, ()> {
- match string {
- "html" => Ok(Self::Html),
- "test" => Ok(Self::Test),
- _ => Err(()),
- }
- }
-}
-
-pub struct Admonish;
-
-impl Preprocessor for Admonish {
- fn name(&self) -> &str {
- "admonish"
- }
-
- fn run(&self, ctx: &PreprocessorContext, mut book: Book) -> MdbookResult<Book> {
- ensure_compatible_assets_version(ctx)?;
- let on_failure = OnFailure::from_context(ctx);
- let admonition_defaults = load_defaults(ctx)?;
- let renderer = Renderer::from_str(&ctx.renderer).map_err(|_| {
- anyhow!(
- "mdbook-admonish called with unsupported renderer '{}",
- &ctx.renderer
- )
- })?;
- let render_mode = match renderer {
- Renderer::Html => RenderMode::Html,
- Renderer::Test => test_render_mode(ctx)?,
- };
- let render_text_mode = match render_mode {
- RenderMode::Preserve => return Ok(book),
- RenderMode::Html => RenderTextMode::Html,
- RenderMode::Strip => RenderTextMode::Strip,
- };
-
- let mut res = None;
- book.for_each_mut(|item: &mut BookItem| {
- if let Some(Err(_)) = res {
- return;
- }
-
- if let BookItem::Chapter(ref mut chapter) = *item {
- res = Some(
- preprocess(
- &chapter.content,
- on_failure,
- &admonition_defaults,
- render_text_mode,
- )
- .map(|md| {
- chapter.content = md;
- }),
- );
- }
- });
-
- res.unwrap_or(Ok(())).map(|_| book)
- }
-
- fn supports_renderer(&self, renderer: &str) -> bool {
- Renderer::from_str(renderer).is_ok()
- }
-}
-
-fn ensure_compatible_assets_version(ctx: &PreprocessorContext) -> Result<()> {
- use semver::{Version, VersionReq};
-
- const REQUIRES_ASSETS_VERSION: &str = std::include_str!("./REQUIRED_ASSETS_VERSION");
- let requirement = VersionReq::parse(REQUIRES_ASSETS_VERSION.trim()).unwrap();
-
- const USER_ACTION: &str = "Please run `mdbook-admonish install` to update installed assets.";
- const DOCS_REFERENCE: &str = "For more information, see: https://github.com/tommilligan/mdbook-admonish#semantic-versioning";
-
- let version = match ctx
- .config
- .get("preprocessor.admonish.assets_version")
- .and_then(|value| value.as_str())
- {
- Some(version) => version,
- None => {
- return Err(anyhow!(
- r#"ERROR:
- Incompatible assets installed: required mdbook-admonish assets version '{requirement}', but did not find a version.
- {USER_ACTION}
- {DOCS_REFERENCE}"#
- ))
- }
- };
-
- let version = Version::parse(version).unwrap();
-
- if !requirement.matches(&version) {
- return Err(anyhow!(
- r#"ERROR:
- Incompatible assets installed: required mdbook-admonish assets version '{requirement}', but found '{version}'.
- {USER_ACTION}
- {DOCS_REFERENCE}"#
- ));
- };
- Ok(())
-}
-
-impl Directive {
- fn classname(&self) -> &'static str {
- match self {
- Directive::Note => "note",
- Directive::Abstract => "abstract",
- Directive::Info => "info",
- Directive::Tip => "tip",
- Directive::Success => "success",
- Directive::Question => "question",
- Directive::Warning => "warning",
- Directive::Failure => "failure",
- Directive::Danger => "danger",
- Directive::Bug => "bug",
- Directive::Example => "example",
- Directive::Quote => "quote",
- }
- }
-}
-
-#[derive(Debug, PartialEq)]
-struct Admonition<'a> {
- directive: Directive,
- title: String,
- content: Cow<'a, str>,
- additional_classnames: Vec<String>,
- collapsible: bool,
-}
-
-impl<'a> Admonition<'a> {
- pub fn new(info: AdmonitionMeta, content: &'a str) -> Self {
- let AdmonitionMeta {
- directive,
- title,
- additional_classnames,
- collapsible,
- } = info;
- Self {
- directive,
- title,
- content: Cow::Borrowed(content),
- additional_classnames,
- collapsible,
- }
- }
-
- fn html(&self, anchor_id: &str) -> String {
- let mut additional_class = Cow::Borrowed(self.directive.classname());
- let title = &self.title;
- let content = &self.content;
-
- let title_block = if self.collapsible { "summary" } else { "div" };
-
- let title_html = if !title.is_empty() {
- Cow::Owned(format!(
- r##"<{title_block} class="admonition-title">
-
-{title}
-
-<a class="admonition-anchor-link" href="#{ANCHOR_ID_PREFIX}-{anchor_id}"></a>
-</{title_block}>
-"##
- ))
- } else {
- Cow::Borrowed("")
- };
-
- if !self.additional_classnames.is_empty() {
- let mut buffer = additional_class.into_owned();
- for additional_classname in &self.additional_classnames {
- buffer.push(' ');
- buffer.push_str(additional_classname);
- }
-
- additional_class = Cow::Owned(buffer);
- }
-
- let admonition_block = if self.collapsible { "details" } else { "div" };
- // Notes on the HTML template:
- // - the additional whitespace around the content are deliberate
- // In line with the commonmark spec, this allows the inner content to be
- // rendered as markdown paragraphs.
- format!(
- r#"
-<{admonition_block} id="{ANCHOR_ID_PREFIX}-{anchor_id}" class="admonition {additional_class}">
-{title_html}<div>
-
-{content}
-
-</div>
-</{admonition_block}>"#,
- )
- }
-
- /// Strips all admonish syntax, leaving the plain content of the block.
- fn strip(&self) -> String {
- // Add in newlines to preserve line numbering for test output
- // These replace the code fences we stripped out
- format!("\n{}\n", self.content)
- }
-}
-
-const ANCHOR_ID_PREFIX: &str = "admonition";
-const ANCHOR_ID_DEFAULT: &str = "default";
-
-/// Given the content in the span of the code block, and the info string,
-/// return `Some(Admonition)` if the code block is an admonition.
-///
-/// If there is an error parsing the admonition, either:
-///
-/// - Display a UI error message output in the book.
-/// - If configured, break the build.
-///
-/// If the code block is not an admonition, return `None`.
-fn parse_admonition<'a>(
- info_string: &'a str,
- admonition_defaults: &'a AdmonitionDefaults,
- content: &'a str,
- on_failure: OnFailure,
-) -> Option<MdbookResult<Admonition<'a>>> {
- // We need to know fence details anyway for error messages
- let extracted = parse::extract_admonish_body(content);
-
- let info = AdmonitionMeta::from_info_string(info_string, admonition_defaults)?;
- let info = match info {
- Ok(info) => info,
- // FIXME return error messages to break build if configured
- // Err(message) => return Some(Err(content)),
- Err(message) => {
- // Construct a fence capable of enclosing whatever we wrote for the
- // actual input block
- let fence = extracted.fence;
- let enclosing_fence: String = std::iter::repeat(fence.character)
- .take(fence.length + 1)
- .collect();
- return Some(match on_failure {
- OnFailure::Continue => Ok(Admonition {
- directive: Directive::Bug,
- title: "Error rendering admonishment".to_owned(),
- additional_classnames: Vec::new(),
- collapsible: false,
- content: Cow::Owned(format!(
- r#"Failed with:
-
-```log
-{message}
-```
-
-Original markdown input:
-
-{enclosing_fence}markdown
-{content}
-{enclosing_fence}
-"#
- )),
- }),
- OnFailure::Bail => Err(anyhow!("Error processing admonition, bailing:\n{content}")),
- });
- }
- };
-
- Some(Ok(Admonition::new(info, extracted.body)))
-}
-
-fn load_defaults(ctx: &PreprocessorContext) -> Result<AdmonitionDefaults> {
- let table = ctx.config.get("preprocessor.admonish.default");
-
- Ok(if let Some(table) = table {
- table
- .to_owned()
- .try_into()
- .context("preprocessor.admonish.default could not be parsed from book.toml")?
- } else {
- Default::default()
- })
-}
-
-fn preprocess(
- content: &str,
- on_failure: OnFailure,
- admonition_defaults: &AdmonitionDefaults,
- render_text_mode: RenderTextMode,
-) -> MdbookResult<String> {
- let mut id_counter = Default::default();
- let mut opts = Options::empty();
- opts.insert(Options::ENABLE_TABLES);
- opts.insert(Options::ENABLE_FOOTNOTES);
- opts.insert(Options::ENABLE_STRIKETHROUGH);
- opts.insert(Options::ENABLE_TASKLISTS);
-
- let mut admonish_blocks = vec![];
-
- let events = Parser::new_ext(content, opts);
-
- for (event, span) in events.into_offset_iter() {
- if let Event::Start(Tag::CodeBlock(Fenced(info_string))) = event.clone() {
- let span_content = &content[span.start..span.end];
-
- let admonition = match parse_admonition(
- info_string.as_ref(),
- &admonition_defaults,
- span_content,
- on_failure,
- ) {
- Some(admonition) => admonition,
- None => continue,
- };
-
- let admonition = admonition?;
-
- // Once we've identitified admonition blocks, handle them differently
- // depending on our render mode
- let new_content = match render_text_mode {
- RenderTextMode::Html => {
- let anchor_id = unique_id_from_content(
- if !admonition.title.is_empty() {
- &admonition.title
- } else {
- ANCHOR_ID_DEFAULT
- },
- &mut id_counter,
- );
- admonition.html(&anchor_id)
- }
- RenderTextMode::Strip => admonition.strip(),
- };
-
- admonish_blocks.push((span, new_content));
- }
- }
-
- let mut content = content.to_string();
- for (span, block) in admonish_blocks.iter().rev() {
- let pre_content = &content[..span.start];
- let post_content = &content[span.end..];
- content = format!("{}{}{}", pre_content, block, post_content);
- }
-
- Ok(content)
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
- use pretty_assertions::assert_eq;
- use serde_json::{json, Value};
-
- fn mock_book(content: &str) -> Book {
- serde_json::from_value(json!({
- "sections": [
- {
- "Chapter": {
- "name": "Chapter 1",
- "content": content,
- "number": [1],
- "sub_items": [],
- "path": "chapter_1.md",
- "source_path": "chapter_1.md",
- "parent_names": []
- }
- }
- ],
- "__non_exhaustive": null
- }))
- .unwrap()
- }
-
- fn mock_context(admonish: &Value, renderer: &str) -> PreprocessorContext {
- let value = json!({
- "root": "/path/to/book",
- "config": {
- "book": {
- "authors": ["AUTHOR"],
- "language": "en",
- "multilingual": false,
- "src": "src",
- "title": "TITLE"
- },
- "preprocessor": {
- "admonish": admonish,
- }
- },
- "renderer": renderer,
- "mdbook_version": "0.4.21"
- });
-
- serde_json::from_value(value).unwrap()
- }
-
- fn prep(content: &str) -> String {
- preprocess(
- content,
- OnFailure::Continue,
- &AdmonitionDefaults::default(),
- RenderTextMode::Html,
- )
- .unwrap()
- }
-
- #[test]
- fn adds_admonish() {
- let content = r#"# Chapter
-```admonish
-A simple admonition.
-```
-Text
-"#;
-
- let expected = r##"# Chapter
-
-<div id="admonition-note" class="admonition note">
-<div class="admonition-title">
-
-Note
-
-<a class="admonition-anchor-link" href="#admonition-note"></a>
-</div>
-<div>
-
-A simple admonition.
-
-</div>
-</div>
-Text
-"##;
-
- assert_eq!(expected, prep(content));
- }
-
- #[test]
- fn adds_admonish_longer_code_fence() {
- let content = r#"# Chapter
-````admonish
-```json
-{}
-```
-````
-Text
-"#;
-
- let expected = r##"# Chapter
-
-<div id="admonition-note" class="admonition note">
-<div class="admonition-title">
-
-Note
-
-<a class="admonition-anchor-link" href="#admonition-note"></a>
-</div>
-<div>
-
-```json
-{}
-```
-
-</div>
-</div>
-Text
-"##;
-
- assert_eq!(expected, prep(content));
- }
-
- #[test]
- fn adds_admonish_directive() {
- let content = r#"# Chapter
-```admonish warning
-A simple admonition.
-```
-Text
-"#;
-
- let expected = r##"# Chapter
-
-<div id="admonition-warning" class="admonition warning">
-<div class="admonition-title">
-
-Warning
-
-<a class="admonition-anchor-link" href="#admonition-warning"></a>
-</div>
-<div>
-
-A simple admonition.
-
-</div>
-</div>
-Text
-"##;
-
- assert_eq!(expected, prep(content));
- }
-
- #[test]
- fn adds_admonish_directive_alternate() {
- let content = r#"# Chapter
-```admonish caution
-A warning with alternate title.
-```
-Text
-"#;
-
- let expected = r##"# Chapter
-
-<div id="admonition-caution" class="admonition warning">
-<div class="admonition-title">
-
-Caution
-
-<a class="admonition-anchor-link" href="#admonition-caution"></a>
-</div>
-<div>
-
-A warning with alternate title.
-
-</div>
-</div>
-Text
-"##;
-
- assert_eq!(expected, prep(content));
- }
-
- #[test]
- fn adds_admonish_directive_title() {
- let content = r#"# Chapter
-```admonish warning "Read **this**!"
-A simple admonition.
-```
-Text
-"#;
-
- let expected = r##"# Chapter
-
-<div id="admonition-read-this" class="admonition warning">
-<div class="admonition-title">
-
-Read **this**!
-
-<a class="admonition-anchor-link" href="#admonition-read-this"></a>
-</div>
-<div>
-
-A simple admonition.
-
-</div>
-</div>
-Text
-"##;
-
- assert_eq!(expected, prep(content));
- }
-
- #[test]
- fn leaves_tables_untouched() {
- // Regression test.
- // Previously we forgot to enable the same markdwon extensions as mdbook itself.
-
- let content = r#"# Heading
-| Head 1 | Head 2 |
-|--------|--------|
-| Row 1 | Row 2 |
-"#;
-
- let expected = r#"# Heading
-| Head 1 | Head 2 |
-|--------|--------|
-| Row 1 | Row 2 |
-"#;
-
- assert_eq!(expected, prep(content));
- }
-
- #[test]
- fn leaves_html_untouched() {
- // Regression test.
- // Don't remove important newlines for syntax nested inside HTML
-
- let content = r#"# Heading
-<del>
-*foo*
-</del>
-"#;
-
- let expected = r#"# Heading
-<del>
-*foo*
-</del>
-"#;
-
- assert_eq!(expected, prep(content));
- }
-
- #[test]
- fn html_in_list() {
- // Regression test.
- // Don't remove important newlines for syntax nested inside HTML
-
- let content = r#"# Heading
-1. paragraph 1
- ```
- code 1
- ```
-2. paragraph 2
-"#;
-
- let expected = r#"# Heading
-1. paragraph 1
- ```
- code 1
- ```
-2. paragraph 2
-"#;
-
- assert_eq!(expected, prep(content));
- }
-
- #[test]
- fn info_string_that_changes_length_when_parsed() {
- let content = r#"
-```admonish note "And \\"<i>in</i>\\" the title"
-With <b>html</b> styling.
-```
-hello
-"#;
-
- let expected = r##"
-
-<div id="admonition-and-in-the-title" class="admonition note">
-<div class="admonition-title">
-
-And "<i>in</i>" the title
-
-<a class="admonition-anchor-link" href="#admonition-and-in-the-title"></a>
-</div>
-<div>
-
-With <b>html</b> styling.
-
-</div>
-</div>
-hello
-"##;
-
- assert_eq!(expected, prep(content));
- }
-
- #[test]
- fn info_string_ending_in_symbol() {
- let content = r#"
-```admonish warning "Trademarkā„¢"
-Should be respected
-```
-hello
-"#;
-
- let expected = r##"
-
-<div id="admonition-trademark" class="admonition warning">
-<div class="admonition-title">
-
-Trademarkā„¢
-
-<a class="admonition-anchor-link" href="#admonition-trademark"></a>
-</div>
-<div>
-
-Should be respected
-
-</div>
-</div>
-hello
-"##;
-
- assert_eq!(expected, prep(content));
- }
-
- #[test]
- fn block_with_additional_classname() {
- let content = r#"
-```admonish tip.my-style.other-style
-Will have bonus classnames
-```
-"#;
-
- let expected = r##"
-
-<div id="admonition-tip" class="admonition tip my-style other-style">
-<div class="admonition-title">
-
-Tip
-
-<a class="admonition-anchor-link" href="#admonition-tip"></a>
-</div>
-<div>
-
-Will have bonus classnames
-
-</div>
-</div>
-"##;
-
- assert_eq!(expected, prep(content));
- }
-
- #[test]
- fn block_with_additional_classname_and_title() {
- let content = r#"
-```admonish tip.my-style.other-style "Developers don't want you to know this one weird tip!"
-Will have bonus classnames
-```
-"#;
-
- let expected = r##"
-
-<div id="admonition-developers-dont-want-you-to-know-this-one-weird-tip" class="admonition tip my-style other-style">
-<div class="admonition-title">
-
-Developers don't want you to know this one weird tip!
-
-<a class="admonition-anchor-link" href="#admonition-developers-dont-want-you-to-know-this-one-weird-tip"></a>
-</div>
-<div>
-
-Will have bonus classnames
-
-</div>
-</div>
-"##;
-
- assert_eq!(expected, prep(content));
- }
-
- #[test]
- fn block_with_empty_additional_classnames_title_content() {
- let content = r#"
-```admonish .... ""
-```
-"#;
-
- let expected = r##"
-
-<div id="admonition-default" class="admonition note">
-<div>
-
-
-
-</div>
-</div>
-"##;
-
- assert_eq!(expected, prep(content));
- }
-
- #[test]
- fn unique_ids_same_title() {
- let content = r#"
-```admonish note "My Note"
-Content zero.
-```
-
-```admonish note "My Note"
-Content one.
-```
-"#;
-
- let expected = r##"
-
-<div id="admonition-my-note" class="admonition note">
-<div class="admonition-title">
-
-My Note
-
-<a class="admonition-anchor-link" href="#admonition-my-note"></a>
-</div>
-<div>
-
-Content zero.
-
-</div>
-</div>
-
-
-<div id="admonition-my-note-1" class="admonition note">
-<div class="admonition-title">
-
-My Note
-
-<a class="admonition-anchor-link" href="#admonition-my-note-1"></a>
-</div>
-<div>
-
-Content one.
-
-</div>
-</div>
-"##;
-
- assert_eq!(expected, prep(content));
- }
-
- #[test]
- fn v2_config_works() {
- let content = r#"
-```admonish tip class="my other-style" title="Article Heading"
-Bonus content!
-```
-"#;
-
- let expected = r##"
-
-<div id="admonition-article-heading" class="admonition tip my other-style">
-<div class="admonition-title">
-
-Article Heading
-
-<a class="admonition-anchor-link" href="#admonition-article-heading"></a>
-</div>
-<div>
-
-Bonus content!
-
-</div>
-</div>
-"##;
-
- assert_eq!(expected, prep(content));
- }
-
- #[test]
- fn continue_on_error_output() {
- let content = r#"
-```admonish title="
-Bonus content!
-```
-"#;
-
- let expected = r##"
-
-<div id="admonition-error-rendering-admonishment" class="admonition bug">
-<div class="admonition-title">
-
-Error rendering admonishment
-
-<a class="admonition-anchor-link" href="#admonition-error-rendering-admonishment"></a>
-</div>
-<div>
-
-Failed with:
-
-```log
-TOML parsing error: TOML parse error at line 1, column 8
- |
-1 | title="
- | ^
-invalid basic string
-
-```
-
-Original markdown input:
-
-````markdown
-```admonish title="
-Bonus content!
-```
-````
-
-
-</div>
-</div>
-"##;
-
- assert_eq!(expected, prep(content));
- }
-
- #[test]
- fn bail_on_error_output() {
- let content = r#"
-```admonish title="
-Bonus content!
-```
-"#;
- assert_eq!(
- preprocess(
- content,
- OnFailure::Bail,
- &AdmonitionDefaults::default(),
- RenderTextMode::Html
- )
- .unwrap_err()
- .to_string(),
- r#"Error processing admonition, bailing:
-```admonish title="
-Bonus content!
-```"#
- .to_owned()
- )
- }
-
- #[test]
- fn run_html() {
- let content = r#"
-````admonish title="Title"
-```rust
-let x = 10;
-x = 20;
-```
-````
-"#;
- let expected_content = r##"
-
-<div id="admonition-title" class="admonition note">
-<div class="admonition-title">
-
-Title
-
-<a class="admonition-anchor-link" href="#admonition-title"></a>
-</div>
-<div>
-
-```rust
-let x = 10;
-x = 20;
-```