foundry_cli/utils/
suggestions.rs

1//! Helper functions for suggesting alternative values for a possibly erroneous user input.
2
3/// Filters multiple strings from a given list of possible values which are similar
4/// to the passed in value `v` within a certain confidence by least confidence.
5///
6/// The jaro winkler similarity boosts candidates that have a common prefix, which is often the case
7/// in the event of typos. Thus, in a list of possible values like ["foo", "bar"], the value "fop"
8/// will yield `Some("foo")`, whereas "blark" would yield `None`.
9pub fn did_you_mean<T, I>(v: &str, candidates: I) -> Vec<String>
10where
11    T: AsRef<str>,
12    I: IntoIterator<Item = T>,
13{
14    let mut candidates: Vec<(f64, String)> = candidates
15        .into_iter()
16        .map(|pv| (strsim::jaro_winkler(v, pv.as_ref()), pv.as_ref().to_owned()))
17        .filter(|(similarity, _)| *similarity > 0.8)
18        .collect();
19    candidates.sort_by(|a, b| a.0.total_cmp(&b.0));
20    candidates.into_iter().map(|(_, pv)| pv).collect()
21}
22
23#[cfg(test)]
24mod tests {
25    use super::*;
26
27    #[test]
28    fn possible_artifacts_match() {
29        let candidates = ["MyContract", "Erc20"];
30        assert_eq!(
31            did_you_mean("MyCtrac", candidates.iter()).pop(),
32            Some("MyContract".to_string())
33        );
34    }
35
36    #[test]
37    fn possible_artifacts_nomatch() {
38        let candidates = ["MyContract", "Erc20", "Greeter"];
39        assert!(did_you_mean("Vault", candidates.iter()).pop().is_none());
40    }
41}