1use crate::export::ExportError;
6use crate::models::odps::*;
7use serde_yaml;
8
9pub struct ODPSExporter;
11
12impl ODPSExporter {
13 pub fn export(&self, product: &ODPSDataProduct) -> Result<String, ExportError> {
23 let yaml = Self::export_product(product);
24
25 #[cfg(feature = "odps-validation")]
27 {
28 #[cfg(feature = "cli")]
29 {
30 use crate::cli::validation::validate_odps_internal;
31 validate_odps_internal(&yaml).map_err(ExportError::ValidationError)?;
32 }
33 #[cfg(not(feature = "cli"))]
34 {
35 use jsonschema::Validator;
37 use serde_json::Value;
38
39 let schema_content = include_str!("../../schemas/odps-json-schema-latest.json");
40 let schema: Value = serde_json::from_str(schema_content).map_err(|e| {
41 ExportError::ValidationError(format!("Failed to load ODPS schema: {}", e))
42 })?;
43
44 let validator = Validator::new(&schema).map_err(|e| {
45 ExportError::ValidationError(format!("Failed to compile ODPS schema: {}", e))
46 })?;
47
48 let data: Value = serde_yaml::from_str(&yaml).map_err(|e| {
49 ExportError::ValidationError(format!("Failed to parse YAML: {}", e))
50 })?;
51
52 if let Err(error) = validator.validate(&data) {
53 return Err(ExportError::ValidationError(format!(
54 "ODPS validation failed: {}",
55 error
56 )));
57 }
58 }
59 }
60
61 Ok(yaml)
62 }
63
64 pub fn export_product(product: &ODPSDataProduct) -> String {
108 let mut yaml = serde_yaml::Mapping::new();
109
110 yaml.insert(
112 serde_yaml::Value::String("apiVersion".to_string()),
113 serde_yaml::Value::String(product.api_version.clone()),
114 );
115
116 yaml.insert(
117 serde_yaml::Value::String("kind".to_string()),
118 serde_yaml::Value::String(product.kind.clone()),
119 );
120
121 yaml.insert(
122 serde_yaml::Value::String("id".to_string()),
123 serde_yaml::Value::String(product.id.clone()),
124 );
125
126 let status_str = match product.status {
127 ODPSStatus::Proposed => "proposed",
128 ODPSStatus::Draft => "draft",
129 ODPSStatus::Active => "active",
130 ODPSStatus::Deprecated => "deprecated",
131 ODPSStatus::Retired => "retired",
132 };
133 yaml.insert(
134 serde_yaml::Value::String("status".to_string()),
135 serde_yaml::Value::String(status_str.to_string()),
136 );
137
138 if let Some(name) = &product.name {
140 yaml.insert(
141 serde_yaml::Value::String("name".to_string()),
142 serde_yaml::Value::String(name.clone()),
143 );
144 }
145
146 if let Some(version) = &product.version {
147 yaml.insert(
148 serde_yaml::Value::String("version".to_string()),
149 serde_yaml::Value::String(version.clone()),
150 );
151 }
152
153 if let Some(domain) = &product.domain {
154 yaml.insert(
155 serde_yaml::Value::String("domain".to_string()),
156 serde_yaml::Value::String(domain.clone()),
157 );
158 }
159
160 if let Some(tenant) = &product.tenant {
161 yaml.insert(
162 serde_yaml::Value::String("tenant".to_string()),
163 serde_yaml::Value::String(tenant.clone()),
164 );
165 }
166
167 if !product.tags.is_empty() {
168 let tags_yaml: Vec<serde_yaml::Value> = product
169 .tags
170 .iter()
171 .map(|t| serde_yaml::Value::String(t.to_string()))
172 .collect();
173 yaml.insert(
174 serde_yaml::Value::String("tags".to_string()),
175 serde_yaml::Value::Sequence(tags_yaml),
176 );
177 }
178
179 if let Some(description) = &product.description {
180 let mut desc_map = serde_yaml::Mapping::new();
181 if let Some(purpose) = &description.purpose {
182 desc_map.insert(
183 serde_yaml::Value::String("purpose".to_string()),
184 serde_yaml::Value::String(purpose.clone()),
185 );
186 }
187 if let Some(limitations) = &description.limitations {
188 desc_map.insert(
189 serde_yaml::Value::String("limitations".to_string()),
190 serde_yaml::Value::String(limitations.clone()),
191 );
192 }
193 if let Some(usage) = &description.usage {
194 desc_map.insert(
195 serde_yaml::Value::String("usage".to_string()),
196 serde_yaml::Value::String(usage.clone()),
197 );
198 }
199 if let Some(auth_defs) = &description.authoritative_definitions {
200 let defs_yaml = Self::serialize_authoritative_definitions(auth_defs);
201 if !defs_yaml.is_empty() {
202 desc_map.insert(
203 serde_yaml::Value::String("authoritativeDefinitions".to_string()),
204 serde_yaml::Value::Sequence(defs_yaml),
205 );
206 }
207 }
208 if let Some(custom_props) = &description.custom_properties {
209 let props_yaml = Self::serialize_custom_properties(custom_props);
210 if !props_yaml.is_empty() {
211 desc_map.insert(
212 serde_yaml::Value::String("customProperties".to_string()),
213 serde_yaml::Value::Sequence(props_yaml),
214 );
215 }
216 }
217 if !desc_map.is_empty() {
218 yaml.insert(
219 serde_yaml::Value::String("description".to_string()),
220 serde_yaml::Value::Mapping(desc_map),
221 );
222 }
223 }
224
225 if let Some(auth_defs) = &product.authoritative_definitions {
226 let defs_yaml = Self::serialize_authoritative_definitions(auth_defs);
228 yaml.insert(
229 serde_yaml::Value::String("authoritativeDefinitions".to_string()),
230 serde_yaml::Value::Sequence(defs_yaml),
231 );
232 }
233
234 if let Some(custom_props) = &product.custom_properties {
235 let props_yaml = Self::serialize_custom_properties(custom_props);
237 yaml.insert(
238 serde_yaml::Value::String("customProperties".to_string()),
239 serde_yaml::Value::Sequence(props_yaml),
240 );
241 }
242
243 if let Some(input_ports) = &product.input_ports {
244 let ports_yaml: Vec<serde_yaml::Value> = input_ports
246 .iter()
247 .map(|port| {
248 let mut port_map = serde_yaml::Mapping::new();
249 port_map.insert(
250 serde_yaml::Value::String("name".to_string()),
251 serde_yaml::Value::String(port.name.clone()),
252 );
253 port_map.insert(
254 serde_yaml::Value::String("version".to_string()),
255 serde_yaml::Value::String(port.version.clone()),
256 );
257 port_map.insert(
258 serde_yaml::Value::String("contractId".to_string()),
259 serde_yaml::Value::String(port.contract_id.clone()),
260 );
261 if !port.tags.is_empty() {
262 let tags_yaml: Vec<serde_yaml::Value> = port
263 .tags
264 .iter()
265 .map(|t| serde_yaml::Value::String(t.to_string()))
266 .collect();
267 port_map.insert(
268 serde_yaml::Value::String("tags".to_string()),
269 serde_yaml::Value::Sequence(tags_yaml),
270 );
271 }
272 if let Some(custom_props) = &port.custom_properties {
273 let props_yaml = Self::serialize_custom_properties(custom_props);
274 if !props_yaml.is_empty() {
275 port_map.insert(
276 serde_yaml::Value::String("customProperties".to_string()),
277 serde_yaml::Value::Sequence(props_yaml),
278 );
279 }
280 }
281 if let Some(auth_defs) = &port.authoritative_definitions {
282 let defs_yaml = Self::serialize_authoritative_definitions(auth_defs);
283 if !defs_yaml.is_empty() {
284 port_map.insert(
285 serde_yaml::Value::String("authoritativeDefinitions".to_string()),
286 serde_yaml::Value::Sequence(defs_yaml),
287 );
288 }
289 }
290 serde_yaml::Value::Mapping(port_map)
291 })
292 .collect();
293 yaml.insert(
295 serde_yaml::Value::String("inputPorts".to_string()),
296 serde_yaml::Value::Sequence(ports_yaml),
297 );
298 }
299
300 if let Some(output_ports) = &product.output_ports {
301 let ports_yaml: Vec<serde_yaml::Value> = output_ports
302 .iter()
303 .map(|port| {
304 let mut port_map = serde_yaml::Mapping::new();
305 port_map.insert(
306 serde_yaml::Value::String("name".to_string()),
307 serde_yaml::Value::String(port.name.clone()),
308 );
309 port_map.insert(
310 serde_yaml::Value::String("version".to_string()),
311 serde_yaml::Value::String(port.version.clone()),
312 );
313 if let Some(description) = &port.description {
314 port_map.insert(
315 serde_yaml::Value::String("description".to_string()),
316 serde_yaml::Value::String(description.clone()),
317 );
318 }
319 if let Some(r#type) = &port.r#type {
320 port_map.insert(
321 serde_yaml::Value::String("type".to_string()),
322 serde_yaml::Value::String(r#type.clone()),
323 );
324 }
325 if let Some(contract_id) = &port.contract_id {
326 port_map.insert(
327 serde_yaml::Value::String("contractId".to_string()),
328 serde_yaml::Value::String(contract_id.clone()),
329 );
330 }
331 if let Some(sbom) = &port.sbom {
332 let sbom_yaml: Vec<serde_yaml::Value> = sbom
333 .iter()
334 .map(|s| {
335 let mut sbom_map = serde_yaml::Mapping::new();
336 sbom_map.insert(
337 serde_yaml::Value::String("url".to_string()),
338 serde_yaml::Value::String(s.url.clone()),
339 );
340 if let Some(r#type) = &s.r#type {
341 sbom_map.insert(
342 serde_yaml::Value::String("type".to_string()),
343 serde_yaml::Value::String(r#type.clone()),
344 );
345 }
346 serde_yaml::Value::Mapping(sbom_map)
347 })
348 .collect();
349 port_map.insert(
350 serde_yaml::Value::String("sbom".to_string()),
351 serde_yaml::Value::Sequence(sbom_yaml),
352 );
353 }
354 if let Some(input_contracts) = &port.input_contracts {
355 let contracts_yaml: Vec<serde_yaml::Value> = input_contracts
356 .iter()
357 .map(|contract| {
358 let mut contract_map = serde_yaml::Mapping::new();
359 contract_map.insert(
360 serde_yaml::Value::String("id".to_string()),
361 serde_yaml::Value::String(contract.id.clone()),
362 );
363 contract_map.insert(
364 serde_yaml::Value::String("version".to_string()),
365 serde_yaml::Value::String(contract.version.clone()),
366 );
367 serde_yaml::Value::Mapping(contract_map)
368 })
369 .collect();
370 port_map.insert(
371 serde_yaml::Value::String("inputContracts".to_string()),
372 serde_yaml::Value::Sequence(contracts_yaml),
373 );
374 }
375 if !port.tags.is_empty() {
376 let tags_yaml: Vec<serde_yaml::Value> = port
377 .tags
378 .iter()
379 .map(|t| serde_yaml::Value::String(t.to_string()))
380 .collect();
381 port_map.insert(
382 serde_yaml::Value::String("tags".to_string()),
383 serde_yaml::Value::Sequence(tags_yaml),
384 );
385 }
386 if let Some(custom_props) = &port.custom_properties {
387 let props_yaml = Self::serialize_custom_properties(custom_props);
388 if !props_yaml.is_empty() {
389 port_map.insert(
390 serde_yaml::Value::String("customProperties".to_string()),
391 serde_yaml::Value::Sequence(props_yaml),
392 );
393 }
394 }
395 if let Some(auth_defs) = &port.authoritative_definitions {
396 let defs_yaml = Self::serialize_authoritative_definitions(auth_defs);
397 if !defs_yaml.is_empty() {
398 port_map.insert(
399 serde_yaml::Value::String("authoritativeDefinitions".to_string()),
400 serde_yaml::Value::Sequence(defs_yaml),
401 );
402 }
403 }
404 serde_yaml::Value::Mapping(port_map)
405 })
406 .collect();
407 yaml.insert(
408 serde_yaml::Value::String("outputPorts".to_string()),
409 serde_yaml::Value::Sequence(ports_yaml),
410 );
411 }
412
413 if let Some(management_ports) = &product.management_ports {
414 let ports_yaml: Vec<serde_yaml::Value> = management_ports
415 .iter()
416 .map(|port| {
417 let mut port_map = serde_yaml::Mapping::new();
418 port_map.insert(
419 serde_yaml::Value::String("name".to_string()),
420 serde_yaml::Value::String(port.name.clone()),
421 );
422 port_map.insert(
423 serde_yaml::Value::String("content".to_string()),
424 serde_yaml::Value::String(port.content.clone()),
425 );
426 if let Some(r#type) = &port.r#type {
427 port_map.insert(
428 serde_yaml::Value::String("type".to_string()),
429 serde_yaml::Value::String(r#type.clone()),
430 );
431 }
432 if let Some(url) = &port.url {
433 port_map.insert(
434 serde_yaml::Value::String("url".to_string()),
435 serde_yaml::Value::String(url.clone()),
436 );
437 }
438 if let Some(channel) = &port.channel {
439 port_map.insert(
440 serde_yaml::Value::String("channel".to_string()),
441 serde_yaml::Value::String(channel.clone()),
442 );
443 }
444 if let Some(description) = &port.description {
445 port_map.insert(
446 serde_yaml::Value::String("description".to_string()),
447 serde_yaml::Value::String(description.clone()),
448 );
449 }
450 if !port.tags.is_empty() {
451 let tags_yaml: Vec<serde_yaml::Value> = port
452 .tags
453 .iter()
454 .map(|t| serde_yaml::Value::String(t.to_string()))
455 .collect();
456 port_map.insert(
457 serde_yaml::Value::String("tags".to_string()),
458 serde_yaml::Value::Sequence(tags_yaml),
459 );
460 }
461 if let Some(custom_props) = &port.custom_properties {
462 let props_yaml = Self::serialize_custom_properties(custom_props);
463 if !props_yaml.is_empty() {
464 port_map.insert(
465 serde_yaml::Value::String("customProperties".to_string()),
466 serde_yaml::Value::Sequence(props_yaml),
467 );
468 }
469 }
470 if let Some(auth_defs) = &port.authoritative_definitions {
471 let defs_yaml = Self::serialize_authoritative_definitions(auth_defs);
472 if !defs_yaml.is_empty() {
473 port_map.insert(
474 serde_yaml::Value::String("authoritativeDefinitions".to_string()),
475 serde_yaml::Value::Sequence(defs_yaml),
476 );
477 }
478 }
479 serde_yaml::Value::Mapping(port_map)
480 })
481 .collect();
482 yaml.insert(
483 serde_yaml::Value::String("managementPorts".to_string()),
484 serde_yaml::Value::Sequence(ports_yaml),
485 );
486 }
487
488 if let Some(support) = &product.support {
489 let support_yaml: Vec<serde_yaml::Value> = support
490 .iter()
491 .map(|s| {
492 let mut support_map = serde_yaml::Mapping::new();
493 support_map.insert(
494 serde_yaml::Value::String("channel".to_string()),
495 serde_yaml::Value::String(s.channel.clone()),
496 );
497 support_map.insert(
498 serde_yaml::Value::String("url".to_string()),
499 serde_yaml::Value::String(s.url.clone()),
500 );
501 if let Some(description) = &s.description {
502 support_map.insert(
503 serde_yaml::Value::String("description".to_string()),
504 serde_yaml::Value::String(description.clone()),
505 );
506 }
507 if let Some(tool) = &s.tool {
508 support_map.insert(
509 serde_yaml::Value::String("tool".to_string()),
510 serde_yaml::Value::String(tool.clone()),
511 );
512 }
513 if let Some(scope) = &s.scope {
514 support_map.insert(
515 serde_yaml::Value::String("scope".to_string()),
516 serde_yaml::Value::String(scope.clone()),
517 );
518 }
519 if let Some(invitation_url) = &s.invitation_url {
520 support_map.insert(
521 serde_yaml::Value::String("invitationUrl".to_string()),
522 serde_yaml::Value::String(invitation_url.clone()),
523 );
524 }
525 if !s.tags.is_empty() {
526 let tags_yaml: Vec<serde_yaml::Value> = s
527 .tags
528 .iter()
529 .map(|t| serde_yaml::Value::String(t.to_string()))
530 .collect();
531 support_map.insert(
532 serde_yaml::Value::String("tags".to_string()),
533 serde_yaml::Value::Sequence(tags_yaml),
534 );
535 }
536 if let Some(custom_props) = &s.custom_properties {
537 let props_yaml = Self::serialize_custom_properties(custom_props);
538 if !props_yaml.is_empty() {
539 support_map.insert(
540 serde_yaml::Value::String("customProperties".to_string()),
541 serde_yaml::Value::Sequence(props_yaml),
542 );
543 }
544 }
545 if let Some(auth_defs) = &s.authoritative_definitions {
546 let defs_yaml = Self::serialize_authoritative_definitions(auth_defs);
547 if !defs_yaml.is_empty() {
548 support_map.insert(
549 serde_yaml::Value::String("authoritativeDefinitions".to_string()),
550 serde_yaml::Value::Sequence(defs_yaml),
551 );
552 }
553 }
554 serde_yaml::Value::Mapping(support_map)
555 })
556 .collect();
557 yaml.insert(
558 serde_yaml::Value::String("support".to_string()),
559 serde_yaml::Value::Sequence(support_yaml),
560 );
561 }
562
563 if let Some(team) = &product.team {
564 let mut team_map = serde_yaml::Mapping::new();
565 if let Some(name) = &team.name {
566 team_map.insert(
567 serde_yaml::Value::String("name".to_string()),
568 serde_yaml::Value::String(name.clone()),
569 );
570 }
571 if let Some(description) = &team.description {
572 team_map.insert(
573 serde_yaml::Value::String("description".to_string()),
574 serde_yaml::Value::String(description.clone()),
575 );
576 }
577 if let Some(members) = &team.members {
578 let members_yaml: Vec<serde_yaml::Value> = members
579 .iter()
580 .map(|member| {
581 let mut member_map = serde_yaml::Mapping::new();
582 member_map.insert(
583 serde_yaml::Value::String("username".to_string()),
584 serde_yaml::Value::String(member.username.clone()),
585 );
586 if let Some(name) = &member.name {
587 member_map.insert(
588 serde_yaml::Value::String("name".to_string()),
589 serde_yaml::Value::String(name.clone()),
590 );
591 }
592 if let Some(description) = &member.description {
593 member_map.insert(
594 serde_yaml::Value::String("description".to_string()),
595 serde_yaml::Value::String(description.clone()),
596 );
597 }
598 if let Some(role) = &member.role {
599 member_map.insert(
600 serde_yaml::Value::String("role".to_string()),
601 serde_yaml::Value::String(role.clone()),
602 );
603 }
604 if let Some(date_in) = &member.date_in {
605 member_map.insert(
606 serde_yaml::Value::String("dateIn".to_string()),
607 serde_yaml::Value::String(date_in.clone()),
608 );
609 }
610 if let Some(date_out) = &member.date_out {
611 member_map.insert(
612 serde_yaml::Value::String("dateOut".to_string()),
613 serde_yaml::Value::String(date_out.clone()),
614 );
615 }
616 if let Some(replaced_by) = &member.replaced_by_username {
617 member_map.insert(
618 serde_yaml::Value::String("replacedByUsername".to_string()),
619 serde_yaml::Value::String(replaced_by.clone()),
620 );
621 }
622 if !member.tags.is_empty() {
623 let tags_yaml: Vec<serde_yaml::Value> = member
624 .tags
625 .iter()
626 .map(|t| serde_yaml::Value::String(t.to_string()))
627 .collect();
628 member_map.insert(
629 serde_yaml::Value::String("tags".to_string()),
630 serde_yaml::Value::Sequence(tags_yaml),
631 );
632 }
633 if let Some(custom_props) = &member.custom_properties {
634 let props_yaml = Self::serialize_custom_properties(custom_props);
635 if !props_yaml.is_empty() {
636 member_map.insert(
637 serde_yaml::Value::String("customProperties".to_string()),
638 serde_yaml::Value::Sequence(props_yaml),
639 );
640 }
641 }
642 if let Some(auth_defs) = &member.authoritative_definitions {
643 let defs_yaml = Self::serialize_authoritative_definitions(auth_defs);
644 if !defs_yaml.is_empty() {
645 member_map.insert(
646 serde_yaml::Value::String(
647 "authoritativeDefinitions".to_string(),
648 ),
649 serde_yaml::Value::Sequence(defs_yaml),
650 );
651 }
652 }
653 serde_yaml::Value::Mapping(member_map)
654 })
655 .collect();
656 team_map.insert(
657 serde_yaml::Value::String("members".to_string()),
658 serde_yaml::Value::Sequence(members_yaml),
659 );
660 }
661 if !team.tags.is_empty() {
662 let tags_yaml: Vec<serde_yaml::Value> = team
663 .tags
664 .iter()
665 .map(|t| serde_yaml::Value::String(t.to_string()))
666 .collect();
667 team_map.insert(
668 serde_yaml::Value::String("tags".to_string()),
669 serde_yaml::Value::Sequence(tags_yaml),
670 );
671 }
672 if let Some(custom_props) = &team.custom_properties {
673 let props_yaml = Self::serialize_custom_properties(custom_props);
674 if !props_yaml.is_empty() {
675 team_map.insert(
676 serde_yaml::Value::String("customProperties".to_string()),
677 serde_yaml::Value::Sequence(props_yaml),
678 );
679 }
680 }
681 if let Some(auth_defs) = &team.authoritative_definitions {
682 let defs_yaml = Self::serialize_authoritative_definitions(auth_defs);
683 if !defs_yaml.is_empty() {
684 team_map.insert(
685 serde_yaml::Value::String("authoritativeDefinitions".to_string()),
686 serde_yaml::Value::Sequence(defs_yaml),
687 );
688 }
689 }
690 if !team_map.is_empty() {
691 yaml.insert(
692 serde_yaml::Value::String("team".to_string()),
693 serde_yaml::Value::Mapping(team_map),
694 );
695 }
696 }
697
698 if let Some(product_created_ts) = &product.product_created_ts {
699 yaml.insert(
700 serde_yaml::Value::String("productCreatedTs".to_string()),
701 serde_yaml::Value::String(product_created_ts.clone()),
702 );
703 }
704
705 serde_yaml::to_string(&serde_yaml::Value::Mapping(yaml))
707 .unwrap_or_else(|_| String::from(""))
708 }
709
710 fn serialize_authoritative_definitions(
712 defs: &[ODPSAuthoritativeDefinition],
713 ) -> Vec<serde_yaml::Value> {
714 defs.iter()
715 .map(|def| {
716 let mut def_map = serde_yaml::Mapping::new();
717 def_map.insert(
718 serde_yaml::Value::String("type".to_string()),
719 serde_yaml::Value::String(def.r#type.clone()),
720 );
721 def_map.insert(
722 serde_yaml::Value::String("url".to_string()),
723 serde_yaml::Value::String(def.url.clone()),
724 );
725 if let Some(description) = &def.description {
726 def_map.insert(
727 serde_yaml::Value::String("description".to_string()),
728 serde_yaml::Value::String(description.clone()),
729 );
730 }
731 serde_yaml::Value::Mapping(def_map)
732 })
733 .collect()
734 }
735
736 fn serialize_custom_properties(props: &[ODPSCustomProperty]) -> Vec<serde_yaml::Value> {
738 props
739 .iter()
740 .map(|prop| {
741 let mut prop_map = serde_yaml::Mapping::new();
742 prop_map.insert(
743 serde_yaml::Value::String("property".to_string()),
744 serde_yaml::Value::String(prop.property.clone()),
745 );
746 prop_map.insert(
747 serde_yaml::Value::String("value".to_string()),
748 Self::json_to_yaml_value(&prop.value),
749 );
750 if let Some(description) = &prop.description {
751 prop_map.insert(
752 serde_yaml::Value::String("description".to_string()),
753 serde_yaml::Value::String(description.clone()),
754 );
755 }
756 serde_yaml::Value::Mapping(prop_map)
757 })
758 .collect()
759 }
760
761 fn json_to_yaml_value(json: &serde_json::Value) -> serde_yaml::Value {
763 match json {
764 serde_json::Value::Null => serde_yaml::Value::Null,
765 serde_json::Value::Bool(b) => serde_yaml::Value::Bool(*b),
766 serde_json::Value::Number(n) => {
767 if let Some(i) = n.as_i64() {
768 serde_yaml::Value::Number(serde_yaml::Number::from(i))
769 } else if let Some(f) = n.as_f64() {
770 serde_yaml::Value::Number(serde_yaml::Number::from(f))
771 } else {
772 serde_yaml::Value::String(n.to_string())
773 }
774 }
775 serde_json::Value::String(s) => serde_yaml::Value::String(s.clone()),
776 serde_json::Value::Array(arr) => {
777 let yaml_arr: Vec<serde_yaml::Value> =
778 arr.iter().map(Self::json_to_yaml_value).collect();
779 serde_yaml::Value::Sequence(yaml_arr)
780 }
781 serde_json::Value::Object(obj) => {
782 let mut yaml_map = serde_yaml::Mapping::new();
783 for (k, v) in obj {
784 yaml_map.insert(
785 serde_yaml::Value::String(k.clone()),
786 Self::json_to_yaml_value(v),
787 );
788 }
789 serde_yaml::Value::Mapping(yaml_map)
790 }
791 }
792 }
793}