//! Public API of `markdown-rs`. //! //! This module exposes primarily [`to_html()`][]. //! It also exposes [`to_html_with_options()`][] and [`to_mdast()`][]. //! //! * [`to_html()`][] //! — safe way to transform (untrusted?) markdown into HTML //! * [`to_html_with_options()`][] //! — like `to_html` but lets you configure how markdown is turned into //! HTML, such as allowing dangerous HTML or turning on/off different //! constructs (GFM, MDX, and the like) //! * [`to_mdast()`][] //! — turn markdown into a syntax tree #![no_std] #![deny(clippy::pedantic)] #![allow(clippy::doc_link_with_quotes)] #![allow(clippy::too_many_lines)] // Would be nice to use `logo-chromatic`, but that looks horrible on Safari at relatively small sizes currently. 😢 #![doc( html_logo_url = "https://raw.githubusercontent.com/wooorm/markdown-rs/8924580/media/logo-monochromatic.svg?sanitize=true" )] extern crate alloc; mod construct; mod event; pub mod mdast; // To do: externalize? mod parser; mod resolve; mod state; mod subtokenize; mod to_html; mod to_mdast; mod tokenizer; pub mod unist; // To do: externalize. mod util; use alloc::{boxed::Box, fmt, string::String}; use mdast::Node; use parser::parse; #[doc(hidden)] // Do not use: exported for quick prototyping, will be removed. pub use util::identifier::{id_cont, id_start}; #[doc(hidden)] // Do not use: exported for quick prototyping, will be removed. pub use util::sanitize_uri::sanitize; #[doc(hidden)] // Do not use: exported for quick prototyping, will be removed. pub use util::location::Location; /// Type of line endings in markdown. /// /// Particularly when working with Windows, you might want to use /// `LineEnding::CarriageReturnLineFeed`. /// /// ## Examples /// /// ``` /// use markdown::LineEnding; /// # fn main() { /// /// // Use a CR + LF combination: /// let crlf = LineEnding::CarriageReturnLineFeed; /// # } /// ``` #[derive(Clone, Debug, Default, Eq, PartialEq)] pub enum LineEnding { /// Both a carriage return (`\r`) and a line feed (`\n`). /// /// ## Example /// /// ```markdown /// a␍␊ /// b /// ``` CarriageReturnLineFeed, /// Sole carriage return (`\r`). /// /// ## Example /// /// ```markdown /// a␍ /// b /// ``` CarriageReturn, /// Sole line feed (`\n`). /// /// ## Example /// /// ```markdown /// a␊ /// b /// ``` #[default] LineFeed, } impl LineEnding { /// Turn the line ending into a [str]. fn as_str(&self) -> &str { match self { LineEnding::CarriageReturnLineFeed => "\r\n", LineEnding::CarriageReturn => "\r", LineEnding::LineFeed => "\n", } } /// Turn a string into a line ending. /// /// ## Panics /// /// Panics if `code` is not `\r\n`, `\r`, or `\n`. fn from_str(str: &str) -> LineEnding { match str { "\r\n" => LineEnding::CarriageReturnLineFeed, "\r" => LineEnding::CarriageReturn, "\n" => LineEnding::LineFeed, _ => unreachable!("invalid str"), } } } /// Signal used as feedback when parsing MDX ESM/expressions. #[derive(Clone, Debug)] pub enum MdxSignal { /// A syntax error. /// /// `markdown-rs` will crash with error message `String`, and convert the /// `usize` (byte offset into `&str` passed to `MdxExpressionParse` or /// `MdxEsmParse`) to where it happened in the whole document. /// /// ## Examples /// /// ```rust ignore /// MdxSignal::Error("Unexpected `\"`, expected identifier".into(), 1) /// ``` Error(String, usize), /// An error at the end of the (partial?) expression. /// /// `markdown-rs` will either crash with error message `String` if it /// doesn’t have any more text, or it will try again later when more text /// is available. /// /// ## Examples /// /// ```rust ignore /// MdxSignal::Eof("Unexpected end of file in string literal".into()) /// ``` Eof(String), /// Done, successfully. /// /// `markdown-rs` knows that this is the end of a valid expression/esm and /// continues with markdown. /// /// ## Examples /// /// ```rust ignore /// MdxSignal::Ok /// ``` Ok, } /// Signature of a function that parses MDX ESM. /// /// Can be passed as `mdx_esm_parse` in [`ParseOptions`][] to support /// ESM according to a certain grammar (typically, a programming language). pub type MdxEsmParse = dyn Fn(&str) -> MdxSignal; /// Expression kind. #[derive(Clone, Debug)] pub enum MdxExpressionKind { /// Kind of expressions in prose. /// /// ```mdx /// > | # {Math.PI} /// ^^^^^^^^^ /// | /// > | {Math.PI} /// ^^^^^^^^^ /// ``` Expression, /// Kind of expressions as attributes. /// /// ```mdx /// > | /// ^^^^^^ /// ``` AttributeExpression, /// Kind of expressions as attribute values. /// /// ```mdx /// > | /// ^^^ /// ``` AttributeValueExpression, } /// Signature of a function that parses MDX expressions. /// /// Can be passed as `mdx_expression_parse` in [`ParseOptions`][] to support /// expressions according to a certain grammar (typically, a programming /// language). pub type MdxExpressionParse = dyn Fn(&str, &MdxExpressionKind) -> MdxSignal; /// Control which constructs are enabled. /// /// Not all constructs can be configured. /// Notably, blank lines and paragraphs cannot be turned off. /// /// ## Examples /// /// ``` /// use markdown::Constructs; /// # fn main() { /// /// // Use the default trait to get `CommonMark` constructs: /// let commonmark = Constructs::default(); /// /// // To turn on all of GFM, use the `gfm` method: /// let gfm = Constructs::gfm(); /// /// // Or, mix and match: /// let custom = Constructs { /// math_flow: true, /// math_text: true, /// ..Constructs::gfm() /// }; /// # } /// ``` #[allow(clippy::struct_excessive_bools)] #[derive(Clone, Debug, Eq, PartialEq)] pub struct Constructs { /// Attention. /// /// ```markdown /// > | a *b* c **d**. /// ^^^ ^^^^^ /// ``` pub attention: bool, /// Autolink. /// /// ```markdown /// > | a b . /// ^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ /// ``` pub autolink: bool, /// Block quote. /// /// ```markdown /// > | > a /// ^^^ /// ``` pub block_quote: bool, /// Character escape. /// /// ```markdown /// > | a \* b /// ^^ /// ``` pub character_escape: bool, /// Character reference. /// /// ```markdown /// > | a & b /// ^^^^^ /// ``` pub character_reference: bool, /// Code (indented). /// /// ```markdown /// > | a /// ^^^^^ /// ``` pub code_indented: bool, /// Code (fenced). /// /// ```markdown /// > | ~~~js /// ^^^^^ /// > | console.log(1) /// ^^^^^^^^^^^^^^ /// > | ~~~ /// ^^^ /// ``` pub code_fenced: bool, /// Code (text). /// /// ```markdown /// > | a `b` c /// ^^^ /// ``` pub code_text: bool, /// Definition. /// /// ```markdown /// > | [a]: b "c" /// ^^^^^^^^^^ /// ``` pub definition: bool, /// Frontmatter. /// /// ````markdown /// > | --- /// ^^^ /// > | title: Neptune /// ^^^^^^^^^^^^^^ /// > | --- /// ^^^ /// ```` pub frontmatter: bool, /// GFM: autolink literal. /// /// ```markdown /// > | https://example.com /// ^^^^^^^^^^^^^^^^^^^ /// ``` pub gfm_autolink_literal: bool, /// GFM: footnote definition. /// /// ```markdown /// > | [^a]: b /// ^^^^^^^ /// ``` pub gfm_footnote_definition: bool, /// GFM: footnote label start. /// /// ```markdown /// > | a[^b] /// ^^ /// ``` pub gfm_label_start_footnote: bool, /// /// ```markdown /// > | a ~b~ c. /// ^^^ /// ``` pub gfm_strikethrough: bool, /// GFM: table. /// /// ```markdown /// > | | a | /// ^^^^^ /// > | | - | /// ^^^^^ /// > | | b | /// ^^^^^ /// ``` pub gfm_table: bool, /// GFM: task list item. /// /// ```markdown /// > | * [x] y. /// ^^^ /// ``` pub gfm_task_list_item: bool, /// Hard break (escape). /// /// ```markdown /// > | a\ /// ^ /// | b /// ``` pub hard_break_escape: bool, /// Hard break (trailing). /// /// ```markdown /// > | a␠␠ /// ^^ /// | b /// ``` pub hard_break_trailing: bool, /// Heading (atx). /// /// ```markdown /// > | # a /// ^^^ /// ``` pub heading_atx: bool, /// Heading (setext). /// /// ```markdown /// > | a /// ^^ /// > | == /// ^^ /// ``` pub heading_setext: bool, /// HTML (flow). /// /// ```markdown /// > |
/// ^^^^^ /// ``` pub html_flow: bool, /// HTML (text). /// /// ```markdown /// > | a c /// ^^^ /// ``` pub html_text: bool, /// Label start (image). /// /// ```markdown /// > | a ![b](c) d /// ^^ /// ``` pub label_start_image: bool, /// Label start (link). /// /// ```markdown /// > | a [b](c) d /// ^ /// ``` pub label_start_link: bool, /// Label end. /// /// ```markdown /// > | a [b](c) d /// ^^^^ /// ``` pub label_end: bool, /// List items. /// /// ```markdown /// > | * a /// ^^^ /// ``` pub list_item: bool, /// Math (flow). /// /// ```markdown /// > | $$ /// ^^ /// > | \frac{1}{2} /// ^^^^^^^^^^^ /// > | $$ /// ^^ /// ``` pub math_flow: bool, /// Math (text). /// /// ```markdown /// > | a $b$ c /// ^^^ /// ``` pub math_text: bool, /// MDX: ESM. /// /// ```markdown /// > | import a from 'b' /// ^^^^^^^^^^^^^^^^^ /// ``` /// /// > 👉 **Note**: to support ESM, you *must* pass /// > [`mdx_esm_parse`][MdxEsmParse] in [`ParseOptions`][] too. /// > Otherwise, ESM is treated as normal markdown. pub mdx_esm: bool, /// MDX: expression (flow). /// /// ```markdown /// > | {Math.PI} /// ^^^^^^^^^ /// ``` /// /// > 👉 **Note**: You *can* pass /// > [`mdx_expression_parse`][MdxExpressionParse] in [`ParseOptions`][] /// > too, to parse expressions according to a certain grammar (typically, /// > a programming language). /// > Otherwise, expressions are parsed with a basic algorithm that only /// > cares about braces. pub mdx_expression_flow: bool, /// MDX: expression (text). /// /// ```markdown /// > | a {Math.PI} c /// ^^^^^^^^^ /// ``` /// /// > 👉 **Note**: You *can* pass /// > [`mdx_expression_parse`][MdxExpressionParse] in [`ParseOptions`][] /// > too, to parse expressions according to a certain grammar (typically, /// > a programming language). /// > Otherwise, expressions are parsed with a basic algorithm that only /// > cares about braces. pub mdx_expression_text: bool, /// MDX: JSX (flow). /// /// ```markdown /// > | /// ^^^^^^^^^^^^^ /// ``` /// /// > 👉 **Note**: You *can* pass /// > [`mdx_expression_parse`][MdxExpressionParse] in [`ParseOptions`][] /// > too, to parse expressions in JSX according to a certain grammar /// > (typically, a programming language). /// > Otherwise, expressions are parsed with a basic algorithm that only /// > cares about braces. pub mdx_jsx_flow: bool, /// MDX: JSX (text). /// /// ```markdown /// > | a c /// ^^^^^^^^^^^^^ /// ``` /// /// > 👉 **Note**: You *can* pass /// > [`mdx_expression_parse`][MdxExpressionParse] in [`ParseOptions`][] /// > too, to parse expressions in JSX according to a certain grammar /// > (typically, a programming language). /// > Otherwise, expressions are parsed with a basic algorithm that only /// > cares about braces. pub mdx_jsx_text: bool, /// Thematic break. /// /// ```markdown /// > | *** /// ^^^ /// ``` pub thematic_break: bool, } impl Default for Constructs { /// `CommonMark`. /// /// `CommonMark` is a relatively strong specification of how markdown /// works. /// Most markdown parsers try to follow it. /// /// For more information, see the `CommonMark` specification: /// . fn default() -> Self { Self { attention: true, autolink: true, block_quote: true, character_escape: true, character_reference: true, code_indented: true, code_fenced: true, code_text: true, definition: true, frontmatter: false, gfm_autolink_literal: false, gfm_label_start_footnote: false, gfm_footnote_definition: false, gfm_strikethrough: false, gfm_table: false, gfm_task_list_item: false, hard_break_escape: true, hard_break_trailing: true, heading_atx: true, heading_setext: true, html_flow: true, html_text: true, label_start_image: true, label_start_link: true, label_end: true, list_item: true, math_flow: false, math_text: false, mdx_esm: false, mdx_expression_flow: false, mdx_expression_text: false, mdx_jsx_flow: false, mdx_jsx_text: false, thematic_break: true, } } } impl Constructs { /// GFM. /// /// GFM stands for **GitHub flavored markdown**. /// GFM extends `CommonMark` and adds support for autolink literals, /// footnotes, strikethrough, tables, and tasklists. /// /// For more information, see the GFM specification: /// . #[must_use] pub fn gfm() -> Self { Self { gfm_autolink_literal: true, gfm_footnote_definition: true, gfm_label_start_footnote: true, gfm_strikethrough: true, gfm_table: true, gfm_task_list_item: true, ..Self::default() } } /// MDX. /// /// This turns on `CommonMark`, turns off some conflicting constructs /// (autolinks, code (indented), and HTML), and turns on MDX (ESM, /// expressions, and JSX). /// /// For more information, see the MDX website: /// . /// /// > 👉 **Note**: to support ESM, you *must* pass /// > [`mdx_esm_parse`][MdxEsmParse] in [`ParseOptions`][] too. /// > Otherwise, ESM is treated as normal markdown. /// > /// > You *can* pass /// > [`mdx_expression_parse`][MdxExpressionParse] /// > to parse expressions according to a certain grammar (typically, a /// > programming language). /// > Otherwise, expressions are parsed with a basic algorithm that only /// > cares about braces. #[must_use] pub fn mdx() -> Self { Self { autolink: false, code_indented: false, html_flow: false, html_text: false, mdx_esm: true, mdx_expression_flow: true, mdx_expression_text: true, mdx_jsx_flow: true, mdx_jsx_text: true, ..Self::default() } } } /// Configuration that describes how to compile to HTML. /// /// You likely either want to turn on the dangerous options /// (`allow_dangerous_html`, `allow_dangerous_protocol`) when dealing with /// input you trust, or want to customize how GFM footnotes are compiled /// (typically because the input markdown is not in English). /// /// ## Examples /// /// ``` /// use markdown::CompileOptions; /// # fn main() { /// /// // Use the default trait to get safe defaults: /// let safe = CompileOptions::default(); /// /// // Live dangerously / trust the author: /// let danger = CompileOptions { /// allow_dangerous_html: true, /// allow_dangerous_protocol: true, /// ..CompileOptions::default() /// }; /// /// // In French: /// let enFrançais = CompileOptions { /// gfm_footnote_label: Some("Notes de bas de page".into()), /// gfm_footnote_back_label: Some("Arrière".into()), /// ..CompileOptions::default() /// }; /// # } /// ``` #[allow(clippy::struct_excessive_bools)] #[derive(Clone, Debug, Default)] pub struct CompileOptions { /// Whether to allow (dangerous) HTML. /// /// The default is `false`, which still parses the HTML according to /// `CommonMark` but shows the HTML as text instead of as elements. /// /// Pass `true` for trusted content to get actual HTML elements. /// /// ## Examples /// /// ``` /// use markdown::{to_html, to_html_with_options, CompileOptions, Options}; /// # fn main() -> Result<(), String> { /// /// // `markdown-rs` is safe by default: /// assert_eq!( /// to_html("Hi, venus!"), /// "

Hi, <i>venus</i>!

" /// ); /// /// // Turn `allow_dangerous_html` on to allow potentially dangerous HTML: /// assert_eq!( /// to_html_with_options( /// "Hi, venus!", /// &Options { /// compile: CompileOptions { /// allow_dangerous_html: true, /// ..CompileOptions::default() /// }, /// ..Options::default() /// } /// )?, /// "

Hi, venus!

" /// ); /// # Ok(()) /// # } /// ``` pub allow_dangerous_html: bool, /// Whether to allow dangerous protocols in links and images. /// /// The default is `false`, which drops URLs in links and images that use /// dangerous protocols. /// /// Pass `true` for trusted content to support all protocols. /// /// URLs that have no protocol (which means it’s relative to the current /// page, such as `./some/page.html`) and URLs that have a safe protocol /// (for images: `http`, `https`; for links: `http`, `https`, `irc`, /// `ircs`, `mailto`, `xmpp`), are safe. /// All other URLs are dangerous and dropped. /// /// ## Examples /// /// ``` /// use markdown::{to_html, to_html_with_options, CompileOptions, Options}; /// # fn main() -> Result<(), String> { /// /// // `markdown-rs` is safe by default: /// assert_eq!( /// to_html(""), /// "
" /// ); /// /// // Turn `allow_dangerous_protocol` on to allow potentially dangerous protocols: /// assert_eq!( /// to_html_with_options( /// "", /// &Options { /// compile: CompileOptions { /// allow_dangerous_protocol: true, /// ..CompileOptions::default() /// }, /// ..Options::default() /// } /// )?, /// "

javascript:alert(1)

" /// ); /// # Ok(()) /// # } /// ``` pub allow_dangerous_protocol: bool, /// Default line ending to use when compiling to HTML, for line endings not /// in `value`. /// /// Generally, `markdown-rs` copies line endings (`\r`, `\n`, `\r\n`) in /// the markdown document over to the compiled HTML. /// In some cases, such as `> a`, CommonMark requires that extra line /// endings are added: `
\n

a

\n
`. /// /// To create that line ending, the document is checked for the first line /// ending that is used. /// If there is no line ending, `default_line_ending` is used. /// If that isn’t configured, `\n` is used. /// /// ## Examples /// /// ``` /// use markdown::{to_html, to_html_with_options, CompileOptions, LineEnding, Options}; /// # fn main() -> Result<(), String> { /// /// // `markdown-rs` uses `\n` by default: /// assert_eq!( /// to_html("> a"), /// "
\n

a

\n
" /// ); /// /// // Define `default_line_ending` to configure the default: /// assert_eq!( /// to_html_with_options( /// "> a", /// &Options { /// compile: CompileOptions { /// default_line_ending: LineEnding::CarriageReturnLineFeed, /// ..CompileOptions::default() /// }, /// ..Options::default() /// } /// )?, /// "
\r\n

a

\r\n
" /// ); /// # Ok(()) /// # } /// ``` pub default_line_ending: LineEnding, /// Textual label to use for the footnotes section. /// /// The default value is `"Footnotes"`. /// Change it when the markdown is not in English. /// /// This label is typically hidden visually (assuming a `sr-only` CSS class /// is defined that does that), and thus affects screen readers only. /// If you do have such a class, but want to show this section to everyone, /// pass different attributes with the `gfm_footnote_label_attributes` /// option. /// /// ## Examples /// /// ``` /// use markdown::{to_html_with_options, CompileOptions, Options, ParseOptions}; /// # fn main() -> Result<(), String> { /// /// // `"Footnotes"` is used by default: /// assert_eq!( /// to_html_with_options( /// "[^a]\n\n[^a]: b", /// &Options::gfm() /// )?, /// "

1

\n

Footnotes

\n
    \n
  1. \n

    b

    \n
  2. \n
\n
\n" /// ); /// /// // Pass `gfm_footnote_label` to use something else: /// assert_eq!( /// to_html_with_options( /// "[^a]\n\n[^a]: b", /// &Options { /// parse: ParseOptions::gfm(), /// compile: CompileOptions { /// gfm_footnote_label: Some("Notes de bas de page".into()), /// ..CompileOptions::gfm() /// } /// } /// )?, /// "

1

\n

Notes de bas de page

\n
    \n
  1. \n

    b

    \n
  2. \n
\n
\n" /// ); /// # Ok(()) /// # } /// ``` pub gfm_footnote_label: Option, /// HTML tag name to use for the footnote label element. /// /// The default value is `"h2"`. /// Change it to match your document structure. /// /// This label is typically hidden visually (assuming a `sr-only` CSS class /// is defined that does that), and thus affects screen readers only. /// If you do have such a class, but want to show this section to everyone, /// pass different attributes with the `gfm_footnote_label_attributes` /// option. /// /// ## Examples /// /// ``` /// use markdown::{to_html_with_options, CompileOptions, Options, ParseOptions}; /// # fn main() -> Result<(), String> { /// /// // `"h2"` is used by default: /// assert_eq!( /// to_html_with_options( /// "[^a]\n\n[^a]: b", /// &Options::gfm() /// )?, /// "

1

\n

Footnotes

\n
    \n
  1. \n

    b

    \n
  2. \n
\n
\n" /// ); /// /// // Pass `gfm_footnote_label_tag_name` to use something else: /// assert_eq!( /// to_html_with_options( /// "[^a]\n\n[^a]: b", /// &Options { /// parse: ParseOptions::gfm(), /// compile: CompileOptions { /// gfm_footnote_label_tag_name: Some("h1".into()), /// ..CompileOptions::gfm() /// } /// } /// )?, /// "

1

\n

Footnotes

\n
    \n
  1. \n

    b

    \n
  2. \n
\n
\n" /// ); /// # Ok(()) /// # } /// ``` pub gfm_footnote_label_tag_name: Option, /// Attributes to use on the footnote label. /// /// The default value is `"class=\"sr-only\""`. /// Change it to show the label and add other attributes. /// /// This label is typically hidden visually (assuming a `sr-only` CSS class /// is defined that does that), and thus affects screen readers only. /// If you do have such a class, but want to show this section to everyone, /// pass an empty string. /// You can also add different attributes. /// /// > 👉 **Note**: `id="footnote-label"` is always added, because footnote /// > calls use it with `aria-describedby` to provide an accessible label. /// /// ## Examples /// /// ``` /// use markdown::{to_html_with_options, CompileOptions, Options, ParseOptions}; /// # fn main() -> Result<(), String> { /// /// // `"class=\"sr-only\""` is used by default: /// assert_eq!( /// to_html_with_options( /// "[^a]\n\n[^a]: b", /// &Options::gfm() /// )?, /// "

1

\n

Footnotes

\n
    \n
  1. \n

    b

    \n
  2. \n
\n
\n" /// ); /// /// // Pass `gfm_footnote_label_attributes` to use something else: /// assert_eq!( /// to_html_with_options( /// "[^a]\n\n[^a]: b", /// &Options { /// parse: ParseOptions::gfm(), /// compile: CompileOptions { /// gfm_footnote_label_attributes: Some("class=\"footnote-heading\"".into()), /// ..CompileOptions::gfm() /// } /// } /// )?, /// "

1

\n

Footnotes

\n
    \n
  1. \n

    b

    \n
  2. \n
\n
\n" /// ); /// # Ok(()) /// # } /// ``` pub gfm_footnote_label_attributes: Option, /// Textual label to describe the backreference back to footnote calls. /// /// The default value is `"Back to content"`. /// Change it when the markdown is not in English. /// /// This label is used in the `aria-label` attribute on each backreference /// (the `↩` links). /// It affects users of assistive technology. /// /// ## Examples /// /// ``` /// use markdown::{to_html_with_options, CompileOptions, Options, ParseOptions}; /// # fn main() -> Result<(), String> { /// /// // `"Back to content"` is used by default: /// assert_eq!( /// to_html_with_options( /// "[^a]\n\n[^a]: b", /// &Options::gfm() /// )?, /// "

1

\n

Footnotes

\n
    \n
  1. \n

    b

    \n
  2. \n
\n
\n" /// ); /// /// // Pass `gfm_footnote_back_label` to use something else: /// assert_eq!( /// to_html_with_options( /// "[^a]\n\n[^a]: b", /// &Options { /// parse: ParseOptions::gfm(), /// compile: CompileOptions { /// gfm_footnote_back_label: Some("Arrière".into()), /// ..CompileOptions::gfm() /// } /// } /// )?, /// "

1

\n

Footnotes

\n
    \n
  1. \n

    b

    \n
  2. \n
\n
\n" /// ); /// # Ok(()) /// # } /// ``` pub gfm_footnote_back_label: Option, /// Prefix to use before the `id` attribute on footnotes to prevent them /// from *clobbering*. /// /// The default is `"user-content-"`. /// Pass `Some("".into())` for trusted markdown and when you are careful /// with polyfilling. /// You could pass a different prefix. /// /// DOM clobbering is this: /// /// ```html ///

/// /// ``` /// /// The above example shows that elements are made available by browsers, /// by their ID, on the `window` object. /// This is a security risk because you might be expecting some other /// variable at that place. /// It can also break polyfills. /// Using a prefix solves these problems. /// /// ## Examples /// /// ``` /// use markdown::{to_html_with_options, CompileOptions, Options, ParseOptions}; /// # fn main() -> Result<(), String> { /// /// // `"user-content-"` is used by default: /// assert_eq!( /// to_html_with_options( /// "[^a]\n\n[^a]: b", /// &Options::gfm() /// )?, /// "

1

\n

Footnotes

\n
    \n
  1. \n

    b

    \n
  2. \n
\n
\n" /// ); /// /// // Pass `gfm_footnote_clobber_prefix` to use something else: /// assert_eq!( /// to_html_with_options( /// "[^a]\n\n[^a]: b", /// &Options { /// parse: ParseOptions::gfm(), /// compile: CompileOptions { /// gfm_footnote_clobber_prefix: Some("".into()), /// ..CompileOptions::gfm() /// } /// } /// )?, /// "

1

\n

Footnotes

\n
    \n
  1. \n

    b

    \n
  2. \n
\n
\n" /// ); /// # Ok(()) /// # } /// ``` pub gfm_footnote_clobber_prefix: Option, /// Whether to support the GFM tagfilter. /// /// This option does nothing if `allow_dangerous_html` is not turned on. /// The default is `false`, which does not apply the GFM tagfilter to HTML. /// Pass `true` for output that is a bit closer to GitHub’s actual output. /// /// The tagfilter is kinda weird and kinda useless. /// The tag filter is a naïve attempt at XSS protection. /// You should use a proper HTML sanitizing algorithm instead. /// /// ## Examples /// /// ``` /// use markdown::{to_html_with_options, CompileOptions, Options, ParseOptions}; /// # fn main() -> Result<(), String> { /// /// // With `allow_dangerous_html`, `markdown-rs` passes HTML through untouched: /// assert_eq!( /// to_html_with_options( /// "

javascript:alert(1)