Skip to content

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

LayerWhat it definesExamples
CommonMark corethe base grammarheadings, lists, code, links
GFM (a formal spec)five additions on top of coretables, strikethrough, task lists, extended autolinks, disallowed raw HTML
Renderer featuresone product's behaviourfootnotes, 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.

SourceResultWhy
~~deleted~~<del>deleted</del>a matching pair
~~ spaced ~~unchangedthe opener is followed by whitespace
~~~three~~~unchangedthe 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 stashWith a stash
the em pass sees a star that the strong pass already used and wraps </strong> in an <em>, giving interleaved tagseach 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.

Up nextPutting It All TogetherProduction Concerns

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…