Skip to main content

markdown_contract/
lib.rs

1//! The Rust engine for markdown-contract, the twin of the TypeScript package
2//! `@osdlc/markdown-contract`. The shared corpus in `packages/ts/markdown-contract/corpus/`
3//! pins the two to the same findings for every YAML-expressible fixture: the same count
4//! and ids in order, and the level, line and hint where a fixture records them
5//! (`tests/corpus.rs`).
6//!
7//! [`validate()`] runs every check in one pass: the projection, the structure plane, the
8//! content plane (frontmatter schema; table, list, code and `maxWords` leaves), the
9//! text constraints and the document rules. Contracts come from the builders
10//! ([`Contract`], [`section`], [`rule`] and the rest) or the YAML loader
11//! ([`load_contract`]); [`run_corpus`] routes documents to contracts by glob.
12//!
13//! ```
14//! use markdown_contract::{load_contract, validate};
15//!
16//! let contract = load_contract("\
17//! mcVersion: 2
18//! kind: contract
19//! body:
20//!   sections:
21//!     - section: Context
22//! ")?;
23//! let findings = validate("## Notes\n", &contract, "note.md");
24//! assert_eq!(findings[0].id, "structure/section-missing");
25//! # Ok::<(), markdown_contract::DeclarativeError>(())
26//! ```
27//!
28//! The core takes strings and does no I/O, so it builds for `wasm32-unknown-unknown`.
29//! Reading files lives behind the `native` feature (on by default; build with
30//! `default-features = false` for wasm32).
31//!
32//! A text rule's `regex` and a frontmatter string's `pattern` use the `regex` crate's
33//! dialect, not JavaScript's: no lookaround or backreferences, and `\w`, `\d` and `\b`
34//! are Unicode-aware. The loader rejects a source the crate cannot compile. The README
35//! lists the other differences from the TS package.
36//!
37//! [`select`] picks part of a note the way an Obsidian link fragment does
38//! (`#Heading`, `#Parent#Child`, `#^block-id`), as a byte range or as text;
39//! [`DocTree`] has the same as methods, and every [`SectionNode`] and
40//! [`BlockNode`] carries its byte range in [`DocTree::body`].
41//!
42//! This file is a barrel only: it re-exports, it holds no logic.
43
44mod camel;
45mod content;
46mod contract;
47mod declarative;
48mod dialect;
49mod finding;
50mod frontmatter;
51mod js;
52mod parse;
53mod registry;
54mod runner;
55mod schema;
56pub mod select;
57mod slots;
58mod structure;
59mod text_constraints;
60mod text_match;
61mod tree;
62mod validate;
63
64pub use contract::{
65    CodeConfig, Contract, DocRule, EveryItem, ExtraColumns, FrontmatterSpec, GapSpec, LeafConfig,
66    LeafSpec, LevelOpts, ListConfig, OneOfSpec, Order, Rule, SectionContent, SectionOpts,
67    SectionSeq, SectionSpec, Spec, TableConfig, doc_rule, gap, gap_bounds, one_of, one_of_with,
68    optional, rule, section, section_with, sections,
69};
70pub use declarative::{
71    ContractResolver, DeclarativeError, compile_contract_object, load_config, load_contract,
72};
73#[cfg(feature = "native")]
74pub use declarative::{load_config_file, load_contract_file};
75pub use dialect::{VaultRef, VaultRefKind, extract_vault_refs};
76pub use finding::{EditRange, Finding, FindingLevel, Fix, SourcePos, TextEdit};
77pub use parse::{FrontmatterSplit, parse_document, split_frontmatter};
78pub use registry::{Ctx, FindingSpec, Registry};
79pub use runner::{
80    CorpusConfig, CorpusRule, GlobError, RunOptions, RunOutcome, RunStats, run_corpus,
81};
82#[cfg(feature = "native")]
83pub use runner::{NativeRunError, run_corpus_dir, walk_dir};
84pub use schema::{ConstValue, Schema, StringFormat};
85pub use text_constraints::{TextRuleSpec, forbids, requires, text_rule};
86pub use text_match::TextMatchSpec;
87pub use tree::{BlockKind, BlockNode, DocTree, Frontmatter, ListItem, SectionNode};
88pub use validate::{validate, validate_tree};