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 } });
+ * // "
\nparagraph
\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("", { render: { figureWithCaption: true } });
+ * // "
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 } });
- * // "\nparagraph
\n
\n"
+ * const html = markdownToHTML(">>>\nparagraph\n>>>", { extension: { multilineBlockQuotes: true } });
+ * assert.equal(html, "\nparagraph
\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 } });
- * // "Hi.
\n\n"
+ * const html = markdownToHTML("Hi[^x].\n\n[^x]: A greeting.\n", { extension: { footnotes: true } });
+ * assert.equal(html, "Hi.
\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| a | \nb | \n
\n\n" +
- * // "\n\n| c | \nd | \n
\n\n
\n"
+ * const html = markdownToHTML("| a | b |\n|---|---|\n| c | d |\n", { extension: { table: true } });
+ * assert.equal(html, "\n\n\n| a | \nb | \n
\n\n\n\n| c | \nd | \n
\n\n
\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", { extension: { tagfilter: true } });
- * // "Hello <xmp>.
\n<xmp>\n"
+ * const html = markdownToHTML("Hello .\n\n", { extension: { tagfilter: true } });
+ * assert.equal(html, "Hello <xmp>.
\n<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 } });
- * // "\n"
+ * const html = markdownToHTML("* [x] Done\n* [ ] Not done\n", { extension: { tasklist: true } });
+ * assert.equal(html, "\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 } });
- * // "underlined text
\n"
+ * const html = markdownToHTML("__underlined text__", { extension: { underline: true } });
+ * assert.equal(html, "underlined text
\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 } });
- * // "H2O
\n"
+ * const html = markdownToHTML("H~2~O", { extension: { subscript: true } });
+ * assert.equal(html, "H2O
\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 } });
- * // "Darth Vader is Luke's father
\n"
+ * const html = markdownToHTML("Darth Vader is ||Luke's father||", { extension: { spoiler: true } });
+ * assert.equal(html, "Darth Vader is Luke's father
\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 } });
- * // ">implying implications
\n"
+ * const html = markdownToHTML(">implying implications", { extension: { greentext: true } });
+ * assert.equal(html, ">implying implications
\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 } });
- * // "この文は重要です。但这句话并不重要。
\n"
+ * const html = markdownToHTML("**この文は重要です。**但这句话并不重要。", { extension: { cjkFriendlyEmphasis: true } });
+ * assert.equal(html, "この文は重要です。但这句话并不重要。
\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");
- * // "fn hello();\n
\n"
+ * let html = markdownToHTML("\`\`\`\nfn hello();\n\`\`\`\n");
+ * assert.equal(html, "fn hello();\n
\n");
*
- * markdownToHTML("\`\`\`\nfn hello();\n\`\`\`\n", { parse: { defaultInfoString: "rust" } });
- * // "fn hello();\n
\n"
+ * html = markdownToHTML("\`\`\`\nfn hello();\n\`\`\`\n", { parse: { defaultInfoString: "rust" } });
+ * assert.equal(html, "fn hello();\n
\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\" ...");
- * // "'Hello,' "world" ...
\n"
+ * let html = markdownToHTML("'Hello,' \"world\" ...");
+ * assert.equal(html, "'Hello,' \"world\" ...
\n");
*
- * markdownToHTML("'Hello,' \"world\" ...", { parse: { smart: true } });
- * // "‘Hello,’ “world” …
\n"
+ * html = markdownToHTML("'Hello,' \"world\" ...", { parse: { smart: true } });
+ * assert.equal(html, "'Hello,' "world" …
\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 } });
- * // "[https://foo.com]
\n"
+ * const html = markdownToHTML("[https://foo.com]", { extension: { autolink: true }, parse: { relaxedAutolinks: true } });
+ * assert.equal(html, "[https://foo.com]
\n");
* ```
*
* @default {false}
@@ -383,12 +401,13 @@ export interface ComrakRenderOptions {
*
* ```ts
* import { markdownToHTML } from "@nick/comrak";
+ * import assert from "node:assert";
*
- * markdownToHTML("italic text");
- * // "italic text
\n"
+ * let html = markdownToHTML("italic text");
+ * assert.equal(html, "italic text
\n");
*
- * markdownToHTML("italic text", { render: { escape: true } });
- * // "<i>italic text</i>
\n"
+ * html = markdownToHTML("italic text", { render: { escape: true } });
+ * assert.equal(html, "<i>italic text</i>
\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");
- * // "fn hello();\n
\n"
+ * let html = markdownToHTML("\`\`\`rust\nfn hello();\n\`\`\`\n");
+ * assert.equal(html, "fn hello();\n
\n");
*
- * markdownToHTML("\`\`\`rust\nfn hello();\n\`\`\`\n", { render: { githubPreLang: true } });
- * // "fn hello();\n
\n"
+ * html = markdownToHTML("\`\`\`rust\nfn hello();\n\`\`\`\n", { render: { githubPreLang: true } });
+ * assert.equal(html, "fn hello();\n
\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");
- * // "Hello.\nWorld.
\n"
+ * let html = markdownToHTML("Hello.\nWorld.\n");
+ * assert.equal(html, "Hello.\nWorld.
\n");
*
- * markdownToHTML("Hello.\nWorld.\n", { render: { hardbreaks: true } });
- * // "Hello.
\nWorld.
\n"
+ * html = markdownToHTML("Hello.\nWorld.\n", { render: { hardbreaks: true } });
+ * assert.equal(html, "Hello.
\nWorld.
\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");
- * // "fn hello();\n
\n"
+ * let html = markdownToHTML("\`\`\`rust extra info\nfn hello();\n\`\`\`\n");
+ * assert.equal(html, "fn hello();\n
\n");
*
- * markdownToHTML("\`\`\`rust extra info\nfn hello();\n\`\`\`\n", { render: { fullInfoString: true } });
- * // "fn hello();\n
\n"
+ * html = markdownToHTML("\`\`\`rust extra info\nfn hello();\n\`\`\`\n", { render: { fullInfoString: true } });
+ * assert.equal(html, "fn hello();\n
\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" } });
- * // "\n"
+ * const html = markdownToHTML("* Item\n* Item\n", { render: { listStyle: "star" } });
+ * assert.equal(html, "\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 } });
- * // "Hello world!
\n"
+ * const html = markdownToHTML("Hello *world*!", { render: { sourcepos: true } });
+ * assert.equal(html, "Hello world!
\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 } });
- * // "Notify user @example
\n"
+ * const html = markdownToHTML("Notify user \\@example", { render: { escapedCharSpans: true } });
+ * assert.equal(html, "Notify user @example
\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 } });
- * // "setext heading
\n
\n"
+ * const html = markdownToHTML("setext heading\n---", { render: { ignoreSetext: true } });
+ * assert.equal(html, "setext heading
\n
\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 } });
- * // "[]()
\n"
+ * const html = markdownToHTML("[]()", { render: { ignoreEmptyLinks: true } });
+ * assert.equal(html, "[]()
\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 } });
- * // "abcd
\n"
+ * const html = markdownToHTML("****abcd****", { render: { gfmQuirks: true } });
+ * assert.equal(html, "abcd
\n");
* ```
*
* @default {false}
@@ -569,9 +597,10 @@ export interface ComrakRenderOptions {
*
* ```ts
* import { markdownToHTML } from "@nick/comrak";
+ * import assert from "node:assert";
*
- * markdownToHTML("", { render: { figureWithCaption: true } });
- * // "
this is an image
\n"
+ * const html = markdownToHTML("", { render: { figureWithCaption: true } });
+ * assert.equal(html, "
this is an image
\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 } });
- * // "\n"
+ * const html = markdownToHTML("- [ ] Foo", { extension: { tasklist: true }, render: { tasklistClasses: true } });
+ * assert.equal(html, "\n");
* ```
*
* @default {false}