Skip to main content

openapi_nexus/generators/kotlin/okhttp/
util.rs

1use std::collections::HashSet;
2
3use crate::ir::types::{IrPrimitive, IrTypeExpr};
4use heck::{ToLowerCamelCase, ToPascalCase};
5
6pub fn kt_type_str(expr: &IrTypeExpr) -> String {
7    match expr {
8        IrTypeExpr::Named(name) => name.to_pascal_case(),
9        IrTypeExpr::Primitive(p) => kt_primitive(p).to_string(),
10        IrTypeExpr::Array(inner) => format!("List<{}>", kt_type_str(inner)),
11        IrTypeExpr::Map(inner) => format!("Map<String, {}>", kt_type_str(inner)),
12        IrTypeExpr::Nullable(inner) => format!("{}?", kt_type_str(inner)),
13        IrTypeExpr::StringLiteral(_) | IrTypeExpr::StringEnum(_) => "String".to_string(),
14        IrTypeExpr::Union(_) | IrTypeExpr::Any => "Any".to_string(),
15    }
16}
17
18pub fn kt_primitive(p: &IrPrimitive) -> &'static str {
19    match p {
20        IrPrimitive::String | IrPrimitive::StringWithFormat(_) => "String",
21        IrPrimitive::Date | IrPrimitive::DateTime => "String",
22        IrPrimitive::Uuid => "String",
23        IrPrimitive::Binary => "ByteArray",
24        IrPrimitive::Integer => "Int",
25        IrPrimitive::IntegerWithFormat(format) => match format.as_str() {
26            "int64" => "Long",
27            _ => "Int",
28        },
29        IrPrimitive::Number => "Double",
30        IrPrimitive::NumberWithFormat(format) => match format.as_str() {
31            "float" => "Float",
32            _ => "Double",
33        },
34        IrPrimitive::Boolean => "Boolean",
35    }
36}
37
38pub fn kt_field_name(name: &str) -> String {
39    let camel = name.to_lower_camel_case();
40    if camel.is_empty() {
41        return "value".to_string();
42    }
43    if is_kotlin_reserved(&camel) {
44        format!("`{camel}`")
45    } else {
46        camel
47    }
48}
49
50pub fn kt_ident(name: &str) -> String {
51    let camel = name.to_lower_camel_case();
52    if camel.is_empty() {
53        return "arg".to_string();
54    }
55    if is_kotlin_reserved(&camel) {
56        format!("`{camel}`")
57    } else {
58        camel
59    }
60}
61
62pub fn is_kotlin_reserved(name: &str) -> bool {
63    matches!(
64        name,
65        "as" | "break"
66            | "class"
67            | "continue"
68            | "do"
69            | "else"
70            | "false"
71            | "for"
72            | "fun"
73            | "if"
74            | "in"
75            | "interface"
76            | "is"
77            | "null"
78            | "object"
79            | "package"
80            | "return"
81            | "super"
82            | "this"
83            | "throw"
84            | "true"
85            | "try"
86            | "typealias"
87            | "typeof"
88            | "val"
89            | "var"
90            | "when"
91            | "while"
92    )
93}
94
95pub fn escape_kt_string(s: &str) -> String {
96    s.replace('\\', "\\\\")
97        .replace('"', "\\\"")
98        .replace('$', "\\$")
99        .replace('\n', "\\n")
100        .replace('\r', "\\r")
101        .replace('\t', "\\t")
102}
103
104pub fn unique_name(desired: &str, used: &mut HashSet<String>) -> String {
105    if used.insert(desired.to_string()) {
106        return desired.to_string();
107    }
108    for i in 2..=u32::MAX {
109        let candidate = format!("{desired}{i}");
110        if used.insert(candidate.clone()) {
111            return candidate;
112        }
113    }
114    unreachable!()
115}
116
117pub fn sanitize_operation_id(op_id: &str, method: &str, path: &str) -> String {
118    if !op_id.is_empty() {
119        return op_id.to_string();
120    }
121    let path_part: String = path
122        .chars()
123        .map(|c| if c.is_alphanumeric() { c } else { '_' })
124        .collect();
125    format!("{method}_{path_part}")
126}
127
128pub fn render_value_as_string(value_expr: &str, t: &IrTypeExpr) -> String {
129    match t {
130        IrTypeExpr::Primitive(
131            IrPrimitive::String
132            | IrPrimitive::Date
133            | IrPrimitive::DateTime
134            | IrPrimitive::Uuid
135            | IrPrimitive::StringWithFormat(_),
136        )
137        | IrTypeExpr::StringLiteral(_)
138        | IrTypeExpr::StringEnum(_) => value_expr.to_string(),
139        IrTypeExpr::Primitive(IrPrimitive::Boolean)
140        | IrTypeExpr::Primitive(IrPrimitive::Integer)
141        | IrTypeExpr::Primitive(IrPrimitive::IntegerWithFormat(_))
142        | IrTypeExpr::Primitive(IrPrimitive::Number)
143        | IrTypeExpr::Primitive(IrPrimitive::NumberWithFormat(_)) => {
144            format!("{value_expr}.toString()")
145        }
146        IrTypeExpr::Nullable(inner) => {
147            let inner_str = render_value_as_string(value_expr, inner);
148            if inner_str == value_expr {
149                format!("{value_expr} ?: \"\"")
150            } else {
151                inner_str
152            }
153        }
154        IrTypeExpr::Array(_) => format!("{value_expr}.joinToString(\",\")"),
155        IrTypeExpr::Named(_) => format!("{value_expr}.toString()"),
156        _ => format!("{value_expr}.toString()"),
157    }
158}