tytanic_utils/
typst.rs

1use std::collections::BTreeMap;
2
3use ecow::EcoString;
4use typst_syntax::package::PackageInfo;
5use typst_syntax::package::PackageManifest;
6use typst_syntax::package::PackageVersion;
7use typst_syntax::package::TemplateInfo;
8use typst_syntax::package::ToolInfo;
9use typst_syntax::package::UnknownFields;
10use typst_syntax::package::VersionBound;
11
12/// A builder for [`PackageManifest`].
13#[derive(Debug, Clone)]
14pub struct PackageManifestBuilder {
15    pub package: PackageInfoBuilder,
16    pub template: Option<TemplateInfoBuilder>,
17    pub tool: ToolInfoBuilder,
18}
19
20impl Default for PackageManifestBuilder {
21    fn default() -> Self {
22        Self::new()
23    }
24}
25
26impl PackageManifestBuilder {
27    pub fn new() -> Self {
28        Self {
29            package: PackageInfoBuilder::new(),
30            template: None,
31            tool: ToolInfoBuilder::new(),
32        }
33    }
34
35    pub fn package<T: Into<PackageInfoBuilder>>(&mut self, value: T) -> &mut Self {
36        self.package = value.into();
37        self
38    }
39
40    pub fn template<T: Into<TemplateInfoBuilder>>(&mut self, value: T) -> &mut Self {
41        self.template = Some(value.into());
42        self
43    }
44
45    pub fn tool<T: Into<ToolInfoBuilder>>(&mut self, value: T) -> &mut Self {
46        self.tool = value.into();
47        self
48    }
49
50    pub fn build(&self) -> PackageManifest {
51        self.clone().into()
52    }
53}
54
55/// A builder for [`PackageInfo`].
56#[derive(Debug, Clone)]
57pub struct PackageInfoBuilder {
58    pub name: EcoString,
59    pub version: PackageVersion,
60    pub entrypoint: EcoString,
61    pub authors: Vec<EcoString>,
62    pub license: Option<EcoString>,
63    pub description: Option<EcoString>,
64    pub homepage: Option<EcoString>,
65    pub repository: Option<EcoString>,
66    pub keywords: Vec<EcoString>,
67    pub categories: Vec<EcoString>,
68    pub disciplines: Vec<EcoString>,
69    pub compiler: Option<VersionBound>,
70    pub exclude: Vec<EcoString>,
71}
72
73impl From<PackageManifest> for PackageManifestBuilder {
74    fn from(value: PackageManifest) -> Self {
75        Self {
76            package: value.package.into(),
77            template: value.template.map(Into::into),
78            tool: value.tool.into(),
79        }
80    }
81}
82
83impl From<PackageManifestBuilder> for PackageManifest {
84    fn from(value: PackageManifestBuilder) -> Self {
85        Self {
86            package: value.package.into(),
87            template: value.template.map(Into::into),
88            tool: value.tool.into(),
89            unknown_fields: UnknownFields::new(),
90        }
91    }
92}
93
94const PACKAGE_INFO_VERSION_DEFAULT: PackageVersion = PackageVersion {
95    major: 0,
96    minor: 1,
97    patch: 0,
98};
99const PACKAGE_INFO_NAME_DEFAULT: &str = "my-package";
100const PACKAGE_INFO_ENTRYPOINT_DEFAULT: &str = "src/lib.typ";
101
102impl Default for PackageInfoBuilder {
103    fn default() -> Self {
104        Self::new()
105    }
106}
107
108impl PackageInfoBuilder {
109    pub fn new() -> Self {
110        Self {
111            name: PACKAGE_INFO_NAME_DEFAULT.into(),
112            version: PACKAGE_INFO_VERSION_DEFAULT,
113            entrypoint: PACKAGE_INFO_ENTRYPOINT_DEFAULT.into(),
114            authors: vec![],
115            license: None,
116            description: None,
117            homepage: None,
118            repository: None,
119            keywords: vec![],
120            categories: vec![],
121            disciplines: vec![],
122            compiler: None,
123            exclude: vec![],
124        }
125    }
126
127    pub fn name<T: Into<EcoString>>(&mut self, value: T) -> &mut Self {
128        self.name = value.into();
129        self
130    }
131
132    pub fn version<T: Into<PackageVersion>>(&mut self, value: T) -> &mut Self {
133        self.version = value.into();
134        self
135    }
136
137    pub fn entrypoint<T: Into<EcoString>>(&mut self, value: T) -> &mut Self {
138        self.entrypoint = value.into();
139        self
140    }
141
142    pub fn authors<T, I>(&mut self, value: I) -> &mut Self
143    where
144        T: Into<EcoString>,
145        I: IntoIterator<Item = T>,
146    {
147        self.authors = value.into_iter().map(Into::into).collect();
148        self
149    }
150
151    pub fn license<T: Into<EcoString>>(&mut self, value: T) -> &mut Self {
152        self.license = Some(value.into());
153        self
154    }
155
156    pub fn description<T: Into<EcoString>>(&mut self, value: T) -> &mut Self {
157        self.description = Some(value.into());
158        self
159    }
160
161    pub fn homepage<T: Into<EcoString>>(&mut self, value: T) -> &mut Self {
162        self.homepage = Some(value.into());
163        self
164    }
165
166    pub fn repository<T: Into<EcoString>>(&mut self, value: T) -> &mut Self {
167        self.repository = Some(value.into());
168        self
169    }
170
171    pub fn keywords<T, I>(&mut self, value: I) -> &mut Self
172    where
173        T: Into<EcoString>,
174        I: IntoIterator<Item = T>,
175    {
176        self.keywords = value.into_iter().map(Into::into).collect();
177        self
178    }
179
180    pub fn categories<T, I>(&mut self, value: I) -> &mut Self
181    where
182        T: Into<EcoString>,
183        I: IntoIterator<Item = T>,
184    {
185        self.categories = value.into_iter().map(Into::into).collect();
186        self
187    }
188
189    pub fn disciplines<T, I>(&mut self, value: I) -> &mut Self
190    where
191        T: Into<EcoString>,
192        I: IntoIterator<Item = T>,
193    {
194        self.disciplines = value.into_iter().map(Into::into).collect();
195        self
196    }
197
198    pub fn compiler<T: Into<VersionBound>>(&mut self, value: T) -> &mut Self {
199        self.compiler = Some(value.into());
200        self
201    }
202
203    pub fn exclude<T, I>(&mut self, value: I) -> &mut Self
204    where
205        T: Into<EcoString>,
206        I: IntoIterator<Item = T>,
207    {
208        self.exclude = value.into_iter().map(Into::into).collect();
209        self
210    }
211
212    pub fn build(&self) -> PackageInfo {
213        self.clone().into()
214    }
215}
216
217impl From<PackageInfo> for PackageInfoBuilder {
218    fn from(value: PackageInfo) -> Self {
219        Self {
220            name: value.name,
221            version: value.version,
222            entrypoint: value.entrypoint,
223            authors: value.authors,
224            license: value.license,
225            description: value.description,
226            homepage: value.homepage,
227            repository: value.repository,
228            keywords: value.keywords,
229            categories: value.categories,
230            disciplines: value.disciplines,
231            compiler: value.compiler,
232            exclude: value.exclude,
233        }
234    }
235}
236
237impl From<PackageInfoBuilder> for PackageInfo {
238    fn from(value: PackageInfoBuilder) -> Self {
239        Self {
240            name: value.name,
241            version: value.version,
242            entrypoint: value.entrypoint,
243            authors: value.authors,
244            license: value.license,
245            description: value.description,
246            homepage: value.homepage,
247            repository: value.repository,
248            keywords: value.keywords,
249            categories: value.categories,
250            disciplines: value.disciplines,
251            compiler: value.compiler,
252            exclude: value.exclude,
253            unknown_fields: UnknownFields::new(),
254        }
255    }
256}
257
258const TEMPLATE_INFO_PATH_DEFAULT: &str = "template";
259const TEMPLATE_INFO_ENTRYPOINT_DEFAULT: &str = "main.typ";
260
261/// A builder for [`TemplateInfo`].
262#[derive(Debug, Clone)]
263pub struct TemplateInfoBuilder {
264    path: EcoString,
265    entrypoint: EcoString,
266    thumbnail: Option<EcoString>,
267}
268
269impl Default for TemplateInfoBuilder {
270    fn default() -> Self {
271        Self::new()
272    }
273}
274
275impl TemplateInfoBuilder {
276    pub fn new() -> Self {
277        Self {
278            path: TEMPLATE_INFO_PATH_DEFAULT.into(),
279            entrypoint: TEMPLATE_INFO_ENTRYPOINT_DEFAULT.into(),
280            thumbnail: None,
281        }
282    }
283
284    pub fn path<T: Into<EcoString>>(&mut self, value: T) -> &mut Self {
285        self.path = value.into();
286        self
287    }
288
289    pub fn entrypoint<T: Into<EcoString>>(&mut self, value: T) -> &mut Self {
290        self.entrypoint = value.into();
291        self
292    }
293
294    pub fn thumbnail<T: Into<EcoString>>(&mut self, value: T) -> &mut Self {
295        self.thumbnail = Some(value.into());
296        self
297    }
298
299    pub fn build(&self) -> TemplateInfo {
300        self.clone().into()
301    }
302}
303
304impl From<TemplateInfo> for TemplateInfoBuilder {
305    fn from(value: TemplateInfo) -> Self {
306        Self {
307            path: value.path,
308            entrypoint: value.entrypoint,
309            thumbnail: value.thumbnail,
310        }
311    }
312}
313
314impl From<TemplateInfoBuilder> for TemplateInfo {
315    fn from(value: TemplateInfoBuilder) -> Self {
316        Self {
317            path: value.path,
318            entrypoint: value.entrypoint,
319            thumbnail: value.thumbnail,
320            unknown_fields: UnknownFields::new(),
321        }
322    }
323}
324
325/// A builder for [`ToolInfo`].
326#[derive(Debug, Clone)]
327pub struct ToolInfoBuilder {
328    pub sections: BTreeMap<EcoString, toml::Table>,
329}
330
331impl Default for ToolInfoBuilder {
332    fn default() -> Self {
333        Self::new()
334    }
335}
336
337impl ToolInfoBuilder {
338    pub fn new() -> Self {
339        Self {
340            sections: BTreeMap::new(),
341        }
342    }
343
344    pub fn section<T: Into<BTreeMap<EcoString, toml::Table>>>(mut self, value: T) -> Self {
345        self.sections = value.into();
346        self
347    }
348
349    pub fn with_section<K: Into<EcoString>, V: Into<toml::Table>>(
350        mut self,
351        key: K,
352        val: V,
353    ) -> Self {
354        self.sections.insert(key.into(), val.into());
355        self
356    }
357
358    pub fn build(&self) -> ToolInfo {
359        self.clone().into()
360    }
361}
362
363impl From<ToolInfo> for ToolInfoBuilder {
364    fn from(value: ToolInfo) -> Self {
365        Self {
366            sections: value.sections,
367        }
368    }
369}
370
371impl From<ToolInfoBuilder> for ToolInfo {
372    fn from(value: ToolInfoBuilder) -> Self {
373        Self {
374            sections: value.sections,
375        }
376    }
377}