framework/lang/
mod.rs

1use crate::framework_detector::FrameworkContainer;
2use std::collections::BTreeMap;
3use std::path::Path;
4use walkdir::{DirEntry, WalkDir};
5
6pub mod go;
7pub mod js;
8pub mod jvm;
9pub mod rust;
10
11type TaggingAction<'a> = fn(dir: &DirEntry) -> Option<&'a str>;
12type FrameworkAnalysisAction = fn(dir: &DirEntry, frameworks: &FrameworkContainer);
13
14struct LangDetector<'a> {
15    tagging: TaggingAction<'a>,
16    framework_analysis: FrameworkAnalysisAction,
17}
18
19pub struct LangDetectors<'a> {
20    pub frameworks: FrameworkContainer,
21
22    pub(crate) tags: BTreeMap<&'a str, bool>,
23    detectors: Vec<LangDetector<'a>>,
24}
25
26impl<'a> Default for LangDetectors<'a> {
27    fn default() -> Self {
28        LangDetectors {
29            tags: BTreeMap::default(),
30            detectors: vec![
31                LangDetector {
32                    tagging: jvm::tagging,
33                    framework_analysis: jvm::framework_analysis,
34                },
35                LangDetector {
36                    tagging: js::tagging,
37                    framework_analysis: js::framework_analysis,
38                },
39                LangDetector {
40                    tagging: go::tagging,
41                    framework_analysis: go::framework_analysis,
42                },
43                LangDetector {
44                    tagging: rust::tagging,
45                    framework_analysis: rust::framework_analysis,
46                },
47            ],
48            frameworks: FrameworkContainer::default(),
49        }
50    }
51}
52
53impl<'a> LangDetectors<'a> {
54    pub fn detect<P: AsRef<Path>>(&mut self, path: P) {
55        traverse_project_directory(path, |dir_entry| {
56            self.tagging(dir_entry);
57            self.framework_analysis(dir_entry);
58        })
59    }
60
61    fn tagging(&mut self, dir_entry: &DirEntry) {
62        for detector in self.detectors.iter() {
63            match (detector.tagging)(dir_entry) {
64                Some(tag) => {
65                    self.tags.insert(tag, true);
66                }
67                _ => continue,
68            }
69        }
70    }
71
72    fn framework_analysis(&mut self, dir_entry: &DirEntry) {
73        for detector in self.detectors.iter() {
74            (detector.framework_analysis)(dir_entry, &mut self.frameworks);
75        }
76    }
77}
78
79fn traverse_project_directory<'a, P: AsRef<Path>, F>(path: P, mut each_entry_callback: F)
80where
81    F: FnMut(&DirEntry),
82{
83    let walk_dir = WalkDir::new(path);
84    for dir_entry in walk_dir.into_iter() {
85        if dir_entry.is_err() {
86            continue;
87        }
88
89        let entry = dir_entry.unwrap();
90        if entry.path().file_name().is_none() {
91            println!("none file_name {:?}", entry.path());
92            continue;
93        }
94
95        (each_entry_callback)(&entry)
96    }
97}