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