From 0ed15bf168d7f5c2b1479f54d520c8fa5d186af2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Oct 2025 00:51:21 +0000 Subject: [PATCH 1/7] Initial plan From 8de799c3aecf75072bcdd202960eb43a776589a9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Oct 2025 00:55:52 +0000 Subject: [PATCH 2/7] Initial plan for comrak 0.43.0 update Co-authored-by: nberlette <11234104+nberlette@users.noreply.github.com> --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 4b54627..e84cf53 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -46,7 +46,7 @@ dependencies = [ [[package]] name = "comrak-wasm" -version = "0.4.2" +version = "0.4.4" dependencies = [ "bumpalo", "comrak", From 846bbc3251e0d51382566f74212af6fa915d1c25 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Oct 2025 00:59:49 +0000 Subject: [PATCH 3/7] Update comrak to 0.43.0 with new extension and render options Co-authored-by: nberlette <11234104+nberlette@users.noreply.github.com> --- Cargo.lock | 129 ++++++++++++-------------- Cargo.toml | 2 +- mod.ts | 262 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 100 ++++++++++++++++++++ 4 files changed, 421 insertions(+), 72 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e84cf53..4eb985e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,42 +3,35 @@ version = 4 [[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "autocfg" -version = "1.4.0" +name = "bumpalo" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] -name = "bumpalo" -version = "3.17.0" +name = "caseless" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "8b6fd507454086c8edfd769ca6ada439193cdb209c7681712ef6275cccbfe5d8" +dependencies = [ + "unicode-normalization", +] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "comrak" -version = "0.17.0" +version = "0.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b9638d96f93f8bf7b050f7505ba0d82b8267f601965b08faa0eb4882a9bba9" +checksum = "5ccfd7678fba9aff54a74a70352d952b345e568823ed9d5a92ebc8ad0adad8ea" dependencies = [ + "caseless", "entities", "memchr", - "once_cell", - "regex", "slug", "typed-arena", "unicode_categories", @@ -59,9 +52,9 @@ dependencies = [ [[package]] name = "deunicode" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc55fe0d1f6c107595572ec8b107c0999bb1a2e0b75e37429a4fb0d6474a0e7d" +checksum = "abd57806937c9cc163efc8ea3910e00a62e2aeb0b8119f1793a978088f8f6b04" [[package]] name = "entities" @@ -81,19 +74,18 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.26" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "lol_alloc" @@ -106,68 +98,39 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "once_cell" -version = "1.21.1" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - [[package]] name = "rustversion" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "scopeguard" @@ -227,15 +190,30 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.100" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "tinyvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "typed-arena" version = "2.0.2" @@ -244,9 +222,18 @@ checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "unicode-normalization" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +dependencies = [ + "tinyvec", +] [[package]] name = "unicode_categories" diff --git a/Cargo.toml b/Cargo.toml index 685e33b..40911ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ mt = ["alloc"] [dependencies] - comrak = { version = "=0.17.0", default-features = false } + comrak = { version = "=0.43.0", default-features = false } js-sys = "=0.3.77" serde = { version = "=1.0.219", features = ["derive"] } wasm-bindgen = { version = "=0.2.100", features = [] } diff --git a/mod.ts b/mod.ts index 187750b..40bb49f 100644 --- a/mod.ts +++ b/mod.ts @@ -170,6 +170,151 @@ export interface ComrakExtensionOptions { * @default {false} */ tasklist?: boolean; + + /** Enables the multiline block quote extension. + * + * Place `>>>` before and after text to make it into a block quote. + * + * ```ts + * import { markdownToHTML } from "@nick/comrak"; + * + * markdownToHTML(">>>\nparagraph\n>>>", { extension: { multilineBlockQuotes: true } }); + * // "
\n

paragraph

\n
\n" + * ``` + * + * @default {false} + */ + multilineBlockQuotes?: boolean; + + /** Enables GitHub style alerts. + * + * ```ts + * import { markdownToHTML } from "@nick/comrak"; + * + * markdownToHTML("> [!note]\n> Something of note", { extension: { alerts: true } }); + * // "
\n

Note

\n

Something of note

\n
\n" + * ``` + * + * @default {false} + */ + alerts?: boolean; + + /** Enables math using dollar syntax. + * + * ```ts + * import { markdownToHTML } from "@nick/comrak"; + * + * markdownToHTML("$1 + 2$ and $$x = y$$", { extension: { mathDollars: true } }); + * // "

1 + 2 and x = y

\n" + * ``` + * + * @default {false} + */ + mathDollars?: boolean; + + /** Enables math using code syntax. + * + * ```ts + * import { markdownToHTML } from "@nick/comrak"; + * + * markdownToHTML("$`1 + 2`$", { extension: { mathCode: true } }); + * // "

1 + 2

\n" + * ``` + * + * @default {false} + */ + mathCode?: boolean; + + /** Enables wikilinks using title after pipe syntax. + * + * ```ts + * import { markdownToHTML } from "@nick/comrak"; + * + * markdownToHTML("[[url|link label]]", { extension: { wikiLinksTitleAfterPipe: true } }); + * // "

link label

\n" + * ``` + * + * @default {false} + */ + wikiLinksTitleAfterPipe?: boolean; + + /** Enables wikilinks using title before pipe syntax. + * + * ```ts + * import { markdownToHTML } from "@nick/comrak"; + * + * markdownToHTML("[[link label|url]]", { extension: { wikiLinksTitleBeforePipe: true } }); + * // "

link label

\n" + * ``` + * + * @default {false} + */ + wikiLinksTitleBeforePipe?: boolean; + + /** Enables underlines using double underscores. + * + * ```ts + * import { markdownToHTML } from "@nick/comrak"; + * + * markdownToHTML("__underlined text__", { extension: { underline: true } }); + * // "

underlined text

\n" + * ``` + * + * @default {false} + */ + underline?: boolean; + + /** Enables subscript text using single tildes. + * + * ```ts + * import { markdownToHTML } from "@nick/comrak"; + * + * markdownToHTML("H~2~O", { extension: { subscript: true } }); + * // "

H2O

\n" + * ``` + * + * @default {false} + */ + subscript?: boolean; + + /** Enables spoilers using double vertical bars. + * + * ```ts + * import { markdownToHTML } from "@nick/comrak"; + * + * markdownToHTML("Darth Vader is ||Luke's father||", { extension: { spoiler: true } }); + * // "

Darth Vader is Luke's father

\n" + * ``` + * + * @default {false} + */ + spoiler?: boolean; + + /** Requires at least one space after a `>` character to generate a blockquote. + * + * ```ts + * import { markdownToHTML } from "@nick/comrak"; + * + * markdownToHTML(">implying implications", { extension: { greentext: true } }); + * // "

>implying implications

\n" + * ``` + * + * @default {false} + */ + greentext?: boolean; + + /** Recognizes many emphasis that appear in CJK contexts. + * + * ```ts + * import { markdownToHTML } from "@nick/comrak"; + * + * markdownToHTML("**この文は重要です。**但这句话并不重要。", { extension: { cjkFriendlyEmphasis: true } }); + * // "

この文は重要です。但这句话并不重要。

\n" + * ``` + * + * @default {false} + */ + cjkFriendlyEmphasis?: boolean; } /** Options for parser functions. */ @@ -215,6 +360,20 @@ export interface ComrakParseOptions { * @default {false} */ relaxedTasklistMatching?: boolean; + + /** Relax parsing of autolinks, allow links to be detected inside brackets + * and allow all url schemes. + * + * ```ts + * import { markdownToHTML } from "@nick/comrak"; + * + * markdownToHTML("[https://foo.com]", { extension: { autolink: true }, parse: { relaxedAutolinks: true } }); + * // "

[https://foo.com]

\n" + * ``` + * + * @default {false} + */ + relaxedAutolinks?: boolean; } /** @@ -335,6 +494,90 @@ export interface ComrakRenderOptions { * @default {"dash"} */ listStyle?: "dash" | "plus" | "star"; + + /** Include source position attributes in HTML and XML output. + * + * ```ts + * import { markdownToHTML } from "@nick/comrak"; + * + * markdownToHTML("Hello *world*!", { render: { sourcepos: true } }); + * // "

Hello world!

\n" + * ``` + * + * @default {false} + */ + sourcepos?: boolean; + + /** Wrap escaped characters in a `` to allow any post-processing to recognize them. + * + * ```ts + * import { markdownToHTML } from "@nick/comrak"; + * + * markdownToHTML("Notify user \\@example", { render: { escapedCharSpans: true } }); + * // "

Notify user @example

\n" + * ``` + * + * @default {false} + */ + escapedCharSpans?: boolean; + + /** Ignore setext headings in input. + * + * ```ts + * import { markdownToHTML } from "@nick/comrak"; + * + * markdownToHTML("setext heading\n---", { render: { ignoreSetext: true } }); + * // "

setext heading

\n
\n" + * ``` + * + * @default {false} + */ + ignoreSetext?: boolean; + + /** Ignore empty links in input. + * + * ```ts + * import { markdownToHTML } from "@nick/comrak"; + * + * markdownToHTML("[]()", { render: { ignoreEmptyLinks: true } }); + * // "

[]()

\n" + * ``` + * + * @default {false} + */ + ignoreEmptyLinks?: boolean; + + /** Enables GFM quirks in HTML output which break CommonMark compatibility. + * + * ```ts + * import { markdownToHTML } from "@nick/comrak"; + * + * markdownToHTML("****abcd****", { render: { gfmQuirks: true } }); + * // "

abcd

\n" + * ``` + * + * @default {false} + */ + gfmQuirks?: boolean; + + /** Prefer fenced code blocks when outputting CommonMark. + * + * @default {false} + */ + preferFenced?: boolean; + + /** Render the image as a figure element with the title as its caption. + * + * ```ts + * import { markdownToHTML } from "@nick/comrak"; + * + * markdownToHTML("![image](https://example.com/image.png \"this is an image\")", { render: { figureWithCaption: true } }); + * // "

\"image\"
this is an image

\n" + * ``` + * + * @default {false} + */ + figureWithCaption?: boolean; } /** @@ -368,9 +611,21 @@ export function markdownToHTML( extension_table: extension.table ?? false, extension_tagfilter: extension.tagfilter ?? false, extension_tasklist: extension.tasklist ?? false, + extension_multiline_block_quotes: extension.multilineBlockQuotes ?? false, + extension_alerts: extension.alerts ?? false, + extension_math_dollars: extension.mathDollars ?? false, + extension_math_code: extension.mathCode ?? false, + extension_wikilinks_title_after_pipe: extension.wikiLinksTitleAfterPipe ?? false, + extension_wikilinks_title_before_pipe: extension.wikiLinksTitleBeforePipe ?? false, + extension_underline: extension.underline ?? false, + extension_subscript: extension.subscript ?? false, + extension_spoiler: extension.spoiler ?? false, + extension_greentext: extension.greentext ?? false, + extension_cjk_friendly_emphasis: extension.cjkFriendlyEmphasis ?? false, parse_default_info_string: parse.defaultInfoString ?? "", parse_smart: parse.smart ?? false, parse_relaxed_tasklist_matching: parse.relaxedTasklistMatching ?? false, + parse_relaxed_autolinks: parse.relaxedAutolinks ?? false, render_escape: render.escape ?? false, render_github_pre_lang: render.githubPreLang ?? false, render_hardbreaks: render.hardbreaks ?? false, @@ -378,6 +633,13 @@ export function markdownToHTML( render_width: render.width ?? 0, render_full_info_string: render.fullInfoString ?? false, render_list_style: render.listStyle ?? "dash", + render_sourcepos: render.sourcepos ?? false, + render_escaped_char_spans: render.escapedCharSpans ?? false, + render_ignore_setext: render.ignoreSetext ?? false, + render_ignore_empty_links: render.ignoreEmptyLinks ?? false, + render_gfm_quirks: render.gfmQuirks ?? false, + render_prefer_fenced: render.preferFenced ?? false, + render_figure_with_caption: render.figureWithCaption ?? false, } satisfies Options; return markdown_to_html(markdown, opts); } diff --git a/src/lib.rs b/src/lib.rs index f0facab..da49089 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -59,9 +59,33 @@ struct FlatComrakOptions { extension_tagfilter: bool, extension_tasklist: bool, #[serde(default)] + extension_multiline_block_quotes: bool, + #[serde(default)] + extension_alerts: bool, + #[serde(default)] + extension_math_dollars: bool, + #[serde(default)] + extension_math_code: bool, + #[serde(default)] + extension_wikilinks_title_after_pipe: bool, + #[serde(default)] + extension_wikilinks_title_before_pipe: bool, + #[serde(default)] + extension_underline: bool, + #[serde(default)] + extension_subscript: bool, + #[serde(default)] + extension_spoiler: bool, + #[serde(default)] + extension_greentext: bool, + #[serde(default)] + extension_cjk_friendly_emphasis: bool, + #[serde(default)] parse_default_info_string: Option, parse_smart: bool, parse_relaxed_tasklist_matching: bool, + #[serde(default)] + parse_relaxed_autolinks: bool, render_escape: bool, render_full_info_string: bool, render_github_pre_lang: bool, @@ -70,6 +94,20 @@ struct FlatComrakOptions { render_list_style: ComrakListStyleType, render_unsafe: bool, render_width: usize, + #[serde(default)] + render_sourcepos: bool, + #[serde(default)] + render_escaped_char_spans: bool, + #[serde(default)] + render_ignore_setext: bool, + #[serde(default)] + render_ignore_empty_links: bool, + #[serde(default)] + render_gfm_quirks: bool, + #[serde(default)] + render_prefer_fenced: bool, + #[serde(default)] + render_figure_with_caption: bool, } impl Default for FlatComrakOptions { @@ -85,9 +123,21 @@ impl Default for FlatComrakOptions { extension_table: true, extension_tagfilter: true, extension_tasklist: true, + extension_multiline_block_quotes: false, + extension_alerts: false, + extension_math_dollars: false, + extension_math_code: false, + extension_wikilinks_title_after_pipe: false, + extension_wikilinks_title_before_pipe: false, + extension_underline: false, + extension_subscript: false, + extension_spoiler: false, + extension_greentext: false, + extension_cjk_friendly_emphasis: false, parse_relaxed_tasklist_matching: false, parse_default_info_string: None, parse_smart: true, + parse_relaxed_autolinks: false, render_escape: true, render_github_pre_lang: true, render_hardbreaks: false, @@ -95,6 +145,13 @@ impl Default for FlatComrakOptions { render_width: 80, render_list_style: Default::default(), render_full_info_string: false, + render_sourcepos: false, + render_escaped_char_spans: false, + render_ignore_setext: false, + render_ignore_empty_links: false, + render_gfm_quirks: false, + render_prefer_fenced: false, + render_figure_with_caption: false, } } } @@ -112,9 +169,21 @@ export interface Options { extension_table: boolean; extension_tagfilter: boolean; extension_tasklist: boolean; + extension_multiline_block_quotes?: boolean; + extension_alerts?: boolean; + extension_math_dollars?: boolean; + extension_math_code?: boolean; + extension_wikilinks_title_after_pipe?: boolean; + extension_wikilinks_title_before_pipe?: boolean; + extension_underline?: boolean; + extension_subscript?: boolean; + extension_spoiler?: boolean; + extension_greentext?: boolean; + extension_cjk_friendly_emphasis?: boolean; parse_default_info_string?: string; parse_smart: boolean; parse_relaxed_tasklist_matching?: boolean; + parse_relaxed_autolinks?: boolean; render_escape: boolean; render_full_info_string?: boolean; render_github_pre_lang: boolean; @@ -122,6 +191,13 @@ export interface Options { render_list_style?: "dash" | "plus" | "star"; render_unsafe: boolean; render_width: number; + render_sourcepos?: boolean; + render_escaped_char_spans?: boolean; + render_ignore_setext?: boolean; + render_ignore_empty_links?: boolean; + render_gfm_quirks?: boolean; + render_prefer_fenced?: boolean; + render_figure_with_caption?: boolean; } "#; @@ -144,11 +220,28 @@ pub fn markdown_to_html( table: opts.extension_table, tagfilter: opts.extension_tagfilter, tasklist: opts.extension_tasklist, + multiline_block_quotes: opts.extension_multiline_block_quotes, + alerts: opts.extension_alerts, + math_dollars: opts.extension_math_dollars, + math_code: opts.extension_math_code, + wikilinks_title_after_pipe: opts.extension_wikilinks_title_after_pipe, + wikilinks_title_before_pipe: opts.extension_wikilinks_title_before_pipe, + underline: opts.extension_underline, + subscript: opts.extension_subscript, + spoiler: opts.extension_spoiler, + greentext: opts.extension_greentext, + cjk_friendly_emphasis: opts.extension_cjk_friendly_emphasis, + image_url_rewriter: None, + link_url_rewriter: None, + #[cfg(feature = "shortcodes")] + shortcodes: false, }, parse: ComrakParseOptions { default_info_string: opts.parse_default_info_string, smart: opts.parse_smart, relaxed_tasklist_matching: opts.parse_relaxed_tasklist_matching, + relaxed_autolinks: opts.parse_relaxed_autolinks, + broken_link_callback: None, }, render: ComrakRenderOptions { escape: opts.render_escape, @@ -158,6 +251,13 @@ pub fn markdown_to_html( width: opts.render_width, full_info_string: opts.render_full_info_string, list_style: opts.render_list_style, + sourcepos: opts.render_sourcepos, + escaped_char_spans: opts.render_escaped_char_spans, + ignore_setext: opts.render_ignore_setext, + ignore_empty_links: opts.render_ignore_empty_links, + gfm_quirks: opts.render_gfm_quirks, + prefer_fenced: opts.render_prefer_fenced, + figure_with_caption: opts.render_figure_with_caption, }, }; let html = comrak::markdown_to_html(md, &opts); From 17cd3f6c581171e77fbac0976794143ade6b7a18 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Oct 2025 01:09:10 +0000 Subject: [PATCH 4/7] Add missing render options (tasklist_classes, ol_width, experimental_minimize_commonmark) Co-authored-by: nberlette <11234104+nberlette@users.noreply.github.com> --- mod.ts | 28 ++++++++++++++++++++++++++++ src/lib.rs | 15 +++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/mod.ts b/mod.ts index 40bb49f..864754b 100644 --- a/mod.ts +++ b/mod.ts @@ -578,6 +578,31 @@ export interface ComrakRenderOptions { * @default {false} */ figureWithCaption?: boolean; + + /** Add classes to the output of the tasklist extension. + * + * ```ts + * import { markdownToHTML } from "@nick/comrak"; + * + * markdownToHTML("- [ ] Foo", { extension: { tasklist: true }, render: { tasklistClasses: true } }); + * // "\n" + * ``` + * + * @default {false} + */ + tasklistClasses?: boolean; + + /** Render ordered list with a minimum marker width. + * + * @default {0} + */ + olWidth?: number; + + /** Minimise escapes used in CommonMark output. + * + * @default {false} + */ + experimentalMinimizeCommonmark?: boolean; } /** @@ -640,6 +665,9 @@ export function markdownToHTML( render_gfm_quirks: render.gfmQuirks ?? false, render_prefer_fenced: render.preferFenced ?? false, render_figure_with_caption: render.figureWithCaption ?? false, + render_tasklist_classes: render.tasklistClasses ?? false, + render_ol_width: render.olWidth ?? 0, + render_experimental_minimize_commonmark: render.experimentalMinimizeCommonmark ?? false, } satisfies Options; return markdown_to_html(markdown, opts); } diff --git a/src/lib.rs b/src/lib.rs index da49089..e09d728 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -108,6 +108,12 @@ struct FlatComrakOptions { render_prefer_fenced: bool, #[serde(default)] render_figure_with_caption: bool, + #[serde(default)] + render_tasklist_classes: bool, + #[serde(default)] + render_ol_width: usize, + #[serde(default)] + render_experimental_minimize_commonmark: bool, } impl Default for FlatComrakOptions { @@ -152,6 +158,9 @@ impl Default for FlatComrakOptions { render_gfm_quirks: false, render_prefer_fenced: false, render_figure_with_caption: false, + render_tasklist_classes: false, + render_ol_width: 0, + render_experimental_minimize_commonmark: false, } } } @@ -198,6 +207,9 @@ export interface Options { render_gfm_quirks?: boolean; render_prefer_fenced?: boolean; render_figure_with_caption?: boolean; + render_tasklist_classes?: boolean; + render_ol_width?: number; + render_experimental_minimize_commonmark?: boolean; } "#; @@ -258,6 +270,9 @@ pub fn markdown_to_html( gfm_quirks: opts.render_gfm_quirks, prefer_fenced: opts.render_prefer_fenced, figure_with_caption: opts.render_figure_with_caption, + tasklist_classes: opts.render_tasklist_classes, + ol_width: opts.render_ol_width, + experimental_minimize_commonmark: opts.render_experimental_minimize_commonmark, }, }; let html = comrak::markdown_to_html(md, &opts); From 73b812cc7479bbc64d340d2861c9494e83438922 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 17 Oct 2025 00:47:43 +0000 Subject: [PATCH 5/7] Refactor to nested options structure with serde rename Co-authored-by: nberlette <11234104+nberlette@users.noreply.github.com> --- mod.ts | 97 ++++---------- src/lib.rs | 380 +++++++++++++++++++++++++---------------------------- 2 files changed, 201 insertions(+), 276 deletions(-) diff --git a/mod.ts b/mod.ts index 864754b..cf6723a 100644 --- a/mod.ts +++ b/mod.ts @@ -1,5 +1,5 @@ // @ts-types="./lib/comrak_wasm.d.ts" -import { markdown_to_html, type Options } from "./lib/comrak_wasm.js"; +import { markdown_to_html } from "./lib/comrak_wasm.js"; /** * Options for the {@linkcode markdownToHTML} function. @@ -177,9 +177,10 @@ export interface ComrakExtensionOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML(">>>\nparagraph\n>>>", { extension: { multilineBlockQuotes: true } }); - * // "
\n

paragraph

\n
\n" + * const html = markdownToHTML(">>>\nparagraph\n>>>", { extension: { multilineBlockQuotes: true } }); + * assert.equal(html, "
\n

paragraph

\n
\n"); * ``` * * @default {false} @@ -190,9 +191,10 @@ export interface ComrakExtensionOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("> [!note]\n> Something of note", { extension: { alerts: true } }); - * // "
\n

Note

\n

Something of note

\n
\n" + * const html = markdownToHTML("> [!note]\n> Something of note", { extension: { alerts: true } }); + * assert.equal(html, "
\n

Note

\n

Something of note

\n
\n"); * ``` * * @default {false} @@ -203,9 +205,10 @@ export interface ComrakExtensionOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("$1 + 2$ and $$x = y$$", { extension: { mathDollars: true } }); - * // "

1 + 2 and x = y

\n" + * const html = markdownToHTML("$1 + 2$ and $$x = y$$", { extension: { mathDollars: true } }); + * assert.equal(html, "

1 + 2 and x = y

\n"); * ``` * * @default {false} @@ -216,40 +219,34 @@ export interface ComrakExtensionOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("$`1 + 2`$", { extension: { mathCode: true } }); - * // "

1 + 2

\n" + * const html = markdownToHTML("$`1 + 2`$", { extension: { mathCode: true } }); + * assert.equal(html, "

1 + 2

\n"); * ``` * * @default {false} */ mathCode?: boolean; - /** Enables wikilinks using title after pipe syntax. + /** Enables wikilinks extension. * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("[[url|link label]]", { extension: { wikiLinksTitleAfterPipe: true } }); - * // "

link label

\n" - * ``` - * - * @default {false} - */ - wikiLinksTitleAfterPipe?: boolean; - - /** Enables wikilinks using title before pipe syntax. + * // Title after pipe: [[url|title]] + * const html1 = markdownToHTML("[[url|link label]]", { extension: { wikilinksTitle: "after" } }); + * assert.equal(html1, "

link label

\n"); * - * ```ts - * import { markdownToHTML } from "@nick/comrak"; - * - * markdownToHTML("[[link label|url]]", { extension: { wikiLinksTitleBeforePipe: true } }); - * // "

link label

\n" + * // Title before pipe: [[title|url]] + * const html2 = markdownToHTML("[[link label|url]]", { extension: { wikilinksTitle: "before" } }); + * assert.equal(html2, "

link label

\n"); * ``` * - * @default {false} + * @default {undefined} */ - wikiLinksTitleBeforePipe?: boolean; + wikilinksTitle?: "before" | "after"; /** Enables underlines using double underscores. * @@ -623,51 +620,5 @@ export function markdownToHTML( markdown: string, options: ComrakOptions = {}, ): string { - const { extension = {}, parse = {}, render = {} } = options; - - const opts = { - extension_autolink: extension.autolink ?? false, - extension_description_lists: extension.descriptionLists ?? false, - extension_footnotes: extension.footnotes ?? false, - extension_front_matter_delimiter: extension.frontMatterDelimiter ?? "---", - extension_header_ids: extension.headerIDs ?? "", - extension_strikethrough: extension.strikethrough ?? false, - extension_superscript: extension.superscript ?? false, - extension_table: extension.table ?? false, - extension_tagfilter: extension.tagfilter ?? false, - extension_tasklist: extension.tasklist ?? false, - extension_multiline_block_quotes: extension.multilineBlockQuotes ?? false, - extension_alerts: extension.alerts ?? false, - extension_math_dollars: extension.mathDollars ?? false, - extension_math_code: extension.mathCode ?? false, - extension_wikilinks_title_after_pipe: extension.wikiLinksTitleAfterPipe ?? false, - extension_wikilinks_title_before_pipe: extension.wikiLinksTitleBeforePipe ?? false, - extension_underline: extension.underline ?? false, - extension_subscript: extension.subscript ?? false, - extension_spoiler: extension.spoiler ?? false, - extension_greentext: extension.greentext ?? false, - extension_cjk_friendly_emphasis: extension.cjkFriendlyEmphasis ?? false, - parse_default_info_string: parse.defaultInfoString ?? "", - parse_smart: parse.smart ?? false, - parse_relaxed_tasklist_matching: parse.relaxedTasklistMatching ?? false, - parse_relaxed_autolinks: parse.relaxedAutolinks ?? false, - render_escape: render.escape ?? false, - render_github_pre_lang: render.githubPreLang ?? false, - render_hardbreaks: render.hardbreaks ?? false, - render_unsafe: render.unsafe ?? false, - render_width: render.width ?? 0, - render_full_info_string: render.fullInfoString ?? false, - render_list_style: render.listStyle ?? "dash", - render_sourcepos: render.sourcepos ?? false, - render_escaped_char_spans: render.escapedCharSpans ?? false, - render_ignore_setext: render.ignoreSetext ?? false, - render_ignore_empty_links: render.ignoreEmptyLinks ?? false, - render_gfm_quirks: render.gfmQuirks ?? false, - render_prefer_fenced: render.preferFenced ?? false, - render_figure_with_caption: render.figureWithCaption ?? false, - render_tasklist_classes: render.tasklistClasses ?? false, - render_ol_width: render.olWidth ?? 0, - render_experimental_minimize_commonmark: render.experimentalMinimizeCommonmark ?? false, - } satisfies Options; - return markdown_to_html(markdown, opts); + return markdown_to_html(markdown, options); } diff --git a/src/lib.rs b/src/lib.rs index e09d728..9123202 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,237 +44,211 @@ pub enum ListStyleType { Star = 42, } +#[derive(Deserialize, Debug, Clone, Copy)] +#[serde(rename_all = "lowercase")] +pub enum WikiLinksTitle { + Before, + After, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase", default)] +struct ExtensionOptions { + autolink: bool, + description_lists: bool, + footnotes: bool, + front_matter_delimiter: Option, + #[serde(rename = "headerIDs")] + header_ids: Option, + strikethrough: bool, + superscript: bool, + table: bool, + tagfilter: bool, + tasklist: bool, + multiline_block_quotes: bool, + alerts: bool, + math_dollars: bool, + math_code: bool, + wikilinks_title: Option, + underline: bool, + subscript: bool, + spoiler: bool, + greentext: bool, + cjk_friendly_emphasis: bool, +} + #[derive(Deserialize)] -struct FlatComrakOptions { - extension_autolink: bool, - extension_description_lists: bool, - extension_footnotes: bool, - #[serde(default)] - extension_front_matter_delimiter: Option, - #[serde(default)] - extension_header_ids: Option, - extension_strikethrough: bool, - extension_superscript: bool, - extension_table: bool, - extension_tagfilter: bool, - extension_tasklist: bool, - #[serde(default)] - extension_multiline_block_quotes: bool, - #[serde(default)] - extension_alerts: bool, - #[serde(default)] - extension_math_dollars: bool, - #[serde(default)] - extension_math_code: bool, - #[serde(default)] - extension_wikilinks_title_after_pipe: bool, - #[serde(default)] - extension_wikilinks_title_before_pipe: bool, - #[serde(default)] - extension_underline: bool, - #[serde(default)] - extension_subscript: bool, - #[serde(default)] - extension_spoiler: bool, - #[serde(default)] - extension_greentext: bool, - #[serde(default)] - extension_cjk_friendly_emphasis: bool, - #[serde(default)] - parse_default_info_string: Option, - parse_smart: bool, - parse_relaxed_tasklist_matching: bool, - #[serde(default)] - parse_relaxed_autolinks: bool, - render_escape: bool, - render_full_info_string: bool, - render_github_pre_lang: bool, - render_hardbreaks: bool, +#[serde(rename_all = "camelCase", default)] +struct ParseOptions { + default_info_string: Option, + smart: bool, + relaxed_tasklist_matching: bool, + relaxed_autolinks: bool, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase", default)] +struct RenderOptions { + escape: bool, + full_info_string: bool, + github_pre_lang: bool, + hardbreaks: bool, #[serde(default, with = "ListStyleType")] - render_list_style: ComrakListStyleType, - render_unsafe: bool, - render_width: usize, - #[serde(default)] - render_sourcepos: bool, - #[serde(default)] - render_escaped_char_spans: bool, - #[serde(default)] - render_ignore_setext: bool, - #[serde(default)] - render_ignore_empty_links: bool, - #[serde(default)] - render_gfm_quirks: bool, - #[serde(default)] - render_prefer_fenced: bool, - #[serde(default)] - render_figure_with_caption: bool, - #[serde(default)] - render_tasklist_classes: bool, - #[serde(default)] - render_ol_width: usize, - #[serde(default)] - render_experimental_minimize_commonmark: bool, + list_style: ComrakListStyleType, + #[serde(rename = "unsafe")] + unsafe_: bool, + width: usize, + sourcepos: bool, + escaped_char_spans: bool, + ignore_setext: bool, + ignore_empty_links: bool, + gfm_quirks: bool, + prefer_fenced: bool, + figure_with_caption: bool, + tasklist_classes: bool, + ol_width: usize, + experimental_minimize_commonmark: bool, +} + +#[derive(Deserialize, Default)] +#[serde(rename_all = "camelCase", default)] +struct Options { + extension: ExtensionOptions, + parse: ParseOptions, + render: RenderOptions, +} + +impl Default for ExtensionOptions { + fn default() -> Self { + Self { + autolink: true, + description_lists: true, + footnotes: true, + front_matter_delimiter: None, + header_ids: None, + strikethrough: true, + superscript: true, + table: true, + tagfilter: true, + tasklist: true, + multiline_block_quotes: false, + alerts: false, + math_dollars: false, + math_code: false, + wikilinks_title: None, + underline: false, + subscript: false, + spoiler: false, + greentext: false, + cjk_friendly_emphasis: false, + } + } } -impl Default for FlatComrakOptions { +impl Default for ParseOptions { fn default() -> Self { Self { - extension_autolink: true, - extension_description_lists: true, - extension_footnotes: true, - extension_front_matter_delimiter: None, - extension_header_ids: None, - extension_strikethrough: true, - extension_superscript: true, - extension_table: true, - extension_tagfilter: true, - extension_tasklist: true, - extension_multiline_block_quotes: false, - extension_alerts: false, - extension_math_dollars: false, - extension_math_code: false, - extension_wikilinks_title_after_pipe: false, - extension_wikilinks_title_before_pipe: false, - extension_underline: false, - extension_subscript: false, - extension_spoiler: false, - extension_greentext: false, - extension_cjk_friendly_emphasis: false, - parse_relaxed_tasklist_matching: false, - parse_default_info_string: None, - parse_smart: true, - parse_relaxed_autolinks: false, - render_escape: true, - render_github_pre_lang: true, - render_hardbreaks: false, - render_unsafe: false, - render_width: 80, - render_list_style: Default::default(), - render_full_info_string: false, - render_sourcepos: false, - render_escaped_char_spans: false, - render_ignore_setext: false, - render_ignore_empty_links: false, - render_gfm_quirks: false, - render_prefer_fenced: false, - render_figure_with_caption: false, - render_tasklist_classes: false, - render_ol_width: 0, - render_experimental_minimize_commonmark: false, + default_info_string: None, + smart: true, + relaxed_tasklist_matching: false, + relaxed_autolinks: false, } } } -#[wasm_bindgen(typescript_custom_section)] -pub const OPTIONS_TYPE: &'static str = r#" -export interface Options { - extension_autolink: boolean; - extension_description_lists: boolean; - extension_footnotes: boolean; - extension_front_matter_delimiter?: string; - extension_header_ids?: string; - extension_strikethrough: boolean; - extension_superscript: boolean; - extension_table: boolean; - extension_tagfilter: boolean; - extension_tasklist: boolean; - extension_multiline_block_quotes?: boolean; - extension_alerts?: boolean; - extension_math_dollars?: boolean; - extension_math_code?: boolean; - extension_wikilinks_title_after_pipe?: boolean; - extension_wikilinks_title_before_pipe?: boolean; - extension_underline?: boolean; - extension_subscript?: boolean; - extension_spoiler?: boolean; - extension_greentext?: boolean; - extension_cjk_friendly_emphasis?: boolean; - parse_default_info_string?: string; - parse_smart: boolean; - parse_relaxed_tasklist_matching?: boolean; - parse_relaxed_autolinks?: boolean; - render_escape: boolean; - render_full_info_string?: boolean; - render_github_pre_lang: boolean; - render_hardbreaks: boolean; - render_list_style?: "dash" | "plus" | "star"; - render_unsafe: boolean; - render_width: number; - render_sourcepos?: boolean; - render_escaped_char_spans?: boolean; - render_ignore_setext?: boolean; - render_ignore_empty_links?: boolean; - render_gfm_quirks?: boolean; - render_prefer_fenced?: boolean; - render_figure_with_caption?: boolean; - render_tasklist_classes?: boolean; - render_ol_width?: number; - render_experimental_minimize_commonmark?: boolean; +impl Default for RenderOptions { + fn default() -> Self { + Self { + escape: true, + full_info_string: false, + github_pre_lang: true, + hardbreaks: false, + list_style: Default::default(), + unsafe_: false, + width: 80, + sourcepos: false, + escaped_char_spans: false, + ignore_setext: false, + ignore_empty_links: false, + gfm_quirks: false, + prefer_fenced: false, + figure_with_caption: false, + tasklist_classes: false, + ol_width: 0, + experimental_minimize_commonmark: false, + } + } } -"#; #[wasm_bindgen] pub fn markdown_to_html( md: &str, - #[wasm_bindgen(unchecked_param_type = "Options")] opts: JsValue, + #[wasm_bindgen(unchecked_param_type = "ComrakOptions")] opts: JsValue, ) -> Result { - let opts: FlatComrakOptions = + let opts: Options = from_value(opts.clone()).map_err(|err| TypeError::new(&err.to_string()))?; - let opts = ComrakOptions { + + let (wikilinks_title_after_pipe, wikilinks_title_before_pipe) = match opts.extension.wikilinks_title { + Some(WikiLinksTitle::After) => (true, false), + Some(WikiLinksTitle::Before) => (false, true), + None => (false, false), + }; + + let comrak_opts = ComrakOptions { extension: ComrakExtensionOptions { - autolink: opts.extension_autolink, - description_lists: opts.extension_description_lists, - footnotes: opts.extension_footnotes, - front_matter_delimiter: opts.extension_front_matter_delimiter, - header_ids: opts.extension_header_ids, - strikethrough: opts.extension_strikethrough, - superscript: opts.extension_superscript, - table: opts.extension_table, - tagfilter: opts.extension_tagfilter, - tasklist: opts.extension_tasklist, - multiline_block_quotes: opts.extension_multiline_block_quotes, - alerts: opts.extension_alerts, - math_dollars: opts.extension_math_dollars, - math_code: opts.extension_math_code, - wikilinks_title_after_pipe: opts.extension_wikilinks_title_after_pipe, - wikilinks_title_before_pipe: opts.extension_wikilinks_title_before_pipe, - underline: opts.extension_underline, - subscript: opts.extension_subscript, - spoiler: opts.extension_spoiler, - greentext: opts.extension_greentext, - cjk_friendly_emphasis: opts.extension_cjk_friendly_emphasis, + autolink: opts.extension.autolink, + description_lists: opts.extension.description_lists, + footnotes: opts.extension.footnotes, + front_matter_delimiter: opts.extension.front_matter_delimiter, + header_ids: opts.extension.header_ids, + strikethrough: opts.extension.strikethrough, + superscript: opts.extension.superscript, + table: opts.extension.table, + tagfilter: opts.extension.tagfilter, + tasklist: opts.extension.tasklist, + multiline_block_quotes: opts.extension.multiline_block_quotes, + alerts: opts.extension.alerts, + math_dollars: opts.extension.math_dollars, + math_code: opts.extension.math_code, + wikilinks_title_after_pipe, + wikilinks_title_before_pipe, + underline: opts.extension.underline, + subscript: opts.extension.subscript, + spoiler: opts.extension.spoiler, + greentext: opts.extension.greentext, + cjk_friendly_emphasis: opts.extension.cjk_friendly_emphasis, image_url_rewriter: None, link_url_rewriter: None, #[cfg(feature = "shortcodes")] shortcodes: false, }, parse: ComrakParseOptions { - default_info_string: opts.parse_default_info_string, - smart: opts.parse_smart, - relaxed_tasklist_matching: opts.parse_relaxed_tasklist_matching, - relaxed_autolinks: opts.parse_relaxed_autolinks, + default_info_string: opts.parse.default_info_string, + smart: opts.parse.smart, + relaxed_tasklist_matching: opts.parse.relaxed_tasklist_matching, + relaxed_autolinks: opts.parse.relaxed_autolinks, broken_link_callback: None, }, render: ComrakRenderOptions { - escape: opts.render_escape, - github_pre_lang: opts.render_github_pre_lang, - hardbreaks: opts.render_hardbreaks, - unsafe_: opts.render_unsafe, - width: opts.render_width, - full_info_string: opts.render_full_info_string, - list_style: opts.render_list_style, - sourcepos: opts.render_sourcepos, - escaped_char_spans: opts.render_escaped_char_spans, - ignore_setext: opts.render_ignore_setext, - ignore_empty_links: opts.render_ignore_empty_links, - gfm_quirks: opts.render_gfm_quirks, - prefer_fenced: opts.render_prefer_fenced, - figure_with_caption: opts.render_figure_with_caption, - tasklist_classes: opts.render_tasklist_classes, - ol_width: opts.render_ol_width, - experimental_minimize_commonmark: opts.render_experimental_minimize_commonmark, + escape: opts.render.escape, + github_pre_lang: opts.render.github_pre_lang, + hardbreaks: opts.render.hardbreaks, + unsafe_: opts.render.unsafe_, + width: opts.render.width, + full_info_string: opts.render.full_info_string, + list_style: opts.render.list_style, + sourcepos: opts.render.sourcepos, + escaped_char_spans: opts.render.escaped_char_spans, + ignore_setext: opts.render.ignore_setext, + ignore_empty_links: opts.render.ignore_empty_links, + gfm_quirks: opts.render.gfm_quirks, + prefer_fenced: opts.render.prefer_fenced, + figure_with_caption: opts.render.figure_with_caption, + tasklist_classes: opts.render.tasklist_classes, + ol_width: opts.render.ol_width, + experimental_minimize_commonmark: opts.render.experimental_minimize_commonmark, }, }; - let html = comrak::markdown_to_html(md, &opts); + let html = comrak::markdown_to_html(md, &comrak_opts); Ok(html) } From eb303ccc3ad916da597ff8d90eb2803917cab5fd Mon Sep 17 00:00:00 2001 From: Nick Berlette Date: Thu, 16 Oct 2025 18:25:35 -0700 Subject: [PATCH 6/7] Update mod.ts Signed-off-by: Nick Berlette --- mod.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mod.ts b/mod.ts index cf6723a..543dc4e 100644 --- a/mod.ts +++ b/mod.ts @@ -172,6 +172,8 @@ export interface ComrakExtensionOptions { tasklist?: boolean; /** Enables the multiline block quote extension. + /** + * Enables the multiline block quote extension. * * Place `>>>` before and after text to make it into a block quote. * From a747f82757f6b167db6ed13eb2d32499d66abc15 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 17 Oct 2025 01:32:15 +0000 Subject: [PATCH 7/7] Update all doc comments to use assertions pattern Co-authored-by: nberlette <11234104+nberlette@users.noreply.github.com> --- mod.ts | 178 +++++++++++++++++++++++++++++++++------------------------ 1 file changed, 104 insertions(+), 74 deletions(-) diff --git a/mod.ts b/mod.ts index 543dc4e..3451b49 100644 --- a/mod.ts +++ b/mod.ts @@ -21,9 +21,10 @@ export interface ComrakExtensionOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("Hello www.github.com.\n", { extension: { autolink: true } }); - * // "

Hello www.github.com.

\n" + * const html = markdownToHTML("Hello www.github.com.\n", { extension: { autolink: true } }); + * assert.equal(html, "

Hello www.github.com.

\n"); * ``` * * @default {false} @@ -37,9 +38,10 @@ export interface ComrakExtensionOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("Term\n\n: Definition", { extension: { descriptionLists: true } }); - * // "
Term
\n
\n

Definition

\n
\n
\n" + * const html = markdownToHTML("Term\n\n: Definition", { extension: { descriptionLists: true } }); + * assert.equal(html, "
Term
\n
\n

Definition

\n
\n
\n"); * ``` * * @default {false} @@ -54,9 +56,10 @@ export interface ComrakExtensionOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("Hi[^x].\n\n[^x]: A greeting.\n", { extension: { footnotes: true } }); - * // "

Hi1.

\n
\n
    \n
  1. \n

    A greeting.

    \n
  2. \n
\n
\n" + * const html = markdownToHTML("Hi[^x].\n\n[^x]: A greeting.\n", { extension: { footnotes: true } }); + * assert.equal(html, "

Hi1.

\n
\n
    \n
  1. \n

    A greeting.

    \n
  2. \n
\n
\n"); * ``` * * @default {false} @@ -72,9 +75,10 @@ export interface ComrakExtensionOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("---\nlayout: post\n---\nText\n", { extension: { frontMatterDelimiter: "---" } }); - * // "

Text

\n" + * const html = markdownToHTML("---\nlayout: post\n---\nText\n", { extension: { frontMatterDelimiter: "---" } }); + * assert.equal(html, "

Text

\n"); * ``` * * @default {null} @@ -85,9 +89,10 @@ export interface ComrakExtensionOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("# README\n", { extension: { headerIDs: "user-content-" } }); - * // "

README

\n" + * const html = markdownToHTML("# README\n", { extension: { headerIDs: "user-content-" } }); + * assert.equal(html, "

README

\n"); * ``` * * @default {null} @@ -100,9 +105,10 @@ export interface ComrakExtensionOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("Hello ~world~ there.\n", { extension: { strikethrough: true } }); - * // "

Hello world there.

\n" + * const html = markdownToHTML("Hello ~world~ there.\n", { extension: { strikethrough: true } }); + * assert.equal(html, "

Hello world there.

\n"); * ``` * * @default {false} @@ -113,9 +119,10 @@ export interface ComrakExtensionOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("e = mc^2^.\n", { extension: { superscript: true } }); - * // "

e = mc2.

\n" + * const html = markdownToHTML("e = mc^2^.\n", { extension: { superscript: true } }); + * assert.equal(html, "

e = mc2.

\n"); * ``` * * @default {false} @@ -128,10 +135,10 @@ export interface ComrakExtensionOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("| a | b |\n|---|---|\n| c | d |\n", { extension: { table: true } }); - * // "\n\n\n\n\n\n\n" + - * // "\n\n\n\n\n\n
ab
cd
\n" + * const html = markdownToHTML("| a | b |\n|---|---|\n| c | d |\n", { extension: { table: true } }); + * assert.equal(html, "\n\n\n\n\n\n\n\n\n\n\n\n\n
ab
cd
\n"); * ``` * * @default {false} @@ -144,9 +151,10 @@ export interface ComrakExtensionOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("Hello .\n\n<xmp>", { extension: { tagfilter: true } }); - * // "<p>Hello &lt;xmp>.</p>\n&lt;xmp>\n" + * const html = markdownToHTML("Hello <xmp>.\n\n<xmp>", { extension: { tagfilter: true } }); + * assert.equal(html, "<p>Hello &lt;xmp>.</p>\n&lt;xmp>\n"); * ``` * * @default {false} @@ -161,10 +169,10 @@ export interface ComrakExtensionOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("* [x] Done\n* [ ] Not done\n", { extension: { tasklist: true } }); - * // "<ul>\n<li><input type=\"checkbox\" disabled=\"\" checked=\"\" /> Done</li>\n\ - * // <li><input type=\"checkbox\" disabled=\"\" /> Not done</li>\n</ul>\n" + * const html = markdownToHTML("* [x] Done\n* [ ] Not done\n", { extension: { tasklist: true } }); + * assert.equal(html, "<ul>\n<li><input type=\"checkbox\" disabled=\"\" checked=\"\" /> Done</li>\n<li><input type=\"checkbox\" disabled=\"\" /> Not done</li>\n</ul>\n"); * ``` * * @default {false} @@ -254,9 +262,10 @@ export interface ComrakExtensionOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("__underlined text__", { extension: { underline: true } }); - * // "<p><u>underlined text</u></p>\n" + * const html = markdownToHTML("__underlined text__", { extension: { underline: true } }); + * assert.equal(html, "<p><u>underlined text</u></p>\n"); * ``` * * @default {false} @@ -267,9 +276,10 @@ export interface ComrakExtensionOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("H~2~O", { extension: { subscript: true } }); - * // "<p>H<sub>2</sub>O</p>\n" + * const html = markdownToHTML("H~2~O", { extension: { subscript: true } }); + * assert.equal(html, "<p>H<sub>2</sub>O</p>\n"); * ``` * * @default {false} @@ -280,9 +290,10 @@ export interface ComrakExtensionOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("Darth Vader is ||Luke's father||", { extension: { spoiler: true } }); - * // "<p>Darth Vader is <span class=\"spoiler\">Luke's father</span></p>\n" + * const html = markdownToHTML("Darth Vader is ||Luke's father||", { extension: { spoiler: true } }); + * assert.equal(html, "<p>Darth Vader is <span class=\"spoiler\">Luke's father</span></p>\n"); * ``` * * @default {false} @@ -293,9 +304,10 @@ export interface ComrakExtensionOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML(">implying implications", { extension: { greentext: true } }); - * // "<p>&gt;implying implications</p>\n" + * const html = markdownToHTML(">implying implications", { extension: { greentext: true } }); + * assert.equal(html, "<p>&gt;implying implications</p>\n"); * ``` * * @default {false} @@ -306,9 +318,10 @@ export interface ComrakExtensionOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("**この文は重要です。**但这句话并不重要。", { extension: { cjkFriendlyEmphasis: true } }); - * // "<p><strong>この文は重要です。</strong>但这句话并不重要。</p>\n" + * const html = markdownToHTML("**この文は重要です。**但这句话并不重要。", { extension: { cjkFriendlyEmphasis: true } }); + * assert.equal(html, "<p><strong>この文は重要です。</strong>但这句话并不重要。</p>\n"); * ``` * * @default {false} @@ -323,12 +336,13 @@ export interface ComrakParseOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("\`\`\`\nfn hello();\n\`\`\`\n"); - * // "<pre><code>fn hello();\n</code></pre>\n" + * let html = markdownToHTML("\`\`\`\nfn hello();\n\`\`\`\n"); + * assert.equal(html, "<pre><code>fn hello();\n</code></pre>\n"); * - * markdownToHTML("\`\`\`\nfn hello();\n\`\`\`\n", { parse: { defaultInfoString: "rust" } }); - * // "<pre><code class=\"language-rust\">fn hello();\n</code></pre>\n" + * html = markdownToHTML("\`\`\`\nfn hello();\n\`\`\`\n", { parse: { defaultInfoString: "rust" } }); + * assert.equal(html, "<pre><code class=\"language-rust\">fn hello();\n</code></pre>\n"); * ``` * * @default {null} @@ -338,14 +352,17 @@ export interface ComrakParseOptions { /** Punctuation (quotes, full-stops and hyphens) are converted into ‘smart’ * punctuation. * + * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("'Hello,' \"world\" ..."); - * // "<p>'Hello,' &quot;world&quot; ...</p>\n" + * let html = markdownToHTML("'Hello,' \"world\" ..."); + * assert.equal(html, "<p>'Hello,' \&quot;world\&quot; ...</p>\n"); * - * markdownToHTML("'Hello,' \"world\" ...", { parse: { smart: true } }); - * // "<p>‘Hello,’ “world” …</p>\n" + * html = markdownToHTML("'Hello,' \"world\" ...", { parse: { smart: true } }); + * assert.equal(html, "<p>'Hello,' "world" …</p>\n"); + * ``` * ``` * * @default {false} @@ -365,9 +382,10 @@ export interface ComrakParseOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("[https://foo.com]", { extension: { autolink: true }, parse: { relaxedAutolinks: true } }); - * // "<p>[<a href=\"https://foo.com\">https://foo.com</a>]</p>\n" + * const html = markdownToHTML("[https://foo.com]", { extension: { autolink: true }, parse: { relaxedAutolinks: true } }); + * assert.equal(html, "<p>[<a href=\"https://foo.com\">https://foo.com</a>]</p>\n"); * ``` * * @default {false} @@ -383,12 +401,13 @@ export interface ComrakRenderOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("<i>italic text</i>"); - * // "<p><!-- raw HTML omitted -->italic text<!-- raw HTML omitted --></p>\n" + * let html = markdownToHTML("<i>italic text</i>"); + * assert.equal(html, "<p><!-- raw HTML omitted -->italic text<!-- raw HTML omitted --></p>\n"); * - * markdownToHTML("<i>italic text</i>", { render: { escape: true } }); - * // "<p>&lt;i&gt;italic text&lt;/i&gt;</p>\n" + * html = markdownToHTML("<i>italic text</i>", { render: { escape: true } }); + * assert.equal(html, "<p>&lt;i&gt;italic text&lt;/i&gt;</p>\n"); * ``` * * @default {false} @@ -400,12 +419,13 @@ export interface ComrakRenderOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("\`\`\`rust\nfn hello();\n\`\`\`\n"); - * // "<pre><code class=\"language-rust\">fn hello();\n</code></pre>\n" + * let html = markdownToHTML("\`\`\`rust\nfn hello();\n\`\`\`\n"); + * assert.equal(html, "<pre><code class=\"language-rust\">fn hello();\n</code></pre>\n"); * - * markdownToHTML("\`\`\`rust\nfn hello();\n\`\`\`\n", { render: { githubPreLang: true } }); - * // "<pre lang=\"rust\"><code>fn hello();\n</code></pre>\n" + * html = markdownToHTML("\`\`\`rust\nfn hello();\n\`\`\`\n", { render: { githubPreLang: true } }); + * assert.equal(html, "<pre lang=\"rust\"><code>fn hello();\n</code></pre>\n"); * ``` * * @default {false} @@ -417,12 +437,13 @@ export interface ComrakRenderOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("Hello.\nWorld.\n"); - * // "<p>Hello.\nWorld.</p>\n" + * let html = markdownToHTML("Hello.\nWorld.\n"); + * assert.equal(html, "<p>Hello.\nWorld.</p>\n"); * - * markdownToHTML("Hello.\nWorld.\n", { render: { hardbreaks: true } }); - * // "<p>Hello.<br />\nWorld.</p>\n" + * html = markdownToHTML("Hello.\nWorld.\n", { render: { hardbreaks: true } }); + * assert.equal(html, "<p>Hello.<br />\nWorld.</p>\n"); * ``` * * @default {false} @@ -469,12 +490,13 @@ export interface ComrakRenderOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("\`\`\`rust extra info\nfn hello();\n\`\`\`\n"); - * // "<pre><code class=\"language-rust\">fn hello();\n</code></pre>\n" + * let html = markdownToHTML("\`\`\`rust extra info\nfn hello();\n\`\`\`\n"); + * assert.equal(html, "<pre><code class=\"language-rust\">fn hello();\n</code></pre>\n"); * - * markdownToHTML("\`\`\`rust extra info\nfn hello();\n\`\`\`\n", { render: { fullInfoString: true } }); - * // "<pre><code class=\"language-rust\" data-meta="extra info">fn hello();\n</code></pre>\n" + * html = markdownToHTML("\`\`\`rust extra info\nfn hello();\n\`\`\`\n", { render: { fullInfoString: true } }); + * assert.equal(html, "<pre><code class=\"language-rust\" data-meta="extra info">fn hello();\n</code></pre>\n"); * ``` * * @default {false} @@ -485,9 +507,10 @@ export interface ComrakRenderOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("* Item\n* Item\n", { render: { listStyle: "star" } }); - * // "<ul>\n<li>Item</li>\n<li>Item</li>\n</ul>\n" + * const html = markdownToHTML("* Item\n* Item\n", { render: { listStyle: "star" } }); + * assert.equal(html, "<ul>\n<li>Item</li>\n<li>Item</li>\n</ul>\n"); * ``` * * @default {"dash"} @@ -498,9 +521,10 @@ export interface ComrakRenderOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("Hello *world*!", { render: { sourcepos: true } }); - * // "<p data-sourcepos=\"1:1-1:14\">Hello <em data-sourcepos=\"1:7-1:13\">world</em>!</p>\n" + * const html = markdownToHTML("Hello *world*!", { render: { sourcepos: true } }); + * assert.equal(html, "<p data-sourcepos=\"1:1-1:14\">Hello <em data-sourcepos=\"1:7-1:13\">world</em>!</p>\n"); * ``` * * @default {false} @@ -511,9 +535,10 @@ export interface ComrakRenderOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("Notify user \\@example", { render: { escapedCharSpans: true } }); - * // "<p>Notify user <span data-escaped-char>@</span>example</p>\n" + * const html = markdownToHTML("Notify user \\@example", { render: { escapedCharSpans: true } }); + * assert.equal(html, "<p>Notify user <span data-escaped-char>@</span>example</p>\n"); * ``` * * @default {false} @@ -524,9 +549,10 @@ export interface ComrakRenderOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("setext heading\n---", { render: { ignoreSetext: true } }); - * // "<p>setext heading</p>\n<hr />\n" + * const html = markdownToHTML("setext heading\n---", { render: { ignoreSetext: true } }); + * assert.equal(html, "<p>setext heading</p>\n<hr />\n"); * ``` * * @default {false} @@ -537,9 +563,10 @@ export interface ComrakRenderOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("[]()", { render: { ignoreEmptyLinks: true } }); - * // "<p>[]()</p>\n" + * const html = markdownToHTML("[]()", { render: { ignoreEmptyLinks: true } }); + * assert.equal(html, "<p>[]()</p>\n"); * ``` * * @default {false} @@ -550,9 +577,10 @@ export interface ComrakRenderOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("****abcd****", { render: { gfmQuirks: true } }); - * // "<p><strong>abcd</strong></p>\n" + * const html = markdownToHTML("****abcd****", { render: { gfmQuirks: true } }); + * assert.equal(html, "<p><strong>abcd</strong></p>\n"); * ``` * * @default {false} @@ -569,9 +597,10 @@ export interface ComrakRenderOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("![image](https://example.com/image.png \"this is an image\")", { render: { figureWithCaption: true } }); - * // "<p><figure><img src=\"https://example.com/image.png\" alt=\"image\" title=\"this is an image\" /><figcaption>this is an image</figcaption></figure></p>\n" + * const html = markdownToHTML("![image](https://example.com/image.png \"this is an image\")", { render: { figureWithCaption: true } }); + * assert.equal(html, "<p><figure><img src=\"https://example.com/image.png\" alt=\"image\" title=\"this is an image\" /><figcaption>this is an image</figcaption></figure></p>\n"); * ``` * * @default {false} @@ -582,9 +611,10 @@ export interface ComrakRenderOptions { * * ```ts * import { markdownToHTML } from "@nick/comrak"; + * import assert from "node:assert"; * - * markdownToHTML("- [ ] Foo", { extension: { tasklist: true }, render: { tasklistClasses: true } }); - * // "<ul class=\"contains-task-list\">\n<li class=\"task-list-item\"><input type=\"checkbox\" class=\"task-list-item-checkbox\" disabled=\"\" /> Foo</li>\n</ul>\n" + * const html = markdownToHTML("- [ ] Foo", { extension: { tasklist: true }, render: { tasklistClasses: true } }); + * assert.equal(html, "<ul class=\"contains-task-list\">\n<li class=\"task-list-item\"><input type=\"checkbox\" class=\"task-list-item-checkbox\" disabled=\"\" /> Foo</li>\n</ul>\n"); * ``` * * @default {false}