use crate::parser::{self, PrimitiveType, Request, SchemaType};
use std::collections::BTreeMap;
use super::utils;
pub fn schema_to_dart(schema: &SchemaType, identifiers: &BTreeMap<String, String>) -> String {
match schema {
SchemaType::Primitive(p) => primitive_to_dart(p),
SchemaType::Array(inner) => {
let inner_type = schema_to_dart(inner, identifiers);
format!("List<{inner_type}>")
}
SchemaType::Object(_) => "Map<String, Object?>".to_string(),
SchemaType::Ref(name) => identifiers
.get(name)
.cloned()
.unwrap_or_else(|| "Object?".to_string()),
SchemaType::OneOf(_) | SchemaType::AnyOf(_) | SchemaType::AllOf(_) => "Object?".to_string(),
SchemaType::Unknown => "Object?".to_string(),
}
}
pub fn params_to_dart_meta(
req: &Request,
identifiers: &BTreeMap<String, String>,
) -> Option<String> {
let params = req.params.as_ref()?;
if params.is_empty() {
return None;
}
let mut by_location: BTreeMap<String, Vec<&parser::ParsedParameter>> = BTreeMap::new();
for param in params {
let location = param
.location
.as_deref()
.unwrap_or("other")
.to_ascii_lowercase();
by_location.entry(location).or_default().push(param);
}
let mut out = String::new();
out.push_str("{\n");
for (location, mut fields) in by_location {
fields.sort_by(|a, b| a.name.cmp(&b.name));
out.push_str(&format!(" {}: {{\n", utils::dart_quote(&location)));
for param in fields {
let mut ty = param
.schema_type
.as_ref()
.map(|schema| schema_to_dart(schema, identifiers))
.unwrap_or_else(|| "Object?".to_string());
if param.required != Some(true) && !ty.ends_with('?') {
ty.push('?');
}
out.push_str(&format!(
" {}: {},\n",
utils::dart_quote(¶m.name),
utils::dart_quote(&ty)
));
}
out.push_str(" },\n");
}
out.push('}');
Some(out)
}
pub fn responses_to_dart_meta(
req: &Request,
identifiers: &BTreeMap<String, String>,
) -> Option<String> {
let responses = req.responses.as_ref()?;
if responses.is_empty() {
return None;
}
let mut out = String::new();
out.push_str("{\n");
for (status, parsed_response) in responses {
let ty = parsed_response_to_dart_type(parsed_response, identifiers);
out.push_str(&format!(" {status}: {},\n", utils::dart_quote(&ty)));
}
out.push('}');
Some(out)
}
pub fn parsed_response_to_dart_type(
parsed_response: &parser::ParsedResponse,
identifiers: &BTreeMap<String, String>,
) -> String {
if let Some(schema_name) = &parsed_response.schema_name {
return identifiers
.get(schema_name)
.cloned()
.unwrap_or_else(|| "Object?".to_string());
}
if let Some(schema_type) = parsed_response.schema_type.as_ref() {
return schema_to_dart(schema_type, identifiers);
}
"Never".to_string()
}
fn primitive_to_dart(primitive: &parser::Primitive) -> String {
let mut base = primitive_kind_to_dart(&primitive.kind).to_string();
if primitive.nullable == Some(true) && !base.ends_with('?') {
base.push('?');
}
base
}
fn primitive_kind_to_dart(kind: &PrimitiveType) -> &'static str {
match kind {
PrimitiveType::String => "String",
PrimitiveType::Integer => "int",
PrimitiveType::Number => "double",
PrimitiveType::Boolean => "bool",
}
}
#[cfg(test)]
mod tests {
use super::*;
fn primitive(kind: PrimitiveType) -> SchemaType {
SchemaType::Primitive(parser::Primitive {
kind,
enum_values: None,
description: None,
default_value: None,
nullable: None,
format: None,
})
}
#[test]
fn renders_object_for_any_of() {
let schema = SchemaType::AnyOf(vec![
primitive(PrimitiveType::String),
primitive(PrimitiveType::Integer),
]);
let identifiers = BTreeMap::new();
assert_eq!(schema_to_dart(&schema, &identifiers), "Object?");
}
#[test]
fn renders_list_for_array_schema() {
let schema = SchemaType::Array(Box::new(primitive(PrimitiveType::Boolean)));
let identifiers = BTreeMap::new();
assert_eq!(schema_to_dart(&schema, &identifiers), "List<bool>");
}
#[test]
fn renders_object_for_unknown_schema_type() {
let identifiers = BTreeMap::new();
assert_eq!(schema_to_dart(&SchemaType::Unknown, &identifiers), "Object?");
}
}