openapi_nexus/generators/kotlin/okhttp/
util.rs1use 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}