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:
+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!(
|
||||
|
||||
Reference in New Issue
Block a user