add shortcodes as the first internal/ext feature
A call is `{{< name key="value" >}}` alone on a line, parsed by a goldmark block
parser into an AST node and rendered by executing a theme template of that name
(ADR-0036). `figure` ships; `include` and `gallery` need the including bundle's
directory, which the parser does not carry yet, so they wait.
The layering did the design work here. internal/render may not import
internal/ext, so render.New takes a callback that receives a Partial and returns
Markdown extensions, and cmd/khosra/wire.go holds the only list of enabled
features. Empty that list and the engine still builds and serves — which is the
property extensions.md says the contract should have.
Raw HTML stays disabled. An author's text reaches a page only as arguments that
html/template escapes in context, which the real binary shows: a hostile alt
becomes <script> and src="javascript:…" becomes #ZgotmplZ. Getting
contextual escaping from the standard library rather than writing it is the whole
reason a fragment renders this instead of the feature.
parseSet became variadic so the fragment set reuses it rather than growing a
second copy of the overlay logic; `Partial` takes map[string]string after the
advisory correctly flagged `any` as generality nothing had asked for.
This commit is contained in:
+13
-7
@@ -2,9 +2,14 @@
|
||||
|
||||
The plugin story, and the gate keeping it from arriving early.
|
||||
|
||||
**STATUS: not buildable yet.** A feature is its own directory under `internal/ext/<name>/`, called
|
||||
explicitly from `wire.go` (ADR-0027) — correct and sufficient until the counters say otherwise. This document exists so the eventual shape is known, not
|
||||
so it can be built now.
|
||||
**STATUS: one feature exists.** `internal/ext/shortcodes` is the first, listed in `cmd/khosra/wire.go`
|
||||
(ADR-0027) — one directory, called explicitly, correct and sufficient until the counters say otherwise. The
|
||||
`Extension` struct below is still unbuilt; this document exists so the eventual shape is known, not so it
|
||||
can be built now.
|
||||
|
||||
How a feature reaches the engine today: `cmd` builds the list, so nothing under `internal/` knows which
|
||||
features exist. A feature that must emit markup is handed `render.Partial` and renders through a theme
|
||||
template, because deciding markup is not a feature's job (ADR-0036).
|
||||
|
||||
## The gate
|
||||
|
||||
@@ -41,9 +46,10 @@ type Extension struct {
|
||||
}
|
||||
```
|
||||
|
||||
`cmd/khosra/wire.go` holds the only list of enabled extensions. Enabling or disabling one is a
|
||||
one-line diff and a rebuild. Removing one leaves no trace elsewhere — that property is the test of
|
||||
whether the contract is right.
|
||||
`cmd/khosra/wire.go` holds the only list of enabled extensions — it exists now, holding one line. Enabling
|
||||
or disabling one is a one-line diff and a rebuild. Removing one leaves no trace elsewhere — that property is
|
||||
the test of whether the contract is right, and it is testable today: empty the list and the engine still
|
||||
builds and serves, minus that feature.
|
||||
|
||||
## Stage phases
|
||||
|
||||
@@ -54,7 +60,7 @@ wearing a disguise.
|
||||
|---|---|---|
|
||||
| `PhaseLoad` | raw bytes + frontmatter | includes, translation fallback |
|
||||
| `PhaseParse` | the parsed Markdown tree | shortcodes, transclusion, image derivatives |
|
||||
| `PhaseMarkup` | rendered HTML fragments, code spans skipped | smart quotes, dashes, widows, Bengali numerals |
|
||||
| `PhaseMarkup` | rendered HTML fragments, code spans skipped | widows. Smart quotes and dashes turned out to be a Markdown parser option, and chrome localisation a template function (ADR-0034) — neither needed a phase |
|
||||
| `PhasePage` | the assembled page object | OpenGraph, JSON-LD, related posts, series nav |
|
||||
| `PhaseOutput` | the final byte stream | minification, dithering, gemtext conversion |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user