1use crate::state::oca::overlay::cardinality::Cardinalitys;
2use crate::state::oca::overlay::character_encoding::CharacterEncodings;
3use crate::state::oca::overlay::conditional::Conditionals;
4use crate::state::oca::overlay::conformance::Conformances;
5use crate::state::oca::overlay::entry::Entries;
6use crate::state::oca::overlay::entry_code::EntryCodes;
7#[cfg(feature = "format_overlay")]
8use crate::state::oca::overlay::format::Formats;
9use crate::state::oca::overlay::information::Information;
10use crate::state::oca::overlay::label::Labels;
11use crate::state::oca::overlay::meta::Metas;
12use crate::state::oca::overlay::unit::{
13 AttributeUnit, ImperialUnit, MeasurementSystem, MeasurementUnit, MetricUnit, Unit,
14};
15use crate::state::oca::OCABundle;
16use crate::state::{
17 attribute::Attribute, encoding::Encoding, entries::EntriesElement,
18 entry_codes::EntryCodes as EntryCodesValue, oca::OCABox,
19};
20use indexmap::IndexMap;
21use oca_ast::ast;
22use std::collections::HashMap;
23use std::str::FromStr;
24
25#[derive(Debug)]
26pub struct OCABuild {
27 pub oca_bundle: OCABundle,
28 pub steps: Vec<OCABuildStep>,
29}
30
31#[derive(Debug)]
32pub struct OCABuildStep {
33 pub parent_said: Option<said::SelfAddressingIdentifier>,
34 pub command: ast::Command,
35 pub result: OCABundle,
36}
37
38#[derive(Debug, Clone, serde::Serialize)]
39pub struct FromASTError {
40 pub line_number: usize,
41 pub raw_line: String,
42 pub message: String,
43}
44
45#[derive(thiserror::Error, Debug, Clone, serde::Serialize)]
46#[serde(untagged)]
47pub enum Error {
48 #[error("Error at line {line_number} ({raw_line}): {message}")]
49 FromASTError {
50 #[serde(rename = "ln")]
51 line_number: usize,
52 #[serde(rename = "c")]
53 raw_line: String,
54 #[serde(rename = "e")]
55 message: String,
56 },
57}
58
59pub fn from_ast(
60 from_oca: Option<OCABundle>,
61 oca_ast: &ast::OCAAst,
62) -> Result<OCABuild, Vec<Error>> {
63 let mut errors = vec![];
64 let mut steps = vec![];
65 let mut parent_said: Option<said::SelfAddressingIdentifier> = match &from_oca {
66 Some(oca_bundle) => oca_bundle.said.clone(),
67 None => None,
68 };
69 let mut base: Option<OCABox> = from_oca.clone().map(OCABox::from);
70 let default_command_meta = ast::CommandMeta {
71 line_number: 0,
72 raw_line: "unknown".to_string(),
73 };
74 for (i, command) in oca_ast.commands.iter().enumerate() {
75 let command_index = match &from_oca {
76 Some(_) => i + 1,
77 None => i,
78 };
79 let command_meta = oca_ast
81 .commands_meta
82 .get(&command_index)
83 .unwrap_or(&default_command_meta);
84 match apply_command(base.clone(), command.clone()) {
85 Ok(oca_box) => {
86 let mut oca_box_mut = oca_box.clone();
87 let oca_bundle = oca_box_mut.generate_bundle();
88 if oca_bundle.said == parent_said {
89 errors.push(Error::FromASTError {
90 line_number: command_meta.line_number,
91 raw_line: command_meta.raw_line.clone(),
92 message: "Applying command failed".to_string(),
93 });
94 } else {
95 steps.push(OCABuildStep {
96 parent_said: parent_said.clone(),
97 command: command.clone(),
98 result: oca_bundle.clone(),
99 });
100 parent_said.clone_from(&oca_bundle.said);
101 base = Some(oca_box);
102 }
103 }
104 Err(mut err) => {
105 errors.extend(err.iter_mut().map(|e| Error::FromASTError {
106 line_number: command_meta.line_number,
107 raw_line: command_meta.raw_line.clone(),
108 message: e.clone(),
109 }));
110 }
111 }
112 }
113 if errors.is_empty() {
114 Ok(OCABuild {
115 oca_bundle: base.unwrap().generate_bundle(),
116 steps,
117 })
118 } else {
119 Err(errors)
120 }
121}
122
123pub fn apply_command(base: Option<OCABox>, op: ast::Command) -> Result<OCABox, Vec<String>> {
124 let mut errors = vec![];
125 let mut oca: OCABox = match base {
126 Some(oca) => oca,
127 None => OCABox::new(),
128 };
129
130 match (op.kind, op.object_kind) {
131 (ast::CommandType::From, _) => {
132 errors.push(
133 "Unsupported FROM command, it should be resolved before applying commands"
134 .to_string(),
135 );
136 }
137 (ast::CommandType::Add, ast::ObjectKind::CaptureBase(content)) => {
138 if let Some(ref attributes) = content.attributes {
139 for (attr_name, attr_type) in attributes {
140 let mut attribute = Attribute::new(attr_name.clone());
141 attribute.set_attribute_type(attr_type.clone());
142 oca.add_attribute(attribute);
143 }
144 }
145 if let Some(ref properties) = content.properties {
146 for (prop_name, prop_value) in properties {
148 if prop_name.eq("classification") {
149 if let ast::NestedValue::Value(value) = prop_value {
150 oca.add_classification(value.clone());
151 }
152 }
153 }
154 }
155 }
156 (ast::CommandType::Add, ast::ObjectKind::Overlay(overlay_type, content)) => {
157 match overlay_type {
158 ast::OverlayType::Meta => {
159 if let Some(ref properties) = content.properties {
160 let mut mut_properties = properties.clone();
161 let lang = mut_properties.remove("lang");
162 let mut lang_iso = None;
163 if let Some(ast::NestedValue::Value(lang_str)) = lang {
164 lang_iso = isolang::Language::from_639_1(lang_str.as_str());
165 }
166
167 for (prop_name, prop_value) in mut_properties {
168 if let ast::NestedValue::Value(value) = prop_value {
169 oca.add_meta(lang_iso.unwrap(), prop_name.clone(), value.clone());
170 }
171 }
172 }
173 }
174 ast::OverlayType::Label => {
175 let mut lang_iso = None;
176 if let Some(ref properties) = content.properties {
177 let mut mut_properties = properties.clone();
178 let lang = mut_properties.remove("lang");
179 if let Some(ast::NestedValue::Value(lang_str)) = lang {
180 lang_iso = isolang::Language::from_639_1(lang_str.as_str());
181 }
182 }
183 if let Some(ref attributes) = content.attributes {
184 for (attr_name, attr_type_value) in attributes {
185 let mut attribute = oca
186 .attributes
187 .get(attr_name)
188 .ok_or_else(|| {
189 errors.push(format!("Undefined attribute: {attr_name}"));
190 errors.clone()
191 })?
192 .clone();
193 if let ast::NestedValue::Value(attr_label) = attr_type_value {
194 attribute.set_label(lang_iso.unwrap(), attr_label.clone());
195 }
196 oca.add_attribute(attribute);
197 }
198 }
199 }
200 ast::OverlayType::Information => {
201 let mut lang_iso = None;
202 if let Some(ref properties) = content.properties {
203 let mut mut_properties = properties.clone();
204 let lang = mut_properties.remove("lang");
205 if let Some(ast::NestedValue::Value(lang_str)) = lang {
206 lang_iso = isolang::Language::from_639_1(lang_str.as_str());
207 }
208 }
209 if let Some(ref attributes) = content.attributes {
210 for (attr_name, attr_type_value) in attributes {
211 let mut attribute = oca
212 .attributes
213 .get(attr_name)
214 .ok_or_else(|| {
215 errors.push(format!("Undefined attribute: {attr_name}"));
216 errors.clone()
217 })?
218 .clone();
219 if let ast::NestedValue::Value(attr_info) = attr_type_value {
220 attribute.set_information(lang_iso.unwrap(), attr_info.clone());
221 }
222 oca.add_attribute(attribute);
223 }
224 }
225 }
226 ast::OverlayType::CharacterEncoding => {
227 if let Some(ref attributes) = content.attributes {
228 for (attr_name, attr_type_value) in attributes {
229 let mut attribute = oca
230 .attributes
231 .get(attr_name)
232 .ok_or_else(|| {
233 errors.push(format!("Undefined attribute: {attr_name}"));
234 errors.clone()
235 })?
236 .clone();
237 if let ast::NestedValue::Value(attr_encoding) = attr_type_value {
238 attribute.set_encoding(Encoding::from_str(attr_encoding).map_err(
239 |_| {
240 errors.push(format!("Unknown encoding: {attr_encoding}"));
241 errors.clone()
242 },
243 )?);
244 }
245 oca.add_attribute(attribute);
246 }
247 }
248 }
249 ast::OverlayType::Conformance => {
250 if let Some(ref attributes) = content.attributes {
251 for (attr_name, attr_type_value) in attributes {
252 let mut attribute = oca
253 .attributes
254 .get(attr_name)
255 .ok_or_else(|| {
256 errors.push(format!("Undefined attribute: {attr_name}"));
257 errors.clone()
258 })?
259 .clone();
260
261 if let ast::NestedValue::Value(attr_conformance) = attr_type_value {
262 attribute.set_conformance(attr_conformance.clone());
263 }
264 oca.add_attribute(attribute);
265 }
266 }
267 }
268 ast::OverlayType::Format => {
269 #[cfg(feature = "format_overlay")]
270 {
271 if let Some(ref attributes) = content.attributes {
272 for (attr_name, attr_type_value) in attributes {
273 let mut attribute = oca
274 .attributes
275 .get(attr_name)
276 .ok_or_else(|| {
277 errors.push(format!("Undefined attribute: {attr_name}"));
278 errors.clone()
279 })?
280 .clone();
281 if let ast::NestedValue::Value(attr_format) = attr_type_value {
282 attribute.set_format(attr_format.clone());
283 }
284 oca.add_attribute(attribute);
285 }
286 }
287 }
288 }
289 ast::OverlayType::Unit => {
290 let mut unit_system_op = None;
291 if let Some(ref properties) = content.properties {
292 let mut mut_properties = properties.clone();
293 let unit_system_prop = mut_properties.remove("unit_system");
294 if let Some(ast::NestedValue::Value(unit_system_str)) = unit_system_prop {
295 unit_system_op = MeasurementSystem::from_str(&unit_system_str).ok();
296 }
297 }
298 if let Some(unit_system) = unit_system_op {
299 if let Some(ref attributes) = content.attributes {
300 for (attr_name, attr_type_value) in attributes {
301 let mut attribute = oca
302 .attributes
303 .get(attr_name)
304 .ok_or_else(|| {
305 errors.push(format!("Undefined attribute: {attr_name}"));
306 errors.clone()
307 })?
308 .clone();
309 if let ast::NestedValue::Value(attr_unit) = attr_type_value {
310 let unit = match unit_system {
311 MeasurementSystem::Metric => Some(MeasurementUnit::Metric(
312 MetricUnit::from_str(attr_unit).unwrap_or_else(|_| {
313 panic!("{}", "Invalid metric unit: {attr_unit}")
314 }),
315 )),
316 MeasurementSystem::Imperial => {
317 Some(MeasurementUnit::Imperial(
318 ImperialUnit::from_str(attr_unit).unwrap_or_else(
319 |_| {
320 panic!(
321 "{}",
322 "Invalid imperial unit: {attr_unit}"
323 )
324 },
325 ),
326 ))
327 }
328 };
329 attribute.set_unit(AttributeUnit {
330 measurement_system: unit_system.clone(),
331 unit: unit.unwrap(),
332 });
333 }
334 oca.add_attribute(attribute);
335 }
336 }
337 }
338 }
339 ast::OverlayType::Cardinality => {
340 if let Some(ref attributes) = content.attributes {
341 for (attr_name, attr_type_value) in attributes {
342 let mut attribute = oca
343 .attributes
344 .get(attr_name)
345 .ok_or_else(|| {
346 errors.push(format!("Undefined attribute: {attr_name}"));
347 errors.clone()
348 })?
349 .clone();
350 if let ast::NestedValue::Value(attr_cardinality) = attr_type_value {
351 attribute.set_cardinality(attr_cardinality.clone());
352 }
353 oca.add_attribute(attribute);
354 }
355 }
356 }
357 ast::OverlayType::Conditional => {
358 if let Some(ref attributes) = content.attributes {
359 for (attr_name, attr_type_value) in attributes {
360 let mut attribute = oca
361 .attributes
362 .get(attr_name)
363 .ok_or_else(|| {
364 errors.push(format!("Undefined attribute: {attr_name}"));
365 errors.clone()
366 })?
367 .clone();
368 if let ast::NestedValue::Value(attr_condition) = attr_type_value {
369 attribute.set_condition(attr_condition.clone());
370 }
371 oca.add_attribute(attribute);
372 }
373 }
374 }
375 ast::OverlayType::EntryCode => {
376 if let Some(ref attributes) = content.attributes {
377 for (attr_name, attr_type_value) in attributes {
378 let mut attribute = oca
379 .attributes
380 .get(attr_name)
381 .ok_or_else(|| {
382 errors.push(format!("Undefined attribute: {attr_name}"));
383 errors.clone()
384 })?
385 .clone();
386 match attr_type_value {
387 ast::NestedValue::Value(attr_entry_codes_sai) => {
388 attribute.set_entry_codes(EntryCodesValue::Sai(
389 attr_entry_codes_sai.clone(),
390 ));
391 }
392 ast::NestedValue::Array(attr_entry_codes) => {
393 let mut entry_codes: Vec<String> = vec![];
394 for attr_entry_code in attr_entry_codes {
395 if let ast::NestedValue::Value(entry_code) = attr_entry_code
396 {
397 entry_codes.push(entry_code.clone());
398 }
399 }
400 attribute.set_entry_codes(EntryCodesValue::Array(entry_codes));
401 }
402 ast::NestedValue::Object(attr_grouped_entry_codes) => {
403 let mut grouped_entry_codes = IndexMap::new();
404 for (group, attr_entry_codes) in attr_grouped_entry_codes {
405 if let ast::NestedValue::Array(entry_codes) = attr_entry_codes
406 {
407 let codes: Vec<String> = entry_codes
408 .iter()
409 .filter_map(|entry_code| {
410 if let ast::NestedValue::Value(entry_code) =
411 entry_code
412 {
413 Some(entry_code.clone())
414 } else {
415 None
416 }
417 })
418 .collect();
419 grouped_entry_codes.insert(group.clone(), codes.clone());
420 }
421 }
422 attribute.set_entry_codes(EntryCodesValue::Object(grouped_entry_codes));
423 }
424 _ => (),
425 }
426 oca.add_attribute(attribute);
427 }
428 }
429 }
430 ast::OverlayType::Entry => {
431 let mut lang_iso = None;
432 if let Some(ref properties) = content.properties {
433 let mut mut_properties = properties.clone();
434 let lang = mut_properties.remove("lang");
435 if let Some(ast::NestedValue::Value(lang_str)) = lang {
436 lang_iso = isolang::Language::from_639_1(lang_str.as_str());
437 }
438 }
439 if let Some(ref attributes) = content.attributes {
440 for (attr_name, attr_type_value) in attributes {
441 let mut attribute = oca
442 .attributes
443 .get(attr_name)
444 .ok_or_else(|| {
445 errors.push(format!("Undefined attribute: {attr_name}"));
446 errors.clone()
447 })?
448 .clone();
449 match attr_type_value {
450 ast::NestedValue::Value(attr_entries) => {
451 attribute.set_entry(
452 lang_iso.unwrap(),
453 EntriesElement::Sai(attr_entries.clone()),
454 );
455 }
456 ast::NestedValue::Object(attr_entries) => {
457 let mut entries = HashMap::new();
458 for (attr_entry_key, attr_entry_value) in attr_entries {
459 if let ast::NestedValue::Value(entry_value) =
460 attr_entry_value
461 {
462 entries.insert(
463 attr_entry_key.clone(),
464 entry_value.clone(),
465 );
466 }
467 }
468 attribute.set_entry(
469 lang_iso.unwrap(),
470 EntriesElement::Object(entries),
471 );
472 }
473 _ => (),
474 }
475 oca.add_attribute(attribute);
476 }
477 }
478 }
479 _ => (),
480 }
481 }
482 (ast::CommandType::Add, ast::ObjectKind::OCABundle(_)) => todo!(),
483 (ast::CommandType::Remove, ast::ObjectKind::CaptureBase(content)) => {
484 if let Some(ref attributes) = content.attributes {
485 for (attr_name, _) in attributes {
486 oca.remove_attribute(attr_name);
487 }
488 }
489 if let Some(ref properties) = content.properties {
490 for (prop_name, _) in properties {
491 if prop_name.eq("classification") {
492 oca.remove_classification()
493 }
494 }
495 }
496 }
497 (ast::CommandType::Remove, ast::ObjectKind::OCABundle(_)) => todo!(),
498 (ast::CommandType::Remove, ast::ObjectKind::Overlay(_, _)) => todo!(),
499 (ast::CommandType::Modify, ast::ObjectKind::CaptureBase(_)) => todo!(),
500 (ast::CommandType::Modify, ast::ObjectKind::OCABundle(_)) => todo!(),
501 (ast::CommandType::Modify, ast::ObjectKind::Overlay(_, _)) => todo!(),
502 }
503
504 if errors.is_empty() {
505 Ok(oca)
506 } else {
507 Err(errors)
508 }
509}
510
511#[cfg(test)]
512mod tests {
513 use super::*;
514 use indexmap::IndexMap;
515 use oca_ast::ast::{AttributeType, CaptureContent};
516 use said::version::Encode;
517
518 #[test]
519 fn test_add_step() {
520 let mut commands = vec![];
521
522 let mut attributes = IndexMap::new();
523 attributes.insert(
524 "d".to_string(),
525 ast::NestedAttrType::Value(AttributeType::Text),
526 );
527 attributes.insert(
528 "i".to_string(),
529 ast::NestedAttrType::Value(AttributeType::Text),
530 );
531 attributes.insert(
532 "passed".to_string(),
533 ast::NestedAttrType::Value(AttributeType::Boolean),
534 );
535 commands.push(ast::Command {
536 kind: ast::CommandType::Add,
537 object_kind: ast::ObjectKind::CaptureBase(CaptureContent {
538 attributes: Some(attributes),
539 properties: None,
540 flagged_attributes: None,
541 }),
542 });
543
544 let mut properties = IndexMap::new();
545 properties.insert(
546 "lang".to_string(),
547 ast::NestedValue::Value("en".to_string()),
548 );
549 properties.insert(
550 "name".to_string(),
551 ast::NestedValue::Value("Entrance credential".to_string()),
552 );
553 properties.insert(
554 "description".to_string(),
555 ast::NestedValue::Value("Entrance credential".to_string()),
556 );
557 commands.push(ast::Command {
558 kind: ast::CommandType::Add,
559 object_kind: ast::ObjectKind::Overlay(
560 ast::OverlayType::Meta,
561 ast::Content {
562 attributes: None,
563 properties: Some(properties),
564 },
565 ),
566 });
567
568 let mut attributes = IndexMap::new();
569 attributes.insert(
570 "d".to_string(),
571 ast::NestedValue::Value("Schema digest".to_string()),
572 );
573 attributes.insert(
574 "i".to_string(),
575 ast::NestedValue::Value("Credential Issuee".to_string()),
576 );
577 attributes.insert(
578 "passed".to_string(),
579 ast::NestedValue::Value("Passed".to_string()),
580 );
581 let mut properties = IndexMap::new();
582 properties.insert(
583 "lang".to_string(),
584 ast::NestedValue::Value("en".to_string()),
585 );
586 commands.push(ast::Command {
587 kind: ast::CommandType::Add,
588 object_kind: ast::ObjectKind::Overlay(
589 ast::OverlayType::Label,
590 ast::Content {
591 attributes: Some(attributes),
592 properties: Some(properties),
593 },
594 ),
595 });
596
597 let mut attributes = IndexMap::new();
598 attributes.insert(
599 "d".to_string(),
600 ast::NestedValue::Value("Schema digest".to_string()),
601 );
602 attributes.insert(
603 "i".to_string(),
604 ast::NestedValue::Value("Credential Issuee".to_string()),
605 );
606 attributes.insert(
607 "passed".to_string(),
608 ast::NestedValue::Value("Enables or disables passing".to_string()),
609 );
610 let mut properties = IndexMap::new();
611 properties.insert(
612 "lang".to_string(),
613 ast::NestedValue::Value("en".to_string()),
614 );
615 commands.push(ast::Command {
616 kind: ast::CommandType::Add,
617 object_kind: ast::ObjectKind::Overlay(
618 ast::OverlayType::Information,
619 ast::Content {
620 attributes: Some(attributes),
621 properties: Some(properties),
622 },
623 ),
624 });
625
626 let mut attributes = IndexMap::new();
627 attributes.insert(
628 "d".to_string(),
629 ast::NestedValue::Value("utf-8".to_string()),
630 );
631 attributes.insert(
632 "i".to_string(),
633 ast::NestedValue::Value("utf-8".to_string()),
634 );
635 attributes.insert(
636 "passed".to_string(),
637 ast::NestedValue::Value("utf-8".to_string()),
638 );
639 commands.push(ast::Command {
640 kind: ast::CommandType::Add,
641 object_kind: ast::ObjectKind::Overlay(
642 ast::OverlayType::CharacterEncoding,
643 ast::Content {
644 attributes: Some(attributes),
645 properties: None,
646 },
647 ),
648 });
649
650 let mut attributes = IndexMap::new();
651 attributes.insert("d".to_string(), ast::NestedValue::Value("M".to_string()));
652 attributes.insert("i".to_string(), ast::NestedValue::Value("M".to_string()));
653 attributes.insert(
654 "passed".to_string(),
655 ast::NestedValue::Value("M".to_string()),
656 );
657 commands.push(ast::Command {
658 kind: ast::CommandType::Add,
659 object_kind: ast::ObjectKind::Overlay(
660 ast::OverlayType::Conformance,
661 ast::Content {
662 attributes: Some(attributes),
663 properties: None,
664 },
665 ),
666 });
667
668 let mut base: Option<OCABox> = None;
670 for command in commands {
671 match apply_command(base.clone(), command.clone()) {
672 Ok(oca) => {
673 base = Some(oca);
674 }
675 Err(errors) => {
676 println!("{:?}", errors);
677 }
678 }
679 }
683 }
684
685 #[test]
686 fn build_from_ast() {
687 let mut commands = vec![];
688
689 let mut attributes = IndexMap::new();
690 attributes.insert(
691 "d".to_string(),
692 ast::NestedAttrType::Value(AttributeType::Text),
693 );
694 attributes.insert(
695 "i".to_string(),
696 ast::NestedAttrType::Value(AttributeType::Text),
697 );
698 attributes.insert(
699 "list".to_string(),
700 ast::NestedAttrType::Value(AttributeType::Text),
701 );
702 attributes.insert(
703 "passed".to_string(),
704 ast::NestedAttrType::Value(AttributeType::Boolean),
705 );
706
707 let flagged_attributes = vec!["d".to_string(), "i".to_string()];
708 commands.push(ast::Command {
709 kind: ast::CommandType::Add,
710 object_kind: ast::ObjectKind::CaptureBase(ast::CaptureContent {
711 attributes: Some(attributes),
712 properties: None,
713 flagged_attributes: Some(flagged_attributes.clone()),
714 }),
715 });
716
717 let mut properties = IndexMap::new();
718 properties.insert(
719 "lang".to_string(),
720 ast::NestedValue::Value("en".to_string()),
721 );
722 properties.insert(
723 "name".to_string(),
724 ast::NestedValue::Value("Entrance credential".to_string()),
725 );
726 properties.insert(
727 "description".to_string(),
728 ast::NestedValue::Value("Entrance credential".to_string()),
729 );
730 commands.push(ast::Command {
731 kind: ast::CommandType::Add,
732 object_kind: ast::ObjectKind::Overlay(
733 ast::OverlayType::Meta,
734 ast::Content {
735 attributes: None,
736 properties: Some(properties),
737 },
738 ),
739 });
740
741 let mut attributes = IndexMap::new();
742 attributes.insert(
743 "d".to_string(),
744 ast::NestedValue::Value("Schema digest".to_string()),
745 );
746 attributes.insert(
747 "i".to_string(),
748 ast::NestedValue::Value("Credential Issuee".to_string()),
749 );
750 attributes.insert(
751 "passed".to_string(),
752 ast::NestedValue::Value("Passed".to_string()),
753 );
754 let mut properties = IndexMap::new();
755 properties.insert(
756 "lang".to_string(),
757 ast::NestedValue::Value("en".to_string()),
758 );
759 commands.push(ast::Command {
760 kind: ast::CommandType::Add,
761 object_kind: ast::ObjectKind::Overlay(
762 ast::OverlayType::Label,
763 ast::Content {
764 attributes: Some(attributes),
765 properties: Some(properties),
766 },
767 ),
768 });
769
770 let mut attributes = IndexMap::new();
771 attributes.insert(
772 "d".to_string(),
773 ast::NestedValue::Value("Schema digest".to_string()),
774 );
775 attributes.insert(
776 "i".to_string(),
777 ast::NestedValue::Value("Credential Issuee".to_string()),
778 );
779 attributes.insert(
780 "passed".to_string(),
781 ast::NestedValue::Value("Enables or disables passing".to_string()),
782 );
783 let mut properties = IndexMap::new();
784 properties.insert(
785 "lang".to_string(),
786 ast::NestedValue::Value("en".to_string()),
787 );
788 commands.push(ast::Command {
789 kind: ast::CommandType::Add,
790 object_kind: ast::ObjectKind::Overlay(
791 ast::OverlayType::Information,
792 ast::Content {
793 attributes: Some(attributes),
794 properties: Some(properties),
795 },
796 ),
797 });
798
799 let mut attributes = IndexMap::new();
800 attributes.insert(
801 "d".to_string(),
802 ast::NestedValue::Value("utf-8".to_string()),
803 );
804 attributes.insert(
805 "i".to_string(),
806 ast::NestedValue::Value("utf-8".to_string()),
807 );
808 attributes.insert(
809 "passed".to_string(),
810 ast::NestedValue::Value("utf-8".to_string()),
811 );
812 commands.push(ast::Command {
813 kind: ast::CommandType::Add,
814 object_kind: ast::ObjectKind::Overlay(
815 ast::OverlayType::CharacterEncoding,
816 ast::Content {
817 attributes: Some(attributes),
818 properties: None,
819 },
820 ),
821 });
822
823 let mut attributes = IndexMap::new();
824 attributes.insert("d".to_string(), ast::NestedValue::Value("M".to_string()));
825 attributes.insert("i".to_string(), ast::NestedValue::Value("M".to_string()));
826 attributes.insert(
827 "passed".to_string(),
828 ast::NestedValue::Value("M".to_string()),
829 );
830 commands.push(ast::Command {
831 kind: ast::CommandType::Add,
832 object_kind: ast::ObjectKind::Overlay(
833 ast::OverlayType::Conformance,
834 ast::Content {
835 attributes: Some(attributes),
836 properties: None,
837 },
838 ),
839 });
840
841 let mut attributes = IndexMap::new();
842 let mut grouped_elements = IndexMap::new();
843 grouped_elements.insert("g1".to_string(), ast::NestedValue::Array(
844 vec![ast::NestedValue::Value("el1".to_string())]
845 ));
846 grouped_elements.insert("g2".to_string(), ast::NestedValue::Array(
847 vec![ast::NestedValue::Value("el2".to_string()), ast::NestedValue::Value("el3".to_string())]
848 ));
849 attributes.insert("list".to_string(), oca_ast::ast::NestedValue::Object(grouped_elements));
850 commands.push(ast::Command {
851 kind: ast::CommandType::Add,
852 object_kind: ast::ObjectKind::Overlay(
853 ast::OverlayType::EntryCode,
854 ast::Content {
855 attributes: Some(attributes),
856 properties: None,
857 },
858 ),
859 });
860
861 let oca_ast = ast::OCAAst {
862 version: "1.0".to_string(),
863 commands,
864 commands_meta: IndexMap::new(),
865 meta: HashMap::new(),
866 };
867
868 let build_result = from_ast(None, &oca_ast);
869 match build_result {
870 Ok(oca_build) => {
871 let oca_bundle_encoded = oca_build.oca_bundle.encode().unwrap();
872 let oca_bundle_json = String::from_utf8(oca_bundle_encoded).unwrap();
873 println!("{}", oca_bundle_json);
874 }
875 Err(e) => {
876 println!("{:?}", e);
877 }
878 }
879 }
880}