1#![doc = include_str!(concat!(env!("OUT_DIR"), "/README.md"))]
2
3pub mod code;
4pub mod config;
5pub mod generator;
6pub mod interpreter;
7pub mod optimizer;
8pub mod parser;
9pub mod quick_xml;
10pub mod schema;
11pub mod types;
12
13mod macros;
14mod misc;
15
16pub type GeneratorError = generator::Error;
18
19pub type InterpreterError = interpreter::Error;
21
22pub type ParserError<E> = parser::Error<E>;
24
25use std::fs::write;
26
27pub use config::Config;
28pub use generator::Generator;
29pub use interpreter::Interpreter;
30pub use misc::{AsAny, Error, WithNamespace};
31pub use optimizer::Optimizer;
32pub use parser::Parser;
33
34use macros::{assert_eq, unreachable};
35use proc_macro2::TokenStream;
36use tracing::instrument;
37
38use self::config::{
39 Generate, GeneratorConfig, InterpreterConfig, InterpreterFlags, OptimizerConfig,
40 OptimizerFlags, ParserConfig, ParserFlags, Renderer, Resolver, Schema,
41};
42use self::generator::renderer::{
43 DefaultsRenderer, NamespaceConstantsRenderer, QuickXmlDeserializeRenderer,
44 QuickXmlSerializeRenderer, TypesRenderer, WithNamespaceTraitRenderer,
45};
46use self::misc::TypesPrinter;
47use self::parser::resolver::{FileResolver, ManyResolver};
48use self::schema::Schemas;
49use self::types::{IdentType, Types};
50
51#[instrument(err, level = "trace")]
65pub fn generate(config: Config) -> Result<TokenStream, Error> {
66 let schemas = exec_parser(config.parser)?;
67 let types = exec_interpreter(config.interpreter, &schemas)?;
68 let types = exec_optimizer(config.optimizer, types)?;
69 let code = exec_generator(config.generator, &schemas, &types)?;
70
71 Ok(code)
72}
73
74#[instrument(err, level = "trace")]
80pub fn exec_parser(config: ParserConfig) -> Result<Schemas, Error> {
81 tracing::info!("Parse Schemas");
82
83 let mut resolver = ManyResolver::new();
84 for r in config.resolver {
85 match r {
86 #[cfg(feature = "web-resolver")]
87 Resolver::Web => {
88 let web_resolver = self::parser::resolver::WebResolver::new();
89
90 resolver = resolver.add_resolver(web_resolver);
91 }
92 Resolver::File => {
93 let file_resolver = FileResolver::new();
94
95 resolver = resolver.add_resolver(file_resolver);
96 }
97 }
98 }
99
100 let mut parser = Parser::new()
101 .with_resolver(resolver)
102 .resolve_includes(config.flags.contains(ParserFlags::RESOLVE_INCLUDES));
103
104 if config.flags.contains(ParserFlags::DEFAULT_NAMESPACES) {
105 parser = parser.with_default_namespaces();
106 }
107
108 for (prefix, namespace) in config.namespaces {
109 parser = parser.with_namespace(prefix, namespace);
110 }
111
112 for schema in config.schemas {
113 match schema {
114 Schema::Url(url) => parser = parser.add_schema_from_url(url)?,
115 Schema::File(path) => parser = parser.add_schema_from_file(path)?,
116 Schema::Schema(schema) => parser = parser.add_schema_from_str(&schema)?,
117 }
118 }
119
120 let schemas = parser.finish();
121
122 if let Some(output) = config.debug_output {
123 let debug = format!("{schemas:#?}");
124
125 write(output, debug)?;
126 }
127
128 Ok(schemas)
129}
130
131#[instrument(err, level = "trace", skip(schemas))]
137pub fn exec_interpreter(config: InterpreterConfig, schemas: &Schemas) -> Result<Types, Error> {
138 tracing::info!("Interpret Schema");
139
140 let mut interpreter = Interpreter::new(schemas);
141
142 if config.flags.contains(InterpreterFlags::BUILDIN_TYPES) {
143 interpreter = interpreter.with_buildin_types()?;
144 }
145
146 if config.flags.contains(InterpreterFlags::DEFAULT_TYPEDEFS) {
147 interpreter = interpreter.with_default_typedefs()?;
148 }
149
150 if config.flags.contains(InterpreterFlags::WITH_XS_ANY_TYPE) {
151 interpreter = interpreter.with_xs_any_type()?;
152 }
153
154 for (ident, ty) in config.types {
155 let ident = ident.resolve(schemas)?;
156 interpreter = interpreter.with_type(ident, ty)?;
157 }
158
159 let types = interpreter.finish()?;
160
161 if let Some(output) = config.debug_output {
162 let printer = TypesPrinter::new(&types);
163 let debug = format!("{printer}");
164
165 write(output, debug)?;
166 }
167
168 Ok(types)
169}
170
171#[instrument(err, level = "trace", skip(types))]
177pub fn exec_optimizer(config: OptimizerConfig, types: Types) -> Result<Types, Error> {
178 tracing::info!("Optimize Types");
179
180 let mut optimizer = Optimizer::new(types);
181
182 macro_rules! exec {
183 ($flag:ident, $method:ident) => {
184 if config.flags.contains(OptimizerFlags::$flag) {
185 optimizer = optimizer.$method();
186 }
187 };
188 }
189
190 exec!(REMOVE_EMPTY_ENUM_VARIANTS, remove_empty_enum_variants);
191 exec!(REMOVE_EMPTY_ENUMS, remove_empty_enums);
192 exec!(
193 REMOVE_DUPLICATE_UNION_VARIANTS,
194 remove_duplicate_union_variants
195 );
196 exec!(REMOVE_EMPTY_UNIONS, remove_empty_unions);
197 exec!(USE_UNRESTRICTED_BASE_TYPE, use_unrestricted_base_type);
198 exec!(CONVERT_DYNAMIC_TO_CHOICE, convert_dynamic_to_choice);
199 exec!(FLATTEN_COMPLEX_TYPES, flatten_complex_types);
200 exec!(FLATTEN_UNIONS, flatten_unions);
201 exec!(MERGE_ENUM_UNIONS, merge_enum_unions);
202 exec!(RESOLVE_TYPEDEFS, resolve_typedefs);
203 exec!(REMOVE_DUPLICATES, remove_duplicates);
204 exec!(RESOLVE_TYPEDEFS, resolve_typedefs);
205 exec!(MERGE_CHOICE_CARDINALITIES, merge_choice_cardinalities);
206
207 let types = optimizer.finish();
208
209 if let Some(output) = config.debug_output {
210 let printer = TypesPrinter::new(&types);
211 let debug = format!("{printer}");
212
213 write(output, debug)?;
214 }
215
216 Ok(types)
217}
218
219#[instrument(err, level = "trace", skip(schemas, types))]
225pub fn exec_generator(
226 config: GeneratorConfig,
227 schemas: &Schemas,
228 types: &Types,
229) -> Result<TokenStream, Error> {
230 tracing::info!("Generate Code");
231
232 let mut generator = Generator::new(types)
233 .flags(config.flags)
234 .box_flags(config.box_flags)
235 .typedef_mode(config.typedef_mode)
236 .serde_support(config.serde_support)
237 .xsd_parser_crate(config.xsd_parser);
238
239 if let Some(derive) = config.derive {
240 generator = generator.derive(derive);
241 }
242
243 if let Some(traits) = config.dyn_type_traits {
244 generator = generator.dyn_type_traits(traits)?;
245 }
246
247 generator = generator.with_type_postfix(IdentType::Type, config.type_postfix.type_);
248 generator = generator.with_type_postfix(IdentType::Element, config.type_postfix.element);
249 generator =
250 generator.with_type_postfix(IdentType::ElementType, config.type_postfix.element_type);
251
252 for triple in config.types {
253 let ident = triple.resolve(schemas)?;
254
255 generator = generator.with_type(ident)?;
256 }
257
258 for renderer in config.renderers {
259 match renderer {
260 Renderer::Types => generator = generator.with_renderer(TypesRenderer),
261 Renderer::Defaults => generator = generator.with_renderer(DefaultsRenderer),
262 Renderer::NamespaceConstants => {
263 generator = generator.with_renderer(NamespaceConstantsRenderer);
264 }
265 Renderer::WithNamespaceTrait => {
266 generator = generator.with_renderer(WithNamespaceTraitRenderer);
267 }
268 Renderer::QuickXmlSerialize => {
269 generator = generator.with_renderer(QuickXmlSerializeRenderer);
270 }
271 Renderer::QuickXmlDeserialize => {
272 generator = generator.with_renderer(QuickXmlDeserializeRenderer);
273 }
274 }
275 }
276
277 let mut generator = generator.into_fixed();
278 match config.generate {
279 Generate::All => generator = generator.generate_all_types()?,
280 Generate::Named => generator = generator.generate_named_types()?,
281 Generate::Types(idents) => {
282 for triple in idents {
283 let ident = triple.resolve(schemas)?;
284
285 generator = generator.generate_type(ident)?;
286 }
287 }
288 }
289
290 let code = generator.finish();
291
292 Ok(code)
293}