openapi_nexus/generators/java/okhttp/
util.rs1use std::collections::HashSet;
2
3use crate::ir::types::{IrPrimitive, IrTypeExpr};
4use heck::{ToLowerCamelCase, ToPascalCase};
5#[allow(unused_imports)]
6use sigil_stitch::lang::java_lang::JavaLang;
7use sigil_stitch::prelude::*;
8
9pub fn java_type_str(expr: &IrTypeExpr) -> String {
10 match expr {
11 IrTypeExpr::Named(name) => name.to_pascal_case(),
12 IrTypeExpr::Primitive(p) => java_primitive(p).to_string(),
13 IrTypeExpr::Array(inner) => format!("List<{}>", java_boxed_type_str(inner)),
14 IrTypeExpr::Map(inner) => format!("Map<String, {}>", java_boxed_type_str(inner)),
15 IrTypeExpr::Nullable(inner) => java_boxed_type_str(inner),
16 IrTypeExpr::StringLiteral(_) | IrTypeExpr::StringEnum(_) => "String".to_string(),
17 IrTypeExpr::Union(_) | IrTypeExpr::Any => "Object".to_string(),
18 }
19}
20
21pub fn java_boxed_type_str(expr: &IrTypeExpr) -> String {
22 match expr {
23 IrTypeExpr::Primitive(p) => java_primitive_boxed(p).to_string(),
24 _ => java_type_str(expr),
25 }
26}
27
28pub fn java_primitive(p: &IrPrimitive) -> &'static str {
29 match p {
30 IrPrimitive::String | IrPrimitive::StringWithFormat(_) => "String",
31 IrPrimitive::Date | IrPrimitive::DateTime => "String",
32 IrPrimitive::Uuid => "String",
33 IrPrimitive::Binary => "byte[]",
34 IrPrimitive::Integer => "int",
35 IrPrimitive::IntegerWithFormat(format) => match format.as_str() {
36 "int64" => "long",
37 _ => "int",
38 },
39 IrPrimitive::Number => "double",
40 IrPrimitive::NumberWithFormat(format) => match format.as_str() {
41 "float" => "float",
42 _ => "double",
43 },
44 IrPrimitive::Boolean => "boolean",
45 }
46}
47
48pub fn java_primitive_boxed(p: &IrPrimitive) -> &'static str {
49 match p {
50 IrPrimitive::String | IrPrimitive::StringWithFormat(_) => "String",
51 IrPrimitive::Date | IrPrimitive::DateTime => "String",
52 IrPrimitive::Uuid => "String",
53 IrPrimitive::Binary => "byte[]",
54 IrPrimitive::Integer => "Integer",
55 IrPrimitive::IntegerWithFormat(format) => match format.as_str() {
56 "int64" => "Long",
57 _ => "Integer",
58 },
59 IrPrimitive::Number => "Double",
60 IrPrimitive::NumberWithFormat(format) => match format.as_str() {
61 "float" => "Float",
62 _ => "Double",
63 },
64 IrPrimitive::Boolean => "Boolean",
65 }
66}
67
68pub fn java_field_name(name: &str) -> String {
69 let camel = name.to_lower_camel_case();
70 if camel.is_empty() {
71 return "value".to_string();
72 }
73 if is_java_reserved(&camel) {
74 format!("{camel}_")
75 } else {
76 camel
77 }
78}
79
80pub fn java_ident(name: &str) -> String {
81 let camel = name.to_lower_camel_case();
82 if camel.is_empty() {
83 return "arg".to_string();
84 }
85 if is_java_reserved(&camel) {
86 format!("{camel}_")
87 } else {
88 camel
89 }
90}
91
92pub fn is_java_reserved(name: &str) -> bool {
93 matches!(
94 name,
95 "abstract"
96 | "assert"
97 | "boolean"
98 | "break"
99 | "byte"
100 | "case"
101 | "catch"
102 | "char"
103 | "class"
104 | "const"
105 | "continue"
106 | "default"
107 | "do"
108 | "double"
109 | "else"
110 | "enum"
111 | "extends"
112 | "final"
113 | "finally"
114 | "float"
115 | "for"
116 | "goto"
117 | "if"
118 | "implements"
119 | "import"
120 | "instanceof"
121 | "int"
122 | "interface"
123 | "long"
124 | "native"
125 | "new"
126 | "package"
127 | "private"
128 | "protected"
129 | "public"
130 | "return"
131 | "short"
132 | "static"
133 | "strictfp"
134 | "super"
135 | "switch"
136 | "synchronized"
137 | "this"
138 | "throw"
139 | "throws"
140 | "transient"
141 | "try"
142 | "void"
143 | "volatile"
144 | "while"
145 )
146}
147
148pub fn escape_java_string(s: &str) -> String {
149 s.replace('\\', "\\\\")
150 .replace('"', "\\\"")
151 .replace('\n', "\\n")
152 .replace('\r', "\\r")
153 .replace('\t', "\\t")
154}
155
156pub fn unique_name(desired: &str, used: &mut HashSet<String>) -> String {
157 if used.insert(desired.to_string()) {
158 return desired.to_string();
159 }
160 for i in 2..=u32::MAX {
161 let candidate = format!("{desired}{i}");
162 if used.insert(candidate.clone()) {
163 return candidate;
164 }
165 }
166 unreachable!()
167}
168
169pub fn sanitize_operation_id(op_id: &str, method: &str, path: &str) -> String {
170 if !op_id.is_empty() {
171 return op_id.to_string();
172 }
173 let path_part: String = path
174 .chars()
175 .map(|c| if c.is_alphanumeric() { c } else { '_' })
176 .collect();
177 format!("{method}_{path_part}")
178}
179
180pub fn render_value_as_string(value_expr: &str, t: &IrTypeExpr) -> String {
181 match t {
182 IrTypeExpr::Primitive(
183 IrPrimitive::String
184 | IrPrimitive::Date
185 | IrPrimitive::DateTime
186 | IrPrimitive::Uuid
187 | IrPrimitive::StringWithFormat(_),
188 )
189 | IrTypeExpr::StringLiteral(_)
190 | IrTypeExpr::StringEnum(_) => value_expr.to_string(),
191 IrTypeExpr::Primitive(IrPrimitive::Boolean)
192 | IrTypeExpr::Primitive(IrPrimitive::Integer)
193 | IrTypeExpr::Primitive(IrPrimitive::IntegerWithFormat(_))
194 | IrTypeExpr::Primitive(IrPrimitive::Number)
195 | IrTypeExpr::Primitive(IrPrimitive::NumberWithFormat(_)) => {
196 format!("String.valueOf({value_expr})")
197 }
198 IrTypeExpr::Nullable(inner) => render_value_as_string(value_expr, inner),
199 IrTypeExpr::Array(_) => format!("String.valueOf({value_expr})"),
200 IrTypeExpr::Named(_) => format!("String.valueOf({value_expr})"),
201 _ => format!("String.valueOf({value_expr})"),
202 }
203}
204
205pub fn build_java_getter(getter_name: &str, type_str: &str, field_name: &str) -> FunSpec {
206 let mut getter = FunSpec::builder(getter_name);
207 getter = getter.visibility(Visibility::Public);
208 getter = getter.returns(TypeName::primitive(type_str));
209 let body = sigil_quote!(JavaLang {
210 return this.$L(field_name);
211 })
212 .expect("getter body");
213 getter = getter.body(body);
214 getter.build().expect("getter")
215}
216
217pub fn type_uses_list(expr: &IrTypeExpr) -> bool {
218 match expr {
219 IrTypeExpr::Array(_) => true,
220 IrTypeExpr::Nullable(inner) => type_uses_list(inner),
221 IrTypeExpr::Map(inner) => type_uses_list(inner),
222 _ => false,
223 }
224}
225
226pub fn type_uses_map(expr: &IrTypeExpr) -> bool {
227 match expr {
228 IrTypeExpr::Map(_) => true,
229 IrTypeExpr::Nullable(inner) => type_uses_map(inner),
230 IrTypeExpr::Array(inner) => type_uses_map(inner),
231 _ => false,
232 }
233}