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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use std::collections::{HashMap, HashSet};

use crate::Resolver;

#[derive(Debug)]
pub struct ResolverOptions {
    pub extensions: Vec<String>,
    pub alias: HashMap<String, Option<String>>,
    pub condition_names: HashSet<String>,
    pub symlinks: bool,
    pub(crate) alias_fields: Vec<String>,
    pub(crate) main_files: Vec<String>,
    pub(crate) main_fields: Vec<String>,
    pub(crate) description_file: String,
    pub(crate) modules: Vec<String>,
}

impl Default for ResolverOptions {
    fn default() -> Self {
        let extensions = vec![
            String::from("js"),
            String::from("json"),
            String::from("node"),
        ];
        let main_files = vec![String::from("index")];
        let main_fields = vec![String::from("main")];
        let description_file = String::from("package.json");
        let alias = HashMap::new();
        let modules = vec![String::from("node_modules")];
        let symlinks = true;
        let alias_fields = vec![];
        let condition_names: HashSet<String> = HashSet::new();
        Self {
            extensions,
            main_files,
            main_fields,
            description_file,
            alias,
            modules,
            symlinks,
            alias_fields,
            condition_names,
        }
    }
}

type From = str;
type To = str;

impl Resolver {
    pub fn with_extensions(self, extensions: Vec<&str>) -> Self {
        let extensions = extensions
            .iter()
            .map(|&s| {
                if s.starts_with('.') {
                    s.chars().skip(1).collect()
                } else {
                    s.into()
                }
            })
            .collect();
        let options = ResolverOptions {
            extensions,
            ..self.options
        };
        Self { options, ..self }
    }

    pub fn with_alias(self, alias: Vec<(&From, Option<&To>)>) -> Self {
        let alias = alias
            .iter()
            .map(|&(k, v)| (k.into(), v.map(|v| v.into())))
            .collect();
        let options = ResolverOptions {
            alias,
            ..self.options
        };
        Self { options, ..self }
    }

    pub fn with_alias_fields(self, alias_fields: Vec<&str>) -> Self {
        let alias_fields = alias_fields.iter().map(|&s| s.into()).collect();
        let options = ResolverOptions {
            alias_fields,
            ..self.options
        };
        Self { options, ..self }
    }

    pub fn with_modules(self, modules: Vec<&str>) -> Self {
        let modules = modules.iter().map(|&s| s.into()).collect();
        let options = ResolverOptions {
            modules,
            ..self.options
        };
        Self { options, ..self }
    }

    pub fn with_symlinks(self, symlinks: bool) -> Self {
        let options = ResolverOptions {
            symlinks,
            ..self.options
        };
        Self { options, ..self }
    }

    pub fn with_condition_names(self, condition_names: HashSet<String>) -> Self {
        let options = ResolverOptions {
            condition_names,
            ..self.options
        };
        Self { options, ..self }
    }
}