1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/// Commit message AST — structurally valid, not semantically validated.
///
/// The parser produces this. It holds raw strings.
/// CommitMessage::try_from(ast) enforces domain invariants:
/// - commit_type string must be a known CommitType variant
/// - description must be ≤ 72 chars
/// - scope must be alphanumeric + hyphens/underscores
///
/// Keeping CommitAst clean of domain types means compiler/ never
/// imports from domain/ — the dependency flows one way only.
/// Root node of the commit AST.
/// Header node — the first line of a conventional commit.
///
/// commit_type is a raw string. Domain validates whether it's
/// a known variant. The parser's job is just to extract it.
/// Body node — the optional multi-line section after a blank line.
/// Footer node — a key/value pair from the footer section.
///
/// Examples: { key: "BREAKING CHANGE", value: "old API removed" }
/// { key: "Refs", value: "#123" }
/// { key: "Co-authored-by", value: "Name <email>" }