Reading — step 1 of 5
Learn
Nested Containers
The blockquote lesson said a container is parsed by stripping its marker and running the block parser again on what is left. Every exercise so far has let you get away with not doing that — one loop over the lines, one branch per construct, done. This lesson is where that stops working, because a list inside a quote inside a list has no fixed line shape for a loop to match.
What makes a block a container?
Only two blocks in CommonMark hold other blocks: the block quote and the list item. Everything else — paragraphs, headings, code, thematic breaks — is a leaf, holding text or nothing. So the document is a tree, and the two container types are its only branch points.
That shape comes from four lines of Markdown: a bullet, its text, then an indented quote line carrying another bullet. Each level of the tree is one marker peeled off the front of a line.
How much of the line is the marker?
For a block quote: up to three spaces of indent, a >, and one optional space.
Strip exactly that and hand the remainder back to the parser.
After one peel the inner lines are an ordinary bullet list, and the same function that parsed the document parses them. No branch anywhere says "list inside a quote" — that case simply cannot come up.
For a list item the marker is not a fixed width. The rule is the item's content column: the marker plus the 1 to 4 spaces after it. Continuation lines belong to the item when they reach that column.
A fixed "nested lists indent by two" rule gets row two wrong by two columns, which is how sublists silently become paragraphs of the parent item.
Why a flat scanner cannot do this
A line-oriented loop asks "what is this line?" — but in a container the answer
depends on how many markers have already been stripped, and by how much. > - x
is a quote line at depth 0, a bullet at depth 1, and text at depth 2. The only
way to keep that straight in a flat loop is a stack of open containers plus
per-line bookkeeping of which ones still match, which is exactly the recursion
written out by hand and harder to get right.
Recursion also gives you the leaf rules for free. A blank line inside an item belongs to that item, not to the document, because the item's slice of lines is all its parse ever sees.
Your exercise
Write the recursive parser: quotes, bullets, paragraphs, any depth.
The mistake the grader catches is flattening a nested list to the top level.
A visible test feeds - outer and - inner; the inner <ul> has to sit
inside the outer <li>, so the expected output closes </ul> before </li>.
Collect the item's own lines first, dedent them by two, then recurse — do not
dispatch on the indented line from the outer loop.
The second is the paragraph wrapper. Inside a list item a paragraph emits its
text bare, which is what makes the list render tight, while a paragraph inside a
block quote keeps its <p>. One flag, passed down through the recursion, decides
which.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…