The convert engine renders markdown→HTML/PDF through named doctype templates selected by the document's `template:` front matter, with per-project/per-party overrides. convert package: - embed.go now embeds the whole templates/ dir (all: prefix so _-prefixed partials are included) as an embed.FS; drop the single viewer-template.html + custom.css embeds. New TemplateSet type + DefaultTemplateSet(name) returning the chosen doctype + its partials. - ToHTML/ToPDF take a TemplateSet; writeTemplateSetToScratch materialises the template + partials flat into the per-call scratch dir (pandoc resolves $partial()$ from the template's own directory). handler: - converttemplate.go: templateNameFromFrontMatter (YAML front-matter scan, sanitized to a bare basename) + resolveTemplateSet, which overlays <level>/.zddc.d/templates/<name>.html overrides onto the embedded defaults, walking docDir→fsRoot so a party dir beats the project-global dir. An override may replace a doctype, a partial, or add a brand-new doctype. - buildAndStore threads fsRoot + source into the html/pdf paths. build: pandoc/templates/ is the single source of truth; shared/build-lib.sh sync_pandoc_templates mirrors it into the embed dir on every build (cmp-guarded, stale-pruning). convert.TestEmbeddedTemplatesMatchSource fails on drift. Tests: drift + DefaultTemplateSet (convert); front-matter parse + cascade override precedence (handler). Full ./... suite green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
71 lines
2.5 KiB
Go
71 lines
2.5 KiB
Go
package convert
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
// canonicalTemplatesDir is the single source of truth for the conversion
|
|
// templates: /pandoc/templates/, relative to this package
|
|
// (zddc/internal/convert → ../../../pandoc/templates).
|
|
const canonicalTemplatesDir = "../../../pandoc/templates"
|
|
|
|
// TestEmbeddedTemplatesMatchSource guards against drift between the embedded
|
|
// templates/ (a build artifact, synced by shared/build-lib.sh:
|
|
// sync_pandoc_templates) and the canonical pandoc/templates/. If this fails,
|
|
// re-run ./build (or copy pandoc/templates/* into this package's templates/).
|
|
func TestEmbeddedTemplatesMatchSource(t *testing.T) {
|
|
srcEntries, err := os.ReadDir(canonicalTemplatesDir)
|
|
if err != nil {
|
|
t.Fatalf("read canonical templates dir %q: %v", canonicalTemplatesDir, err)
|
|
}
|
|
|
|
embedded := embeddedTemplateFiles()
|
|
srcCount := 0
|
|
for _, e := range srcEntries {
|
|
if e.IsDir() || filepath.Ext(e.Name()) != ".html" {
|
|
continue
|
|
}
|
|
srcCount++
|
|
want, err := os.ReadFile(filepath.Join(canonicalTemplatesDir, e.Name()))
|
|
if err != nil {
|
|
t.Fatalf("read %s: %v", e.Name(), err)
|
|
}
|
|
got, ok := embedded[e.Name()]
|
|
if !ok {
|
|
t.Errorf("embedded templates/ is missing %s (run ./build to sync)", e.Name())
|
|
continue
|
|
}
|
|
if string(got) != string(want) {
|
|
t.Errorf("embedded %s differs from pandoc/templates/%s (run ./build to sync)", e.Name(), e.Name())
|
|
}
|
|
}
|
|
|
|
if srcCount != len(embedded) {
|
|
t.Errorf("template count mismatch: canonical=%d embedded=%d (stale file in one tree?)", srcCount, len(embedded))
|
|
}
|
|
}
|
|
|
|
// TestDefaultTemplateSet checks the doctype fallback + that partials ride along.
|
|
func TestDefaultTemplateSet(t *testing.T) {
|
|
for _, name := range EmbeddedTemplateNames() {
|
|
ts := DefaultTemplateSet(name)
|
|
if ts.Name != name+".html" {
|
|
t.Errorf("DefaultTemplateSet(%q).Name = %q, want %q.html", name, ts.Name, name)
|
|
}
|
|
if ts.Files[ts.Name] == nil {
|
|
t.Errorf("DefaultTemplateSet(%q) Files missing primary %q", name, ts.Name)
|
|
}
|
|
if ts.Files["_head.html"] == nil {
|
|
t.Errorf("DefaultTemplateSet(%q) Files missing _head.html partial", name)
|
|
}
|
|
}
|
|
// Unknown / empty fall back to the default doctype.
|
|
if ts := DefaultTemplateSet("nope"); ts.Name != DefaultTemplateName+".html" {
|
|
t.Errorf("unknown doctype fell back to %q, want %q.html", ts.Name, DefaultTemplateName)
|
|
}
|
|
if ts := DefaultTemplateSet(""); ts.Name != DefaultTemplateName+".html" {
|
|
t.Errorf("empty doctype fell back to %q, want %q.html", ts.Name, DefaultTemplateName)
|
|
}
|
|
}
|