Step 1 of 5 · Reading · ~4 min
Read
Production Concerns
Extensions: Tables & Strikethrough
CommonMark is deliberately small. It standardises the constructs everyone already agreed on and stops there: no tables, no strikethrough, no task lists. Everything beyond that is an extension, and knowing which layer a feature lives in is the difference between portable Markdown and Markdown that only renders on one site. Your program will add the first inline extension, strikethrough, to the emphasis machinery you already have.
Three layers, not one
| Layer | What it defines | Examples |
|---|---|---|
| CommonMark core | the base grammar | headings, lists, code, links |
| GFM (a formal spec) | five additions on top of core | tables, strikethrough, task lists, extended autolinks, disallowed raw HTML |
| Renderer features | one product's behaviour | footnotes, callouts, mermaid fences, LaTeX math |
A parser that claims "GFM support" owes you exactly those five things. Anything in the third row is a promise made by a website, not by a specification, which is why the same document looks different on a wiki, in a chat client, and in a static site generator. Two of the five you have already met: disallowed raw HTML in the previous lesson, and extended autolinks in the autolinks lesson.
Strikethrough
~~deleted~~ becomes <del>deleted</del>. GFM accepts a matching pair of one or two tildes, so ~deleted~ also works on GitHub; two is the portable form, because plenty of CommonMark-only parsers implement neither. This exercise uses the portable form only.
The rules are the emphasis rules with a different character, plus one tightening: a tilde run must be exactly the length of the delimiter. Emphasis lets *** serve as a strong opener because a longer run can be split; a run of three tildes is not strikethrough at all.
| Source | Result | Why |
|---|---|---|
~~deleted~~ | <del>deleted</del> | a matching pair |
~~ spaced ~~ | unchanged | the opener is followed by whitespace |
~~~three~~~ | unchanged | the runs are three long, not two |
~~with **bold**~~ | <del>with <strong>bold</strong></del> | strikethrough nests with emphasis |
Tables
| Name | Age |
|:------|----:|
| Alice | 30 |
The header row is ordinary text until the delimiter row under it proves otherwise. That row is the disambiguator: without it, | a | b | is just a paragraph that happens to contain pipes. Colons in the delimiter cells set the alignment: a leading colon is left, a trailing colon is right, both is center, neither is the default. Tables are block-level, so they get their own lesson later in this course; this one stays inside a line.
The trap that costs an afternoon
Inline transforms rewrite the string you are still scanning. Each pass can walk straight back into the HTML the previous pass produced. Take ~~outer **inner *deepest*** end~~ with the passes run one after another:
| Without a stash | With a stash |
|---|---|
the em pass sees a star that the strong pass already used and wraps </strong> in an <em>, giving interleaved tags | each finished tag is parked behind a placeholder, so later passes cannot see it |
<del>outer <strong>inner <em>deepest</strong></em> end</del> (invalid) | <del>outer <strong>inner <em>deepest</em></strong> end</del> |
The same stash that protects code spans protects finished tags, and the text between a pair of tags stays visible, so the passes can nest in any direction: strikethrough inside strong, strong inside strikethrough, or both around an emphasis.
Order of operations
Code spans first, so nothing inside backticks is touched. Then the three star passes, longest first. Then the tilde pass. Then restore. Because every pass parks its tags, properly nested input works whichever pass runs first; the code step is the one that has to come first.
Common mistakes
- Running strikethrough before code spans. A line holding
`~~code~~`next to a real strikethrough must keep the tildes inside the backticks. - Accepting any run of tildes.
~~~x~~~is not strikethrough. - Substituting in place. Without the stash you get interleaved tags like the left column above.
- Skipping the flanking check.
~~ spaced ~~stays literal.
Your exercise
Generalise the emphasis pass so the delimiter character and the exactness rule are parameters, then use it for stars and tildes. The starter gives you the stash and code_spans; you write delim_pass and render_line.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…