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#[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#[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#[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#[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}