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}