Skip to main content

tsain_pattern/patterns/
mod.rs

1use super::formatter::{DefaultPropsFormatter, PropsFormatter};
2
3mod props;
4mod vars;
5
6pub use props::*;
7pub use vars::*;
8
9/// Object Pattern
10pub enum TsainPattern {
11    Enum(EnumPattern),
12    Struct(PropsPattern),
13}
14
15pub struct Composition<T> {
16    /// Rs type name
17    /// * Enum / Struct: Rs ident name
18    /// * Variant: "{enum-name}{var-name}"
19    rs_name: &'static str,
20    /// Ts type name
21    /// * Enum / Struct: Ts export name
22    /// * Variant: "{enum-name}{var-name}"
23    ts_name: &'static str,
24    ///
25    type_args: Vec<&'static str>,
26    /// * Enum: vars
27    /// * Struct / Variant: props
28    list: T,
29    /// skip default brand of "__brand"
30    skip_brand: bool,
31    ///
32    /// [[brand-key, brand's value]]
33    extra_brands: Vec<[&'static str; 2]>,
34}
35
36impl<T> Composition<T> {
37    pub fn new(
38        rs_name: &'static str,
39        ts_name: &'static str,
40        type_args: Vec<&'static str>,
41        list: T,
42        skip_brand: bool,
43        extra_brands: Vec<[&'static str; 2]>,
44    ) -> Self {
45        Self {
46            rs_name,
47            ts_name,
48            type_args,
49            list,
50            skip_brand,
51            extra_brands,
52        }
53    }
54
55    fn build_brands_script(&self) -> String {
56        let mut pairs = Vec::new();
57        if !self.skip_brand {
58            pairs.push(format!(r#"readonly __brand: "{}""#, self.ts_name));
59        }
60        pairs.extend(
61            self.extra_brands.iter().map(|[brand_name, brand_ts_type]| {
62                format!("readonly {brand_name}: {brand_ts_type}")
63            }),
64        );
65
66        if pairs.is_empty() {
67            Default::default()
68        } else {
69            let pairs = pairs.join(", ");
70            format!(" & {{{}}}", pairs)
71        }
72    }
73}
74
75impl TsainPattern {
76    pub fn new_enum(
77        rs_name: &'static str,
78        ts_name: &'static str,
79        type_args: Vec<&'static str>,
80        // [Option<(var-"full"-ts-name, props-pattern)>]
81        list: Vec<Option<(&'static str, PropsPattern)>>,
82    ) -> Self {
83        Self::Enum(EnumPattern::new(
84            rs_name,
85            ts_name,
86            type_args,
87            list,
88            // enum itself should not have brand
89            true,
90            Default::default(),
91        ))
92    }
93
94    pub fn new_struct(
95        rs_name: &'static str,
96        ts_name: &'static str,
97        type_args: Vec<&'static str>,
98        list: Vec<(&'static str, &'static str)>,
99        skip_brand: bool,
100        extra_brands: Vec<[&'static str; 2]>,
101    ) -> Self {
102        Self::Struct(PropsPattern::new(
103            rs_name,
104            ts_name,
105            type_args,
106            list,
107            skip_brand,
108            extra_brands,
109        ))
110    }
111
112    pub fn rs_name(&self) -> &str {
113        match self {
114            Self::Enum(Composition { rs_name, .. }) | Self::Struct(Composition { rs_name, .. }) => {
115                rs_name
116            }
117        }
118    }
119
120    pub fn format_type_script(&self) -> String {
121        match self {
122            Self::Enum(e) => e.format_enum_type_script(&DefaultPropsFormatter),
123            Self::Struct(e) => DefaultPropsFormatter.format_type_script(e, None),
124        }
125    }
126}