// Copyright 2022 Oxide Computer Company use convert_case::{Case, Casing}; use indexmap::IndexMap; use openapiv3::{ Components, Parameter, ReferenceOr, RequestBody, Response, Schema, }; use unicode_xid::UnicodeXID; use crate::Result; pub(crate) trait ReferenceOrExt { fn item<'a>(&'a self, components: &'a Option) -> Result<&'a T>; } pub(crate) trait ComponentLookup: Sized { fn get_components( components: &Components, ) -> &IndexMap>; } impl ReferenceOrExt for openapiv3::ReferenceOr { fn item<'a>(&'a self, components: &'a Option) -> Result<&'a T> { match self { ReferenceOr::Item(item) => Ok(item), ReferenceOr::Reference { reference } => { let idx = reference.rfind('/').unwrap(); let key = &reference[idx + 1..]; let parameters = T::get_components(components.as_ref().unwrap()); parameters.get(key).unwrap().item(components) } } } } impl ComponentLookup for Parameter { fn get_components( components: &Components, ) -> &IndexMap> { &components.parameters } } impl ComponentLookup for RequestBody { fn get_components( components: &Components, ) -> &IndexMap> { &components.request_bodies } } impl ComponentLookup for Response { fn get_components( components: &Components, ) -> &IndexMap> { &components.responses } } impl ComponentLookup for Schema { fn get_components( components: &Components, ) -> &IndexMap> { &components.schemas } } pub(crate) fn sanitize(input: &str, case: Case) -> String { let out = input .replace("'", "") .replace(|c: char| !c.is_xid_continue(), "-") .to_case(case); let out = match out.chars().next() { None => "x".to_case(case), Some(c) if c.is_xid_start() => out, Some(_) => format!("_{}", out), }; // Make sure the string is a valid Rust identifier. if syn::parse_str::(&out).is_ok() { out } else { format!("{}_", out) } }