✨ Show arbitrary text as a fenced Markdown code block (#658) - #661
Merged
Conversation
Add `<CodeBlock>`, a core default that places any supplied string inside one fenced Markdown code block and chooses a fence the value cannot close: one backtick longer than the value's longest backtick run, never shorter than three. The value is returned unchanged — nothing trimmed, normalized, escaped or removed — so generated source and diagnostics can be shown as inert text without writing delimiter arithmetic in an eval block. `value` and the optional single-token `language` are ordinary props on a closed schema, so a repository `CodeBlock.md` receives them the way it receives any other prop. The self-closing form is declared to canonical dispatch rather than decided in the body, so a paired spelling is refused before the body runs and its content never expands.
PR #661: ✨ Show arbitrary text as a fenced Markdown code block (#658)8 files, +732 / -3 Scope🟡 735 lines changed. PRs under 400 receive more thorough review. Structural✅ No structural bloat detected. Slop✅ Slop indicators look low. Static AnalysisOxlint: 3 diagnostics across 1 file (2 rules) no-base-to-string (2): packages/core/src/components/CodeBlock.ts CorrectnessNo extraneous code patterns detected. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #658. Parallel prerequisite of #260.
Why
A document that renders text it did not write — generated candidate source, a
validator's diagnostics, a command transcript — needs that text to arrive as
text. The hazard is the fence: a value holding three backticks closes a
three-backtick block early, and everything after it lands in the document as
Markdown, as headings, as element invocations, as another fence. Today every
author who has something to quote writes that delimiter arithmetic themselves in
an eval block.
What changes
Before: showing arbitrary text safely meant computing a fence in an eval block
at every site that needed one.
After:
<CodeBlock value={source} language="markdown" />is a core default thatdoes it, and does nothing else to the value.
How it works
The whole value is scanned for the longest contiguous run of U+0060, and the
fence is one backtick longer than that, never shorter than three — a fence the
value cannot close, whatever it holds. Both framing characters are U+000A and
belong to the envelope rather than to the value, and there is no line feed after
the closing fence.
Nothing else about the value is read. It is not trimmed, line-ending-normalized,
escaped, re-encoded, or searched for an apparent closing fence.
Review guide
Start with:
packages/core/src/components/CodeBlock.tsThen review:
FormDeclarationfenceFor()and the returned stringpackages/core/src/components/registry.tspackages/core/tests/code-block-component.test.ts, then the registration,catalog and CLI-syntax additions
Look carefully at:
languagecharacter class. The hyphen is last so it stays literal; ahyphen that became a range would admit
/,:,,and;into the openingfence line.
What must stay true
enforced by
fenceFor()and checked by CB2's table of complete fence lengths.rewriting, and checked by CB3, which slices the known envelope off and
compares code unit by code unit.
forms: "self-closing"to canonical dispatch rather than readingComponent.hasContent(), and checked by CB5's paired cases, which count a<Tripwire />written inside the refused content.valueis an ordinary prop, not a capture — enforced by leaving it on theschema, and checked by CR22d, where a repository
CodeBlock.mdreceives thestring through the ordinary boundary.
ascapture, notafter output middleware — every byte assertion in Tier CB reads one of those
two boundaries, and no case installs
useNormalizedOutput().How to verify it
three-backtick fence, the two framing line feeds and no final one; fails on an
extra newline, a trim, a default language or a wrong minimum.
several unequal runs and a long run; fails on off-by-one, first-run-only or a
fixed fence.
tabs,
\rand embedded runs; fails on any normalization.every refused token fails validation with no fence; fails on a widened or
narrowed pattern and on partial output after a refusal.
value, an unknown prop and bothpaired spellings are refused with no fence and zero tripwire calls.
asbinds the byte-identical string while emitting nothing at the site.CodeBlock-specific durable event exists, that a partialreplay re-renders from the newly reconstructed string, and that a completed
root reuses its result without consulting the live source.
and the CLI
Syntax.test.mdsuite proves the rendered production catalognames it across the subprocess boundary.
Four mutations were run against the committed tests and each was caught:
max(3, longest), a.trim()on the value,forms: "either", and alanguageclasswhose hyphen becomes a range.
Focused commands, all green at
1c6fbb2a:Delivery battery, all green:
Scope
Included
<CodeBlock>: the pure renderer, the closed props schema, the self-closingform declaration and its paired refusal.
as/contextmetadata.
row.
Intentionally unchanged
escaping, parsing or syntax highlighting.
xmd run --rawkeep their existing roles and their existing tests.architecture.mdandspecs/executable-mdx-spec.mdoverlap after ✨ Render arbitrary text safely with<CodeBlock>#658 and ✨ Deliberately fail an XMD document with<Fail>#659 merge; that policyis not resolved here.
Risks and limitations
component's bytes. Exactness is a promise at the component return and the
ascapture boundary, and the specification says so.
nothing else resolves the name.
Scope confirmation