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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// SPDX-License-Identifier: MIT OR Apache-2.0
// Copyright (c) 2026 Noyalib. All rights reserved.
//! Side-table CST (concrete syntax tree) for lossless round-tripping.
//!
//! This module is the implementation of the design described in
//! `docs/design/green-tree.md`. It exposes a `Document` type that
//! parses YAML byte-faithfully — every byte of the input is retained
//! as a green-tree leaf — so that
//! `parse_document(s).unwrap().to_string()` is byte-identical to `s`
//! for any input the parser accepts.
//!
//! The `Document` API depends on the parser's `SpanTree`, which lives
//! under the `std` feature.
//!
//! The `Value` API (`from_str`, `to_string`, `StreamingDeserializer`)
//! is unchanged. Trivia capture is enabled only on this path; the
//! fast path pays no extra cost.
//!
//! # Current scope
//!
//! - **Read access.** [`Document::as_value`]
//! for a typed view, [`Document::span_at`]
//! / [`Document::get`] for byte-range
//! lookups by `path`, and
//! [`Document::syntax`] for the green
//! tree itself.
//! - **Mutation.** [`Document::replace_span`]
//! (primitive byte replacement) and
//! [`Document::set`] (path-targeted, the
//! wrapper most callers want). Both re-parse on edit and reject
//! the change if the spliced source is invalid YAML, leaving the
//! document untouched.
//! [`Document::edit`] creates an
//! [`EditSession`] that batches independent
//! byte-range replacements and validates the assembled result once.
//!
//! - **Comments.** [`Document::comments_at`]
//! classifies the comments decorating a node into a
//! [`CommentBundle`], and
//! [`Document::set_comment`] /
//! [`Document::remove_comment`]
//! write them back, addressed by
//! [`CommentPosition`]. A leading block
//! is written at the node's own indentation. Both go through
//! `replace_span`, so they inherit its guard.
//!
//! - **Auto-formatting.** [`Emit`] turns a typed
//! value into the YAML spelling that re-parses to exactly that
//! value at a given site, so
//! [`Document::insert_entry_value`],
//! [`Document::push_back_value`]
//! and
//! [`Document::insert_after_value`]
//! quote and escape what the fragment-taking mutators splice
//! verbatim.
//!
//! The green tree itself is still a flat sequence of leaves under a
//! single `Document` parent — sufficient for byte-faithful
//! round-tripping and for the span-based edit primitive. Hierarchical
//! nesting (per-mapping / per-sequence parent nodes) is tracked as a
//! follow-up in `docs/design/green-tree.md`.
//!
//! # Examples
//!
//! ```
//! use noyalib::cst::parse_document;
//!
//! let src = "name: noyalib # the project\nversion: 0.0.1\n";
//! let doc = parse_document(src).unwrap();
//! assert_eq!(doc.to_string(), src);
//! ```
//!
//! # Parser configuration
//!
//! [`parse_document`] and
//! [`parse_stream`] run under the default
//! [`ParserConfig`](crate::ParserConfig), the same limits as
//! [`from_str`](crate::from_str).
//! [`parse_document_with_config`]
//! and [`parse_stream_with_config`]
//! take one, mirroring [`from_str_with_config`](crate::from_str_with_config);
//! the returned [`Document`] keeps it for every
//! later re-parse of its own source, so an edit never falls back to
//! the defaults.
//!
//! # Multi-document streams
//!
//! Use [`parse_stream`] for inputs
//! containing `---` / `...` separators — one
//! [`Document`] per logical YAML document,
//! with each slice covering the exact bytes of that document so
//! concatenation reproduces the input verbatim:
//!
//! ```
//! use noyalib::cst::{parse_stream, Document};
//!
//! let src = "---\nfoo: 1\n...\n---\nbar: 2\n";
//! let docs = parse_stream(src).unwrap();
//! assert_eq!(docs.len(), 2);
//! assert_eq!(docs[0].as_value()["foo"].as_i64(), Some(1));
//! assert_eq!(docs[1].as_value()["bar"].as_i64(), Some(2));
//! let joined: String = docs.iter().map(Document::source).collect();
//! assert_eq!(joined, src);
//! ```
pub use ;
pub use ;
pub use coerce_to_schema;
pub use ;
pub use ;
pub use Entry;
pub use ;
pub use ;
pub use SyntaxKind;