CodeRigor

LESSON

Report unsupported syntax at its source location

Compose the parser and renderer, distinguish source errors from configuration/programmer failures and return no partial page on failure.

Unsupported input should explain itself. A heading outside the subset, an unclosed code fence or a forbidden link needs a source line, column and fixed code. Returning half a page with a success flag is not a useful publishing result.

compile_page composes block parsing and rendering. It catches SourceError and converts it into a stable failure record. It does not catch every exception and call it bad Markdown.

A complete page or a located failure
start / 3
Compilation returns success only after all stages finish. A source failure carries its location and no partial HTML.
A complete page or a located failure
Compilation returns success only after all stages finish. A source failure carries its location and no partial HTML.

A source error belongs to authored input. A title outside configuration limits is a configuration error. An unexpected RuntimeError inside the renderer is an implementation bug. Keep those categories distinct so the person fixing the problem has honest evidence.

An empty normalized file has no blocks and cannot become a usable page. That is a source failure at line one, column one, even though normalization itself accepted the empty string.

Python
def outcome(ok,html=None,error=None):
    return {"ok":ok,"html":html,"error":error}
print(outcome(False,error={"line":3,"column":5,"code":"unclosed-inline"}))
print(outcome(True,html="<p>Complete page fragment</p>"))

Line/column data must survive every stage. The block parser retained each source line and content offset; the inline scanner added its local opener index; the renderer reused that token location when a link policy failed. The wrapper should copy those values, not replace every column with one.

The result contains no source snippets or raw local paths. It reports the fixed error code and location. The local CLI can print that diagnosis and refuse to replace a previously successful output file.

Tests intentionally inject an implementation failure to ensure it is not converted into a false source error. The fixture restores the original renderer afterward. That checks failure ownership rather than hiding a bug behind a catch-all handler.

Preserve failure ownership
start / 3
Source syntax becomes a diagnostic, configuration stays a configuration error, and unexpected implementation failures remain visible.
Preserve failure ownership
Source syntax becomes a diagnostic, configuration stays a configuration error, and unexpected implementation failures remain visible.
Python
class SourceError(ValueError): pass
for error in [SourceError("unclosed"),RuntimeError("bug")]:
    try: raise error
    except SourceError: print("source diagnostic")
    except RuntimeError: print("implementation failure")

Complete the wrapper and test successful block counts, an inline error on a later source line, a forbidden link, empty source and an unexpected renderer failure. Every failed source result must have html None.

Next we fingerprint the successful bytes and connect the pure model to a repeatable local publishing command.

Watch & read

Free lectures, talks and readings that cover this skill from another angle. All resources →

Optional file-I/O companion for the local build command. The original parser and HTML-escaping rules are taught in the authored lessons.