1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
use inflections::case;
use inflections::Inflect;
use inflector::string::pluralize::to_plural;
use inflector::string::singularize::to_singular;

mod deduped_vec;

pub fn inflect_all(words: &Vec<String>) -> Vec<Vec<String>> {
    inflect_ord(words).iter().flat_map(|ws| inflect_case(ws)).collect()
}

fn inflect_ord(words: &Vec<String>) -> Vec<Vec<String>> {
    inflect_when_some_dont_match(
        words,
        vec![
            (is_plural, to_plural),
            // note: keep after plural
            // so that singular replacements do not interfere with plurals ones
            // e.g., we want:
            //   FOOS BARS
            //   FOO BAR
            // rather than:
            //  FOO BAR
            //  FOOS BARS <- FOOS will already have been partially matched by FOO in previous line
            (is_singular, to_singular),
        ],
    )
}

fn inflect_case(words: &Vec<String>) -> Vec<Vec<String>> {
    inflect_when_some_dont_match(
        words,
        vec![
            (case::is_camel_case, case::to_camel_case),
            (case::is_pascal_case, case::to_pascal_case),
            (case::is_kebab_case, case::to_kebab_case),
            (case::is_train_case, case::to_train_case),
            (case::is_snake_case, case::to_snake_case),
            (case::is_constant_case, case::to_constant_case),
            (is_all_lower, to_all_lower),
            (is_all_upper, to_all_upper), // note: keep last to not conflict with CONSTANT_CASE
        ],
    )
}

// if not all words match a pred (i.e. there are some words that do not match), applies the inflecting fn to those words
fn inflect_when_some_dont_match(
    words: &Vec<String>,
    preds_and_fns: Vec<(fn(&str) -> bool, fn(&str) -> String)>,
) -> Vec<Vec<String>> {
    let mut out = deduped_vec::DedupedVec::new();

    out.push(words.clone());

    for (pred, f) in preds_and_fns.iter() {
        let all_match = words.iter().all(|w| pred(w));
        if !all_match {
            let mapped: Vec<String> = words.iter().map(|w| f(w)).collect();
            out.push(mapped);
        }
    }

    out.items
}

fn to_all_lower(word: &str) -> String {
    word.to_camel_case().to_lowercase()
}

fn to_all_upper(word: &str) -> String {
    word.to_camel_case().to_uppercase()
}

fn is_all_lower(word: &str) -> bool {
    to_all_lower(word) == word
}

fn is_all_upper(word: &str) -> bool {
    to_all_upper(word) == word
}

fn is_singular(word: &str) -> bool {
    to_singular(word) == word
}

fn is_plural(word: &str) -> bool {
    to_plural(word) == word
}

pub fn print_matrix(xxs: Vec<Vec<String>>) {
    for xs in xxs {
        println!("{}", xs.join(" "));
    }
}