Mountain/ProcessManagement/ExtractDevTag.rs
1#![allow(non_snake_case)]
2
3//! Cocoon stdout-line inspector. Detects the `[DEV:<TAG>]` prefix written by
4//! `Cocoon/Source/Services/DevLog.ts::CocoonDevLog` and returns the lower-
5//! cased tag for dispatch into Mountain's per-tag `dev_log!` sinks. Returns
6//! `None` for bare stdout so the caller falls back to the catch-all `cocoon`
7//! tag.
8
9pub fn Fn(Line:&str) -> Option<String> {
10 let Stripped = Line.strip_prefix("[DEV:")?;
11
12 let (TagUpper, _Rest) = Stripped.split_once(']')?;
13
14 if TagUpper.is_empty() {
15 return None;
16 }
17
18 // Reject anything that isn't a simple tag ident - prevents stray
19 // `[DEV: something with space]` headers from being treated as tags.
20 if !TagUpper.chars().all(|C| C.is_ascii_uppercase() || C == '-' || C == '_') {
21 return None;
22 }
23
24 Some(TagUpper.to_ascii_lowercase())
25}
26
27#[cfg(test)]
28mod Tests {
29
30 use super::Fn;
31
32 #[test]
33 fn StripsKnownTag() {
34 assert_eq!(
35 Fn("[DEV:BOOTSTRAP-STAGE] [Bootstrap] stage=Environment event=start"),
36 Some("bootstrap-stage".to_string())
37 );
38 }
39
40 #[test]
41 fn RejectsPlainText() {
42 assert_eq!(Fn("plain stdout line"), None);
43 }
44
45 #[test]
46 fn RejectsMalformed() {
47 assert_eq!(Fn("[DEV: BOOT] x"), None);
48
49 assert_eq!(Fn("[DEV:]"), None);
50
51 assert_eq!(Fn("[DEV:BOOT"), None);
52 }
53}