1#![recursion_limit = "256"]
2#![doc = include_str!(concat!(env!("OUT_DIR"), "/README.md"))]
3
4pub mod code;
5pub mod config;
6pub mod generator;
7pub mod interpreter;
8pub mod optimizer;
9pub mod parser;
10pub mod quick_xml;
11pub mod schema;
12pub mod types;
13
14mod macros;
15mod misc;
16
17pub type GeneratorError = generator::Error;
19
20pub type InterpreterError = interpreter::Error;
22
23pub type ParserError<E> = parser::Error<E>;
25
26use std::fs::write;
27
28pub use code::{Module, SubModules};
29pub use config::Config;
30pub use generator::Generator;
31pub use interpreter::Interpreter;
32pub use misc::{AsAny, Error, WithNamespace};
33pub use optimizer::Optimizer;
34pub use parser::Parser;
35
36use macros::{assert_eq, unreachable};
37use proc_macro2::TokenStream;
38use quote::ToTokens;
39use tracing::instrument;
40
41use self::config::{
42 Generate, GeneratorConfig, InterpreterConfig, InterpreterFlags, OptimizerConfig,
43 OptimizerFlags, ParserConfig, ParserFlags, Renderer, Resolver, Schema,
44};
45use self::generator::renderer::{
46 DefaultsRenderer, NamespaceConstantsRenderer, QuickXmlDeserializeRenderer,
47 QuickXmlSerializeRenderer, TypesRenderer, WithNamespaceTraitRenderer,
48};
49use self::misc::TypesPrinter;
50use self::parser::resolver::{FileResolver, ManyResolver};
51use self::schema::Schemas;
52use self::types::{IdentType, Types};
53
54#[instrument(err, level = "trace")]
68pub fn generate(config: Config) -> Result<TokenStream, Error> {
69 let module = generate_modules(config)?;
70 let code = module.to_token_stream();
71
72 Ok(code)
73}
74
75#[instrument(err, level = "trace")]
87pub fn generate_modules(config: Config) -> Result<Module, Error> {
88 let schemas = exec_parser(config.parser)?;
89 let types = exec_interpreter(config.interpreter, &schemas)?;
90 let types = exec_optimizer(config.optimizer, types)?;
91 let module = exec_generator_module(config.generator, &schemas, &types)?;
92
93 Ok(module)
94}
95
96#[instrument(err, level = "trace")]
102pub fn exec_parser(config: ParserConfig) -> Result<Schemas, Error> {
103 tracing::info!("Parse Schemas");
104
105 let mut resolver = ManyResolver::new();
106 for r in config.resolver {
107 match r {
108 #[cfg(feature = "web-resolver")]
109 Resolver::Web => {
110 let web_resolver = self::parser::resolver::WebResolver::new();
111
112 resolver = resolver.add_resolver(web_resolver);
113 }
114 Resolver::File => {
115 let file_resolver = FileResolver::new();
116
117 resolver = resolver.add_resolver(file_resolver);
118 }
119 }
120 }
121
122 let mut parser = Parser::new()
123 .with_resolver(resolver)
124 .resolve_includes(config.flags.contains(ParserFlags::RESOLVE_INCLUDES));
125
126 if config.flags.contains(ParserFlags::DEFAULT_NAMESPACES) {
127 parser = parser.with_default_namespaces();
128 }
129
130 for (prefix, namespace) in config.namespaces {
131 parser = parser.with_namespace(prefix, namespace);
132 }
133
134 for schema in config.schemas {
135 match schema {
136 Schema::Url(url) => parser = parser.add_schema_from_url(url)?,
137 Schema::File(path) => parser = parser.add_schema_from_file(path)?,
138 Schema::Schema(schema) => parser = parser.add_schema_from_str(&schema)?,
139 }
140 }
141
142 let schemas = parser.finish();
143
144 if let Some(output) = config.debug_output {
145 let debug = format!("{schemas:#?}");
146
147 write(output, debug)?;
148 }
149
150 Ok(schemas)
151}
152
153#[instrument(err, level = "trace", skip(schemas))]
159pub fn exec_interpreter(config: InterpreterConfig, schemas: &Schemas) -> Result<Types, Error> {
160 tracing::info!("Interpret Schema");
161
162 let mut interpreter = Interpreter::new(schemas);
163
164 if config.flags.contains(InterpreterFlags::BUILDIN_TYPES) {
165 interpreter = interpreter.with_buildin_types()?;
166 }
167
168 if config.flags.contains(InterpreterFlags::DEFAULT_TYPEDEFS) {
169 interpreter = interpreter.with_default_typedefs()?;
170 }
171
172 if config.flags.contains(InterpreterFlags::WITH_XS_ANY_TYPE) {
173 interpreter = interpreter.with_xs_any_type()?;
174 }
175
176 for (ident, ty) in config.types {
177 let ident = ident.resolve(schemas)?;
178 interpreter = interpreter.with_type(ident, ty)?;
179 }
180
181 let types = interpreter.finish()?;
182
183 if let Some(output) = config.debug_output {
184 let printer = TypesPrinter::new(&types);
185 let debug = format!("{printer}");
186
187 write(output, debug)?;
188 }
189
190 Ok(types)
191}
192
193#[instrument(err, level = "trace", skip(types))]
199pub fn exec_optimizer(config: OptimizerConfig, types: Types) -> Result<Types, Error> {
200 tracing::info!("Optimize Types");
201
202 let mut optimizer = Optimizer::new(types);
203
204 macro_rules! exec {
205 ($flag:ident, $method:ident) => {
206 if config.flags.contains(OptimizerFlags::$flag) {
207 optimizer = optimizer.$method();
208 }
209 };
210 }
211
212 exec!(REMOVE_EMPTY_ENUM_VARIANTS, remove_empty_enum_variants);
213 exec!(REMOVE_EMPTY_ENUMS, remove_empty_enums);
214 exec!(
215 REMOVE_DUPLICATE_UNION_VARIANTS,
216 remove_duplicate_union_variants
217 );
218 exec!(REMOVE_EMPTY_UNIONS, remove_empty_unions);
219 exec!(USE_UNRESTRICTED_BASE_TYPE, use_unrestricted_base_type);
220 exec!(CONVERT_DYNAMIC_TO_CHOICE, convert_dynamic_to_choice);
221 exec!(FLATTEN_COMPLEX_TYPES, flatten_complex_types);
222 exec!(FLATTEN_UNIONS, flatten_unions);
223 exec!(MERGE_ENUM_UNIONS, merge_enum_unions);
224 exec!(RESOLVE_TYPEDEFS, resolve_typedefs);
225 exec!(REMOVE_DUPLICATES, remove_duplicates);
226 exec!(RESOLVE_TYPEDEFS, resolve_typedefs);
227 exec!(MERGE_CHOICE_CARDINALITIES, merge_choice_cardinalities);
228
229 let types = optimizer.finish();
230
231 if let Some(output) = config.debug_output {
232 let printer = TypesPrinter::new(&types);
233 let debug = format!("{printer}");
234
235 write(output, debug)?;
236 }
237
238 Ok(types)
239}
240
241#[instrument(err, level = "trace", skip(schemas, types))]
248pub fn exec_generator(
249 config: GeneratorConfig,
250 schemas: &Schemas,
251 types: &Types,
252) -> Result<TokenStream, Error> {
253 let module = exec_generator_module(config, schemas, types)?;
254 let code = module.to_token_stream();
255
256 Ok(code)
257}
258
259#[instrument(err, level = "trace", skip(schemas, types))]
266pub fn exec_generator_module(
267 config: GeneratorConfig,
268 schemas: &Schemas,
269 types: &Types,
270) -> Result<Module, Error> {
271 tracing::info!("Generate Module");
272
273 let mut generator = Generator::new(types)
274 .flags(config.flags)
275 .box_flags(config.box_flags)
276 .typedef_mode(config.typedef_mode)
277 .serde_support(config.serde_support)
278 .xsd_parser_crate(config.xsd_parser);
279
280 if let Some(derive) = config.derive {
281 generator = generator.derive(derive);
282 }
283
284 if let Some(traits) = config.dyn_type_traits {
285 generator = generator.dyn_type_traits(traits)?;
286 }
287
288 generator = generator.with_type_postfix(IdentType::Type, config.type_postfix.type_);
289 generator = generator.with_type_postfix(IdentType::Element, config.type_postfix.element);
290 generator =
291 generator.with_type_postfix(IdentType::ElementType, config.type_postfix.element_type);
292
293 for triple in config.types {
294 let ident = triple.resolve(schemas)?;
295
296 generator = generator.with_type(ident)?;
297 }
298
299 for renderer in config.renderers {
300 match renderer {
301 Renderer::Types => generator = generator.with_renderer(TypesRenderer),
302 Renderer::Defaults => generator = generator.with_renderer(DefaultsRenderer),
303 Renderer::NamespaceConstants => {
304 generator = generator.with_renderer(NamespaceConstantsRenderer);
305 }
306 Renderer::WithNamespaceTrait => {
307 generator = generator.with_renderer(WithNamespaceTraitRenderer);
308 }
309 Renderer::QuickXmlSerialize => {
310 generator = generator.with_renderer(QuickXmlSerializeRenderer);
311 }
312 Renderer::QuickXmlDeserialize { boxed_deserializer } => {
313 generator =
314 generator.with_renderer(QuickXmlDeserializeRenderer { boxed_deserializer });
315 }
316 }
317 }
318
319 let mut generator = generator.into_fixed();
320 match config.generate {
321 Generate::All => generator = generator.generate_all_types()?,
322 Generate::Named => generator = generator.generate_named_types()?,
323 Generate::Types(idents) => {
324 for triple in idents {
325 let ident = triple.resolve(schemas)?;
326
327 generator = generator.generate_type(ident)?;
328 }
329 }
330 }
331
332 let module = generator.into_module();
333
334 Ok(module)
335}