Maintain/Eliminate/
Process.rs1use std::{
8 fs,
9 path::{Path, PathBuf},
10};
11
12use globset::{Glob, GlobSet, GlobSetBuilder};
13use walkdir::WalkDir;
14
15use super::{Definition, Error, Transform};
16
17pub fn Process(Root:&Path, Pattern:&str, Options:&Definition::Options) -> Error::Result<Definition::Stats> {
30 let mut Stats = Definition::Stats::default();
31
32 let GlobMatcher = BuildGlobSet(Pattern)?;
33
34 let Files = CollectFiles(Root, &GlobMatcher);
35
36 for FilePath in Files {
37 Stats.FilesProcessed += 1;
38
39 ProcessFile(&FilePath, Options, &mut Stats)?;
40 }
41
42 Ok(Stats)
43}
44
45fn BuildGlobSet(Pattern:&str) -> Error::Result<GlobSet> {
50 let mut Builder = GlobSetBuilder::new();
51
52 Builder.add(Glob::new(Pattern)?);
53
54 Ok(Builder.build()?)
55}
56
57fn CollectFiles(Root:&Path, GlobMatcher:&GlobSet) -> Vec<PathBuf> {
58 if Root.is_file() {
59 return vec![Root.to_path_buf()];
60 }
61
62 WalkDir::new(Root)
63 .follow_links(false)
64 .into_iter()
65 .filter_map(|Entry| Entry.ok())
66 .filter(|Entry| Entry.file_type().is_file())
67 .filter(|Entry| {
68 let RelativePath = Entry.path().strip_prefix(Root).unwrap_or(Entry.path());
69
70 GlobMatcher.is_match(RelativePath)
71 })
72 .map(|Entry| Entry.path().to_path_buf())
73 .collect()
74}
75
76fn ProcessFile(FilePath:&Path, Options:&Definition::Options, Stats:&mut Definition::Stats) -> Error::Result<()> {
77 let Source = fs::read_to_string(FilePath)?;
78
79 let TransformResult = if Options.Reformat {
83 Transform::Run(&Source, Options)
84 } else {
85 Transform::RunPreserve(&Source, Options)
86 }
87 .map_err(|E| {
88 if let Error::Error::Parse { Source: Src, .. } = E {
89 Error::Error::Parse { Path:FilePath.display().to_string(), Source:Src }
90 } else {
91 E
92 }
93 })?;
94
95 let Some(Transformed) = TransformResult else {
96 return Ok(());
97 };
98
99 Stats.FilesModified += 1;
100
101 let Before = Source.lines().filter(|L| L.trim_start().starts_with("let ")).count();
103
104 let After = Transformed.lines().filter(|L| L.trim_start().starts_with("let ")).count();
105
106 Stats.BindingsInlined += Before.saturating_sub(After);
107
108 if Options.Verbose {
109 log::info!("{}: {} binding(s) inlined", FilePath.display(), Before.saturating_sub(After));
110 }
111
112 if Options.DryRun {
113 log::info!("--- {} (dry-run, not written) ---\n{}", FilePath.display(), Transformed);
114 } else {
115 fs::write(FilePath, Transformed)?;
116 }
117
118 Ok(())
119}