feat: render richer blocks and inline nodes (task 0004) #3

Merged
alexion merged 1 commits from task-0004-richer-blocks-and-inline into main 2026-07-29 19:47:11 -04:00
Owner

Task: .claude/tasks/0004-richer-blocks-and-inline.md

Summary

Extends @kitchen-md/core and the CLI renderer to cover the rest of the everyday Markdown body, so kitchen view renders lists, blockquotes, code, thematic breaks, and inline emphasis faithfully.

  • Core AST gains ListBlock (ordered flag + ListItemBlock container items), BlockquoteBlock, CodeBlock (optional language + literal text), ThematicBreakBlock, and inline EmphasisNode, StrongNode, CodeSpanNode, LinkNode.
  • Raw fallback: any remark block or inline node core does not model falls through to RawBlock / RawInline, whose verbatim value is position-sliced from the original input — never re-stringified — so unmodelled constructs round-trip byte-for-byte.
  • remark-gfm is added to the pipeline; tables and strikethrough parse as their own nodes and therefore reach the raw fallback. The translation layer recurses into container children rather than collapsing them.
  • Renderer: bulleted/numbered lists (one item per line), literal code blocks, a thematic-break rule, blockquotes, and inline styling (emphasis italic, strong bold, code span inverse, links show inline content only).

Deviations

  • ListItemBlock is scoped to ListBlock.items, not the top-level Block union. A list item exists only inside a list, so it is dispatched through renderItemContent rather than renderBlock, keeping the type as tight as the spec's shape (raised by the Spec review below and addressed).
  • CodeBlock.lang is omitted rather than set to undefined when a fence has no language, so the parser output deep-equals { type: "code", value: … }.
  • "Content not annotation-parsed" holds structurally. Code blocks and code spans store their literal value and are never fed to translateInline; annotation parsing itself lands in task 0006.

No acceptance criteria were dropped.

Review

Risk

Overall: Low

  • Blast radius: Low — three source files in one CLI package plus tests; internal functions, no external callers affected.
  • Reversibility: Low — pure code additions/renames, no migrations or persisted schema; trivial git revert.
  • Test coverage: Low — each new node type, the raw fallbacks (byte-for-byte source), the list-item shape, and styling are covered by ~20 added tests alongside the diff.
  • Sensitive domain: Low — no auth, permissions, payments, concurrency, or data migration; the one input-slicing path guards undefined offsets by returning "".
  • Size & complexity: Low — moderate additions but straightforward switch-based dispatch, no tangled control flow or shared mutable state.
  • Runtime criticality: Low — dev/CLI Markdown rendering tool, not a production hot path.

Unaddressed findings

Standards: none. No documented-standard violations; the only baseline smell noted was inherent Shotgun Surgery (adding a node kind touches the union, the parse case, and the render case) — that is the intrinsic cost of an explicit AST with exhaustive dispatch, mitigated by the exhaustive switch arms, and not worth refactoring.

Spec: none outstanding. The one finding (the ListItemBlock widening) was fixed in this branch, so it is already in the diff.

Task: `.claude/tasks/0004-richer-blocks-and-inline.md` ## Summary Extends `@kitchen-md/core` and the CLI renderer to cover the rest of the everyday Markdown body, so `kitchen view` renders lists, blockquotes, code, thematic breaks, and inline emphasis faithfully. - **Core AST** gains `ListBlock` (ordered flag + `ListItemBlock` container items), `BlockquoteBlock`, `CodeBlock` (optional language + literal text), `ThematicBreakBlock`, and inline `EmphasisNode`, `StrongNode`, `CodeSpanNode`, `LinkNode`. - **Raw fallback**: any remark block or inline node core does not model falls through to `RawBlock` / `RawInline`, whose verbatim `value` is position-sliced from the original input — never re-stringified — so unmodelled constructs round-trip byte-for-byte. - **remark-gfm** is added to the pipeline; tables and strikethrough parse as their own nodes and therefore reach the raw fallback. The translation layer recurses into container children rather than collapsing them. - **Renderer**: bulleted/numbered lists (one item per line), literal code blocks, a thematic-break rule, blockquotes, and inline styling (emphasis italic, strong bold, code span inverse, links show inline content only). ### Deviations - **`ListItemBlock` is scoped to `ListBlock.items`, not the top-level `Block` union.** A list item exists only inside a list, so it is dispatched through `renderItemContent` rather than `renderBlock`, keeping the type as tight as the spec's shape (raised by the Spec review below and addressed). - **`CodeBlock.lang` is omitted rather than set to `undefined`** when a fence has no language, so the parser output deep-equals `{ type: "code", value: … }`. - **"Content not annotation-parsed" holds structurally.** Code blocks and code spans store their literal `value` and are never fed to `translateInline`; annotation parsing itself lands in task 0006. No acceptance criteria were dropped. ## Review ### Risk **Overall: Low** - Blast radius: Low — three source files in one CLI package plus tests; internal functions, no external callers affected. - Reversibility: Low — pure code additions/renames, no migrations or persisted schema; trivial git revert. - Test coverage: Low — each new node type, the raw fallbacks (byte-for-byte source), the list-item shape, and styling are covered by ~20 added tests alongside the diff. - Sensitive domain: Low — no auth, permissions, payments, concurrency, or data migration; the one input-slicing path guards undefined offsets by returning `""`. - Size & complexity: Low — moderate additions but straightforward switch-based dispatch, no tangled control flow or shared mutable state. - Runtime criticality: Low — dev/CLI Markdown rendering tool, not a production hot path. ### Unaddressed findings **Standards:** none. No documented-standard violations; the only baseline smell noted was inherent Shotgun Surgery (adding a node kind touches the union, the parse case, and the render case) — that is the intrinsic cost of an explicit AST with exhaustive dispatch, mitigated by the exhaustive `switch` arms, and not worth refactoring. **Spec:** none outstanding. The one finding (the `ListItemBlock` widening) was fixed in this branch, so it is already in the diff.
alexion added 1 commit 2026-07-29 07:35:37 -04:00
Extend the core parser and the CLI renderer to cover the everyday Markdown
body beyond headings and paragraphs: lists, blockquotes, fenced code,
thematic breaks, and inline emphasis, strong, code spans, and links.

Add remark-gfm to the pipeline so tables and strikethrough parse as their
own nodes. Any block or inline node core does not model falls through to
RawBlock / RawInline, whose verbatim value is position-sliced from the
original input so unmodelled constructs round-trip byte-for-byte.
alexion merged commit 22befaaa71 into main 2026-07-29 19:47:11 -04:00
alexion deleted branch task-0004-richer-blocks-and-inline 2026-07-29 19:47:11 -04:00
This repo is archived. You cannot comment on pull requests.
No Reviewers
No Label
1 Participants
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: alexion/kitchen-md#3