Skip to content
Lesson 18 of 20

Step 1 of 5 · Reading · ~4 min

Read

Production Concerns

Putting It All Together

Every piece you have written so far handled one construct in isolation. This is where they become a program: one function that takes a document and returns HTML, with each handler you built now living as a branch of a single block dispatcher and a single inline scanner. Your program will convert a whole document, including quotes inside lists inside quotes.

What the finished converter contains

PhaseHandlers
Block, in dispatch orderfenced code, ATX heading, thematic break, blockquote, list, paragraph (which may turn into a setext heading)
Inline, one left-to-right scanbackslash escape, code span, image, link, entity or HTML escape
Inline, then passesstrong and em (stars), strikethrough (tildes), restore

The block table is ordered, and so is the inline one: each order exists because an earlier rule would otherwise steal a line, or a later rule would otherwise walk into HTML that an earlier rule produced.

Fenced code content leaves the block phase and goes straight to the renderer, never passing through inline parsing. That is what keeps *not italic* literal inside a fence.

Why does dispatch order decide correctness?

Three lines can each be claimed by two handlers:

LineCompeting readingsWinner
--- under paragraph textsetext H2 underline, or thematic breakthe underline, so the paragraph handler looks ahead
* * *thematic break, or a bullet itemthe break, so it is tested before lists
a line inside an open fenceanything at allthe fence: nothing else gets to see it

Same input, same rules, different order, different document: a heading turns into a paragraph plus a rule, or a list swallows a break. The paragraph handler goes last because a paragraph is defined as "whatever nothing else claimed".

Containers are recursion

A block quote or list item is handled the way the nesting lesson taught: collect the container's lines, remove its marker, and run the same function on what is left. The converter has one new problem beyond that: tight versus loose is a property of a whole list, but each item is rendered separately. Collect all items first, run each item once only to ask "did a blank line separate two of your blocks?", decide for the list, then render every item for real with the right setting. A blank line between two items also makes the list loose; one after the last item does not.

Two details keep the output right. A tight item writes its paragraph without <p>, while a block quote inside an item goes back to normal paragraphs. And a quote's lazy continuation is allowed only while its last line left a paragraph open.

Inline: one scan, then passes

The inline phase scans the paragraph text once. Whenever a construct is finished (an escaped character, a code span, a link, an image) its HTML goes into the stash behind a placeholder; every other character is escaped on the spot; * and ~ are left alone. Link text goes back through the whole inline phase (that is how [*em*](/u) works), but a link may never contain a link. Then the star and tilde passes pair delimiters, and the placeholders are swapped back.

What your parser still does not do

Link reference definitions, hard line breaks, indented code blocks, autolinks and raw HTML (here a < is always escaped), tables, and the full delimiter-stack emphasis algorithm. CommonMark ships 652 conformance examples in version 0.31.2 because that list is long. cmark is the reference implementation in C; markdown-it, goldmark, pulldown-cmark and markdig are the widely used ports. Use one of those in production. Write your own to understand parsing, which is what you just did.

Common mistakes

  • Skipping setext headings. Handle only ATX and Title over ----- comes out as a paragraph plus an <hr />.
  • Running inline rules inside a fence. Block content must reach the output untouched except for escaping.
  • Deciding tight or loose per item. The whole list is wrapped or none of it is.
  • Forgetting that a link's text is inline content too.

Your exercise

Write inline and render_blocks. The starter gives you the recognisers and helpers from every earlier lesson (headings, fences, markers, entities, code spans, link tails, delimiter passes, the stash) so that what remains is the integration itself. Output is the HTML for the whole document.

Up nextGFM TablesProduction Concerns

Discussion

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

Sign in to post a comment or reply.

Loading…