1use proc_macro2::TokenStream;
2use quote::quote;
3use std::{fs, path::Path};
4use syn::{parse_str, Ident, ItemMod};
5
6use crate::generator::context::GenContext;
7use crate::generator::deserializer::gen_deserializers;
8use crate::generator::open_xml_part::gen_open_xml_parts;
9use crate::generator::open_xml_schema::gen_open_xml_schemas;
10use crate::generator::serializer::gen_serializer;
11use crate::generator::validator::gen_validators;
12
13pub mod generator;
14pub mod includes;
15pub mod models;
16pub mod utils;
17
18pub fn generate(data_dir: &str, out_dir: &str) {
19 let out_dir_path = Path::new(out_dir);
20
21 let mut gen_context = GenContext::new(data_dir);
22
23 for namespace in gen_context.namespaces.iter() {
24 gen_context
25 .prefix_namespace_map
26 .insert(&namespace.prefix, namespace);
27
28 gen_context
29 .uri_namespace_map
30 .insert(&namespace.uri, namespace);
31 }
32
33 for typed_namespace in gen_context.typed_namespaces.iter() {
34 gen_context
35 .namespace_typed_namespace_map
36 .insert(&typed_namespace.namespace, typed_namespace);
37 }
38
39 for typed_schema in gen_context.typed_schemas.iter() {
40 for ty in typed_schema.iter() {
41 if !ty.part_class_name.is_empty() {
42 gen_context
43 .part_name_type_name_map
44 .insert(&ty.part_class_name, &ty.name);
45 }
46 }
47 }
48
49 for schema in gen_context.schemas.iter() {
50 let namespace = gen_context
51 .uri_namespace_map
52 .get(schema.target_namespace.as_str())
53 .ok_or(format!("{:?}", schema.target_namespace))
54 .unwrap();
55
56 gen_context
57 .prefix_schema_map
58 .insert(&namespace.prefix, schema);
59
60 for e in schema.enums.iter() {
61 gen_context.enum_type_enum_map.insert(&e.r#type, e);
62
63 gen_context
64 .enum_type_namespace_map
65 .insert(&e.r#type, namespace);
66 }
67
68 for ty in schema.types.iter() {
69 gen_context.type_name_type_map.insert(&ty.name, ty);
70
71 gen_context
72 .type_name_namespace_map
73 .insert(&ty.name, namespace);
74
75 if !ty.part.is_empty() {
76 gen_context
77 .part_name_type_name_map
78 .insert(&ty.part, &ty.name);
79 }
80 }
81 }
82
83 gen_context
84 .part_name_type_name_map
85 .insert("StyleDefinitionsPart", "w:CT_Styles/w:styles");
86 gen_context
87 .part_name_type_name_map
88 .insert("StylesWithEffectsPart", "w:CT_Styles/w:styles");
89
90 write_schemas(&gen_context, out_dir_path);
91
92 write_deserializers(&gen_context, out_dir_path);
93
94 write_serializers(&gen_context, out_dir_path);
95
96 #[cfg(feature = "parts")]
97 let with_parts = true;
98 #[cfg(not(feature = "parts"))]
99 let with_parts = false;
100
101 if with_parts {
102 write_parts(&gen_context, out_dir_path);
103 }
104
105 #[cfg(feature = "validators")]
106 let with_validators = true;
107 #[cfg(not(feature = "validators"))]
108 let with_validators = false;
109
110 if with_validators {
111 write_validators(&gen_context, out_dir_path);
112 }
113}
114
115pub(crate) fn write_schemas(gen_context: &GenContext, out_dir_path: &Path) {
116 let out_schemas_dir_path = out_dir_path.join("schemas");
117 let out_common_dir_path = out_dir_path.join("common");
118
119 fs::create_dir_all(&out_schemas_dir_path).unwrap();
120 fs::create_dir_all(&out_common_dir_path).unwrap();
121
122 let mut schemas_mod_use_list: Vec<ItemMod> = vec![];
123
124 for schema in gen_context.schemas.iter() {
125 let token_stream = gen_open_xml_schemas(schema, gen_context);
126 let syntax_tree = syn::parse2(token_stream).unwrap();
127 let formatted = prettyplease::unparse(&syntax_tree);
128 let schema_path = out_schemas_dir_path.join(format!("{}.rs", &schema.module_name));
129 fs::write(schema_path, formatted).unwrap();
130
131 let schema_mod_ident: Ident = parse_str(&schema.module_name).unwrap();
132 let shcemas_mod_use: ItemMod = parse_str(
133 "e! {
134 pub mod #schema_mod_ident;
135 }
136 .to_string(),
137 )
138 .unwrap();
139 schemas_mod_use_list.push(shcemas_mod_use);
140 }
141
142 let token_stream: TokenStream = parse_str(include_str!("includes/simple_type.rs")).unwrap();
143 let syntax_tree = syn::parse2(token_stream).unwrap();
144 let formatted = prettyplease::unparse(&syntax_tree);
145 let schemas_mod_path = out_schemas_dir_path.join("simple_type.rs");
146 fs::write(schemas_mod_path, formatted).unwrap();
147
148 let token_stream: TokenStream = parse_str(include_str!("includes/common.rs")).unwrap();
149 let syntax_tree = syn::parse2(token_stream).unwrap();
150 let formatted = prettyplease::unparse(&syntax_tree);
151 let schemas_mod_path = out_common_dir_path.join("mod.rs");
152 fs::write(schemas_mod_path, formatted).unwrap();
153
154 let token_stream: TokenStream =
155 parse_str(include_str!("includes/packages/opc_content_types.rs")).unwrap();
156 let syntax_tree = syn::parse2(token_stream).unwrap();
157 let formatted = prettyplease::unparse(&syntax_tree);
158 let schemas_mod_path = out_schemas_dir_path.join("opc_content_types.rs");
159 fs::write(schemas_mod_path, formatted).unwrap();
160
161 let token_stream: TokenStream =
162 parse_str(include_str!("includes/packages/opc_relationships.rs")).unwrap();
163 let syntax_tree = syn::parse2(token_stream).unwrap();
164 let formatted = prettyplease::unparse(&syntax_tree);
165 let schemas_mod_path = out_schemas_dir_path.join("opc_relationships.rs");
166 fs::write(schemas_mod_path, formatted).unwrap();
167
168 let token_stream: TokenStream =
169 parse_str(include_str!("includes/packages/opc_core_properties.rs")).unwrap();
170 let syntax_tree = syn::parse2(token_stream).unwrap();
171 let formatted = prettyplease::unparse(&syntax_tree);
172 let schemas_mod_path = out_schemas_dir_path.join("opc_core_properties.rs");
173 fs::write(schemas_mod_path, formatted).unwrap();
174
175 let token_stream: TokenStream = quote! {
176 pub mod simple_type;
177 pub mod opc_content_types;
178 pub mod opc_core_properties;
179 pub mod opc_relationships;
180 #( #schemas_mod_use_list )*
181 };
182 let syntax_tree = syn::parse2(token_stream).unwrap();
183 let formatted = prettyplease::unparse(&syntax_tree);
184 let schemas_mod_path = out_schemas_dir_path.join("mod.rs");
185 fs::write(schemas_mod_path, formatted).unwrap();
186}
187
188pub(crate) fn write_deserializers(gen_context: &GenContext, out_dir_path: &Path) {
189 let out_deserializers_dir_path = &out_dir_path.join("deserializers");
190
191 fs::create_dir_all(out_deserializers_dir_path).unwrap();
192
193 let mut deserializers_mod_use_list: Vec<ItemMod> = vec![];
194
195 for schema in gen_context.schemas.iter() {
196 let token_stream = gen_deserializers(schema, gen_context);
197 let syntax_tree = syn::parse2(token_stream).unwrap();
198 let formatted = prettyplease::unparse(&syntax_tree);
199 let part_path = out_deserializers_dir_path.join(format!("{}.rs", &schema.module_name));
200 fs::write(part_path, formatted).unwrap();
201
202 let deserializer_mod_ident: Ident = parse_str(&schema.module_name).unwrap();
203 let deserializer_mod_use: ItemMod = parse_str(
204 "e! {
205 pub mod #deserializer_mod_ident;
206 }
207 .to_string(),
208 )
209 .unwrap();
210 deserializers_mod_use_list.push(deserializer_mod_use);
211 }
212
213 let token_stream: TokenStream = quote! {
214 #( #deserializers_mod_use_list )*
215 };
216 let syntax_tree = syn::parse2(token_stream).unwrap();
217 let formatted = prettyplease::unparse(&syntax_tree);
218 let deserializers_mod_path = out_deserializers_dir_path.join("mod.rs");
219 fs::write(deserializers_mod_path, formatted).unwrap();
220}
221
222pub(crate) fn write_serializers(gen_context: &GenContext, out_dir_path: &Path) {
223 let out_serializers_dir_path = &out_dir_path.join("serializers");
224
225 fs::create_dir_all(out_serializers_dir_path).unwrap();
226
227 let mut serializers_mod_use_list: Vec<ItemMod> = vec![];
228
229 for schema in gen_context.schemas.iter() {
230 let token_stream = gen_serializer(schema, gen_context);
231 let syntax_tree = syn::parse2(token_stream).unwrap();
232 let formatted = prettyplease::unparse(&syntax_tree);
233 let part_path = out_serializers_dir_path.join(format!("{}.rs", &schema.module_name));
234 fs::write(part_path, formatted).unwrap();
235
236 let serializer_mod_ident: Ident = parse_str(&schema.module_name).unwrap();
237 let serializer_mod_use: ItemMod = parse_str(
238 "e! {
239 pub mod #serializer_mod_ident;
240 }
241 .to_string(),
242 )
243 .unwrap();
244 serializers_mod_use_list.push(serializer_mod_use);
245 }
246
247 let token_stream: TokenStream = quote! {
248 #( #serializers_mod_use_list )*
249 };
250 let syntax_tree = syn::parse2(token_stream).unwrap();
251 let formatted = prettyplease::unparse(&syntax_tree);
252 let serializers_mod_path = out_serializers_dir_path.join("mod.rs");
253 fs::write(serializers_mod_path, formatted).unwrap();
254}
255
256pub(crate) fn write_parts(gen_context: &GenContext, out_dir_path: &Path) {
257 let out_parts_dir_path = &out_dir_path.join("parts");
258
259 fs::create_dir_all(out_parts_dir_path).unwrap();
260
261 let mut parts_mod_use_list: Vec<ItemMod> = vec![];
262
263 for part in gen_context.parts.iter() {
264 let token_stream = gen_open_xml_parts(part, gen_context);
265 let syntax_tree = syn::parse2(token_stream).unwrap();
266 let formatted = prettyplease::unparse(&syntax_tree);
267 let part_path = out_parts_dir_path.join(format!("{}.rs", &part.module_name));
268 fs::write(part_path, formatted).unwrap();
269
270 let part_mod_ident: Ident = parse_str(&part.module_name).unwrap();
271 let part_mod_use: ItemMod = parse_str(
272 "e! {
273 pub mod #part_mod_ident;
274 }
275 .to_string(),
276 )
277 .unwrap();
278 parts_mod_use_list.push(part_mod_use);
279 }
280
281 let token_stream: TokenStream = quote! {
282 #( #parts_mod_use_list )*
283 };
284
285 let syntax_tree = syn::parse2(token_stream).unwrap();
286 let formatted = prettyplease::unparse(&syntax_tree);
287
288 let parts_mod_path = out_parts_dir_path.join("mod.rs");
289
290 fs::write(parts_mod_path, formatted).unwrap();
291}
292
293pub(crate) fn write_validators(gen_context: &GenContext, out_dir_path: &Path) {
294 let out_validators_dir_path = &out_dir_path.join("validators");
295
296 fs::create_dir_all(out_validators_dir_path).unwrap();
297
298 let mut validators_mod_use_list: Vec<ItemMod> = vec![];
299
300 for part in gen_context.schemas.iter() {
301 let token_stream = gen_validators(part, gen_context);
302 let syntax_tree = syn::parse2(token_stream).unwrap();
303 let formatted = prettyplease::unparse(&syntax_tree);
304 let part_path = out_validators_dir_path.join(format!("{}.rs", &part.module_name));
305 fs::write(part_path, formatted).unwrap();
306
307 let validator_mod_ident: Ident = parse_str(&part.module_name).unwrap();
308 let validator_mod_use: ItemMod = parse_str(
309 "e! {
310 pub mod #validator_mod_ident;
311 }
312 .to_string(),
313 )
314 .unwrap();
315 validators_mod_use_list.push(validator_mod_use);
316 }
317
318 let token_stream: TokenStream = quote! {
319 #( #validators_mod_use_list )*
320 };
321 let syntax_tree = syn::parse2(token_stream).unwrap();
322 let formatted = prettyplease::unparse(&syntax_tree);
323 let validators_mod_path = out_validators_dir_path.join("mod.rs");
324 fs::write(validators_mod_path, formatted).unwrap();
325}
326
327#[cfg(test)]
328mod tests {
329 use super::*;
330
331 #[test]
332 fn test_gen() {
333 generate("../ooxmlsdk/data", "src");
334 }
335}