Skip to main content

tsain_pattern/patterns/
props.rs

1use super::*;
2
3/// # Contains List of (Ts prop name, Ts-type): For Struct or Variant
4pub type PropsPattern = Composition<Vec<(&'static str, &'static str)>>;
5
6impl PropsPattern {
7    pub fn list(&self) -> &Vec<(&'static str, &'static str)> {
8        &self.list
9    }
10
11    /// Comma joined props names
12    fn prop_names(&self) -> String {
13        self.list
14            .iter()
15            .map(|(n, _)| *n)
16            .collect::<Vec<_>>()
17            .join(", ")
18    }
19
20    /// Comma joined props types
21    fn prop_types(&self) -> String {
22        self.list
23            .iter()
24            .map(|(_, t)| *t)
25            .collect::<Vec<_>>()
26            .join(", ")
27    }
28
29    /// comma joined props' "name: type"
30    fn prop_name2types(&self) -> String {
31        self.list
32            .iter()
33            .map(|(n, t)| format!("{n}: {t}"))
34            .collect::<Vec<_>>()
35            .join(", ")
36    }
37}
38
39/// Default formatting
40impl PropsPattern {
41    fn default_declaration_script(&self, var_id: Option<u32>) -> String {
42        let ts_name = &self.ts_name;
43        let prop_types = self.prop_types();
44        let type_args = crate::format_type_args(&self.type_args);
45
46        let brands_script = self.build_brands_script();
47
48        match var_id {
49            None => format!(r#"export type {ts_name}{type_args} = [{prop_types}]{brands_script};"#),
50            Some(var_id) => format!(
51                r#"export type {ts_name}{type_args} = [{var_id}, [{prop_types}]]{brands_script};"#
52            ),
53        }
54    }
55
56    fn default_constructor_name(&self) -> String {
57        format!("{}_", self.ts_name)
58    }
59
60    fn default_constructor_script(&self, var_id: Option<u32>) -> String {
61        let ts_name = &self.ts_name;
62        let type_args = crate::format_type_args(&self.type_args);
63        let constructor_name = self.default_constructor_name();
64
65        let prop_names = self.prop_names();
66        let prop_name2types = self.prop_name2types();
67
68        match var_id {
69            None => format!(
70                "export const {constructor_name} = {type_args}({prop_name2types}) => [{prop_names}] as {ts_name}{type_args};"
71            ),
72            Some(var_id) => format!(
73                "export const {constructor_name} = {type_args}({prop_name2types}) => [{var_id}, [{prop_names}]] as {ts_name}{type_args};"
74            ),
75        }
76    }
77
78    fn default_prop_getter_script(
79        &self,
80        prop_name: &str,
81        prop_type: &str,
82        prop_idx: usize,
83        is_variant: bool,
84    ) -> String {
85        let ts_name = &self.ts_name;
86        let type_args = crate::format_type_args(&self.type_args);
87
88        // prop id
89        let mut script = format!("export const {ts_name}_{prop_name}_id: number = {prop_idx};\n");
90
91        // getter
92        let getter = match is_variant {
93            false => {
94                format!(
95                    "export const {ts_name}_{prop_name} = {type_args}(v: {ts_name}{type_args}): {prop_type} => v[{prop_idx}];\n"
96                )
97            }
98            true => {
99                format!(
100                    "export const {ts_name}_{prop_name} = {type_args}(v: {ts_name}{type_args}): {prop_type} => v[1][{prop_idx}];\n"
101                )
102            }
103        };
104        script.push_str(&getter);
105        return script;
106    }
107
108    fn default_prop_getters_script(&self, is_variant: bool) -> String {
109        self.list
110            .iter()
111            .enumerate()
112            .map(|(i, (name, ty))| self.default_prop_getter_script(name, ty, i, is_variant))
113            .collect::<Vec<_>>()
114            .join("\n")
115    }
116
117    pub(crate) fn default_as_variant_script(
118        &self,
119        enum_ts_name: &str,
120        enum_type_args: &str,
121        var_id: u32,
122    ) -> String {
123        let ts_name = self.ts_name;
124        let type_args = crate::format_type_args(&self.type_args);
125        format!(
126            "export const as{ts_name} = {enum_type_args}(e: {enum_ts_name}{enum_type_args}): {ts_name}{type_args} | undefined => e[0] == {var_id} ? e as {ts_name}{type_args} : undefined;"
127        )
128    }
129}
130
131impl PropsFormatter for DefaultPropsFormatter {
132    fn props_head_script(&self, props: &PropsPattern, var_id: Option<u32>) -> String {
133        let ts_name = &props.ts_name;
134        match var_id {
135            None => format!("// # Struct {ts_name}"),
136            Some(var_id) => format!("// ## Variant {var_id}: {ts_name}"),
137        }
138    }
139
140    fn props_script_list(
141        &self,
142        props: &PropsPattern,
143        var_id: Option<u32>,
144    ) -> Vec<(String, String)> {
145        vec![
146            (
147                // 1. type Declaration
148                format!("// 1. Type"),
149                props.default_declaration_script(var_id),
150            ),
151            (
152                // 2. Constructor
153                format!("// 2. Constructor"),
154                props.default_constructor_script(var_id),
155            ),
156            (
157                // 3. Prop(Field) Getters
158                format!("// 3. Getters"),
159                props.default_prop_getters_script(var_id.is_some()),
160            ),
161        ]
162    }
163
164    fn as_variant_script(
165        &self,
166        props: &PropsPattern,
167        enum_ts_name: &str,
168        enum_type_args: &str,
169        var_id: u32,
170    ) -> String {
171        props.default_as_variant_script(enum_ts_name, enum_type_args, var_id)
172    }
173}