forked from bai/curriculum-project-hub
feat(cph): implement nested outline manifest and batch/combined export
ADR-0029 — nested outline manifest, supersedes ADR-0008's flat [[parts]]:
- cph-model: recursive loader over manifest.toml containers / element.toml
leaves; Lesson.parts (pure elements, DFS order) + Lesson.outline (elements
interleaved with section headings at their DFS-open position); rejects
ambiguous/incomplete folders and root-vs-container table misplacement
- cph-diag: new DiagCode::ManifestMalformed for carrier-document structure
errors (discharges an existing TODO)
- cph-typst: augmented manifest now serializes the outline (element/section
entries) instead of a flat parts array
- render/lib.typ: render-lesson renders section headings at their depth
- examples/TH-141 migrated to 5 nested section containers + 3 root segments,
byte-identical element order; smoke-verified via cph check/build + pdftotext
ADR-0030 — batch & combined export, extends ADR-0009/0011:
- cph build with no --target batches every declared target (repeatable
--target for an explicit subset); any target failure => non-zero exit,
per-target ledger, independent per-target execution
- cph-model: bundle.toml loader (directory + [info]/[targets.*]/ordered
lessons with per-lesson target overrides)
- cph-typst: augmented bundle manifest (path-prefixed member outlines),
Engine::{compile_check_bundle,build_bundle_pdf}
- render/lib.typ: render-bundle assembles member lessons under per-lesson
headings, depth-shifts their own section headings, resets example/lemma
counters at each lesson boundary by default
- cph-cli: `cph bundle <path> --target <name>` subcommand, same batching
contract as `cph build`
- new bundle fixtures/tests (cph-model unit + cph-typst through-template PDF
compile), smoke-verified via a real 2-lesson merged PDF
Verification: cargo fmt/clippy/test clean across the workspace (68 tests);
real cph check/build/bundle runs against TH-141 and a bundle fixture, PDF
content inspected via pdftotext.
This commit is contained in:
@@ -59,7 +59,7 @@ name = "broken"
|
||||
[info]
|
||||
title = "broken"
|
||||
|
||||
[[parts]]
|
||||
[[children]]
|
||||
kind = "frob"
|
||||
path = "elements/widget"
|
||||
"#,
|
||||
@@ -123,7 +123,7 @@ name = "broken"
|
||||
[info]
|
||||
title = "broken"
|
||||
|
||||
[[parts]]
|
||||
[[children]]
|
||||
kind = "segment"
|
||||
path = "segments/does-not-exist"
|
||||
"#,
|
||||
@@ -150,7 +150,7 @@ name = "cov"
|
||||
[info]
|
||||
title = "cov"
|
||||
|
||||
[[parts]]
|
||||
[[children]]
|
||||
kind = "segment"
|
||||
path = "segments/intro"
|
||||
|
||||
@@ -276,7 +276,7 @@ name = "sh"
|
||||
[info]
|
||||
title = "sh"
|
||||
|
||||
[[parts]]
|
||||
[[children]]
|
||||
kind = "segment"
|
||||
path = "segments/intro"
|
||||
|
||||
@@ -350,7 +350,7 @@ name = "sh"
|
||||
[info]
|
||||
title = "sh"
|
||||
|
||||
[[parts]]
|
||||
[[children]]
|
||||
kind = "segment"
|
||||
path = "segments/missing"
|
||||
|
||||
@@ -390,7 +390,7 @@ fn write_markdown_assemble_target_lesson(tmp: &Path, slides: &[(&str, &str)]) {
|
||||
parts.push('\n');
|
||||
}
|
||||
parts.push_str(&format!(
|
||||
"[[parts]]\nkind = \"segment\"\npath = \"segments/{name}\"\n"
|
||||
"[[children]]\nkind = \"segment\"\npath = \"segments/{name}\"\n"
|
||||
));
|
||||
}
|
||||
std::fs::write(
|
||||
@@ -468,8 +468,8 @@ fn run_markdown_assemble_target_skips_parts_without_the_field() {
|
||||
// Only the first segment has a slides.md; the second is skipped (optional).
|
||||
let tmp = tempdir();
|
||||
let mut parts = String::new();
|
||||
parts.push_str("[[parts]]\nkind = \"segment\"\npath = \"segments/a\"\n\n");
|
||||
parts.push_str("[[parts]]\nkind = \"segment\"\npath = \"segments/b\"\n");
|
||||
parts.push_str("[[children]]\nkind = \"segment\"\npath = \"segments/a\"\n\n");
|
||||
parts.push_str("[[children]]\nkind = \"segment\"\npath = \"segments/b\"\n");
|
||||
std::fs::write(
|
||||
tmp.join("manifest.toml"),
|
||||
format!(
|
||||
@@ -527,7 +527,7 @@ name = "md"
|
||||
[info]
|
||||
title = "md"
|
||||
|
||||
[[parts]]
|
||||
[[children]]
|
||||
kind = "segment"
|
||||
path = "segments/a"
|
||||
|
||||
@@ -584,7 +584,7 @@ name = "md"
|
||||
[info]
|
||||
title = "md"
|
||||
|
||||
[[parts]]
|
||||
[[children]]
|
||||
kind = "segment"
|
||||
path = "segments/a"
|
||||
|
||||
@@ -630,7 +630,7 @@ name = "md"
|
||||
[info]
|
||||
title = "md"
|
||||
|
||||
[[parts]]
|
||||
[[children]]
|
||||
kind = "segment"
|
||||
path = "segments/missing"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user