Skip to content

feat(content): retained Markdown document model, parser, and renderers [L01.01.05.10.02] - #940

Merged
dotnetcadet merged 1 commit into
mainfrom
feature/L01.01.05.10-markdown-model
Jul 20, 2026
Merged

feat(content): retained Markdown document model, parser, and renderers [L01.01.05.10.02]#940
dotnetcadet merged 1 commit into
mainfrom
feature/L01.01.05.10-markdown-model

Conversation

@dotnetcadet

Copy link
Copy Markdown
Contributor

Summary

Turns Assimalign.Cohesion.Content.Markdown from a placeholder into the Markdown format package of the Content family — the first consumer of the Content.Text TextTokenizer (PR #931), and the prerequisite for the static content engine resource.

  • Named baseline, explicit subset. The package implements a documented subset of CommonMark 0.31.2: ATX headings, paragraphs with lazy continuation, block quotes, bullet/ordered lists (tight/loose, interruption rules), fenced code, thematic breaks; inline escapes, code spans, emphasis/strong via the spec's delimiter-stack algorithm (flanking, intraword-underscore, multiple-of-three), inline links/images, URI autolinks, hard/soft breaks, numeric character references plus the five XML-predefined entities. docs/DESIGN.md carries the full subset and degradation table.
  • Predictable degradation, total parsing. Excluded constructs (setext headings, indented code, raw HTML, reference links/definitions, unknown named entities, email autolinks, GFM) degrade to literal text; the parser never throws for input, and the package deliberately defines no exception root — a documented design decision, not an omission.
  • Two-phase parser on the shared text layer. Block phase drives lines from TextTokenizer default options (open-container stack, tab-aware columns, container depth cap of 128); inline phase tokenizes leaf content through a custom delimiter table and assembles delimiter runs by offset contiguity.
  • Model per family convention. Closed MarkdownNode family (private protected root, sealed concretes), mutable with validating setters for programmatic document construction; MarkdownText facade mirrors YamlText (Format, Parse(string|Stream|ITextContent) with encoding detection, ToHtml, Write, CreateReader/CreateWriter seams).
  • Two renderers, both iterative. HTML output in the spec's shapes (tight/loose list rendering, alt-text flattening, reference-safe URL percent-encoding); canonical Markdown writer with prefix-stack container writing and conservative escaping. Both walk with explicit op stacks so adversarial inline nesting cannot overflow the call stack (verified by a 5000-deep emphasis test).
  • Round-trip guarantee: for parser-produced trees, write → parse → write is a fixed point and reparse preserves rendered HTML — enforced across a 30-document theory.

Testing

142 tests, all passing: block structure (28), inlines (27), spec-derived corpus cases transcribed from CommonMark 0.31.2 with section attribution (38 theory rows), round-trip fixed-point + canonicalization (35), model/facade/seams (10+), plus degradation pins for every excluded construct. The full spec corpus harness remains #469's scope. Content.Text's 46 tests still pass; Release build is warning-free.

Wiring

  • CI: Assimalign.Cohesion.Content.Markdown added to the Content workflow matrix.
  • Area project map updated (libraries/Content/README.md); package README.md/docs/OVERVIEW.md/docs/DESIGN.md created.
  • Solutions already carried the project; placeholder Class1.cs/UnitTest1.cs and the placeholder test csproj's forbidden <Using Include> removed.

Work items resolved by this PR

Closes #468

🤖 Generated with Claude Code

…, and renderers [L01.01.05.10.02]

Turns Content.Markdown from a placeholder into the Markdown format package:
a closed node family (blocks, inlines, document, list items), a two-phase
parser over Content.Text's TextTokenizer implementing a documented subset of
CommonMark 0.31.2, an HTML renderer in the spec's output shapes, and a
canonical Markdown writer with a round-trip guarantee (write-parse-write is a
fixed point; reparse preserves rendered HTML). Excluded constructs (setext
headings, indented code, raw HTML, reference links, GFM) degrade predictably
to literal text and the parser never throws for input; both renderers walk
iteratively so hostile nesting cannot overflow the stack.

MarkdownText follows the YamlText facade convention (Format descriptor,
Parse over string/stream/ITextContent, ToHtml, Write, content-seam
reader/writer). Adds Content.Markdown to the Content CI matrix and updates
the area project map.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@dotnetcadet
dotnetcadet merged commit b03f520 into main Jul 20, 2026
12 checks passed
@dotnetcadet
dotnetcadet deleted the feature/L01.01.05.10-markdown-model branch July 20, 2026 20:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[L01.01.05.10.02] Implement a retained Markdown document model, parser, and renderer scope

1 participant