pub fn normalize(root: &Root) -> Result<NormalizeTable, NormalizeError>Expand description
Normalize every binding group in a parsed tree.
Returns the plans for groups that actually need one. A group with no duplicate static key and no dotted path is NOT recorded — consumers keep their existing path for it, which is what bounds this pass’s blast radius.
§Errors
Returns the first NormalizeError in source order, matching nix’s
parse-time rejection.
Examples found in repository?
examples/scan.rs (line 85)
58fn main() {
59 let roots: Vec<PathBuf> = std::env::args().skip(1).map(PathBuf::from).collect();
60 if roots.is_empty() {
61 eprintln!("usage: scan <dir> [<dir>…]");
62 std::process::exit(2);
63 }
64
65 let mut files = Vec::new();
66 for r in &roots {
67 nix_files(r, &mut files);
68 }
69
70 let (mut unparseable, mut clean, mut planned, mut rejected) = (0usize, 0usize, 0usize, 0usize);
71 let mut groups = 0usize;
72 let mut rejects: Vec<(PathBuf, String)> = Vec::new();
73
74 for f in &files {
75 let Ok(src) = std::fs::read_to_string(f) else {
76 continue;
77 };
78 let parse = rnix::Root::parse(&src);
79 if !parse.errors().is_empty() {
80 // rnix could not parse it — not this pass's business, and counted
81 // separately so it can never be mistaken for a clean result.
82 unparseable += 1;
83 continue;
84 }
85 match sui_normalize::normalize(&parse.tree()) {
86 Ok(table) if table.is_empty() => clean += 1,
87 Ok(table) => {
88 planned += 1;
89 groups += table.len();
90 }
91 Err(e) => {
92 rejected += 1;
93 rejects.push((f.clone(), e.to_string()));
94 }
95 }
96 }
97
98 println!("scanned {}", files.len());
99 println!(" clean {clean} (no duplicate key, no dotted path — untouched)");
100 println!(" planned {planned} ({groups} binding groups — THE BLAST RADIUS)");
101 println!(" rejected {rejected} (each MUST be one `nix-instantiate --parse` also refuses)");
102 println!(" unparseable {unparseable} (rnix could not read; not this pass's business)");
103
104 for (p, e) in rejects.iter().take(25) {
105 println!(" REJECT {}: {e}", p.display());
106 }
107 if rejects.len() > 25 {
108 println!(" … and {} more", rejects.len() - 25);
109 }
110}