moss_core/heading.rs
1//! Everything moss knows about a heading, in one place.
2//!
3//! Headings used to be spread over four homes — `heading.rs` (the article
4//! title rule), `heading_anchor.rs` (the Obsidian slug algorithm),
5//! `extract_headings.rs` (the autocomplete walker), and a private
6//! `collect_heading_text` inside `ast/parser.rs`. They are not four
7//! subjects; they are four steps of one pipeline:
8//!
9//! ```text
10//! inline nodes / parser events ──[text]──> plain text
11//! │
12//! ├─[anchor]──> the <hN id="…">
13//! └─[extract]─> autocomplete rows
14//! file path + frontmatter ───────[state]───> the auto-injected <h1>
15//! ```
16//!
17//! The keystone invariant of the whole cluster is **byte-identity**: the
18//! slug `extract` reports, the `id` the renderer emits, and the raw-line
19//! slug the wikilink scanner computes in `build/scan/scan.rs` must agree
20//! character for character, or a `[[Page#Heading]]` link resolves to a
21//! fragment the page does not have. Spread across four files that identity
22//! was something tests had to keep re-checking; a math bug cluster hit
23//! three of the four homes independently in July 2026 precisely because
24//! nothing structural tied them together. Co-locating them makes the
25//! shared step ([`text`]) a single function instead of a coincidence.
26//!
27//! Consolidation mandated by
28//! `docs/reference/target/05-consolidation-map.md`
29//! (row 36 and the F10 tiny-file merge list).
30
31pub mod anchor;
32pub mod extract;
33pub mod state;
34pub mod text;
35
36pub use anchor::obsidian_heading_anchor;
37pub use extract::{extract_headings, extract_headings_with_config, HeadingInfo};
38pub use state::{
39 hero_at_top_owns_title, compute, filename_text, filename_text_with_root, HeadingInputs,
40 HeadingSource, HeadingState,
41};