✨ Add gfm-like2 preset with task lists, alerts, and single-tilde strikethrough#388
✨ Add gfm-like2 preset with task lists, alerts, and single-tilde strikethrough#388chrisjsewell merged 5 commits intomasterfrom
gfm-like2 preset with task lists, alerts, and single-tilde strikethrough#388Conversation
…rikethrough ### Summary Adds a new `gfm-like2` preset that extends `gfm-like` with three GFM features: - **Task lists** — `- [x] done` / `- [ ] todo` checkbox syntax in list items - **Alerts** — `> [!NOTE]`, `> [!TIP]`, `> [!WARNING]`, etc. inside blockquotes - **Single-tilde strikethrough** — `~text~` in addition to `~~text~~` These are enabled via the `gfm-like2` preset or individually through the `tasklists`, `alerts`, and `strikethrough_single_tilde` options. The existing `gfm-like` preset is unchanged, so as to remain back-compatible. ### Why in markdown-it-py, not mdit-py-plugins? Task lists and alerts are implemented by integrating detection directly into the existing block-level parsers (list.py and blockquote.py), rather than as post-processing rules. This mirrors [the approach taken in ubc_parser_md](https://github.com/useblocks/ubcode/tree/main/rust/ubc_parser_md) (the Rust markdown-it port), where: - Checkbox detection happens during list item parsing, before the sub-parser runs on the item content - Alert detection happens during blockquote parsing, before the inner content is tokenized This design is not achievable from a plugin: plugins can only add new rules or post-process the token stream — they cannot modify the internals of `list_block()` or `blockquote()` to inject detection at the right point in the parsing pipeline. Implementing these as post-processing core rules would work functionally, but it means re-walking and mutating the token stream after the fact, which is less clean and less consistent with how the block parsers are designed to work. Single-tilde strikethrough similarly extends the existing strikethrough rule's matching logic (opener/closer width matching), which is more naturally done inside the rule than bolted on externally. ### Changes - **`rules_block/list.py`** — Detect `[ ]`/`[x]`/`[X]` at content start during list item parsing; set `token.meta["checked"]`; advance `bMarks` past the checkbox; add CSS classes (`task-list-item`, `contains-task-list`) after the list loop - **`rules_block/blockquote.py`** — Detect `[!TYPE]` on the first content line; emit `alert_open`/`alert_close` + title tokens instead of `blockquote_open`/`blockquote_close`; skip the marker line during tokenization - **`rules_inline/strikethrough.py`** — When `strikethrough_single_tilde` is enabled, accept 1 or 2 tildes (reject 3+); enforce opener/closer width matching in `_postProcess` - **renderer.py** — Add `list_item_open` render method that injects checkbox HTML when `meta["checked"]` is present - **`presets/__init__.py`** — Add `gfm_like2` preset class - **`main.py`** — Register `gfm-like2` in `_PRESETS` - **utils.py** — Add `tasklists`, `alerts`, `strikethrough_single_tilde` keys to `OptionsType` - **pyproject.toml** — Add `pytest-timeout` to test deps; set 10s default timeout - **Test fixtures** — 11 tasklist cases, 15 alert cases, 13 single-tilde strikethrough cases ### Usage ```python from markdown_it import MarkdownIt md = MarkdownIt("gfm-like2") md.render("- [x] done\n- [ ] todo") md.render("> [!NOTE]\n> This is a note.") md.render("~strikethrough~") ```
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #388 +/- ##
========================================
Coverage 95.84% 95.84%
========================================
Files 64 64
Lines 3487 3611 +124
========================================
+ Hits 3342 3461 +119
- Misses 145 150 +5
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
OverviewThis PR adds a new Strengths
Issues & Suggestions1. Checkbox HTML is not
|
Changes Since Last ReviewThe PR now has 3 commits, 14 files changed (+680/−24). The new commits address the previous review feedback: ✅ Previously Raised Issues — Now Resolved
✅ New: Documentation Updates (commit 3)
Remaining Minor Items1.
|
Rename `tasklists_enabled` to `tasklists_editable` for clarity and set it explicitly to `False` in the `gfm-like2` preset. Add focused tests for editable task list checkboxes and alert token line maps, and make the alert container map handling explicit in `blockquote.py`.
Summary
Adds a new
gfm-like2preset that extendsgfm-likewith three GFM features:- [x] done/- [ ] todocheckbox syntax in list items> [!NOTE],> [!TIP],> [!WARNING], etc. inside blockquotes~text~in addition to~~text~~These are enabled via the
gfm-like2preset or individually through thetasklists,alerts, andstrikethrough_single_tildeoptions. The existinggfm-likepreset is unchanged, so as to remain back-compatible.Why in markdown-it-py, not mdit-py-plugins?
Task lists and alerts are implemented by integrating detection directly into the existing block-level parsers (list.py and blockquote.py), rather than as post-processing rules:
This design is not achievable from a plugin: plugins can only add new rules or post-process the token stream — they cannot modify the internals of
list_block()orblockquote()to inject detection at the right point in the parsing pipeline. Implementing these as post-processing core rules would work functionally, but it means re-walking and mutating the token stream after the fact, which is less clean and less consistent with how the block parsers are designed to work.Single-tilde strikethrough similarly extends the existing strikethrough rule's matching logic (opener/closer width matching), which is more naturally done inside the rule than bolted on externally.
Changes
rules_block/list.py— Detect[ ]/[x]/[X]at content start during list item parsing; settoken.meta["checked"]; advancebMarkspast the checkbox; add CSS classes (task-list-item,contains-task-list) after the list looprules_block/blockquote.py— Detect[!TYPE]on the first content line; emitalert_open/alert_close+ title tokens instead ofblockquote_open/blockquote_close; skip the marker line during tokenizationrules_inline/strikethrough.py— Whenstrikethrough_single_tildeis enabled, accept 1 or 2 tildes (reject 3+); enforce opener/closer width matching in_postProcesslist_item_openrender method that injects checkbox HTML whenmeta["checked"]is presentpresets/__init__.py— Addgfm_like2preset classmain.py— Registergfm-like2in_PRESETStasklists,alerts,strikethrough_single_tildekeys toOptionsTypepytest-timeoutto test deps; set 10s default timeoutUsage