Skip to main content

tsain_core/
script.rs

1use super::*;
2
3#[derive(Default)]
4pub struct TsScript {
5    comment: Option<String>,
6    exclusive: Vec<String>,
7    exclude: Vec<String>,
8}
9
10impl TsScript {
11    pub fn new() -> Self {
12        Self::default()
13    }
14
15    /// Set comment
16    pub fn with_comment<T: Into<String>>(mut self, comment: T) -> Self {
17        self.comment.replace(comment.into());
18        self
19    }
20
21    /// Set exclusive type list
22    pub fn with_exclusive<T: Into<String>>(mut self, exclusive: Vec<T>) -> Self {
23        self.exclusive = exclusive.into_iter().map(|x| x.into()).collect::<Vec<_>>();
24        self
25    }
26
27    /// Add excluded type list
28    pub fn with_exclude<T: Into<String>>(mut self, exclude: Vec<T>) -> Self {
29        self.exclude.extend(exclude.into_iter().map(|x| x.into()));
30        self
31    }
32
33    /// Build and return the script
34    pub fn build_script(&self) -> String {
35        build_ts_script_with(
36            self.comment.as_ref(),
37            self.exclusive.as_slice(),
38            self.exclude.as_slice(),
39        )
40    }
41
42    /// Create a script file at the path
43    pub fn export_script(&self, path: impl AsRef<std::path::Path>) {
44        let script = self.build_script();
45
46        let path = path.as_ref();
47        if let Some(parent) = path.parent() {
48            std::fs::create_dir_all(parent).expect("Failed to create parent directories");
49        }
50        std::fs::write(path, script).expect("Failed to write Tsain TypeScript file");
51        println!(
52            "cargo:warning=Exported Tsain TypeScript definitions to {}",
53            path.display()
54        );
55    }
56
57    /// Create a script file at the path
58    pub fn export(path: impl AsRef<std::path::Path>) {
59        Self::new().export_script(path);
60    }
61}
62
63fn build_ts_script_with(
64    comment: Option<&String>,
65    exclusive: &[String],
66    exclude: &[String],
67) -> String {
68    #[cfg(not(target_arch = "wasm32"))]
69    {
70        let mut script = include_str!("../script/head.txt").to_owned();
71        script.push_str("\n");
72
73        // 0. Comment
74        if let Some(comment) = comment {
75            script.push_str(comment);
76            script.push('\n');
77        }
78
79        script.push_str("\n\n");
80
81        // 1. Tsain Pattern
82        for def in inventory::iter::<TsainPatternDefinition>() {
83            let pattern = (def.__pattern_fn)();
84            let exclude = (!exclusive.is_empty()
85                && !exclusive
86                    .iter()
87                    .find(|x| x.eq(&pattern.rs_name()))
88                    .is_some())
89                || exclude.iter().find(|x| x.eq(&pattern.rs_name())).is_some();
90            if exclude {
91                continue;
92            }
93            script.push_str(&pattern.format_type_script());
94            script.push('\n');
95        }
96
97        // 2. Tsain Alias
98        for def in inventory::iter::<TsainAliasDefinition>() {
99            let script_ = def.__script;
100            script.push_str(script_);
101            script.push('\n');
102        }
103
104        return script;
105    }
106
107    #[allow(unreachable_code)]
108    return String::from("CAN NOT BUILD SCRIPT IN WASM TARGET");
109}
110
111// inventory
112
113#[cfg(not(target_arch = "wasm32"))]
114pub struct TsainPatternDefinition {
115    pub __pattern_fn: fn() -> TsainPattern,
116}
117
118#[cfg(not(target_arch = "wasm32"))]
119inventory::collect!(TsainPatternDefinition);
120
121#[cfg(not(target_arch = "wasm32"))]
122pub struct TsainAliasDefinition {
123    pub __script: &'static str,
124}
125#[cfg(not(target_arch = "wasm32"))]
126inventory::collect!(TsainAliasDefinition);