Something went wrong. Try again.
Markdown parser fork with extended syntax for personal use.
Something went wrong. Try again.
54 kB · 1553 lines
Rust
at hack
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554use crate::util::{ line_ending::LineEnding, mdx::{EsmParse as MdxEsmParse, ExpressionParse as MdxExpressionParse},};use alloc::{boxed::Box, fmt, string::String};
/// 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)]#[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "camelCase"))]pub struct Constructs { /// Attention. /// /// ```markdown /// > | a *b* c **d**. /// ^^^ ^^^^^ /// ``` pub attention: bool, /// Autolink. /// /// ```markdown /// > | a <https://example.com> b <user@example.org>. /// ^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ /// ``` 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, /// wikilink syntax. /// /// ```markdown /// > | [[a]] /// ^^^^^ /// ``` pub wikilink: bool, pub obs_block_quote: 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 /// > | <div> /// ^^^^^ /// ``` pub html_flow: bool, /// HTML (text). /// /// ```markdown /// > | a <b> c /// ^^^ /// ``` pub html_text: bool, /// Label start (image). /// /// ```markdown /// > | a  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 /// > | <Component /> /// ^^^^^^^^^^^^^ /// ``` /// /// > 👉 **Note**: You *must* pass `html_flow: false` to use this, /// > as it’s preferred when on over `mdx_jsx_flow`. /// /// > 👉 **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 <Component /> c /// ^^^^^^^^^^^^^ /// ``` /// /// > 👉 **Note**: You *must* pass `html_text: false` to use this, /// > as it’s preferred when on over `mdx_jsx_text`. /// /// > 👉 **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: /// <https://spec.commonmark.org>. 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, wikilink: false, obs_block_quote: false, } }}
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: /// <https://github.github.com/gfm/>. 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: /// <https://mdxjs.com>. /// /// > 👉 **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. 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_back_label: Some("Arrière".into()),/// gfm_footnote_label: Some("Notes de bas de page".into()),/// ..CompileOptions::default()/// };/// # }/// ```#[allow(clippy::struct_excessive_bools)]#[derive(Clone, Debug, Default)]#[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(default, rename_all = "camelCase"))]pub struct CompileOptions { /// Whether to allow all values in images. /// /// The default is `false`, /// which lets `allow_dangerous_protocol` control protocol safety for /// both links and images. /// /// Pass `true` to allow all values as `src` on images, /// regardless of `allow_dangerous_protocol`. /// This is safe because the /// [HTML specification][whatwg-html-image-processing] /// does not allow executable code in images. /// /// [whatwg-html-image-processing]: https://html.spec.whatwg.org/multipage/images.html#images-processing-model /// /// ## Examples /// /// ``` /// use markdown::{to_html_with_options, CompileOptions, Options}; /// # fn main() -> Result<(), markdown::message::Message> { /// /// // By default, some protocols in image sources are dropped: /// assert_eq!( /// to_html_with_options( /// "", /// &Options::default() /// )?, /// "<p><img src=\"\" alt=\"\" /></p>" /// ); /// /// // Turn `allow_any_img_src` on to allow all values as `src` on images. /// // This is safe because browsers do not execute code in images. /// assert_eq!( /// to_html_with_options( /// ")", /// &Options { /// compile: CompileOptions { /// allow_any_img_src: true, /// ..CompileOptions::default() /// }, /// ..Options::default() /// } /// )?, /// "<p><img src=\"javascript:alert(1)\" alt=\"\" /></p>" /// ); /// # Ok(()) /// # } /// ``` pub allow_any_img_src: bool,
/// 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. /// /// When using GFM, make sure to also turn off `gfm_tagfilter`. /// Otherwise, some dangerous HTML is still ignored. /// /// ## Examples /// /// ``` /// use markdown::{to_html, to_html_with_options, CompileOptions, Options}; /// # fn main() -> Result<(), markdown::message::Message> { /// /// // `markdown-rs` is safe by default: /// assert_eq!( /// to_html("Hi, <i>venus</i>!"), /// "<p>Hi, <i>venus</i>!</p>" /// ); /// /// // Turn `allow_dangerous_html` on to allow potentially dangerous HTML: /// assert_eq!( /// to_html_with_options( /// "Hi, <i>venus</i>!", /// &Options { /// compile: CompileOptions { /// allow_dangerous_html: true, /// ..CompileOptions::default() /// }, /// ..Options::default() /// } /// )?, /// "<p>Hi, <i>venus</i>!</p>" /// ); /// # 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. /// /// When the option `allow_all_protocols_in_img` is enabled, /// `allow_dangerous_protocol` only applies to links. /// /// This is safe because the /// [HTML specification][whatwg-html-image-processing] /// does not allow executable code in images. /// All modern browsers respect this. /// /// [whatwg-html-image-processing]: https://html.spec.whatwg.org/multipage/images.html#images-processing-model /// /// ## Examples /// /// ``` /// use markdown::{to_html, to_html_with_options, CompileOptions, Options}; /// # fn main() -> Result<(), markdown::message::Message> { /// /// // `markdown-rs` is safe by default: /// assert_eq!( /// to_html("<javascript:alert(1)>"), /// "<p><a href=\"\">javascript:alert(1)</a></p>" /// ); /// /// // Turn `allow_dangerous_protocol` on to allow potentially dangerous protocols: /// assert_eq!( /// to_html_with_options( /// "<javascript:alert(1)>", /// &Options { /// compile: CompileOptions { /// allow_dangerous_protocol: true, /// ..CompileOptions::default() /// }, /// ..Options::default() /// } /// )?, /// "<p><a href=\"javascript:alert(1)\">javascript:alert(1)</a></p>" /// ); /// # Ok(()) /// # } /// ``` pub allow_dangerous_protocol: bool,
// To do: `doc_markdown` is broken. #[allow(clippy::doc_markdown)] /// 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: `<blockquote>\n<p>a</p>\n</blockquote>`. /// /// 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<(), markdown::message::Message> { /// /// // `markdown-rs` uses `\n` by default: /// assert_eq!( /// to_html("> a"), /// "<blockquote>\n<p>a</p>\n</blockquote>" /// ); /// /// // 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() /// } /// )?, /// "<blockquote>\r\n<p>a</p>\r\n</blockquote>" /// ); /// # Ok(()) /// # } /// ``` pub default_line_ending: LineEnding,
/// 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<(), markdown::message::Message> { /// /// // `"Back to content"` is used by default: /// assert_eq!( /// to_html_with_options( /// "[^a]\n\n[^a]: b", /// &Options::gfm() /// )?, /// "<p><sup><a href=\"#user-content-fn-a\" id=\"user-content-fnref-a\" data-footnote-ref=\"\" aria-describedby=\"footnote-label\">1</a></sup></p>\n<section data-footnotes=\"\" class=\"footnotes\"><h2 id=\"footnote-label\" class=\"sr-only\">Footnotes</h2>\n<ol>\n<li id=\"user-content-fn-a\">\n<p>b <a href=\"#user-content-fnref-a\" data-footnote-backref=\"\" aria-label=\"Back to content\" class=\"data-footnote-backref\">↩</a></p>\n</li>\n</ol>\n</section>\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() /// } /// } /// )?, /// "<p><sup><a href=\"#user-content-fn-a\" id=\"user-content-fnref-a\" data-footnote-ref=\"\" aria-describedby=\"footnote-label\">1</a></sup></p>\n<section data-footnotes=\"\" class=\"footnotes\"><h2 id=\"footnote-label\" class=\"sr-only\">Footnotes</h2>\n<ol>\n<li id=\"user-content-fn-a\">\n<p>b <a href=\"#user-content-fnref-a\" data-footnote-backref=\"\" aria-label=\"Arrière\" class=\"data-footnote-backref\">↩</a></p>\n</li>\n</ol>\n</section>\n" /// ); /// # Ok(()) /// # } /// ``` pub gfm_footnote_back_label: Option<String>,
/// 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 /// <p id="x"></p> /// <script>alert(x) // `x` now refers to the `p#x` DOM element</script> /// ``` /// /// 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<(), markdown::message::Message> { /// /// // `"user-content-"` is used by default: /// assert_eq!( /// to_html_with_options( /// "[^a]\n\n[^a]: b", /// &Options::gfm() /// )?, /// "<p><sup><a href=\"#user-content-fn-a\" id=\"user-content-fnref-a\" data-footnote-ref=\"\" aria-describedby=\"footnote-label\">1</a></sup></p>\n<section data-footnotes=\"\" class=\"footnotes\"><h2 id=\"footnote-label\" class=\"sr-only\">Footnotes</h2>\n<ol>\n<li id=\"user-content-fn-a\">\n<p>b <a href=\"#user-content-fnref-a\" data-footnote-backref=\"\" aria-label=\"Back to content\" class=\"data-footnote-backref\">↩</a></p>\n</li>\n</ol>\n</section>\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() /// } /// } /// )?, /// "<p><sup><a href=\"#fn-a\" id=\"fnref-a\" data-footnote-ref=\"\" aria-describedby=\"footnote-label\">1</a></sup></p>\n<section data-footnotes=\"\" class=\"footnotes\"><h2 id=\"footnote-label\" class=\"sr-only\">Footnotes</h2>\n<ol>\n<li id=\"fn-a\">\n<p>b <a href=\"#fnref-a\" data-footnote-backref=\"\" aria-label=\"Back to content\" class=\"data-footnote-backref\">↩</a></p>\n</li>\n</ol>\n</section>\n" /// ); /// # Ok(()) /// # } /// ``` pub gfm_footnote_clobber_prefix: Option<String>,
/// 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<(), markdown::message::Message> { /// /// // `"class=\"sr-only\""` is used by default: /// assert_eq!( /// to_html_with_options( /// "[^a]\n\n[^a]: b", /// &Options::gfm() /// )?, /// "<p><sup><a href=\"#user-content-fn-a\" id=\"user-content-fnref-a\" data-footnote-ref=\"\" aria-describedby=\"footnote-label\">1</a></sup></p>\n<section data-footnotes=\"\" class=\"footnotes\"><h2 id=\"footnote-label\" class=\"sr-only\">Footnotes</h2>\n<ol>\n<li id=\"user-content-fn-a\">\n<p>b <a href=\"#user-content-fnref-a\" data-footnote-backref=\"\" aria-label=\"Back to content\" class=\"data-footnote-backref\">↩</a></p>\n</li>\n</ol>\n</section>\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() /// } /// } /// )?, /// "<p><sup><a href=\"#user-content-fn-a\" id=\"user-content-fnref-a\" data-footnote-ref=\"\" aria-describedby=\"footnote-label\">1</a></sup></p>\n<section data-footnotes=\"\" class=\"footnotes\"><h2 id=\"footnote-label\" class=\"footnote-heading\">Footnotes</h2>\n<ol>\n<li id=\"user-content-fn-a\">\n<p>b <a href=\"#user-content-fnref-a\" data-footnote-backref=\"\" aria-label=\"Back to content\" class=\"data-footnote-backref\">↩</a></p>\n</li>\n</ol>\n</section>\n" /// ); /// # Ok(()) /// # } /// ``` pub gfm_footnote_label_attributes: Option<String>,
/// 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<(), markdown::message::Message> { /// /// // `"h2"` is used by default: /// assert_eq!( /// to_html_with_options( /// "[^a]\n\n[^a]: b", /// &Options::gfm() /// )?, /// "<p><sup><a href=\"#user-content-fn-a\" id=\"user-content-fnref-a\" data-footnote-ref=\"\" aria-describedby=\"footnote-label\">1</a></sup></p>\n<section data-footnotes=\"\" class=\"footnotes\"><h2 id=\"footnote-label\" class=\"sr-only\">Footnotes</h2>\n<ol>\n<li id=\"user-content-fn-a\">\n<p>b <a href=\"#user-content-fnref-a\" data-footnote-backref=\"\" aria-label=\"Back to content\" class=\"data-footnote-backref\">↩</a></p>\n</li>\n</ol>\n</section>\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() /// } /// } /// )?, /// "<p><sup><a href=\"#user-content-fn-a\" id=\"user-content-fnref-a\" data-footnote-ref=\"\" aria-describedby=\"footnote-label\">1</a></sup></p>\n<section data-footnotes=\"\" class=\"footnotes\"><h1 id=\"footnote-label\" class=\"sr-only\">Footnotes</h1>\n<ol>\n<li id=\"user-content-fn-a\">\n<p>b <a href=\"#user-content-fnref-a\" data-footnote-backref=\"\" aria-label=\"Back to content\" class=\"data-footnote-backref\">↩</a></p>\n</li>\n</ol>\n</section>\n" /// ); /// # Ok(()) /// # } /// ``` pub gfm_footnote_label_tag_name: Option<String>,
/// 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<(), markdown::message::Message> { /// /// // `"Footnotes"` is used by default: /// assert_eq!( /// to_html_with_options( /// "[^a]\n\n[^a]: b", /// &Options::gfm() /// )?, /// "<p><sup><a href=\"#user-content-fn-a\" id=\"user-content-fnref-a\" data-footnote-ref=\"\" aria-describedby=\"footnote-label\">1</a></sup></p>\n<section data-footnotes=\"\" class=\"footnotes\"><h2 id=\"footnote-label\" class=\"sr-only\">Footnotes</h2>\n<ol>\n<li id=\"user-content-fn-a\">\n<p>b <a href=\"#user-content-fnref-a\" data-footnote-backref=\"\" aria-label=\"Back to content\" class=\"data-footnote-backref\">↩</a></p>\n</li>\n</ol>\n</section>\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() /// } /// } /// )?, /// "<p><sup><a href=\"#user-content-fn-a\" id=\"user-content-fnref-a\" data-footnote-ref=\"\" aria-describedby=\"footnote-label\">1</a></sup></p>\n<section data-footnotes=\"\" class=\"footnotes\"><h2 id=\"footnote-label\" class=\"sr-only\">Notes de bas de page</h2>\n<ol>\n<li id=\"user-content-fn-a\">\n<p>b <a href=\"#user-content-fnref-a\" data-footnote-backref=\"\" aria-label=\"Back to content\" class=\"data-footnote-backref\">↩</a></p>\n</li>\n</ol>\n</section>\n" /// ); /// # Ok(()) /// # } /// ``` pub gfm_footnote_label: Option<String>,
/// Whether or not GFM task list html `<input>` items are enabled. /// /// This determines whether or not the user of the browser is able /// to click and toggle generated checkbox items. The default is false. /// /// ## Examples /// /// ``` /// use markdown::{to_html_with_options, CompileOptions, Options, ParseOptions}; /// # fn main() -> Result<(), markdown::message::Message> { /// /// // With `gfm_task_list_item_checkable`, generated `<input type="checkbox" />` /// // tags do not contain the attribute `disabled=""` and are thus toggleable by /// // browser users. /// assert_eq!( /// to_html_with_options( /// "* [x] y.", /// &Options { /// parse: ParseOptions::gfm(), /// compile: CompileOptions { /// gfm_task_list_item_checkable: true, /// ..CompileOptions::gfm() /// } /// } /// )?, /// "<ul>\n<li><input type=\"checkbox\" checked=\"\" /> y.</li>\n</ul>" /// ); /// # Ok(()) /// # } /// ``` pub gfm_task_list_item_checkable: bool,
/// 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<(), markdown::message::Message> { /// /// // With `allow_dangerous_html`, `markdown-rs` passes HTML through untouched: /// assert_eq!( /// to_html_with_options( /// "<iframe>", /// &Options { /// parse: ParseOptions::gfm(), /// compile: CompileOptions { /// allow_dangerous_html: true, /// ..CompileOptions::default() /// } /// } /// )?, /// "<iframe>" /// ); /// /// // Pass `gfm_tagfilter: true` to make some of that safe: /// assert_eq!( /// to_html_with_options( /// "<iframe>", /// &Options { /// parse: ParseOptions::gfm(), /// compile: CompileOptions { /// allow_dangerous_html: true, /// gfm_tagfilter: true, /// ..CompileOptions::default() /// } /// } /// )?, /// "<iframe>" /// ); /// # Ok(()) /// # } /// ``` /// /// ## References /// /// * [*§ 6.1 Disallowed Raw HTML (extension)* in GFM](https://github.github.com/gfm/#disallowed-raw-html-extension-) /// * [`cmark-gfm#extensions/tagfilter.c`](https://github.com/github/cmark-gfm/blob/master/extensions/tagfilter.c) pub gfm_tagfilter: bool,}
impl CompileOptions { /// GFM. /// /// GFM stands for **GitHub flavored markdown**. /// On the compilation side, GFM turns on the GFM tag filter. /// The tagfilter is useless, but it’s included here for consistency, and /// this method exists for parity to parse options. /// /// For more information, see the GFM specification: /// <https://github.github.com/gfm/>. pub fn gfm() -> Self { Self { gfm_tagfilter: true, ..Self::default() } }}
/// Configuration that describes how to parse from markdown.////// You can use this:////// * To control what markdown constructs are turned on and off/// * To control some of those constructs/// * To add support for certain programming languages when parsing MDX////// In most cases, you will want to use the default trait or `gfm` method.////// ## Examples////// ```/// use markdown::ParseOptions;/// # fn main() {////// // Use the default trait to parse markdown according to `CommonMark`:/// let commonmark = ParseOptions::default();////// // Use the `gfm` method to parse markdown according to GFM:/// let gfm = ParseOptions::gfm();/// # }/// ```#[allow(clippy::struct_excessive_bools)]#[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(default, rename_all = "camelCase"))]pub struct ParseOptions { // Note: when adding fields, don’t forget to add them to `fmt::Debug` below. /// Which constructs to enable and disable. /// /// The default is to follow `CommonMark`. /// /// ## Examples /// /// ``` /// use markdown::{to_html, to_html_with_options, Constructs, Options, ParseOptions}; /// # fn main() -> Result<(), markdown::message::Message> { /// /// // `markdown-rs` follows CommonMark by default: /// assert_eq!( /// to_html(" indented code?"), /// "<pre><code>indented code?\n</code></pre>" /// ); /// /// // Pass `constructs` to choose what to enable and disable: /// assert_eq!( /// to_html_with_options( /// " indented code?", /// &Options { /// parse: ParseOptions { /// constructs: Constructs { /// code_indented: false, /// ..Constructs::default() /// }, /// ..ParseOptions::default() /// }, /// ..Options::default() /// } /// )?, /// "<p>indented code?</p>" /// ); /// # Ok(()) /// # } /// ``` #[cfg_attr(feature = "serde", serde(default))] pub constructs: Constructs,
/// Whether to support GFM strikethrough with a single tilde /// /// This option does nothing if `gfm_strikethrough` is not turned on in /// `constructs`. /// This option does not affect strikethrough with double tildes. /// /// The default is `true`, which follows how markdown on `github.com` /// works, as strikethrough with single tildes is supported. /// Pass `false`, to follow the GFM spec more strictly, by not allowing /// strikethrough with single tildes. /// /// ## Examples /// /// ``` /// use markdown::{to_html_with_options, Constructs, Options, ParseOptions}; /// # fn main() -> Result<(), markdown::message::Message> { /// /// // `markdown-rs` supports single tildes by default: /// assert_eq!( /// to_html_with_options( /// "~a~", /// &Options { /// parse: ParseOptions { /// constructs: Constructs::gfm(), /// ..ParseOptions::default() /// }, /// ..Options::default() /// } /// )?, /// "<p><del>a</del></p>" /// ); /// /// // Pass `gfm_strikethrough_single_tilde: false` to turn that off: /// assert_eq!( /// to_html_with_options( /// "~a~", /// &Options { /// parse: ParseOptions { /// constructs: Constructs::gfm(), /// gfm_strikethrough_single_tilde: false, /// ..ParseOptions::default() /// }, /// ..Options::default() /// } /// )?, /// "<p>~a~</p>" /// ); /// # Ok(()) /// # } /// ``` #[cfg_attr(feature = "serde", serde(default))] pub gfm_strikethrough_single_tilde: bool,
/// Whether to support math (text) with a single dollar /// /// This option does nothing if `math_text` is not turned on in /// `constructs`. /// This option does not affect math (text) with two or more dollars. /// /// The default is `true`, which is more close to how code (text) and /// Pandoc work, as it allows math with a single dollar to form. /// However, single dollars can interfere with “normal” dollars in text. /// Pass `false`, to only allow math (text) to form when two or more /// dollars are used. /// If you pass `false`, you can still use two or more dollars for text /// math. /// /// ## Examples /// /// ``` /// use markdown::{to_html_with_options, Constructs, Options, ParseOptions}; /// # fn main() -> Result<(), markdown::message::Message> { /// /// // `markdown-rs` supports single dollars by default: /// assert_eq!( /// to_html_with_options( /// "$a$", /// &Options { /// parse: ParseOptions { /// constructs: Constructs { /// math_text: true, /// ..Constructs::default() /// }, /// ..ParseOptions::default() /// }, /// ..Options::default() /// } /// )?, /// "<p><code class=\"language-math math-inline\">a</code></p>" /// ); /// /// // Pass `math_text_single_dollar: false` to turn that off: /// assert_eq!( /// to_html_with_options( /// "$a$", /// &Options { /// parse: ParseOptions { /// constructs: Constructs { /// math_text: true, /// ..Constructs::default() /// }, /// math_text_single_dollar: false, /// ..ParseOptions::default() /// }, /// ..Options::default() /// } /// )?, /// "<p>$a$</p>" /// ); /// # Ok(()) /// # } /// ``` #[cfg_attr(feature = "serde", serde(default))] pub math_text_single_dollar: bool,
/// Function to parse expressions with. /// /// This function can be used to add support for arbitrary programming /// languages within expressions. /// /// It only makes sense to pass this when compiling to a syntax tree /// with [`to_mdast()`][crate::to_mdast()]. /// /// For an example that adds support for JavaScript with SWC, see /// `tests/test_utils/mod.rs`. #[cfg_attr(feature = "serde", serde(skip))] pub mdx_expression_parse: Option<Box<MdxExpressionParse>>,
/// Function to parse ESM with. /// /// This function can be used to add support for arbitrary programming /// languages within ESM blocks, however, the keywords (`export`, /// `import`) are currently hardcoded JavaScript-specific. /// /// > 👉 **Note**: please raise an issue if you’re interested in working on /// > MDX that is aware of, say, Rust, or other programming languages. /// /// It only makes sense to pass this when compiling to a syntax tree /// with [`to_mdast()`][crate::to_mdast()]. /// /// For an example that adds support for JavaScript with SWC, see /// `tests/test_utils/mod.rs`. #[cfg_attr(feature = "serde", serde(skip))] pub mdx_esm_parse: Option<Box<MdxEsmParse>>, // Note: when adding fields, don’t forget to add them to `fmt::Debug` below.}
impl fmt::Debug for ParseOptions { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ParseOptions") .field("constructs", &self.constructs) .field( "gfm_strikethrough_single_tilde", &self.gfm_strikethrough_single_tilde, ) .field("math_text_single_dollar", &self.math_text_single_dollar) .field( "mdx_expression_parse", &self.mdx_expression_parse.as_ref().map(|_d| "[Function]"), ) .field( "mdx_esm_parse", &self.mdx_esm_parse.as_ref().map(|_d| "[Function]"), ) .finish() }}
impl Default for ParseOptions { /// `CommonMark` defaults. fn default() -> Self { Self { constructs: Constructs::default(), gfm_strikethrough_single_tilde: true, math_text_single_dollar: true, mdx_expression_parse: None, mdx_esm_parse: None, } }}
impl ParseOptions { /// 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: /// <https://github.github.com/gfm/> pub fn gfm() -> Self { Self { constructs: Constructs::gfm(), ..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: /// <https://mdxjs.com>. /// /// > 👉 **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. pub fn mdx() -> Self { Self { constructs: Constructs::mdx(), ..Self::default() } }}
/// Configuration that describes how to parse from markdown and compile to/// HTML.////// In most cases, you will want to use the default trait or `gfm` method.////// ## Examples////// ```/// use markdown::Options;/// # fn main() {////// // Use the default trait to compile markdown to HTML according to `CommonMark`:/// let commonmark = Options::default();////// // Use the `gfm` method to compile markdown to HTML according to GFM:/// let gfm = Options::gfm();/// # }/// ```#[allow(clippy::struct_excessive_bools)]#[derive(Debug, Default)]#[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(default))]pub struct Options { /// Configuration that describes how to parse from markdown. pub parse: ParseOptions, /// Configuration that describes how to compile to HTML. pub compile: CompileOptions,}
impl Options { /// GFM. /// /// GFM stands for GitHub flavored markdown. /// GFM extends `CommonMark` and adds support for autolink literals, /// footnotes, strikethrough, tables, and tasklists. /// On the compilation side, GFM turns on the GFM tag filter. /// The tagfilter is useless, but it’s included here for consistency. /// /// For more information, see the GFM specification: /// <https://github.github.com/gfm/> pub fn gfm() -> Self { Self { parse: ParseOptions::gfm(), compile: CompileOptions::gfm(), } }}
#[cfg(test)]mod tests { use super::*; use crate::util::mdx::Signal; use alloc::format;
#[test] fn test_constructs() { Constructs::default(); Constructs::gfm(); Constructs::mdx();
let constructs = Constructs::default(); assert!(constructs.attention, "should default to `CommonMark` (1)"); assert!( !constructs.gfm_autolink_literal, "should default to `CommonMark` (2)" ); assert!( !constructs.mdx_jsx_flow, "should default to `CommonMark` (3)" ); assert!( !constructs.frontmatter, "should default to `CommonMark` (4)" );
let constructs = Constructs::gfm(); assert!(constructs.attention, "should support `gfm` shortcut (1)"); assert!( constructs.gfm_autolink_literal, "should support `gfm` shortcut (2)" ); assert!( !constructs.mdx_jsx_flow, "should support `gfm` shortcut (3)" ); assert!(!constructs.frontmatter, "should support `gfm` shortcut (4)");
let constructs = Constructs::mdx(); assert!(constructs.attention, "should support `gfm` shortcut (1)"); assert!( !constructs.gfm_autolink_literal, "should support `mdx` shortcut (2)" ); assert!(constructs.mdx_jsx_flow, "should support `mdx` shortcut (3)"); assert!(!constructs.frontmatter, "should support `mdx` shortcut (4)"); }
#[test] fn test_parse_options() { ParseOptions::default(); ParseOptions::gfm(); ParseOptions::mdx();
let options = ParseOptions::default(); assert!( options.constructs.attention, "should default to `CommonMark` (1)" ); assert!( !options.constructs.gfm_autolink_literal, "should default to `CommonMark` (2)" ); assert!( !options.constructs.mdx_jsx_flow, "should default to `CommonMark` (3)" );
let options = ParseOptions::gfm(); assert!( options.constructs.attention, "should support `gfm` shortcut (1)" ); assert!( options.constructs.gfm_autolink_literal, "should support `gfm` shortcut (2)" ); assert!( !options.constructs.mdx_jsx_flow, "should support `gfm` shortcut (3)" );
let options = ParseOptions::mdx(); assert!( options.constructs.attention, "should support `mdx` shortcut (1)" ); assert!( !options.constructs.gfm_autolink_literal, "should support `mdx` shortcut (2)" ); assert!( options.constructs.mdx_jsx_flow, "should support `mdx` shortcut (3)" );
assert_eq!( format!("{:?}", ParseOptions::default()), "ParseOptions { constructs: Constructs { 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, wikilink: false, gfm_autolink_literal: false, gfm_footnote_definition: false, gfm_label_start_footnote: 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 }, gfm_strikethrough_single_tilde: true, math_text_single_dollar: true, mdx_expression_parse: None, mdx_esm_parse: None }", "should support `Debug` trait" ); assert_eq!( format!("{:?}", ParseOptions { mdx_esm_parse: Some(Box::new(|_value| { Signal::Ok })), mdx_expression_parse: Some(Box::new(|_value, _kind| { Signal::Ok })), ..Default::default() }), "ParseOptions { constructs: Constructs { 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, wikilink: false, gfm_autolink_literal: false, gfm_footnote_definition: false, gfm_label_start_footnote: 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 }, gfm_strikethrough_single_tilde: true, math_text_single_dollar: true, mdx_expression_parse: Some(\"[Function]\"), mdx_esm_parse: Some(\"[Function]\") }", "should support `Debug` trait on mdx functions" ); }
#[test] fn test_compile_options() { CompileOptions::default(); CompileOptions::gfm();
let options = CompileOptions::default(); assert!( !options.allow_dangerous_html, "should default to safe `CommonMark` (1)" ); assert!( !options.gfm_tagfilter, "should default to safe `CommonMark` (2)" );
let options = CompileOptions::gfm(); assert!( !options.allow_dangerous_html, "should support safe `gfm` shortcut (1)" ); assert!( options.gfm_tagfilter, "should support safe `gfm` shortcut (1)" ); }
#[test] fn test_options() { Options::default();
let options = Options::default(); assert!( options.parse.constructs.attention, "should default to safe `CommonMark` (1)" ); assert!( !options.parse.constructs.gfm_autolink_literal, "should default to safe `CommonMark` (2)" ); assert!( !options.parse.constructs.mdx_jsx_flow, "should default to safe `CommonMark` (3)" ); assert!( !options.compile.allow_dangerous_html, "should default to safe `CommonMark` (4)" );
let options = Options::gfm(); assert!( options.parse.constructs.attention, "should support safe `gfm` shortcut (1)" ); assert!( options.parse.constructs.gfm_autolink_literal, "should support safe `gfm` shortcut (2)" ); assert!( !options.parse.constructs.mdx_jsx_flow, "should support safe `gfm` shortcut (3)" ); assert!( !options.compile.allow_dangerous_html, "should support safe `gfm` shortcut (4)" ); }}