forked from EduCraft/curriculum-project-hub
docs(adr): cph 的 nested-manifest / batch-export 改号 0036/0037
上游 0029/0030 与本地 filelib 侧同号 ADR 相撞,cph 两份改到本地空闲号段, 代码锚点引用一并跟随。
This commit is contained in:
@@ -35,7 +35,7 @@ cph outline <工程目录> --format pdf --force # 明确允许覆盖已有 o
|
||||
hub 语义):`init` 产出一个 `cph check` 可过的工程根;`add` 按 kind 建
|
||||
`<子目录>/<名称>/` + `element.toml` + 必填内容字段(`segment→textbook.typ`、
|
||||
`example→problem/solution.typ`、`lemma→stmt.typ`、`sop→sop.typ`),并把配套
|
||||
`[[children]]` 追加进根 `manifest.toml`(保持数组连续,不破坏注释;ADR-0029)。缺省
|
||||
`[[children]]` 追加进根 `manifest.toml`(保持数组连续,不破坏注释;ADR-0036)。缺省
|
||||
`--root` 为当前目录。
|
||||
|
||||
**版本契约(ADR-0016):** 教研工程文件根放一个 `.cph-version` 文件,内容为它面向的 cph 版本(如 `0.0.2`)。`cph` 加载时比对自身版本,不相容则报 `E-CPH-VERSION` error 并拒绝(当前判定为版本完全相等;后续可放宽为 semver 区间,只改一处谓词)。`examples/` 与本仓 fixture 已带该文件作为迁移起点;缺文件的工程暂时跳过此检查(OPEN)。
|
||||
|
||||
+3
-3
@@ -3,11 +3,11 @@
|
||||
These crates implement the rule-based lesson checker whose semantics are
|
||||
pinned by the ADRs in `docs/adr/`: it reads an engineering-file (one lesson,
|
||||
ADR-0005)
|
||||
laid out per ADR-0029 (a nested outline manifest — every container folder
|
||||
laid out per ADR-0036 (a nested outline manifest — every container folder
|
||||
carries `manifest.toml`, every leaf carries `element.toml`; supersedes
|
||||
ADR-0008's flat `[[parts]]`), validates structure and content, and emits
|
||||
diagnostics. `cph-diag` (the shared diagnostic vocabulary), `cph-model` (the
|
||||
ADR-0029 loader, also loading `bundle.toml` arrangements per ADR-0030), and
|
||||
ADR-0036 loader, also loading `bundle.toml` arrangements per ADR-0037), and
|
||||
`cph-typst` (the typst `World` / compile / span-mapping layer) are
|
||||
deliberately reusable by future components such as an `exporter`, which is why
|
||||
they live in this repo-wide `crates/` directory rather than under any single
|
||||
@@ -20,7 +20,7 @@ entrypoint) are the checker proper.
|
||||
| crate | owner | role |
|
||||
|---------------|-------|------|
|
||||
| `cph-diag` | WU-1 | shared diagnostic vocabulary (`Severity`, `DiagCode`, `Diagnostic`, `SourceSpan`) — reusable |
|
||||
| `cph-model` | WU-1 | parses the ADR-0029 nested outline layout (+ ADR-0030 bundles) into an in-memory ordered `Lesson`/`Bundle` — reusable |
|
||||
| `cph-model` | WU-1 | parses the ADR-0036 nested outline layout (+ ADR-0037 bundles) into an in-memory ordered `Lesson`/`Bundle` — reusable |
|
||||
| `cph-schema` | WU-3 | the 4 stdlib kind JSON Schemas + structural validation |
|
||||
| `cph-typst` | WU-4 | typst `World`, driver generation, compile, PDF, span mapping — reusable |
|
||||
| `cph-check` | WU-5 | orchestration: render-coverage and the full check pipeline |
|
||||
|
||||
@@ -229,9 +229,9 @@ pub fn build(root: &Path, engine: &Engine, target: &str) -> (Option<Vec<u8>>, Ch
|
||||
}
|
||||
}
|
||||
|
||||
/// Build a PDF for a **bundle** target (ADR-0030): the multi-lesson combined
|
||||
/// Build a PDF for a **bundle** target (ADR-0037): the multi-lesson combined
|
||||
/// artifact. Mirrors [`build`]'s contract and gating, but runs phases (a)–(c)
|
||||
/// over **every member lesson independently** (ADR-0030's invariant: each
|
||||
/// over **every member lesson independently** (ADR-0037's invariant: each
|
||||
/// lesson stays independently checkable; the bundle only reads them for
|
||||
/// assembly). Any member's structural/schema error refuses the whole bundle
|
||||
/// build — a broken member lesson makes the combined artifact invalid too.
|
||||
@@ -288,7 +288,7 @@ pub fn build_bundle(root: &Path, engine: &Engine, target: &str) -> (Option<Vec<u
|
||||
}
|
||||
|
||||
/// The bundle's declared export-target names, in declared order — or
|
||||
/// `[DEFAULT_TARGET]` if it declares none (ADR-0030 batch default, mirroring
|
||||
/// `[DEFAULT_TARGET]` if it declares none (ADR-0037 batch default, mirroring
|
||||
/// [`declared_target_names`]).
|
||||
pub fn declared_bundle_target_names(root: &Path) -> Vec<String> {
|
||||
let (bundle, _) = cph_model::load_bundle(root);
|
||||
@@ -301,7 +301,7 @@ pub fn declared_bundle_target_names(root: &Path) -> Vec<String> {
|
||||
}
|
||||
|
||||
/// The lesson's declared export-target names, in declared order — or
|
||||
/// `[DEFAULT_TARGET]` if it declares none (ADR-0030 batch default: `cph build`
|
||||
/// `[DEFAULT_TARGET]` if it declares none (ADR-0037 batch default: `cph build`
|
||||
/// with no `--target` builds every declared target).
|
||||
///
|
||||
/// Loads the lesson read-only, ignoring diagnostics: an unloadable lesson (or
|
||||
@@ -564,7 +564,7 @@ pub struct MarkdownAssembleReport {
|
||||
}
|
||||
|
||||
/// Execute the `AssembleMarkdown` steps of a target (ADR-0015): concatenate each
|
||||
/// element's `<field>.md` markdown content file in `parts` order (ADR-0029's
|
||||
/// element's `<field>.md` markdown content file in `parts` order (ADR-0036's
|
||||
/// depth-first element sequence) into the target's single-file artifact.
|
||||
/// This is the **third typed step**: unlike
|
||||
/// [`build`] (typst template → PDF) the framework owns the read/concatenate/write
|
||||
|
||||
+12
-12
@@ -41,7 +41,7 @@ enum Command {
|
||||
/// Build one or more render targets. Exits 1 if any target fails.
|
||||
///
|
||||
/// With no `--target`, batches every target the lesson declares
|
||||
/// (ADR-0030): each target builds independently — one failing does not
|
||||
/// (ADR-0037): each target builds independently — one failing does not
|
||||
/// stop the rest — and the exit code is non-zero if any target failed.
|
||||
/// Repeat `--target` to build an explicit ordered subset instead.
|
||||
Build {
|
||||
@@ -57,7 +57,7 @@ enum Command {
|
||||
#[arg(short = 'o', long, value_name = "OUT")]
|
||||
out: Option<PathBuf>,
|
||||
},
|
||||
/// Build one or more bundle targets (ADR-0030): combine an ordered
|
||||
/// Build one or more bundle targets (ADR-0037): combine an ordered
|
||||
/// arrangement of self-contained lessons (`bundle.toml`) into one
|
||||
/// artifact. Same batching/exit-code contract as `build`.
|
||||
Bundle {
|
||||
@@ -209,12 +209,12 @@ fn run_completions(shell: CompletionTarget) -> ExitCode {
|
||||
// authoritative: whatever these write, `cph check` must accept.
|
||||
|
||||
/// The stock `exports/student.typ` written by `init` — the framework's default
|
||||
/// render template (ADR-0011, outline-shape ADR-0029), the same file the
|
||||
/// render template (ADR-0011, outline-shape ADR-0036), the same file the
|
||||
/// examples ship. Kept verbatim so a freshly scaffolded engineering file
|
||||
/// renders out of the box; it imports `@local/cph-render:0.1.0`, which the
|
||||
/// engine resolves from the embedded package. Presentation (heading numbering,
|
||||
/// styling) is editable here per engineering file, not in the manifest.
|
||||
const DEFAULT_STUDENT_TEMPLATE: &str = r##"// DEFAULT STUDENT TEMPLATE (framework default; ADR-0011, outline shape ADR-0029).
|
||||
const DEFAULT_STUDENT_TEMPLATE: &str = r##"// DEFAULT STUDENT TEMPLATE (framework default; ADR-0011, outline shape ADR-0036).
|
||||
//
|
||||
// This is a *real, editable* file that lives in an engineering file at
|
||||
// `exports/student.typ`. The framework compiles it AS THE MAIN FILE with the
|
||||
@@ -232,7 +232,7 @@ const DEFAULT_STUDENT_TEMPLATE: &str = r##"// DEFAULT STUDENT TEMPLATE (framewor
|
||||
// PACKAGE, not the engineering root. A `/<part.path>/<field>.typ` written HERE
|
||||
// (this template lives under `--root`) resolves against `--root`. So the
|
||||
// template loads content and hands cph-render an already-assembled `outline`
|
||||
// array (elements interleaved with section headings, ADR-0029).
|
||||
// array (elements interleaved with section headings, ADR-0036).
|
||||
//
|
||||
// OPEN CONTRACT POINT — optional-content presence. typst has no "does this file
|
||||
// exist" primitive (a missing `include` is a hard compile error). So the
|
||||
@@ -259,7 +259,7 @@ const DEFAULT_STUDENT_TEMPLATE: &str = r##"// DEFAULT STUDENT TEMPLATE (framewor
|
||||
// resolved against --root) and read scalar fields from <path>/element.toml.
|
||||
// `part-fields` (from cph-render) is the single source of truth for
|
||||
// kind->fields.
|
||||
// - a "section" entry (ADR-0029): pass its title/depth straight through — no
|
||||
// - a "section" entry (ADR-0036): pass its title/depth straight through — no
|
||||
// content to load, it is a heading.
|
||||
#let outline = raw-outline.map(raw => {
|
||||
if raw.at("type", default: "element") == "section" {
|
||||
@@ -432,7 +432,7 @@ template = "exports/student.typ"
|
||||
|
||||
/// Add a new part to the engineering file at `root`: create its folder with
|
||||
/// `element.toml` + blank required content files, then append its `[[children]]`
|
||||
/// entry to the root `manifest.toml` (ADR-0029 root children). Rejects unknown
|
||||
/// entry to the root `manifest.toml` (ADR-0036 root children). Rejects unknown
|
||||
/// kinds, unsafe names, and anything that would double-register an existing part.
|
||||
fn run_add(root: &std::path::Path, kind: &str, name: &str) -> ExitCode {
|
||||
let dir = match kind_dir(kind) {
|
||||
@@ -524,7 +524,7 @@ fn manifest_has_child(manifest: &str, rel: &str) -> bool {
|
||||
/// adjacent). The block goes immediately before the first section header that is
|
||||
/// neither `[project]`/`[info]` nor an existing `[[children]]` entry (i.e. before
|
||||
/// `[targets.*]`), or at end-of-file if none — either way it lands at the tail
|
||||
/// of the root-children run, after `[info]` and any existing children (ADR-0029).
|
||||
/// of the root-children run, after `[info]` and any existing children (ADR-0036).
|
||||
/// Comment blocks are preserved.
|
||||
fn insert_child(manifest: &str, kind: &str, rel: &str) -> String {
|
||||
let block = format!("[[children]]\nkind = \"{kind}\"\npath = \"{rel}\"\n");
|
||||
@@ -717,13 +717,13 @@ fn write_outline_output(path: &std::path::Path, bytes: &[u8], force: bool) -> Re
|
||||
}
|
||||
}
|
||||
|
||||
/// Dispatch `cph build` (ADR-0030): with an explicit `--target` (repeatable),
|
||||
/// Dispatch `cph build` (ADR-0037): with an explicit `--target` (repeatable),
|
||||
/// build exactly that ordered set; with none, batch every target the lesson
|
||||
/// declares. Each target builds **independently** — one failing does not stop
|
||||
/// the rest — and prints a per-target ledger when building more than one.
|
||||
/// Exits non-zero iff **any** target failed to produce its artifact (a build
|
||||
/// failure is a real defect, distinct from the non-blocking `renderIgnored`
|
||||
/// warning class — ADR-0030).
|
||||
/// warning class — ADR-0037).
|
||||
fn run_build_command(
|
||||
path: &std::path::Path,
|
||||
engine: &Engine,
|
||||
@@ -819,10 +819,10 @@ fn run_build_one(
|
||||
}
|
||||
}
|
||||
|
||||
/// Dispatch `cph bundle` (ADR-0030) — same batching/exit-code contract as
|
||||
/// Dispatch `cph bundle` (ADR-0037) — same batching/exit-code contract as
|
||||
/// [`run_build_command`], over a bundle's own declared targets. MVP bundle
|
||||
/// targets are `typst-compile` only (no shell/markdown-assemble routing —
|
||||
/// ADR-0030 did not extend those step kinds to bundles).
|
||||
/// ADR-0037 did not extend those step kinds to bundles).
|
||||
fn run_bundle_command(
|
||||
path: &std::path::Path,
|
||||
engine: &Engine,
|
||||
|
||||
@@ -90,8 +90,8 @@ pub enum DiagCode {
|
||||
/// A `manifest.toml`/`bundle.toml` is structurally broken: invalid TOML, a
|
||||
/// required table missing (root `[project]`/`[info]`), a folder that is
|
||||
/// neither a container (`manifest.toml`) nor a leaf (`element.toml`) — or
|
||||
/// is ambiguously both (ADR-0029) — or a bundle `lessons` entry malformed
|
||||
/// (ADR-0030). Distinct from `SchemaViolation` (instance data vs. its
|
||||
/// is ambiguously both (ADR-0036) — or a bundle `lessons` entry malformed
|
||||
/// (ADR-0037). Distinct from `SchemaViolation` (instance data vs. its
|
||||
/// kind's schema): this code is for the *carrier document's own*
|
||||
/// structure. Added to discharge the manifest-level errors that used to
|
||||
/// overload `SchemaViolation` before this code existed.
|
||||
|
||||
+20
-20
@@ -1,4 +1,4 @@
|
||||
//! `cph-model` — load the ADR-0029 nested outline manifest into an in-memory
|
||||
//! `cph-model` — load the ADR-0036 nested outline manifest into an in-memory
|
||||
//! lesson.
|
||||
//!
|
||||
//! This crate is the **loader**, not the full checker. A lesson's structure is
|
||||
@@ -12,7 +12,7 @@
|
||||
//! pipeline validate and include content from — unaffected by nesting.
|
||||
//! - [`Lesson::outline`] — the **full rendering-order sequence**: elements
|
||||
//! interleaved with section headings, at the depth-first traversal position
|
||||
//! they open at (ADR-0029). This is what the augmented manifest (built by
|
||||
//! they open at (ADR-0036). This is what the augmented manifest (built by
|
||||
//! `cph-typst`) walks to hand the template a rendering order that includes
|
||||
//! headings.
|
||||
//!
|
||||
@@ -34,7 +34,7 @@ use std::path::{Component, Path, PathBuf};
|
||||
use cph_diag::{DiagCode, Diagnostic, Severity};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// An in-memory lesson loaded from an engineering file (ADR-0029).
|
||||
/// An in-memory lesson loaded from an engineering file (ADR-0036).
|
||||
#[derive(Debug, Clone, PartialEq, Serialize)]
|
||||
pub struct Lesson {
|
||||
/// `[project]` from the root manifest (id, name).
|
||||
@@ -43,12 +43,12 @@ pub struct Lesson {
|
||||
pub info: Info,
|
||||
/// The ordered **element** sequence — the lesson's element order (ADR-0005).
|
||||
/// Contains only leaves; containers never appear here (a container
|
||||
/// "contributes no element of its own", ADR-0029). Index-stable: an
|
||||
/// "contributes no element of its own", ADR-0036). Index-stable: an
|
||||
/// [`OutlineEntry::Element`] names a position in this `Vec` by index.
|
||||
pub parts: Vec<Part>,
|
||||
/// The full depth-first rendering order: elements (by index into `parts`)
|
||||
/// interleaved with section headings, at the position they open in the
|
||||
/// tree (ADR-0029). Consumed by the augmented-manifest builder so a
|
||||
/// tree (ADR-0036). Consumed by the augmented-manifest builder so a
|
||||
/// template can render headings in their real position; `cph-check`'s
|
||||
/// structural/schema/coverage phases do not need it (they use `parts`).
|
||||
pub outline: Vec<OutlineEntry>,
|
||||
@@ -77,7 +77,7 @@ impl Lesson {
|
||||
}
|
||||
}
|
||||
|
||||
/// One entry in the lesson's full rendering-order sequence (ADR-0029).
|
||||
/// One entry in the lesson's full rendering-order sequence (ADR-0036).
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
||||
pub enum OutlineEntry {
|
||||
/// An element at this position: `part_index` into [`Lesson::parts`].
|
||||
@@ -88,7 +88,7 @@ pub enum OutlineEntry {
|
||||
depth: u32,
|
||||
},
|
||||
/// A section container opens here. Contributes no element; it is a
|
||||
/// heading, not a part (ADR-0029). `depth` is the section's nesting depth
|
||||
/// heading, not a part (ADR-0036). `depth` is the section's nesting depth
|
||||
/// (1 = a section directly under the engineering-file root).
|
||||
Section {
|
||||
/// The container's declared kind (MVP: always `"section"`; validated
|
||||
@@ -378,17 +378,17 @@ pub struct Info {
|
||||
/// One element leaf, plus its loaded `element.toml` descriptor.
|
||||
///
|
||||
/// `path` is the element folder's path relative to the engineering-file root,
|
||||
/// regardless of how deeply nested it is in the outline tree (ADR-0029) — the
|
||||
/// regardless of how deeply nested it is in the outline tree (ADR-0036) — the
|
||||
/// loader accumulates full root-relative paths during the depth-first walk, so
|
||||
/// every downstream consumer (schema validation, augmented-manifest include
|
||||
/// paths) keeps working against a root-relative path exactly as before ADR-0029.
|
||||
/// paths) keeps working against a root-relative path exactly as before ADR-0036.
|
||||
#[derive(Debug, Clone, PartialEq, Serialize)]
|
||||
pub struct Part {
|
||||
/// Declared kind from the containing outline entry (ADR-0006). This is the
|
||||
/// **declared** kind, which may disagree with the `element.toml` kind (a
|
||||
/// disagreement is reported as [`DiagCode::UnknownKind`], but the declared
|
||||
/// kind — not the descriptor's — is what `cph-check`'s known-kind check
|
||||
/// tests, matching pre-ADR-0029 behavior).
|
||||
/// tests, matching pre-ADR-0036 behavior).
|
||||
pub kind: String,
|
||||
/// Element folder path, root-relative, kept verbatim (forward/back slashes
|
||||
/// as the OS provides) for diagnostics/display.
|
||||
@@ -418,7 +418,7 @@ pub struct ElementDescriptor {
|
||||
|
||||
// --- raw deserialization shapes (mirror the on-disk TOML) ---------------------
|
||||
|
||||
/// One `manifest.toml`, root or container (ADR-0029). Root-only tables
|
||||
/// One `manifest.toml`, root or container (ADR-0036). Root-only tables
|
||||
/// (`project`/`info`/`targets`) and the container-only `group` table coexist in
|
||||
/// one shape; [`load`]/[`load_children`] enforce which is expected where and
|
||||
/// flag misplacement rather than rejecting parse outright (non-fatal, like
|
||||
@@ -471,14 +471,14 @@ impl RawAuthor {
|
||||
}
|
||||
}
|
||||
|
||||
/// A container's optional `[group]` table (ADR-0029): presentation metadata for
|
||||
/// A container's optional `[group]` table (ADR-0036): presentation metadata for
|
||||
/// a section, kept minimal per the ADR's recommended default.
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct RawGroup {
|
||||
title: Option<String>,
|
||||
}
|
||||
|
||||
/// One `children` entry (ADR-0029): a `kind` + a **parent-relative** `path`.
|
||||
/// One `children` entry (ADR-0036): a `kind` + a **parent-relative** `path`.
|
||||
/// The loader resolves on disk whether the named folder is a leaf
|
||||
/// (`element.toml`) or a container (`manifest.toml`) — `kind` is the declared
|
||||
/// label, cross-checked against the leaf's `element.toml` kind (unchanged from
|
||||
@@ -600,7 +600,7 @@ pub fn load(root: &Path) -> (Option<Lesson>, Vec<Diagnostic>) {
|
||||
}
|
||||
};
|
||||
|
||||
// The root is the implicit top container (ADR-0029): it must not declare
|
||||
// The root is the implicit top container (ADR-0036): it must not declare
|
||||
// `[group]` (that is container-only presentation metadata).
|
||||
if raw.group.is_some() {
|
||||
diags.push(
|
||||
@@ -625,7 +625,7 @@ pub fn load(root: &Path) -> (Option<Lesson>, Vec<Diagnostic>) {
|
||||
.map(|(name, value)| parse_target(name, value, &mut diags))
|
||||
.collect();
|
||||
|
||||
// Walk the outline tree depth-first (ADR-0029), starting at the root's own
|
||||
// Walk the outline tree depth-first (ADR-0036), starting at the root's own
|
||||
// children. A direct child section of the root opens at depth 1.
|
||||
let mut parts = Vec::new();
|
||||
let mut outline = Vec::new();
|
||||
@@ -652,7 +652,7 @@ pub fn load(root: &Path) -> (Option<Lesson>, Vec<Diagnostic>) {
|
||||
}
|
||||
|
||||
/// Recursively load one container's ordered `children` into `parts`/`outline`
|
||||
/// (ADR-0029). `container_dir` is the container's own absolute directory;
|
||||
/// (ADR-0036). `container_dir` is the container's own absolute directory;
|
||||
/// `rel_prefix` is that container's own root-relative path (empty for the
|
||||
/// engineering-file root). `next_section_depth` is the depth a **direct**
|
||||
/// section child of this container would open at (1 for the root's children).
|
||||
@@ -884,7 +884,7 @@ fn read_container_manifest(dir: &Path, diags: &mut Vec<Diagnostic>) -> Option<Ra
|
||||
|
||||
/// Record a broken child as a placeholder leaf (empty descriptor) so that
|
||||
/// order/count stays observable even when the folder could not be resolved to
|
||||
/// either a leaf or a container. Mirrors the pre-ADR-0029 behavior for a
|
||||
/// either a leaf or a container. Mirrors the pre-ADR-0036 behavior for a
|
||||
/// missing part folder.
|
||||
fn push_broken_leaf(
|
||||
parts: &mut Vec<Part>,
|
||||
@@ -1498,9 +1498,9 @@ fn has_parent_traversal(path: &Path) -> bool {
|
||||
path.components().any(|c| matches!(c, Component::ParentDir))
|
||||
}
|
||||
|
||||
// --- bundle: an ordered arrangement of lessons (ADR-0030) --------------------
|
||||
// --- bundle: an ordered arrangement of lessons (ADR-0037) --------------------
|
||||
|
||||
/// A **bundle** (ADR-0030): a directory carrying `bundle.toml`, which arranges
|
||||
/// A **bundle** (ADR-0037): a directory carrying `bundle.toml`, which arranges
|
||||
/// an ordered list of already-authored, self-contained lessons into one export
|
||||
/// unit. Discharges ADR-0005's deferred "course = arrangement of lessons" for
|
||||
/// the export purpose, without inventing a full course-authoring model.
|
||||
@@ -1540,7 +1540,7 @@ pub struct BundleLesson {
|
||||
/// `bundle.toml` (kept verbatim for diagnostics/display).
|
||||
pub path: PathBuf,
|
||||
/// Which of that lesson's own declared targets to render into the bundle
|
||||
/// (ADR-0030: the bundle assembles a lesson's already-authored content, it
|
||||
/// (ADR-0037: the bundle assembles a lesson's already-authored content, it
|
||||
/// does not re-target it). Defaults to the lesson's first declared target,
|
||||
/// or `"student"` if the lesson declares none.
|
||||
pub target: String,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Integration tests for `cph_model::load_bundle` (ADR-0030): an ordered
|
||||
//! Integration tests for `cph_model::load_bundle` (ADR-0037): an ordered
|
||||
//! arrangement of self-contained lessons, loaded from `bundle.toml`.
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//! Integration tests for `cph_model::load`, driven by static fixtures under
|
||||
//! `tests/fixtures/`. The fixtures double as documentation of the ADR-0029
|
||||
//! `tests/fixtures/`. The fixtures double as documentation of the ADR-0036
|
||||
//! on-disk format (a nested outline manifest; supersedes ADR-0008's flat
|
||||
//! `[[parts]]`).
|
||||
|
||||
@@ -111,7 +111,7 @@ fn nested_sections_flatten_depth_first_with_correct_depths() {
|
||||
"nested fixture must have no diagnostics, got: {diags:?}"
|
||||
);
|
||||
|
||||
// DFS pre-order element sequence (ADR-0029): containers contribute no
|
||||
// DFS pre-order element sequence (ADR-0036): containers contribute no
|
||||
// element of their own.
|
||||
let paths: Vec<_> = lesson.parts.iter().map(|p| p.path.clone()).collect();
|
||||
assert_eq!(
|
||||
|
||||
@@ -181,7 +181,7 @@ impl Engine {
|
||||
))
|
||||
}
|
||||
|
||||
/// Compile-check `bundle` for `target` (ADR-0030) — same contract as
|
||||
/// Compile-check `bundle` for `target` (ADR-0037) — same contract as
|
||||
/// [`Engine::compile_check`], but over a [`Bundle`]'s own declared targets
|
||||
/// and the augmented **bundle** manifest (each member lesson's outline,
|
||||
/// path-prefixed to resolve against the bundle root).
|
||||
@@ -200,7 +200,7 @@ impl Engine {
|
||||
out
|
||||
}
|
||||
|
||||
/// Build a PDF for `bundle` / `target` (ADR-0030) — same contract as
|
||||
/// Build a PDF for `bundle` / `target` (ADR-0037) — same contract as
|
||||
/// [`Engine::build_pdf`], over a [`Bundle`]'s own declared targets.
|
||||
pub fn build_bundle_pdf(
|
||||
&self,
|
||||
@@ -244,7 +244,7 @@ impl Default for Engine {
|
||||
|
||||
/// Validate a `(targets, target)` request and resolve the template path to
|
||||
/// compile. Shared by [`Engine::world_for`] (a lesson's `targets`) and
|
||||
/// [`Engine::world_for_bundle`] (a bundle's own `targets` — ADR-0030 gives a
|
||||
/// [`Engine::world_for_bundle`] (a bundle's own `targets` — ADR-0037 gives a
|
||||
/// bundle target the exact same build/artifact/step shape). Returns
|
||||
/// `Ok(template_path)` (relative to the lesson/bundle root) when the request is
|
||||
/// buildable, or `Err(blocking_diagnostics)` when it is not:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Augmented-manifest construction (ADR-0011, outline shape per ADR-0029).
|
||||
//! Augmented-manifest construction (ADR-0011, outline shape per ADR-0036).
|
||||
//!
|
||||
//! The template (`exports/<target>.typ`) reads the manifest via
|
||||
//! `toml(sys.inputs.manifest)`, then for each **element** outline entry
|
||||
@@ -10,13 +10,13 @@
|
||||
//!
|
||||
//! The ENGINE has filesystem access, so it closes that gap: it builds an
|
||||
//! **augmented manifest** = the lesson's `[info]` + the ordered `[[outline]]`
|
||||
//! (ADR-0029's depth-first rendering order — elements interleaved with section
|
||||
//! (ADR-0036's depth-first rendering order — elements interleaved with section
|
||||
//! headings at their DFS-open position). Each `[[outline]]` entry carries a
|
||||
//! `type` discriminator (`"element"` | `"section"`):
|
||||
//!
|
||||
//! - `type = "element"`: `kind`, `path`, and a per-part **`fields` array**
|
||||
//! listing the content fields whose `<field>.typ` actually exists under the
|
||||
//! lesson root (same contract as before ADR-0029).
|
||||
//! lesson root (same contract as before ADR-0036).
|
||||
//! - `type = "section"`: `kind`, `title`, `depth`, `path` — a section heading;
|
||||
//! the template renders it without touching any content file.
|
||||
//!
|
||||
@@ -41,7 +41,7 @@ use cph_model::{Bundle, BundleLesson, Lesson, OutlineEntry};
|
||||
///
|
||||
/// The result is a self-contained TOML document the template's
|
||||
/// `toml(sys.inputs.manifest)` reads. It carries `[info]` (title + optional
|
||||
/// author) and the ordered `[[outline]]` (ADR-0029's depth-first rendering
|
||||
/// author) and the ordered `[[outline]]` (ADR-0036's depth-first rendering
|
||||
/// order), each entry typed `"element"` or `"section"` per the module docs. It
|
||||
/// does **not** reproduce `[project]` or `[targets.*]` — the template only
|
||||
/// consumes `info` and `outline`.
|
||||
@@ -50,7 +50,7 @@ pub fn build_augmented_manifest(lesson: &Lesson) -> String {
|
||||
|
||||
doc.insert("info".to_string(), toml::Value::Table(info_table(lesson)));
|
||||
|
||||
// [[outline]] — ADR-0029's depth-first rendering order: elements
|
||||
// [[outline]] — ADR-0036's depth-first rendering order: elements
|
||||
// interleaved with section headings at their DFS-open position.
|
||||
let outline: Vec<toml::Value> = lesson
|
||||
.outline
|
||||
@@ -62,7 +62,7 @@ pub fn build_augmented_manifest(lesson: &Lesson) -> String {
|
||||
toml::to_string(&doc).expect("augmented manifest serializes")
|
||||
}
|
||||
|
||||
/// Build the augmented **bundle** manifest TOML source for `bundle` (ADR-0030).
|
||||
/// Build the augmented **bundle** manifest TOML source for `bundle` (ADR-0037).
|
||||
///
|
||||
/// The bundle template (`exports/<target>.typ` under the `bundle.toml` root)
|
||||
/// reads it via `toml(sys.inputs.manifest)`. It carries `[info]` (the bundle's
|
||||
@@ -71,7 +71,7 @@ pub fn build_augmented_manifest(lesson: &Lesson) -> String {
|
||||
/// would assemble, except every outline entry's `path` is **prefixed with that
|
||||
/// lesson's own bundle-root-relative directory** (`BundleLesson::path`), since
|
||||
/// the bundle template's computed include paths resolve against the *bundle*
|
||||
/// root, not each lesson's own root (ADR-0030: combination reads
|
||||
/// root, not each lesson's own root (ADR-0037: combination reads
|
||||
/// already-authored lessons at export time; each lesson's `path` bookkeeping
|
||||
/// stays correct because the prefix is applied only here, in the manifest the
|
||||
/// template consumes — never inside a lesson's own authored content).
|
||||
@@ -147,7 +147,7 @@ fn info_table(lesson: &Lesson) -> toml::Table {
|
||||
}
|
||||
|
||||
/// Build one `[[outline]]` entry's table for either variant of
|
||||
/// [`OutlineEntry`]. `bundle_prefix`, when set (ADR-0030's bundle case), is
|
||||
/// [`OutlineEntry`]. `bundle_prefix`, when set (ADR-0037's bundle case), is
|
||||
/// joined onto the emitted `path` so the bundle template's computed include
|
||||
/// resolves against the bundle root rather than the lesson's own root.
|
||||
fn outline_entry_table(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Integration tests for the bundle build path (ADR-0030): compiling a bundle
|
||||
//! Integration tests for the bundle build path (ADR-0037): compiling a bundle
|
||||
//! target's template (`exports/<target>.typ` under a `bundle.toml` root) as
|
||||
//! main, injecting the augmented **bundle** manifest, against the real
|
||||
//! `render/` package.
|
||||
@@ -32,7 +32,7 @@ fn load_bundle() -> cph_model::Bundle {
|
||||
|
||||
/// PURE UNIT TEST (no fonts, no render package): the augmented bundle manifest
|
||||
/// carries the bundle's own `[info]` and an ordered `[[lessons]]`, each with
|
||||
/// that member's own `info`/`target` and a `path`-prefixed outline (ADR-0030).
|
||||
/// that member's own `info`/`target` and a `path`-prefixed outline (ADR-0037).
|
||||
#[test]
|
||||
fn augmented_bundle_manifest_prefixes_member_paths() {
|
||||
let bundle = load_bundle();
|
||||
|
||||
@@ -39,7 +39,7 @@ fn load_mini() -> cph_model::Lesson {
|
||||
}
|
||||
|
||||
/// PURE UNIT TEST (no fonts, no render package): the augmented manifest carries
|
||||
/// `[info]` and the ordered `[[outline]]` (ADR-0029) — elements (with a
|
||||
/// `[info]` and the ordered `[[outline]]` (ADR-0036) — elements (with a
|
||||
/// per-element `fields` array of the content fields present on disk)
|
||||
/// interleaved with the section heading the mini fixture nests its two lemmas
|
||||
/// under.
|
||||
@@ -58,7 +58,7 @@ fn augmented_manifest_has_outline_with_section_and_fields() {
|
||||
.get("outline")
|
||||
.and_then(|p| p.as_array())
|
||||
.expect("outline array present");
|
||||
// segment, section, lemma, lemma, example — 5 entries (ADR-0029: the
|
||||
// segment, section, lemma, lemma, example — 5 entries (ADR-0036: the
|
||||
// section contributes a heading entry, not an element).
|
||||
assert_eq!(outline.len(), 5, "five outline entries:\n{src}");
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// DEFAULT BUNDLE TEMPLATE (ADR-0030, outline shape ADR-0029).
|
||||
// DEFAULT BUNDLE TEMPLATE (ADR-0037, outline shape ADR-0036).
|
||||
//
|
||||
// Lives in a bundle at `<bundle-root>/exports/<target>.typ`, e.g.
|
||||
// `exports/merged.typ`. Compiled AS MAIN with the augmented BUNDLE manifest
|
||||
@@ -66,7 +66,7 @@
|
||||
))
|
||||
|
||||
// Presentation: shared per-level heading numbering across the whole bundle,
|
||||
// and the ADR-0030 recommended default of resetting auto-counters at each
|
||||
// and the ADR-0037 recommended default of resetting auto-counters at each
|
||||
// lesson boundary (override `reset-counters: false` for continuous numbering).
|
||||
#render-bundle(
|
||||
info: info,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// DEFAULT STUDENT TEMPLATE (framework default; ADR-0011, outline shape ADR-0029).
|
||||
// DEFAULT STUDENT TEMPLATE (framework default; ADR-0011, outline shape ADR-0036).
|
||||
//
|
||||
// This is a *real, editable* file that lives in an engineering file at
|
||||
// `exports/student.typ`. The framework compiles it AS THE MAIN FILE with the
|
||||
@@ -16,7 +16,7 @@
|
||||
// PACKAGE, not the engineering root. A `/<part.path>/<field>.typ` written HERE
|
||||
// (this template lives under `--root`) resolves against `--root`. So the
|
||||
// template loads content and hands cph-render an already-assembled `outline`
|
||||
// array (elements interleaved with section headings, ADR-0029).
|
||||
// array (elements interleaved with section headings, ADR-0036).
|
||||
//
|
||||
// OPEN CONTRACT POINT — optional-content presence. typst has no "does this file
|
||||
// exist" primitive (a missing `include` is a hard compile error). So the
|
||||
@@ -43,7 +43,7 @@
|
||||
// resolved against --root) and read scalar fields from <path>/element.toml.
|
||||
// `part-fields` (from cph-render) is the single source of truth for
|
||||
// kind->fields.
|
||||
// - a "section" entry (ADR-0029): pass its title/depth straight through — no
|
||||
// - a "section" entry (ADR-0036): pass its title/depth straight through — no
|
||||
// content to load, it is a heading.
|
||||
#let outline = raw-outline.map(raw => {
|
||||
if raw.at("type", default: "element") == "section" {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// DEFAULT TEACHER TEMPLATE (framework default; ADR-0011, outline shape ADR-0029).
|
||||
// DEFAULT TEACHER TEMPLATE (framework default; ADR-0011, outline shape ADR-0036).
|
||||
//
|
||||
// Lives in an engineering file at `exports/teacher.typ`. Compiled AS MAIN with
|
||||
// the manifest injected:
|
||||
@@ -21,7 +21,7 @@
|
||||
#let raw-outline = manifest.at("outline", default: ())
|
||||
|
||||
// Assemble each outline entry: an "element" entry includes its content fields
|
||||
// and reads scalars from element.toml; a "section" entry (ADR-0029) passes
|
||||
// and reads scalars from element.toml; a "section" entry (ADR-0036) passes
|
||||
// title/depth straight through as a heading, no content to load.
|
||||
#let outline = raw-outline.map(raw => {
|
||||
if raw.at("type", default: "element") == "section" {
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
# ADR 0029: Engineering-File Structure Is A Nested Outline Manifest
|
||||
# ADR 0036: Engineering-File Structure Is A Nested Outline Manifest
|
||||
|
||||
## Status
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
# ADR 0030: Batch & Combined Export
|
||||
# ADR 0037: Batch & Combined Export
|
||||
|
||||
## Status
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// DEFAULT STUDENT TEMPLATE (framework default; ADR-0011, outline shape ADR-0029).
|
||||
// DEFAULT STUDENT TEMPLATE (framework default; ADR-0011, outline shape ADR-0036).
|
||||
//
|
||||
// This is a *real, editable* file that lives in an engineering file at
|
||||
// `exports/student.typ`. The framework compiles it AS THE MAIN FILE with the
|
||||
@@ -16,7 +16,7 @@
|
||||
// PACKAGE, not the engineering root. A `/<part.path>/<field>.typ` written HERE
|
||||
// (this template lives under `--root`) resolves against `--root`. So the
|
||||
// template loads content and hands cph-render an already-assembled `outline`
|
||||
// array (elements interleaved with section headings, ADR-0029).
|
||||
// array (elements interleaved with section headings, ADR-0036).
|
||||
//
|
||||
// OPEN CONTRACT POINT — optional-content presence. typst has no "does this file
|
||||
// exist" primitive (a missing `include` is a hard compile error). So the
|
||||
@@ -43,7 +43,7 @@
|
||||
// resolved against --root) and read scalar fields from <path>/element.toml.
|
||||
// `part-fields` (from cph-render) is the single source of truth for
|
||||
// kind->fields.
|
||||
// - a "section" entry (ADR-0029): pass its title/depth straight through — no
|
||||
// - a "section" entry (ADR-0036): pass its title/depth straight through — no
|
||||
// content to load, it is a heading.
|
||||
#let outline = raw-outline.map(raw => {
|
||||
if raw.at("type", default: "element") == "section" {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// DEFAULT TEACHER TEMPLATE (framework default; ADR-0011, outline shape ADR-0029).
|
||||
// DEFAULT TEACHER TEMPLATE (framework default; ADR-0011, outline shape ADR-0036).
|
||||
//
|
||||
// Lives in an engineering file at `exports/teacher.typ`. Compiled AS MAIN with
|
||||
// the manifest injected:
|
||||
@@ -21,7 +21,7 @@
|
||||
#let raw-outline = manifest.at("outline", default: ())
|
||||
|
||||
// Assemble each outline entry: an "element" entry includes its content fields
|
||||
// and reads scalars from element.toml; a "section" entry (ADR-0029) passes
|
||||
// and reads scalars from element.toml; a "section" entry (ADR-0036) passes
|
||||
// title/depth straight through as a heading, no content to load.
|
||||
#let outline = raw-outline.map(raw => {
|
||||
if raw.at("type", default: "element") == "section" {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// DEFAULT STUDENT TEMPLATE (framework default; ADR-0011, outline shape ADR-0029).
|
||||
// DEFAULT STUDENT TEMPLATE (framework default; ADR-0011, outline shape ADR-0036).
|
||||
//
|
||||
// This is a *real, editable* file that lives in an engineering file at
|
||||
// `exports/student.typ`. The framework compiles it AS THE MAIN FILE with the
|
||||
@@ -16,7 +16,7 @@
|
||||
// PACKAGE, not the engineering root. A `/<part.path>/<field>.typ` written HERE
|
||||
// (this template lives under `--root`) resolves against `--root`. So the
|
||||
// template loads content and hands cph-render an already-assembled `outline`
|
||||
// array (elements interleaved with section headings, ADR-0029).
|
||||
// array (elements interleaved with section headings, ADR-0036).
|
||||
//
|
||||
// OPEN CONTRACT POINT — optional-content presence. typst has no "does this file
|
||||
// exist" primitive (a missing `include` is a hard compile error). So the
|
||||
@@ -43,7 +43,7 @@
|
||||
// resolved against --root) and read scalar fields from <path>/element.toml.
|
||||
// `part-fields` (from cph-render) is the single source of truth for
|
||||
// kind->fields.
|
||||
// - a "section" entry (ADR-0029): pass its title/depth straight through — no
|
||||
// - a "section" entry (ADR-0036): pass its title/depth straight through — no
|
||||
// content to load, it is a heading.
|
||||
#let outline = raw-outline.map(raw => {
|
||||
if raw.at("type", default: "element") == "section" {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// DEFAULT TEACHER TEMPLATE (framework default; ADR-0011, outline shape ADR-0029).
|
||||
// DEFAULT TEACHER TEMPLATE (framework default; ADR-0011, outline shape ADR-0036).
|
||||
//
|
||||
// Lives in an engineering file at `exports/teacher.typ`. Compiled AS MAIN with
|
||||
// the manifest injected:
|
||||
@@ -21,7 +21,7 @@
|
||||
#let raw-outline = manifest.at("outline", default: ())
|
||||
|
||||
// Assemble each outline entry: an "element" entry includes its content fields
|
||||
// and reads scalars from element.toml; a "section" entry (ADR-0029) passes
|
||||
// and reads scalars from element.toml; a "section" entry (ADR-0036) passes
|
||||
// title/depth straight through as a heading, no content to load.
|
||||
#let outline = raw-outline.map(raw => {
|
||||
if raw.at("type", default: "element") == "section" {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Throwaway smoke engineering file for the cph-render template round
|
||||
# (ADR-0011, outline shape ADR-0029). Exercises all 4 kinds + a section heading
|
||||
# (ADR-0011, outline shape ADR-0036). Exercises all 4 kinds + a section heading
|
||||
# + nested headings (per-level numbering) + an example with a `source` scalar
|
||||
# and one without + a lemma with proof and one without.
|
||||
#
|
||||
@@ -27,7 +27,7 @@ kind = "segment"
|
||||
path = "segments/向量数量积"
|
||||
fields = ["textbook"]
|
||||
|
||||
# A section heading (ADR-0029): opens depth-1, groups the two examples that
|
||||
# A section heading (ADR-0036): opens depth-1, groups the two examples that
|
||||
# follow. Contributes no element to the sequence.
|
||||
[[outline]]
|
||||
type = "section"
|
||||
|
||||
+8
-8
@@ -2,7 +2,7 @@
|
||||
//
|
||||
// PUBLIC ENTRY: `render-lesson(info, target, outline, heading-numbering)`.
|
||||
//
|
||||
// MODEL (ADR-0011, outline shape per ADR-0029). A build compiles a *template
|
||||
// MODEL (ADR-0011, outline shape per ADR-0036). A build compiles a *template
|
||||
// file* (e.g. `exports/student.typ`) as the typst main, with the manifest
|
||||
// injected via `--input manifest=<path>`. The template reads the manifest,
|
||||
// loads each **element** entry's content, and calls `render-lesson` here.
|
||||
@@ -25,7 +25,7 @@
|
||||
// - an ELEMENT: `entry-type: "element"`, `kind` plus that kind's
|
||||
// content/scalar fields. Content field VALUES are already-evaluated typst
|
||||
// content (the template produced them via `include`).
|
||||
// - a SECTION (ADR-0029): `entry-type: "section"`, `title` (heading text),
|
||||
// - a SECTION (ADR-0036): `entry-type: "section"`, `title` (heading text),
|
||||
// `depth` (1-based heading level). Contributes no element; it is a
|
||||
// heading at its depth-first-open position in the outline.
|
||||
//
|
||||
@@ -109,14 +109,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
/// Render one section-heading outline entry (ADR-0029): `entry.title` at
|
||||
/// Render one section-heading outline entry (ADR-0036): `entry.title` at
|
||||
/// `entry.depth` (1-based heading level).
|
||||
#let _render-section(entry) = {
|
||||
heading(level: entry.at("depth", default: 1))[#entry.at("title", default: "")]
|
||||
}
|
||||
|
||||
/// Render one outline entry: an element dispatches on `kind` via
|
||||
/// [`_render-part`]; a section (ADR-0029) renders its heading and contributes
|
||||
/// [`_render-part`]; a section (ADR-0036) renders its heading and contributes
|
||||
/// no element.
|
||||
#let _render-entry(entry, flags) = {
|
||||
if entry.at("entry-type", default: "element") == "section" {
|
||||
@@ -132,7 +132,7 @@
|
||||
/// Templates typically pass `manifest.at("info", default: (:))`.
|
||||
/// - `target`: string. MVP: "student" | "teacher". Unknown => conservative.
|
||||
/// Each template hardcodes its own target (student.typ => "student").
|
||||
/// - `outline`: ordered array of outline-entry dicts (ADR-0029), ALREADY
|
||||
/// - `outline`: ordered array of outline-entry dicts (ADR-0036), ALREADY
|
||||
/// ASSEMBLED by the template (element content fields included,
|
||||
/// scalars read; section entries carry `title`/`depth`). See file
|
||||
/// header for the entry shapes.
|
||||
@@ -183,7 +183,7 @@
|
||||
entry
|
||||
}
|
||||
|
||||
/// THE BUNDLE ENTRY POINT (ADR-0030) — called by a bundle target's template
|
||||
/// THE BUNDLE ENTRY POINT (ADR-0037) — called by a bundle target's template
|
||||
/// (`exports/<target>.typ` under a `bundle.toml` root) to assemble several
|
||||
/// already-loaded lessons into one combined document.
|
||||
///
|
||||
@@ -195,14 +195,14 @@
|
||||
/// bundle (ADR-0011 presentation-in-template stance; same knob as
|
||||
/// `render-lesson`).
|
||||
/// - `reset-counters`: whether `example`/`lemma` auto-counters reset at each
|
||||
/// lesson boundary. **Default `true`** (ADR-0030's recommended default: a
|
||||
/// lesson boundary. **Default `true`** (ADR-0037's recommended default: a
|
||||
/// lesson's internal "例题3" means that lesson's 例题3, so cross-lesson
|
||||
/// continuation would silently break author references). Pass `false` for
|
||||
/// a genuine "全书连续编号" 合集.
|
||||
///
|
||||
/// Each lesson's own outline is rendered under a depth-1 heading naming that
|
||||
/// lesson (`lesson.info.title`); the lesson's own section headings shift one
|
||||
/// level deeper (ADR-0029's per-lesson depths are relative to that lesson, so
|
||||
/// level deeper (ADR-0036's per-lesson depths are relative to that lesson, so
|
||||
/// nesting under the lesson-title heading keeps the outline↔structure
|
||||
/// correspondence meaningful in the combined document). `@label`/`@ref`
|
||||
/// cross-references stay global across the whole compiled document (typst's
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Default export templates (ADR-0011, outline shape ADR-0029)
|
||||
# Default export templates (ADR-0011, outline shape ADR-0036)
|
||||
|
||||
`student.typ` / `teacher.typ` are the **framework default templates**. In a real
|
||||
engineering file they live at `exports/student.typ` / `exports/teacher.typ`; the
|
||||
@@ -9,7 +9,7 @@ offline smoke test below.
|
||||
Each template:
|
||||
|
||||
1. reads the injected manifest: `toml(sys.inputs.manifest)`;
|
||||
2. loops `manifest.outline` (ADR-0029's depth-first rendering order — elements
|
||||
2. loops `manifest.outline` (ADR-0036's depth-first rendering order — elements
|
||||
interleaved with section headings at their DFS-open position). For an
|
||||
`type = "element"` entry: `include`-ing each content field via a computed
|
||||
**root-relative absolute** path `/<part.path>/<field>.typ`, and reading
|
||||
@@ -46,7 +46,7 @@ content and hands `render-lesson` an already-assembled `outline` array;
|
||||
disk. *(OPEN: the exact manifest shape for this is for the Rust/manifest
|
||||
contract to pin.)*
|
||||
- **Sections carry no content fields.** A `type = "section"` outline entry
|
||||
(ADR-0029) has only `kind`/`title`/`depth`/`path`; the template passes it
|
||||
(ADR-0036) has only `kind`/`title`/`depth`/`path`; the template passes it
|
||||
through untouched — no `include`, no `element.toml` read.
|
||||
|
||||
## Offline smoke test
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// DEFAULT BUNDLE TEMPLATE (ADR-0030, outline shape ADR-0029).
|
||||
// DEFAULT BUNDLE TEMPLATE (ADR-0037, outline shape ADR-0036).
|
||||
//
|
||||
// Lives in a bundle at `<bundle-root>/exports/<target>.typ`, e.g.
|
||||
// `exports/merged.typ`. Compiled AS MAIN with the augmented BUNDLE manifest
|
||||
@@ -66,7 +66,7 @@
|
||||
))
|
||||
|
||||
// Presentation: shared per-level heading numbering across the whole bundle,
|
||||
// and the ADR-0030 recommended default of resetting auto-counters at each
|
||||
// and the ADR-0037 recommended default of resetting auto-counters at each
|
||||
// lesson boundary (override `reset-counters: false` for continuous numbering).
|
||||
#render-bundle(
|
||||
info: info,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// DEFAULT STUDENT TEMPLATE (framework default; ADR-0011, outline shape ADR-0029).
|
||||
// DEFAULT STUDENT TEMPLATE (framework default; ADR-0011, outline shape ADR-0036).
|
||||
//
|
||||
// This is a *real, editable* file that lives in an engineering file at
|
||||
// `exports/student.typ`. The framework compiles it AS THE MAIN FILE with the
|
||||
@@ -16,7 +16,7 @@
|
||||
// PACKAGE, not the engineering root. A `/<part.path>/<field>.typ` written HERE
|
||||
// (this template lives under `--root`) resolves against `--root`. So the
|
||||
// template loads content and hands cph-render an already-assembled `outline`
|
||||
// array (elements interleaved with section headings, ADR-0029).
|
||||
// array (elements interleaved with section headings, ADR-0036).
|
||||
//
|
||||
// OPEN CONTRACT POINT — optional-content presence. typst has no "does this file
|
||||
// exist" primitive (a missing `include` is a hard compile error). So the
|
||||
@@ -43,7 +43,7 @@
|
||||
// resolved against --root) and read scalar fields from <path>/element.toml.
|
||||
// `part-fields` (from cph-render) is the single source of truth for
|
||||
// kind->fields.
|
||||
// - a "section" entry (ADR-0029): pass its title/depth straight through — no
|
||||
// - a "section" entry (ADR-0036): pass its title/depth straight through — no
|
||||
// content to load, it is a heading.
|
||||
#let outline = raw-outline.map(raw => {
|
||||
if raw.at("type", default: "element") == "section" {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// DEFAULT TEACHER TEMPLATE (framework default; ADR-0011, outline shape ADR-0029).
|
||||
// DEFAULT TEACHER TEMPLATE (framework default; ADR-0011, outline shape ADR-0036).
|
||||
//
|
||||
// Lives in an engineering file at `exports/teacher.typ`. Compiled AS MAIN with
|
||||
// the manifest injected:
|
||||
@@ -21,7 +21,7 @@
|
||||
#let raw-outline = manifest.at("outline", default: ())
|
||||
|
||||
// Assemble each outline entry: an "element" entry includes its content fields
|
||||
// and reads scalars from element.toml; a "section" entry (ADR-0029) passes
|
||||
// and reads scalars from element.toml; a "section" entry (ADR-0036) passes
|
||||
// title/depth straight through as a heading, no content to load.
|
||||
#let outline = raw-outline.map(raw => {
|
||||
if raw.at("type", default: "element") == "section" {
|
||||
|
||||
Reference in New Issue
Block a user