Lift a `:::scope-in` / `:::scope-out` container into a `ScopeItem`. `kind` is "scope-in" or "scope-out" and drives the generated id slug. Prose body is the unconstrained narrative (never graded). Nested `::file-ref{path=}` leaves name the files this boundary covers — same leaf directive a `:::task` uses for `TOUCHES` — so a `:::scope-out` can declare concrete files out of scope for breach detectio
(d: &Directive, id_base: &str, kind: &str, n: usize)
| 250 | /// directive a `:::task` uses for `TOUCHES` — so a `:::scope-out` can declare |
| 251 | /// concrete files out of scope for breach detection. |
| 252 | fn lift_scope(d: &Directive, id_base: &str, kind: &str, n: usize) -> ScopeItem { |
| 253 | let local = |
| 254 | d.id.clone() |
| 255 | .unwrap_or_else(|| format!("{}-{kind}-{n}", slug(id_base))); |
| 256 | let files = d |
| 257 | .children |
| 258 | .iter() |
| 259 | .filter(|c| c.name == "file-ref") |
| 260 | .filter_map(|c| c.attr("path").map(str::to_string)) |
| 261 | .collect(); |
| 262 | ScopeItem { |
| 263 | type_: NodeType::ScopeItem.as_str().to_string(), |
| 264 | id: as_urn("scope", &local), |
| 265 | text: d.body.clone(), |
| 266 | files, |
| 267 | } |
| 268 | } |
| 269 | |
| 270 | /// Lift a `:::constraint` container into a `Constraint`. |
| 271 | fn lift_constraint(d: &Directive, id_base: &str, n: usize) -> Constraint { |