1use crate::export::ExportError;
6use crate::models::cads::*;
7use serde_yaml;
8
9pub struct CADSExporter;
11
12impl CADSExporter {
13 pub fn export(&self, asset: &CADSAsset) -> Result<String, ExportError> {
23 let yaml = Self::export_asset(asset);
24
25 #[cfg(feature = "schema-validation")]
27 {
28 use crate::validation::schema::validate_cads_internal;
29 validate_cads_internal(&yaml).map_err(ExportError::ValidationError)?;
30 }
31
32 Ok(yaml)
33 }
34
35 pub fn export_asset(asset: &CADSAsset) -> String {
81 let mut yaml = serde_yaml::Mapping::new();
82
83 yaml.insert(
85 serde_yaml::Value::String("apiVersion".to_string()),
86 serde_yaml::Value::String(asset.api_version.clone()),
87 );
88
89 let kind_str = match asset.kind {
90 CADSKind::AIModel => "AIModel",
91 CADSKind::MLPipeline => "MLPipeline",
92 CADSKind::Application => "Application",
93 CADSKind::ETLPipeline => "ETLPipeline",
94 CADSKind::SourceSystem => "SourceSystem",
95 CADSKind::DestinationSystem => "DestinationSystem",
96 };
97 yaml.insert(
98 serde_yaml::Value::String("kind".to_string()),
99 serde_yaml::Value::String(kind_str.to_string()),
100 );
101
102 yaml.insert(
103 serde_yaml::Value::String("id".to_string()),
104 serde_yaml::Value::String(asset.id.clone()),
105 );
106
107 yaml.insert(
108 serde_yaml::Value::String("name".to_string()),
109 serde_yaml::Value::String(asset.name.clone()),
110 );
111
112 yaml.insert(
113 serde_yaml::Value::String("version".to_string()),
114 serde_yaml::Value::String(asset.version.clone()),
115 );
116
117 let status_str = match asset.status {
118 CADSStatus::Draft => "draft",
119 CADSStatus::Validated => "validated",
120 CADSStatus::Production => "production",
121 CADSStatus::Deprecated => "deprecated",
122 };
123 yaml.insert(
124 serde_yaml::Value::String("status".to_string()),
125 serde_yaml::Value::String(status_str.to_string()),
126 );
127
128 if let Some(domain) = &asset.domain {
130 yaml.insert(
131 serde_yaml::Value::String("domain".to_string()),
132 serde_yaml::Value::String(domain.clone()),
133 );
134 }
135
136 if !asset.tags.is_empty() {
137 let tags_yaml: Vec<serde_yaml::Value> = asset
138 .tags
139 .iter()
140 .map(|t| serde_yaml::Value::String(t.to_string()))
141 .collect();
142 yaml.insert(
143 serde_yaml::Value::String("tags".to_string()),
144 serde_yaml::Value::Sequence(tags_yaml),
145 );
146 }
147
148 if let Some(description) = &asset.description {
149 let mut desc_map = serde_yaml::Mapping::new();
150 if let Some(purpose) = &description.purpose {
151 desc_map.insert(
152 serde_yaml::Value::String("purpose".to_string()),
153 serde_yaml::Value::String(purpose.clone()),
154 );
155 }
156 if let Some(usage) = &description.usage {
157 desc_map.insert(
158 serde_yaml::Value::String("usage".to_string()),
159 serde_yaml::Value::String(usage.clone()),
160 );
161 }
162 if let Some(limitations) = &description.limitations {
163 desc_map.insert(
164 serde_yaml::Value::String("limitations".to_string()),
165 serde_yaml::Value::String(limitations.clone()),
166 );
167 }
168 if let Some(external_links) = &description.external_links {
169 let links_yaml: Vec<serde_yaml::Value> = external_links
170 .iter()
171 .map(|link| {
172 let mut link_map = serde_yaml::Mapping::new();
173 link_map.insert(
174 serde_yaml::Value::String("url".to_string()),
175 serde_yaml::Value::String(link.url.clone()),
176 );
177 if let Some(desc) = &link.description {
178 link_map.insert(
179 serde_yaml::Value::String("description".to_string()),
180 serde_yaml::Value::String(desc.clone()),
181 );
182 }
183 serde_yaml::Value::Mapping(link_map)
184 })
185 .collect();
186 desc_map.insert(
187 serde_yaml::Value::String("externalLinks".to_string()),
188 serde_yaml::Value::Sequence(links_yaml),
189 );
190 }
191 if !desc_map.is_empty() {
192 yaml.insert(
193 serde_yaml::Value::String("description".to_string()),
194 serde_yaml::Value::Mapping(desc_map),
195 );
196 }
197 }
198
199 if let Some(runtime) = &asset.runtime {
200 let mut runtime_map = serde_yaml::Mapping::new();
201 if let Some(environment) = &runtime.environment {
202 runtime_map.insert(
203 serde_yaml::Value::String("environment".to_string()),
204 serde_yaml::Value::String(environment.clone()),
205 );
206 }
207 if let Some(endpoints) = &runtime.endpoints {
208 let endpoints_yaml: Vec<serde_yaml::Value> = endpoints
209 .iter()
210 .map(|e| serde_yaml::Value::String(e.clone()))
211 .collect();
212 runtime_map.insert(
213 serde_yaml::Value::String("endpoints".to_string()),
214 serde_yaml::Value::Sequence(endpoints_yaml),
215 );
216 }
217 if let Some(container) = &runtime.container {
218 let mut container_map = serde_yaml::Mapping::new();
219 if let Some(image) = &container.image {
220 container_map.insert(
221 serde_yaml::Value::String("image".to_string()),
222 serde_yaml::Value::String(image.clone()),
223 );
224 }
225 if !container_map.is_empty() {
226 runtime_map.insert(
227 serde_yaml::Value::String("container".to_string()),
228 serde_yaml::Value::Mapping(container_map),
229 );
230 }
231 }
232 if let Some(resources) = &runtime.resources {
233 let mut resources_map = serde_yaml::Mapping::new();
234 if let Some(cpu) = &resources.cpu {
235 resources_map.insert(
236 serde_yaml::Value::String("cpu".to_string()),
237 serde_yaml::Value::String(cpu.clone()),
238 );
239 }
240 if let Some(memory) = &resources.memory {
241 resources_map.insert(
242 serde_yaml::Value::String("memory".to_string()),
243 serde_yaml::Value::String(memory.clone()),
244 );
245 }
246 if let Some(gpu) = &resources.gpu {
247 resources_map.insert(
248 serde_yaml::Value::String("gpu".to_string()),
249 serde_yaml::Value::String(gpu.clone()),
250 );
251 }
252 if !resources_map.is_empty() {
253 runtime_map.insert(
254 serde_yaml::Value::String("resources".to_string()),
255 serde_yaml::Value::Mapping(resources_map),
256 );
257 }
258 }
259 if !runtime_map.is_empty() {
260 yaml.insert(
261 serde_yaml::Value::String("runtime".to_string()),
262 serde_yaml::Value::Mapping(runtime_map),
263 );
264 }
265 }
266
267 if let Some(sla) = &asset.sla
268 && let Some(properties) = &sla.properties
269 {
270 let mut sla_map = serde_yaml::Mapping::new();
271 let props_yaml: Vec<serde_yaml::Value> = properties
272 .iter()
273 .map(|prop| {
274 let mut prop_map = serde_yaml::Mapping::new();
275 prop_map.insert(
276 serde_yaml::Value::String("element".to_string()),
277 serde_yaml::Value::String(prop.element.clone()),
278 );
279 prop_map.insert(
280 serde_yaml::Value::String("value".to_string()),
281 Self::json_to_yaml_value(&prop.value),
282 );
283 prop_map.insert(
284 serde_yaml::Value::String("unit".to_string()),
285 serde_yaml::Value::String(prop.unit.clone()),
286 );
287 if let Some(driver) = &prop.driver {
288 prop_map.insert(
289 serde_yaml::Value::String("driver".to_string()),
290 serde_yaml::Value::String(driver.clone()),
291 );
292 }
293 serde_yaml::Value::Mapping(prop_map)
294 })
295 .collect();
296 sla_map.insert(
297 serde_yaml::Value::String("properties".to_string()),
298 serde_yaml::Value::Sequence(props_yaml),
299 );
300 yaml.insert(
301 serde_yaml::Value::String("sla".to_string()),
302 serde_yaml::Value::Mapping(sla_map),
303 );
304 }
305
306 if let Some(pricing) = &asset.pricing {
307 let mut pricing_map = serde_yaml::Mapping::new();
308 if let Some(model) = &pricing.model {
309 let model_str = match model {
310 CADSPricingModel::PerRequest => "per_request",
311 CADSPricingModel::PerHour => "per_hour",
312 CADSPricingModel::PerBatch => "per_batch",
313 CADSPricingModel::Subscription => "subscription",
314 CADSPricingModel::Internal => "internal",
315 };
316 pricing_map.insert(
317 serde_yaml::Value::String("model".to_string()),
318 serde_yaml::Value::String(model_str.to_string()),
319 );
320 }
321 if let Some(currency) = &pricing.currency {
322 pricing_map.insert(
323 serde_yaml::Value::String("currency".to_string()),
324 serde_yaml::Value::String(currency.clone()),
325 );
326 }
327 if let Some(unit_cost) = pricing.unit_cost {
328 pricing_map.insert(
329 serde_yaml::Value::String("unitCost".to_string()),
330 serde_yaml::Value::Number(serde_yaml::Number::from(unit_cost)),
331 );
332 }
333 if let Some(billing_unit) = &pricing.billing_unit {
334 pricing_map.insert(
335 serde_yaml::Value::String("billingUnit".to_string()),
336 serde_yaml::Value::String(billing_unit.clone()),
337 );
338 }
339 if let Some(notes) = &pricing.notes {
340 pricing_map.insert(
341 serde_yaml::Value::String("notes".to_string()),
342 serde_yaml::Value::String(notes.clone()),
343 );
344 }
345 if !pricing_map.is_empty() {
346 yaml.insert(
347 serde_yaml::Value::String("pricing".to_string()),
348 serde_yaml::Value::Mapping(pricing_map),
349 );
350 }
351 }
352
353 if let Some(team) = &asset.team {
354 let team_yaml: Vec<serde_yaml::Value> = team
355 .iter()
356 .map(|member| {
357 let mut member_map = serde_yaml::Mapping::new();
358 member_map.insert(
359 serde_yaml::Value::String("role".to_string()),
360 serde_yaml::Value::String(member.role.clone()),
361 );
362 member_map.insert(
363 serde_yaml::Value::String("name".to_string()),
364 serde_yaml::Value::String(member.name.clone()),
365 );
366 if let Some(contact) = &member.contact {
367 member_map.insert(
368 serde_yaml::Value::String("contact".to_string()),
369 serde_yaml::Value::String(contact.clone()),
370 );
371 }
372 serde_yaml::Value::Mapping(member_map)
373 })
374 .collect();
375 yaml.insert(
376 serde_yaml::Value::String("team".to_string()),
377 serde_yaml::Value::Sequence(team_yaml),
378 );
379 }
380
381 if let Some(risk) = &asset.risk {
382 let mut risk_map = serde_yaml::Mapping::new();
383 if let Some(classification) = &risk.classification {
384 let class_str = match classification {
385 CADSRiskClassification::Minimal => "minimal",
386 CADSRiskClassification::Low => "low",
387 CADSRiskClassification::Medium => "medium",
388 CADSRiskClassification::High => "high",
389 };
390 risk_map.insert(
391 serde_yaml::Value::String("classification".to_string()),
392 serde_yaml::Value::String(class_str.to_string()),
393 );
394 }
395 if let Some(impact_areas) = &risk.impact_areas {
396 let areas_yaml: Vec<serde_yaml::Value> = impact_areas
397 .iter()
398 .map(|area| {
399 let area_str = match area {
400 CADSImpactArea::Fairness => "fairness",
401 CADSImpactArea::Privacy => "privacy",
402 CADSImpactArea::Safety => "safety",
403 CADSImpactArea::Security => "security",
404 CADSImpactArea::Financial => "financial",
405 CADSImpactArea::Operational => "operational",
406 CADSImpactArea::Reputational => "reputational",
407 };
408 serde_yaml::Value::String(area_str.to_string())
409 })
410 .collect();
411 risk_map.insert(
412 serde_yaml::Value::String("impactAreas".to_string()),
413 serde_yaml::Value::Sequence(areas_yaml),
414 );
415 }
416 if let Some(intended_use) = &risk.intended_use {
417 risk_map.insert(
418 serde_yaml::Value::String("intendedUse".to_string()),
419 serde_yaml::Value::String(intended_use.clone()),
420 );
421 }
422 if let Some(out_of_scope_use) = &risk.out_of_scope_use {
423 risk_map.insert(
424 serde_yaml::Value::String("outOfScopeUse".to_string()),
425 serde_yaml::Value::String(out_of_scope_use.clone()),
426 );
427 }
428 if let Some(assessment) = &risk.assessment {
429 let mut assess_map = serde_yaml::Mapping::new();
430 if let Some(methodology) = &assessment.methodology {
431 assess_map.insert(
432 serde_yaml::Value::String("methodology".to_string()),
433 serde_yaml::Value::String(methodology.clone()),
434 );
435 }
436 if let Some(date) = &assessment.date {
437 assess_map.insert(
438 serde_yaml::Value::String("date".to_string()),
439 serde_yaml::Value::String(date.clone()),
440 );
441 }
442 if let Some(assessor) = &assessment.assessor {
443 assess_map.insert(
444 serde_yaml::Value::String("assessor".to_string()),
445 serde_yaml::Value::String(assessor.clone()),
446 );
447 }
448 if !assess_map.is_empty() {
449 risk_map.insert(
450 serde_yaml::Value::String("assessment".to_string()),
451 serde_yaml::Value::Mapping(assess_map),
452 );
453 }
454 }
455 if let Some(mitigations) = &risk.mitigations {
456 let mitigations_yaml: Vec<serde_yaml::Value> = mitigations
457 .iter()
458 .map(|mit| {
459 let mut mit_map = serde_yaml::Mapping::new();
460 mit_map.insert(
461 serde_yaml::Value::String("description".to_string()),
462 serde_yaml::Value::String(mit.description.clone()),
463 );
464 let status_str = match mit.status {
465 CADSMitigationStatus::Planned => "planned",
466 CADSMitigationStatus::Implemented => "implemented",
467 CADSMitigationStatus::Verified => "verified",
468 };
469 mit_map.insert(
470 serde_yaml::Value::String("status".to_string()),
471 serde_yaml::Value::String(status_str.to_string()),
472 );
473 serde_yaml::Value::Mapping(mit_map)
474 })
475 .collect();
476 risk_map.insert(
477 serde_yaml::Value::String("mitigations".to_string()),
478 serde_yaml::Value::Sequence(mitigations_yaml),
479 );
480 }
481 if !risk_map.is_empty() {
482 yaml.insert(
483 serde_yaml::Value::String("risk".to_string()),
484 serde_yaml::Value::Mapping(risk_map),
485 );
486 }
487 }
488
489 if let Some(compliance) = &asset.compliance {
490 let mut comp_map = serde_yaml::Mapping::new();
491 if let Some(frameworks) = &compliance.frameworks {
492 let frameworks_yaml: Vec<serde_yaml::Value> = frameworks
493 .iter()
494 .map(|fw| {
495 let mut fw_map = serde_yaml::Mapping::new();
496 fw_map.insert(
497 serde_yaml::Value::String("name".to_string()),
498 serde_yaml::Value::String(fw.name.clone()),
499 );
500 if let Some(category) = &fw.category {
501 fw_map.insert(
502 serde_yaml::Value::String("category".to_string()),
503 serde_yaml::Value::String(category.clone()),
504 );
505 }
506 let status_str = match fw.status {
507 CADSComplianceStatus::NotApplicable => "not_applicable",
508 CADSComplianceStatus::Assessed => "assessed",
509 CADSComplianceStatus::Compliant => "compliant",
510 CADSComplianceStatus::NonCompliant => "non_compliant",
511 };
512 fw_map.insert(
513 serde_yaml::Value::String("status".to_string()),
514 serde_yaml::Value::String(status_str.to_string()),
515 );
516 serde_yaml::Value::Mapping(fw_map)
517 })
518 .collect();
519 comp_map.insert(
520 serde_yaml::Value::String("frameworks".to_string()),
521 serde_yaml::Value::Sequence(frameworks_yaml),
522 );
523 }
524 if let Some(controls) = &compliance.controls {
525 let controls_yaml: Vec<serde_yaml::Value> = controls
526 .iter()
527 .map(|ctrl| {
528 let mut ctrl_map = serde_yaml::Mapping::new();
529 ctrl_map.insert(
530 serde_yaml::Value::String("id".to_string()),
531 serde_yaml::Value::String(ctrl.id.clone()),
532 );
533 ctrl_map.insert(
534 serde_yaml::Value::String("description".to_string()),
535 serde_yaml::Value::String(ctrl.description.clone()),
536 );
537 if let Some(evidence) = &ctrl.evidence {
538 ctrl_map.insert(
539 serde_yaml::Value::String("evidence".to_string()),
540 serde_yaml::Value::String(evidence.clone()),
541 );
542 }
543 serde_yaml::Value::Mapping(ctrl_map)
544 })
545 .collect();
546 comp_map.insert(
547 serde_yaml::Value::String("controls".to_string()),
548 serde_yaml::Value::Sequence(controls_yaml),
549 );
550 }
551 if !comp_map.is_empty() {
552 yaml.insert(
553 serde_yaml::Value::String("compliance".to_string()),
554 serde_yaml::Value::Mapping(comp_map),
555 );
556 }
557 }
558
559 if let Some(validation_profiles) = &asset.validation_profiles {
560 let profiles_yaml: Vec<serde_yaml::Value> = validation_profiles
561 .iter()
562 .map(|profile| {
563 let mut profile_map = serde_yaml::Mapping::new();
564 profile_map.insert(
565 serde_yaml::Value::String("name".to_string()),
566 serde_yaml::Value::String(profile.name.clone()),
567 );
568 if let Some(applies_to) = &profile.applies_to {
569 let mut applies_map = serde_yaml::Mapping::new();
570 if let Some(kind) = &applies_to.kind {
571 applies_map.insert(
572 serde_yaml::Value::String("kind".to_string()),
573 serde_yaml::Value::String(kind.clone()),
574 );
575 }
576 if let Some(risk_classification) = &applies_to.risk_classification {
577 applies_map.insert(
578 serde_yaml::Value::String("riskClassification".to_string()),
579 serde_yaml::Value::String(risk_classification.clone()),
580 );
581 }
582 if !applies_map.is_empty() {
583 profile_map.insert(
584 serde_yaml::Value::String("appliesTo".to_string()),
585 serde_yaml::Value::Mapping(applies_map),
586 );
587 }
588 }
589 let checks_yaml: Vec<serde_yaml::Value> = profile
590 .required_checks
591 .iter()
592 .map(|c| serde_yaml::Value::String(c.clone()))
593 .collect();
594 profile_map.insert(
595 serde_yaml::Value::String("requiredChecks".to_string()),
596 serde_yaml::Value::Sequence(checks_yaml),
597 );
598 serde_yaml::Value::Mapping(profile_map)
599 })
600 .collect();
601 yaml.insert(
602 serde_yaml::Value::String("validationProfiles".to_string()),
603 serde_yaml::Value::Sequence(profiles_yaml),
604 );
605 }
606
607 if let Some(bpmn_models) = &asset.bpmn_models {
608 let models_yaml: Vec<serde_yaml::Value> = bpmn_models
609 .iter()
610 .map(|model| {
611 let mut model_map = serde_yaml::Mapping::new();
612 model_map.insert(
613 serde_yaml::Value::String("name".to_string()),
614 serde_yaml::Value::String(model.name.clone()),
615 );
616 model_map.insert(
617 serde_yaml::Value::String("reference".to_string()),
618 serde_yaml::Value::String(model.reference.clone()),
619 );
620 let format_str = match model.format {
621 CADSBPMNFormat::Bpmn20Xml => "bpmn20-xml",
622 CADSBPMNFormat::Json => "json",
623 };
624 model_map.insert(
625 serde_yaml::Value::String("format".to_string()),
626 serde_yaml::Value::String(format_str.to_string()),
627 );
628 if let Some(description) = &model.description {
629 model_map.insert(
630 serde_yaml::Value::String("description".to_string()),
631 serde_yaml::Value::String(description.clone()),
632 );
633 }
634 serde_yaml::Value::Mapping(model_map)
635 })
636 .collect();
637 yaml.insert(
638 serde_yaml::Value::String("bpmnModels".to_string()),
639 serde_yaml::Value::Sequence(models_yaml),
640 );
641 }
642
643 if let Some(dmn_models) = &asset.dmn_models {
644 let models_yaml: Vec<serde_yaml::Value> = dmn_models
645 .iter()
646 .map(|model| {
647 let mut model_map = serde_yaml::Mapping::new();
648 model_map.insert(
649 serde_yaml::Value::String("name".to_string()),
650 serde_yaml::Value::String(model.name.clone()),
651 );
652 model_map.insert(
653 serde_yaml::Value::String("reference".to_string()),
654 serde_yaml::Value::String(model.reference.clone()),
655 );
656 let format_str = match model.format {
657 CADSDMNFormat::Dmn13Xml => "dmn13-xml",
658 };
659 model_map.insert(
660 serde_yaml::Value::String("format".to_string()),
661 serde_yaml::Value::String(format_str.to_string()),
662 );
663 if let Some(description) = &model.description {
664 model_map.insert(
665 serde_yaml::Value::String("description".to_string()),
666 serde_yaml::Value::String(description.clone()),
667 );
668 }
669 serde_yaml::Value::Mapping(model_map)
670 })
671 .collect();
672 yaml.insert(
673 serde_yaml::Value::String("dmnModels".to_string()),
674 serde_yaml::Value::Sequence(models_yaml),
675 );
676 }
677
678 if let Some(openapi_specs) = &asset.openapi_specs {
679 let specs_yaml: Vec<serde_yaml::Value> = openapi_specs
680 .iter()
681 .map(|spec| {
682 let mut spec_map = serde_yaml::Mapping::new();
683 spec_map.insert(
684 serde_yaml::Value::String("name".to_string()),
685 serde_yaml::Value::String(spec.name.clone()),
686 );
687 spec_map.insert(
688 serde_yaml::Value::String("reference".to_string()),
689 serde_yaml::Value::String(spec.reference.clone()),
690 );
691 let format_str = match spec.format {
692 CADSOpenAPIFormat::Openapi311Yaml => "openapi-311-yaml",
693 CADSOpenAPIFormat::Openapi311Json => "openapi-311-json",
694 };
695 spec_map.insert(
696 serde_yaml::Value::String("format".to_string()),
697 serde_yaml::Value::String(format_str.to_string()),
698 );
699 if let Some(description) = &spec.description {
700 spec_map.insert(
701 serde_yaml::Value::String("description".to_string()),
702 serde_yaml::Value::String(description.clone()),
703 );
704 }
705 serde_yaml::Value::Mapping(spec_map)
706 })
707 .collect();
708 yaml.insert(
709 serde_yaml::Value::String("openapiSpecs".to_string()),
710 serde_yaml::Value::Sequence(specs_yaml),
711 );
712 }
713
714 if let Some(custom_properties) = &asset.custom_properties {
715 let mut custom_map = serde_yaml::Mapping::new();
716 for (key, value) in custom_properties {
717 custom_map.insert(
718 serde_yaml::Value::String(key.clone()),
719 Self::json_to_yaml_value(value),
720 );
721 }
722 if !custom_map.is_empty() {
723 yaml.insert(
724 serde_yaml::Value::String("customProperties".to_string()),
725 serde_yaml::Value::Mapping(custom_map),
726 );
727 }
728 }
729
730 serde_yaml::to_string(&serde_yaml::Value::Mapping(yaml))
732 .unwrap_or_else(|_| String::from(""))
733 }
734
735 fn json_to_yaml_value(json: &serde_json::Value) -> serde_yaml::Value {
737 match json {
738 serde_json::Value::Null => serde_yaml::Value::Null,
739 serde_json::Value::Bool(b) => serde_yaml::Value::Bool(*b),
740 serde_json::Value::Number(n) => {
741 if let Some(i) = n.as_i64() {
742 serde_yaml::Value::Number(serde_yaml::Number::from(i))
743 } else if let Some(f) = n.as_f64() {
744 serde_yaml::Value::Number(serde_yaml::Number::from(f))
745 } else {
746 serde_yaml::Value::String(n.to_string())
747 }
748 }
749 serde_json::Value::String(s) => serde_yaml::Value::String(s.clone()),
750 serde_json::Value::Array(arr) => {
751 let yaml_arr: Vec<serde_yaml::Value> =
752 arr.iter().map(Self::json_to_yaml_value).collect();
753 serde_yaml::Value::Sequence(yaml_arr)
754 }
755 serde_json::Value::Object(obj) => {
756 let mut yaml_map = serde_yaml::Mapping::new();
757 for (k, v) in obj {
758 yaml_map.insert(
759 serde_yaml::Value::String(k.clone()),
760 Self::json_to_yaml_value(v),
761 );
762 }
763 serde_yaml::Value::Mapping(yaml_map)
764 }
765 }
766 }
767}