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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// SPDX-License-Identifier: MIT OR Apache-2.0
// Copyright (c) 2026 Noyalib. All rights reserved.
//! `!include` directive support — compose YAML documents from
//! multiple files via the `!include path/to/file.yaml` tag.
//!
//! Two layers:
//!
//! - **`include` feature** (this module's free-standing types) —
//! defines `IncludeResolver`, `IncludeRequest`, and
//! `InputSource`. The resolver is a `Send + Sync` closure
//! stored on [`crate::ParserConfig`]; users wire it up via
//! [`crate::ParserConfig::include_resolver`].
//!
//! - **`include_fs` feature** (`SafeFileResolver`) — a Unix
//! capability-rooted filesystem implementation, with a Windows
//! canonical-root fallback, symlink-policy enforcement
//! (`SymlinkPolicy`), and max-depth cycle protection.
//!
//! Fragment anchors (`!include file.yaml#name`) resolve the named
//! YAML anchor inside the included document and substitute its
//! value rather than the whole document. Plain `!include
//! file.yaml` substitutes the document root.
//!
//! Cyclic includes (A includes B includes A) are rejected via a
//! per-resolution visited set; the depth ceiling
//! [`crate::ParserConfig::max_include_depth`] (default 24)
//! bounds the recursion.
use crateResult;
use crate*;
pub use ;
/// Describes one `!include` request the loader hands to the
/// resolver.
///
/// The `spec` is the YAML scalar text after `!include` —
/// typically a file path, possibly with a `#anchor` fragment.
/// Resolvers are free to interpret the spec however they like
/// (file path, URL, key in a virtual filesystem); the
/// [`SafeFileResolver`] interprets it as a filesystem path.
/// What a resolver returns: the YAML text plus a stable
/// identifier that downstream layers use for cycle detection
/// and span-source attribution.
///
/// `name` is shown in diagnostic output — typically the
/// canonicalised file path. `bytes` is the YAML text the loader
/// will parse.
/// Resolver closure stored on [`crate::ParserConfig`].
///
/// Wraps an `Arc<dyn Fn>` so the type is `Clone + Debug` (the
/// underlying `dyn Fn` is not). Construct with
/// [`IncludeResolver::new`].
///
/// `Arc` (not `Box`) keeps configs cheap to clone. The closure
/// is `Send + Sync` so the resolver can be invoked from any
/// thread of a parallel parse.
+ Send + Sync>);
/// Split `path#fragment` into `(path, Some(fragment))` /
/// `(path, None)`. Used by both the resolver and the post-parse
/// walk so they agree on which characters are path-bytes.
///
/// # Examples
///
/// ```
/// use noyalib::include::split_fragment;
/// assert_eq!(split_fragment("a.yaml#anchor"), ("a.yaml", Some("anchor")));
/// assert_eq!(split_fragment("a.yaml"), ("a.yaml", None));
/// ```