wit_spell_check/
checks.rs

1use std::path::Path;
2use hunspell_rs::{CheckResult, Hunspell};
3use wit_parser::{Function, Interface, PackageName, UnresolvedPackage};
4
5/// A spell checker for wit files.
6pub struct WitSpellCheck {
7    hunspell: Hunspell,
8    check_function: bool,
9    check_parameter: bool,
10}
11
12impl WitSpellCheck {
13    /// Create a new spell checker with the given hunspell directory.
14    pub fn new<P>(directory: P) -> anyhow::Result<Self> where P: AsRef<Path> {
15        let dir = directory.as_ref();
16        let aff = dir.join("en_US.aff");
17        let dic = dir.join("en_US.dic");
18        let mut hun = Hunspell::new(&aff.to_string_lossy(), &dic.to_string_lossy());
19        // useless
20        // hun.add_dictionary(&dir.join("custom.dic").to_string_lossy());
21        let custom = std::fs::read_to_string(&dir.join("custom.dic"))?;
22        for line in custom.lines() {
23            if !line.trim().is_empty() {
24                hun.add(line.trim());
25            }
26        }
27        Ok(Self {
28            hunspell: hun,
29            check_function: true,
30            check_parameter: true,
31        })
32    }
33    /// Whether to check function names.
34    pub fn check_functions(self, check: bool) -> Self {
35        Self {
36            check_function: check,
37            ..self
38        }
39    }
40    /// Whether to check parameter names.
41    pub fn check_parameters(self, check: bool) -> Self {
42        Self {
43            check_parameter: check,
44            ..self
45        }
46    }
47}
48
49impl WitSpellCheck {
50    /// Check the given directory for spelling errors.
51    pub fn check<P>(&self, directory: P) where P: AsRef<Path> {
52        let package = UnresolvedPackage::parse_dir(directory.as_ref()).unwrap();
53        for (_, interface) in package.interfaces.iter() {
54            for (name, function) in interface.functions.iter() {
55                if self.check_parameter {
56                    for (parameter, _) in function.params.iter() {
57                        for part in parameter.split("-") {
58                            match self.hunspell.check(part) {
59                                CheckResult::FoundInDictionary => {}
60                                CheckResult::MissingInDictionary => {
61                                    println!("- parameter may wrong: `{}`", part);
62                                    println!("  - in function `{}`", name);
63                                    match &interface.name {
64                                        Some(s) => {
65                                            println!("  - in interface `{}`", s);
66                                        }
67                                        None => {}
68                                    }
69                                    println!("  - in package `{}`", package.name);
70                                    println!("  - perhaps {:?}", self.hunspell.suggest(part));
71                                }
72                            }
73                        }
74                    }
75                }
76                if self.check_function {
77                    self.check_function(function, interface, &package.name);
78                }
79            }
80        }
81    }
82    /// Check the given function for spelling errors.
83    fn check_function(&self, function: &Function, interface: &Interface, package: &PackageName) {
84        let norm = function.name.trim_start_matches("[constructor]").trim_start_matches("[static]").trim_start_matches("[method]");
85        for split in norm.split(".") {
86            for part in split.split("-") {
87                match self.hunspell.check(part) {
88                    CheckResult::FoundInDictionary => {}
89                    CheckResult::MissingInDictionary => {
90                        println!("- function may wrong: `{}`", part);
91                        match &interface.name {
92                            Some(s) => {
93                                println!("  - in interface `{}`", s);
94                            }
95                            None => {}
96                        }
97                        println!("  - in package `{}`", package.name);
98                        println!("  - perhaps {:?}", self.hunspell.suggest(part));
99                    }
100                }
101            }
102        }
103    }
104}