pub fn check_yaml_nesting_depth(
content: &str,
max_depth: usize,
) -> Result<(), usize>Expand description
Scans raw YAML text for block/flow recursion deeper than max_depth.
YamlLoader::load_from_str has no public option to cap recursion, so
callers must reject pathological input before handing it to the parser.
This performs a single-pass structural scan — no actual parsing, so it
cannot itself recurse or overflow — that bounds the two independent ways
YAML content drives yaml-rust2’s recursion:
- Flow-style bracket nesting:
[/{and]/}pairs, as in[[[1]]]or{a: {a: 1}}. - Block-style indentation: each line whose leading indentation is
deeper than the enclosing block context opens one nesting level (e.g. a
mapping key or sequence item indented under its parent); each
-in a compact chained sequence item (- - - 1) opens one level per dash, since it is equivalent to one nested single-item sequence per level.
Both counts accumulate into one shared depth budget bounded by
max_depth. Line-start block indentation is scanned unconditionally on
every line, even one that looks like a continuation of a still-open flow
bracket from a previous line — an unclosed [/{ must never be able to
suppress scanning for the rest of the file (impl-critic C2), so this
guard accepts occasionally over-counting a multi-line flow collection’s
continuation lines as extra block levels in exchange for never being able
to go blind. A quote character is only treated as opening a quoted
scalar when it sits at a token-start position (line start, or right
after : , - , [, {, ,) — never mid-token — so an apostrophe
inside a plain scalar like doesn't is left alone rather than
mistaken for the start of a string (impl-critic C1). Once a quoted
scalar is opened, it is only ever trusted to close on the same line:
hitting an unescaped \n before the matching quote resynchronizes the
scanner at that newline unconditionally (including across a \ right
before it, which cannot extend the string past the line), rather than
scanning forward indefinitely looking for a close — so neither a stray
unquoted apostrophe nor a genuinely unterminated quoted scalar can ever
blind the scanner to more than the remainder of one line. # outside a
quoted scalar always starts a comment to end of line. Content indented
under a literal/folded block scalar (|/>) is not specially exempted
and is scanned like any other indentation, which can only make this
guard more conservative, never less. Only ASCII space counts as
indentation — a tab-indented line reads as indent 0, an assumption that
currently holds only because yaml-rust2 itself rejects tabs used for
block indentation before recursing deep enough to matter.
§Errors
Returns Err(depth) with the depth reached the instant nesting exceeds
max_depth.
§Examples
use deps_core::parser::check_yaml_nesting_depth;
assert!(check_yaml_nesting_depth("a:\n b:\n c: 1\n", 4).is_ok());
let deeply_nested = format!("{}1", "- ".repeat(10));
assert!(check_yaml_nesting_depth(&deeply_nested, 4).is_err());
// An apostrophe mid-scalar must not blind the scanner to nesting later
// in the file (impl-critic C1).
let content = format!("a: it doesn't panic\n{}1", "- ".repeat(10));
assert!(check_yaml_nesting_depth(&content, 4).is_err());