use crate::core::config::Language;
use crate::core::ir::{PrimitiveType, TypeRef};
use crate::docs::naming::type_name;
pub fn doc_type(ty: &TypeRef, lang: Language, ffi_prefix: &str) -> String {
match ty {
TypeRef::String | TypeRef::Char => match lang {
Language::Python => "str".to_string(),
Language::Node | Language::Wasm => "string".to_string(),
Language::Go => "string".to_string(),
Language::Java => "String".to_string(),
Language::Csharp => "string".to_string(),
Language::Ruby => "String".to_string(),
Language::Php => "string".to_string(),
Language::Elixir => "String.t()".to_string(),
Language::R => "character".to_string(),
Language::Rust => "String".to_string(),
Language::Ffi | Language::C | Language::Jni => "const char*".to_string(),
Language::Kotlin | Language::KotlinAndroid | Language::Swift | Language::Dart => "String".to_string(),
Language::Gleam => "String".to_string(),
Language::Zig => "[:0]const u8".to_string(),
},
TypeRef::Bytes => match lang {
Language::Python => "bytes".to_string(),
Language::Node | Language::Wasm => "Buffer".to_string(),
Language::Go => "[]byte".to_string(),
Language::Java => "byte[]".to_string(),
Language::Csharp => "byte[]".to_string(),
Language::Ruby => "String".to_string(),
Language::Php => "string".to_string(),
Language::Elixir => "binary()".to_string(),
Language::R => "raw".to_string(),
Language::Rust => "Vec<u8>".to_string(),
Language::Ffi | Language::C | Language::Jni => "const uint8_t*".to_string(),
Language::Kotlin | Language::KotlinAndroid => "ByteArray".to_string(),
Language::Swift => "Data".to_string(),
Language::Dart => "Uint8List".to_string(),
Language::Gleam => "BitArray".to_string(),
Language::Zig => "[]const u8".to_string(),
},
TypeRef::Primitive(p) => doc_primitive(p, lang),
TypeRef::Optional(inner) => {
let inner_ty = doc_type(inner, lang, ffi_prefix);
match lang {
Language::Python => format!("{inner_ty} | None"),
Language::Node | Language::Wasm => format!("{inner_ty} | null"),
Language::Go => format!("*{inner_ty}"),
Language::Java => {
let boxed = java_boxed_type(inner);
format!("Optional<{boxed}>")
}
Language::Csharp => format!("{inner_ty}?"),
Language::Ruby => format!("{inner_ty}?"),
Language::Php => format!("?{inner_ty}"),
Language::Elixir => format!("{inner_ty} | nil"),
Language::R => format!("{inner_ty} or NULL"),
Language::Rust => format!("Option<{inner_ty}>"),
Language::Ffi | Language::C | Language::Jni => format!("{inner_ty}*"),
Language::Kotlin | Language::KotlinAndroid | Language::Swift | Language::Dart => format!("{inner_ty}?"),
Language::Gleam => format!("Option({inner_ty})"),
Language::Zig => format!("?{inner_ty}"),
}
}
TypeRef::Vec(inner) => {
match lang {
Language::Java => {
let inner_ty = java_boxed_type(inner);
format!("List<{inner_ty}>")
}
Language::Csharp => {
let inner_ty = doc_type(inner, lang, ffi_prefix);
format!("List<{inner_ty}>")
}
_ => {
let inner_ty = doc_type(inner, lang, ffi_prefix);
match lang {
Language::Python => format!("list[{inner_ty}]"),
Language::Node | Language::Wasm => format!("Array<{inner_ty}>"),
Language::Go => format!("[]{inner_ty}"),
Language::Ruby => format!("Array<{inner_ty}>"),
Language::Php => format!("array<{inner_ty}>"),
Language::Elixir => format!("list({inner_ty})"),
Language::R => "list".to_string(),
Language::Rust => format!("Vec<{inner_ty}>"),
Language::Ffi | Language::C | Language::Jni => format!("{inner_ty}*"),
Language::Java | Language::Csharp => unreachable!(),
Language::Kotlin | Language::KotlinAndroid | Language::Dart => format!("List<{inner_ty}>"),
Language::Swift => format!("[{inner_ty}]"),
Language::Gleam => format!("List({inner_ty})"),
Language::Zig => format!("[]const {inner_ty}"),
}
}
}
}
TypeRef::Map(k, v) => {
if lang == Language::Java {
let kty = java_boxed_type(k);
let vty = java_boxed_type(v);
return format!("Map<{kty}, {vty}>");
}
let kty = doc_type(k, lang, ffi_prefix);
let vty = doc_type(v, lang, ffi_prefix);
match lang {
Language::Python => format!("dict[{kty}, {vty}]"),
Language::Node | Language::Wasm => format!("Record<{kty}, {vty}>"),
Language::Go => format!("map[{kty}]{vty}"),
Language::Java => format!("Map<{kty}, {vty}>"),
Language::Csharp => format!("Dictionary<{kty}, {vty}>"),
Language::Ruby => format!("Hash{{{kty}=>{vty}}}"),
Language::Php => format!("array<{kty}, {vty}>"),
Language::Elixir => "map()".to_string(),
Language::R => "list".to_string(),
Language::Rust => format!("HashMap<{kty}, {vty}>"),
Language::Ffi | Language::C | Language::Jni => "void*".to_string(),
Language::Kotlin | Language::KotlinAndroid => format!("Map<{kty}, {vty}>"),
Language::Swift => format!("[{kty}: {vty}]"),
Language::Dart => format!("Map<{kty}, {vty}>"),
Language::Gleam => format!("Dict({kty}, {vty})"),
Language::Zig => format!("std.StringHashMap({vty})"),
}
}
TypeRef::Named(name) if name.starts_with('(') && name.ends_with(')') => {
let inner = &name[1..name.len() - 1];
let rendered: Vec<String> = inner
.split(',')
.map(|part| {
let trimmed = part.trim();
match trimmed {
"usize" | "u64" | "u32" | "u16" | "u8" | "i64" | "i32" | "i16" | "i8" | "isize" => {
let swift_name = match trimmed {
"u64" | "usize" => "UInt64",
"u32" => "UInt32",
"u16" => "UInt16",
"u8" => "UInt8",
"i64" | "isize" => "Int64",
"i32" => "Int32",
"i16" => "Int16",
"i8" => "Int8",
_ => "Int64",
};
match lang {
Language::Python => "int".to_string(),
Language::Node | Language::Wasm => "number".to_string(),
Language::Go => "int".to_string(),
Language::Java => "long".to_string(),
Language::Csharp => "long".to_string(),
Language::Ruby => "Integer".to_string(),
Language::Php => "int".to_string(),
Language::Elixir => "integer()".to_string(),
Language::R => "integer".to_string(),
Language::Rust => trimmed.to_string(),
Language::Ffi | Language::C | Language::Jni => "uint64_t".to_string(),
Language::Kotlin | Language::KotlinAndroid => "Long".to_string(),
Language::Swift => swift_name.to_string(),
Language::Dart => "int".to_string(),
Language::Gleam => "Int".to_string(),
Language::Zig => "i64".to_string(),
}
}
s @ ("str" | "&str" | "String" | "&'static str" | "&'staticstr") => match lang {
Language::Python => "str".to_string(),
Language::Node | Language::Wasm => "string".to_string(),
Language::Go => "string".to_string(),
Language::Java => "String".to_string(),
Language::Csharp => "string".to_string(),
Language::Ruby => "String".to_string(),
Language::Php => "string".to_string(),
Language::Elixir => "String.t()".to_string(),
Language::R => "character".to_string(),
Language::Rust => s.to_string(),
Language::Ffi | Language::C | Language::Jni => "const char*".to_string(),
Language::Kotlin | Language::KotlinAndroid | Language::Swift | Language::Dart => {
"String".to_string()
}
Language::Gleam => "String".to_string(),
Language::Zig => "[]const u8".to_string(),
},
s if s.contains("[&")
|| s.contains("[String")
|| s.contains("Vec<&")
|| s.contains("Vec<String")
|| s.contains("staticstr") =>
{
match lang {
Language::Python => "list[str]".to_string(),
Language::Node | Language::Wasm => "string[]".to_string(),
Language::Go => "[]string".to_string(),
Language::Java => "List<String>".to_string(),
Language::Csharp => "List<string>".to_string(),
Language::Ruby => "Array<String>".to_string(),
Language::Php => "array<string>".to_string(),
Language::Elixir => "list(String.t())".to_string(),
Language::R => "list".to_string(),
Language::Rust => s.to_string(),
Language::Ffi | Language::C | Language::Jni => "const char**".to_string(),
Language::Kotlin | Language::KotlinAndroid | Language::Swift | Language::Dart => {
"List<String>".to_string()
}
Language::Gleam => "List(String)".to_string(),
Language::Zig => "[]const []const u8".to_string(),
}
}
other => {
if lang == Language::Rust {
other.to_string()
} else {
type_name(other, lang, ffi_prefix)
}
}
}
})
.collect();
match lang {
Language::Python => format!("tuple[{}]", rendered.join(", ")),
Language::Node | Language::Wasm => format!("[{}]", rendered.join(", ")),
Language::Go => format!("({})", rendered.join(", ")),
Language::Java => format!("Tuple<{}>", rendered.join(", ")),
Language::Csharp => format!("({})", rendered.join(", ")),
Language::Ruby => format!("[{}]", rendered.join(", ")),
Language::Php => format!("array{{{}}}", rendered.join(", ")),
Language::Elixir => format!("{{{}}}", rendered.join(", ")),
Language::R => "list".to_string(),
Language::Rust => format!("({})", rendered.join(", ")),
Language::Ffi | Language::C | Language::Jni => "void*".to_string(),
Language::Kotlin | Language::KotlinAndroid => format!("Pair<{}>", rendered.join(", ")),
Language::Swift => format!("({})", rendered.join(", ")),
Language::Dart => format!("({})", rendered.join(", ")),
Language::Gleam => format!("#({})", rendered.join(", ")),
Language::Zig => format!("struct {{ {} }}", rendered.join(", ")),
}
}
TypeRef::Named(name) => type_name(name, lang, ffi_prefix),
TypeRef::Path => match lang {
Language::Python => "str".to_string(),
Language::Node | Language::Wasm => "string".to_string(),
Language::Go => "string".to_string(),
Language::Java => "String".to_string(),
Language::Csharp => "string".to_string(),
Language::Ruby => "String".to_string(),
Language::Php => "string".to_string(),
Language::Elixir => "String.t()".to_string(),
Language::R => "character".to_string(),
Language::Rust => "PathBuf".to_string(),
Language::Ffi | Language::C | Language::Jni => "const char*".to_string(),
Language::Kotlin | Language::KotlinAndroid => "Path".to_string(),
Language::Swift => "URL".to_string(),
Language::Dart => "String".to_string(),
Language::Gleam => "String".to_string(),
Language::Zig => "[:0]const u8".to_string(),
},
TypeRef::Unit => match lang {
Language::Python => "None".to_string(),
Language::Node | Language::Wasm => "void".to_string(),
Language::Go => "".to_string(),
Language::Java => "void".to_string(),
Language::Csharp => "void".to_string(),
Language::Ruby => "nil".to_string(),
Language::Php => "void".to_string(),
Language::Elixir => ":ok".to_string(),
Language::R => "NULL".to_string(),
Language::Rust => "()".to_string(),
Language::Ffi | Language::C | Language::Jni => "void".to_string(),
Language::Kotlin | Language::KotlinAndroid => "Unit".to_string(),
Language::Swift => "Void".to_string(),
Language::Dart => "void".to_string(),
Language::Gleam => "Nil".to_string(),
Language::Zig => "void".to_string(),
},
TypeRef::Json => match lang {
Language::Python => "dict[str, Any]".to_string(),
Language::Node | Language::Wasm => "unknown".to_string(),
Language::Go => "interface{}".to_string(),
Language::Java => "Object".to_string(),
Language::Csharp => "object".to_string(),
Language::Ruby => "Object".to_string(),
Language::Php => "mixed".to_string(),
Language::Elixir => "term()".to_string(),
Language::R => "list".to_string(),
Language::Rust => "serde_json::Value".to_string(),
Language::Ffi | Language::C | Language::Jni => "void*".to_string(),
Language::Kotlin | Language::KotlinAndroid => "Any".to_string(),
Language::Swift => "String".to_string(),
Language::Dart => "String".to_string(),
Language::Gleam => "String".to_string(),
Language::Zig => "[:0]const u8".to_string(),
},
TypeRef::Duration => match lang {
Language::Python => "float".to_string(),
Language::Node | Language::Wasm => "number".to_string(),
Language::Go => "time.Duration".to_string(),
Language::Java => "Duration".to_string(),
Language::Csharp => "TimeSpan".to_string(),
Language::Ruby => "Float".to_string(),
Language::Php => "float".to_string(),
Language::Elixir => "integer()".to_string(),
Language::R => "numeric".to_string(),
Language::Rust => "std::time::Duration".to_string(),
Language::Ffi | Language::C | Language::Jni => "uint64_t".to_string(),
Language::Kotlin | Language::KotlinAndroid => "Duration".to_string(),
Language::Swift => "Duration".to_string(),
Language::Dart => "Duration".to_string(),
Language::Gleam => "Int".to_string(),
Language::Zig => "i64".to_string(),
},
}
}
pub(crate) fn doc_primitive(p: &PrimitiveType, lang: Language) -> String {
match lang {
Language::Python => match p {
PrimitiveType::Bool => "bool".to_string(),
PrimitiveType::F32 | PrimitiveType::F64 => "float".to_string(),
_ => "int".to_string(),
},
Language::Node | Language::Wasm => match p {
PrimitiveType::Bool => "boolean".to_string(),
_ => "number".to_string(),
},
Language::Go => match p {
PrimitiveType::Bool => "bool".to_string(),
PrimitiveType::U8 => "uint8".to_string(),
PrimitiveType::U16 => "uint16".to_string(),
PrimitiveType::U32 => "uint32".to_string(),
PrimitiveType::U64 => "uint64".to_string(),
PrimitiveType::I8 => "int8".to_string(),
PrimitiveType::I16 => "int16".to_string(),
PrimitiveType::I32 => "int32".to_string(),
PrimitiveType::I64 => "int64".to_string(),
PrimitiveType::F32 => "float32".to_string(),
PrimitiveType::F64 => "float64".to_string(),
PrimitiveType::Usize | PrimitiveType::Isize => "int".to_string(),
},
Language::Java => match p {
PrimitiveType::Bool => "boolean".to_string(),
PrimitiveType::U8 | PrimitiveType::I8 => "byte".to_string(),
PrimitiveType::U16 | PrimitiveType::I16 => "short".to_string(),
PrimitiveType::U32 | PrimitiveType::I32 => "int".to_string(),
PrimitiveType::U64 | PrimitiveType::I64 | PrimitiveType::Usize | PrimitiveType::Isize => "long".to_string(),
PrimitiveType::F32 => "float".to_string(),
PrimitiveType::F64 => "double".to_string(),
},
Language::Csharp => match p {
PrimitiveType::Bool => "bool".to_string(),
PrimitiveType::U8 => "byte".to_string(),
PrimitiveType::U16 => "ushort".to_string(),
PrimitiveType::U32 => "uint".to_string(),
PrimitiveType::U64 => "ulong".to_string(),
PrimitiveType::I8 => "sbyte".to_string(),
PrimitiveType::I16 => "short".to_string(),
PrimitiveType::I32 => "int".to_string(),
PrimitiveType::I64 => "long".to_string(),
PrimitiveType::Usize => "nuint".to_string(),
PrimitiveType::Isize => "nint".to_string(),
PrimitiveType::F32 => "float".to_string(),
PrimitiveType::F64 => "double".to_string(),
},
Language::Ruby => match p {
PrimitiveType::Bool => "Boolean".to_string(),
PrimitiveType::F32 | PrimitiveType::F64 => "Float".to_string(),
_ => "Integer".to_string(),
},
Language::Php => match p {
PrimitiveType::Bool => "bool".to_string(),
PrimitiveType::F32 | PrimitiveType::F64 => "float".to_string(),
_ => "int".to_string(),
},
Language::Elixir => match p {
PrimitiveType::Bool => "boolean()".to_string(),
PrimitiveType::F32 | PrimitiveType::F64 => "float()".to_string(),
_ => "integer()".to_string(),
},
Language::R => match p {
PrimitiveType::Bool => "logical".to_string(),
PrimitiveType::F32 | PrimitiveType::F64 => "numeric".to_string(),
_ => "integer".to_string(),
},
Language::Ffi | Language::C | Language::Jni => match p {
PrimitiveType::Bool => "bool".to_string(),
PrimitiveType::U8 => "uint8_t".to_string(),
PrimitiveType::U16 => "uint16_t".to_string(),
PrimitiveType::U32 => "uint32_t".to_string(),
PrimitiveType::U64 => "uint64_t".to_string(),
PrimitiveType::I8 => "int8_t".to_string(),
PrimitiveType::I16 => "int16_t".to_string(),
PrimitiveType::I32 => "int32_t".to_string(),
PrimitiveType::I64 => "int64_t".to_string(),
PrimitiveType::Usize => "uintptr_t".to_string(),
PrimitiveType::Isize => "intptr_t".to_string(),
PrimitiveType::F32 => "float".to_string(),
PrimitiveType::F64 => "double".to_string(),
},
Language::Rust => match p {
PrimitiveType::Bool => "bool".to_string(),
PrimitiveType::U8 => "u8".to_string(),
PrimitiveType::U16 => "u16".to_string(),
PrimitiveType::U32 => "u32".to_string(),
PrimitiveType::U64 => "u64".to_string(),
PrimitiveType::I8 => "i8".to_string(),
PrimitiveType::I16 => "i16".to_string(),
PrimitiveType::I32 => "i32".to_string(),
PrimitiveType::I64 => "i64".to_string(),
PrimitiveType::Usize => "usize".to_string(),
PrimitiveType::Isize => "isize".to_string(),
PrimitiveType::F32 => "f32".to_string(),
PrimitiveType::F64 => "f64".to_string(),
},
Language::Kotlin | Language::KotlinAndroid => match p {
PrimitiveType::Bool => "Boolean".to_string(),
PrimitiveType::U8 | PrimitiveType::I8 => "Byte".to_string(),
PrimitiveType::U16 | PrimitiveType::I16 => "Short".to_string(),
PrimitiveType::U32 | PrimitiveType::I32 => "Int".to_string(),
PrimitiveType::U64 | PrimitiveType::I64 | PrimitiveType::Usize | PrimitiveType::Isize => "Long".to_string(),
PrimitiveType::F32 => "Float".to_string(),
PrimitiveType::F64 => "Double".to_string(),
},
Language::Swift => match p {
PrimitiveType::Bool => "Bool".to_string(),
PrimitiveType::U8 => "UInt8".to_string(),
PrimitiveType::U16 => "UInt16".to_string(),
PrimitiveType::U32 => "UInt32".to_string(),
PrimitiveType::U64 | PrimitiveType::Usize => "UInt64".to_string(),
PrimitiveType::I8 => "Int8".to_string(),
PrimitiveType::I16 => "Int16".to_string(),
PrimitiveType::I32 => "Int32".to_string(),
PrimitiveType::I64 | PrimitiveType::Isize => "Int64".to_string(),
PrimitiveType::F32 => "Float".to_string(),
PrimitiveType::F64 => "Double".to_string(),
},
Language::Dart => match p {
PrimitiveType::Bool => "bool".to_string(),
PrimitiveType::F32 | PrimitiveType::F64 => "double".to_string(),
_ => "int".to_string(),
},
Language::Gleam => match p {
PrimitiveType::Bool => "Bool".to_string(),
PrimitiveType::F32 | PrimitiveType::F64 => "Float".to_string(),
_ => "Int".to_string(),
},
Language::Zig => match p {
PrimitiveType::Bool => "bool".to_string(),
PrimitiveType::U8 => "u8".to_string(),
PrimitiveType::U16 => "u16".to_string(),
PrimitiveType::U32 => "u32".to_string(),
PrimitiveType::U64 => "u64".to_string(),
PrimitiveType::I8 => "i8".to_string(),
PrimitiveType::I16 => "i16".to_string(),
PrimitiveType::I32 => "i32".to_string(),
PrimitiveType::I64 => "i64".to_string(),
PrimitiveType::Usize => "u64".to_string(),
PrimitiveType::Isize => "i64".to_string(),
PrimitiveType::F32 => "f32".to_string(),
PrimitiveType::F64 => "f64".to_string(),
},
}
}
pub(crate) fn java_boxed_type(ty: &TypeRef) -> String {
match ty {
TypeRef::Primitive(p) => match p {
PrimitiveType::Bool => "Boolean".to_string(),
PrimitiveType::U8 | PrimitiveType::I8 => "Byte".to_string(),
PrimitiveType::U16 | PrimitiveType::I16 => "Short".to_string(),
PrimitiveType::U32 | PrimitiveType::I32 => "Integer".to_string(),
PrimitiveType::U64 | PrimitiveType::I64 | PrimitiveType::Usize | PrimitiveType::Isize => "Long".to_string(),
PrimitiveType::F32 => "Float".to_string(),
PrimitiveType::F64 => "Double".to_string(),
},
_ => doc_type(ty, Language::Java, ""),
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::config::Language;
use crate::docs::test_helpers::TEST_PREFIX;
#[test]
fn test_doc_type_string() {
assert_eq!(doc_type(&TypeRef::String, Language::Python, TEST_PREFIX), "str");
assert_eq!(doc_type(&TypeRef::String, Language::Node, TEST_PREFIX), "string");
assert_eq!(doc_type(&TypeRef::String, Language::Java, TEST_PREFIX), "String");
assert_eq!(doc_type(&TypeRef::String, Language::Ffi, TEST_PREFIX), "const char*");
}
#[test]
fn test_doc_type_optional() {
let ty = TypeRef::Optional(Box::new(TypeRef::String));
assert_eq!(doc_type(&ty, Language::Python, TEST_PREFIX), "str | None");
assert_eq!(doc_type(&ty, Language::Node, TEST_PREFIX), "string | null");
assert_eq!(doc_type(&ty, Language::Go, TEST_PREFIX), "*string");
assert_eq!(doc_type(&ty, Language::Csharp, TEST_PREFIX), "string?");
}
#[test]
fn test_doc_type_vec() {
let ty = TypeRef::Vec(Box::new(TypeRef::String));
assert_eq!(doc_type(&ty, Language::Python, TEST_PREFIX), "list[str]");
assert_eq!(doc_type(&ty, Language::Node, TEST_PREFIX), "Array<string>");
assert_eq!(doc_type(&ty, Language::Go, TEST_PREFIX), "[]string");
assert_eq!(doc_type(&ty, Language::Java, TEST_PREFIX), "List<String>");
}
#[test]
fn test_doc_type_primitives() {
assert_eq!(
doc_type(&TypeRef::Primitive(PrimitiveType::Bool), Language::Python, TEST_PREFIX),
"bool"
);
assert_eq!(
doc_type(&TypeRef::Primitive(PrimitiveType::Bool), Language::Node, TEST_PREFIX),
"boolean"
);
assert_eq!(
doc_type(&TypeRef::Primitive(PrimitiveType::U64), Language::Node, TEST_PREFIX),
"number"
);
assert_eq!(
doc_type(&TypeRef::Primitive(PrimitiveType::F64), Language::Python, TEST_PREFIX),
"float"
);
assert_eq!(
doc_type(&TypeRef::Primitive(PrimitiveType::U32), Language::Ffi, TEST_PREFIX),
"uint32_t"
);
}
#[test]
fn test_doc_type_rust_static_str_in_named_tuple() {
let ty = TypeRef::Named("(&'static str)".to_string());
assert_eq!(doc_type(&ty, Language::Rust, TEST_PREFIX), "(&'static str)");
}
#[test]
fn test_doc_type_named_static_str_renders_correctly_for_non_rust() {
let ty = TypeRef::Named("(&'static str, u32)".to_string());
assert_eq!(doc_type(&ty, Language::Python, TEST_PREFIX), "tuple[str, int]");
assert_eq!(doc_type(&ty, Language::Node, TEST_PREFIX), "[string, number]");
}
#[test]
fn test_doc_type_static_slice_in_tuple_element_rust() {
let ty = TypeRef::Named("(&'static [&'static str], u32)".to_string());
assert_eq!(doc_type(&ty, Language::Python, TEST_PREFIX), "tuple[list[str], int]");
assert_eq!(doc_type(&ty, Language::Go, TEST_PREFIX), "([]string, int)");
}
#[test]
fn test_doc_type_char_maps_like_string() {
for lang in [
Language::Python,
Language::Node,
Language::Go,
Language::Java,
Language::Csharp,
Language::Ruby,
Language::Php,
Language::Elixir,
Language::R,
Language::Rust,
Language::Ffi,
] {
assert_eq!(
doc_type(&TypeRef::Char, lang, TEST_PREFIX),
doc_type(&TypeRef::String, lang, TEST_PREFIX),
"Char != String for {lang:?}"
);
}
}
#[test]
fn test_doc_type_bytes_all_languages() {
assert_eq!(doc_type(&TypeRef::Bytes, Language::Python, TEST_PREFIX), "bytes");
assert_eq!(doc_type(&TypeRef::Bytes, Language::Node, TEST_PREFIX), "Buffer");
assert_eq!(doc_type(&TypeRef::Bytes, Language::Go, TEST_PREFIX), "[]byte");
assert_eq!(doc_type(&TypeRef::Bytes, Language::Java, TEST_PREFIX), "byte[]");
assert_eq!(doc_type(&TypeRef::Bytes, Language::Csharp, TEST_PREFIX), "byte[]");
assert_eq!(doc_type(&TypeRef::Bytes, Language::Ruby, TEST_PREFIX), "String");
assert_eq!(doc_type(&TypeRef::Bytes, Language::Rust, TEST_PREFIX), "Vec<u8>");
assert_eq!(doc_type(&TypeRef::Bytes, Language::Ffi, TEST_PREFIX), "const uint8_t*");
assert_eq!(doc_type(&TypeRef::Bytes, Language::Kotlin, TEST_PREFIX), "ByteArray");
assert_eq!(doc_type(&TypeRef::Bytes, Language::Swift, TEST_PREFIX), "Data");
assert_eq!(doc_type(&TypeRef::Bytes, Language::Dart, TEST_PREFIX), "Uint8List");
assert_eq!(doc_type(&TypeRef::Bytes, Language::Gleam, TEST_PREFIX), "BitArray");
assert_eq!(doc_type(&TypeRef::Bytes, Language::Zig, TEST_PREFIX), "[]const u8");
}
#[test]
fn test_doc_type_string_kotlin_gleam_zig() {
assert_eq!(doc_type(&TypeRef::String, Language::Kotlin, TEST_PREFIX), "String");
assert_eq!(doc_type(&TypeRef::String, Language::Gleam, TEST_PREFIX), "String");
assert_eq!(doc_type(&TypeRef::String, Language::Zig, TEST_PREFIX), "[:0]const u8");
}
#[test]
fn test_doc_type_unit_all_languages() {
assert_eq!(doc_type(&TypeRef::Unit, Language::Python, TEST_PREFIX), "None");
assert_eq!(doc_type(&TypeRef::Unit, Language::Node, TEST_PREFIX), "void");
assert_eq!(doc_type(&TypeRef::Unit, Language::Go, TEST_PREFIX), "");
assert_eq!(doc_type(&TypeRef::Unit, Language::Java, TEST_PREFIX), "void");
assert_eq!(doc_type(&TypeRef::Unit, Language::Csharp, TEST_PREFIX), "void");
assert_eq!(doc_type(&TypeRef::Unit, Language::Ruby, TEST_PREFIX), "nil");
assert_eq!(doc_type(&TypeRef::Unit, Language::Php, TEST_PREFIX), "void");
assert_eq!(doc_type(&TypeRef::Unit, Language::Elixir, TEST_PREFIX), ":ok");
assert_eq!(doc_type(&TypeRef::Unit, Language::R, TEST_PREFIX), "NULL");
assert_eq!(doc_type(&TypeRef::Unit, Language::Rust, TEST_PREFIX), "()");
assert_eq!(doc_type(&TypeRef::Unit, Language::Ffi, TEST_PREFIX), "void");
assert_eq!(doc_type(&TypeRef::Unit, Language::Kotlin, TEST_PREFIX), "Unit");
assert_eq!(doc_type(&TypeRef::Unit, Language::Gleam, TEST_PREFIX), "Nil");
assert_eq!(doc_type(&TypeRef::Unit, Language::Zig, TEST_PREFIX), "void");
}
#[test]
fn test_doc_type_path_all_languages() {
assert_eq!(doc_type(&TypeRef::Path, Language::Python, TEST_PREFIX), "str");
assert_eq!(doc_type(&TypeRef::Path, Language::Node, TEST_PREFIX), "string");
assert_eq!(doc_type(&TypeRef::Path, Language::Go, TEST_PREFIX), "string");
assert_eq!(doc_type(&TypeRef::Path, Language::Java, TEST_PREFIX), "String");
assert_eq!(doc_type(&TypeRef::Path, Language::Csharp, TEST_PREFIX), "string");
assert_eq!(doc_type(&TypeRef::Path, Language::Ruby, TEST_PREFIX), "String");
assert_eq!(doc_type(&TypeRef::Path, Language::Php, TEST_PREFIX), "string");
assert_eq!(doc_type(&TypeRef::Path, Language::Elixir, TEST_PREFIX), "String.t()");
assert_eq!(doc_type(&TypeRef::Path, Language::R, TEST_PREFIX), "character");
assert_eq!(doc_type(&TypeRef::Path, Language::Rust, TEST_PREFIX), "PathBuf");
assert_eq!(doc_type(&TypeRef::Path, Language::Ffi, TEST_PREFIX), "const char*");
assert_eq!(doc_type(&TypeRef::Path, Language::Kotlin, TEST_PREFIX), "Path");
assert_eq!(doc_type(&TypeRef::Path, Language::Gleam, TEST_PREFIX), "String");
assert_eq!(doc_type(&TypeRef::Path, Language::Zig, TEST_PREFIX), "[:0]const u8");
}
#[test]
fn test_doc_type_json_all_languages() {
assert_eq!(
doc_type(&TypeRef::Json, Language::Python, TEST_PREFIX),
"dict[str, Any]"
);
assert_eq!(doc_type(&TypeRef::Json, Language::Node, TEST_PREFIX), "unknown");
assert_eq!(doc_type(&TypeRef::Json, Language::Go, TEST_PREFIX), "interface{}");
assert_eq!(doc_type(&TypeRef::Json, Language::Java, TEST_PREFIX), "Object");
assert_eq!(doc_type(&TypeRef::Json, Language::Csharp, TEST_PREFIX), "object");
assert_eq!(doc_type(&TypeRef::Json, Language::Ruby, TEST_PREFIX), "Object");
assert_eq!(doc_type(&TypeRef::Json, Language::Php, TEST_PREFIX), "mixed");
assert_eq!(doc_type(&TypeRef::Json, Language::Elixir, TEST_PREFIX), "term()");
assert_eq!(doc_type(&TypeRef::Json, Language::R, TEST_PREFIX), "list");
assert_eq!(
doc_type(&TypeRef::Json, Language::Rust, TEST_PREFIX),
"serde_json::Value"
);
assert_eq!(doc_type(&TypeRef::Json, Language::Ffi, TEST_PREFIX), "void*");
assert_eq!(doc_type(&TypeRef::Json, Language::Kotlin, TEST_PREFIX), "Any");
assert_eq!(doc_type(&TypeRef::Json, Language::Swift, TEST_PREFIX), "String");
assert_eq!(doc_type(&TypeRef::Json, Language::Dart, TEST_PREFIX), "String");
assert_eq!(doc_type(&TypeRef::Json, Language::Gleam, TEST_PREFIX), "String");
assert_eq!(doc_type(&TypeRef::Json, Language::Zig, TEST_PREFIX), "[:0]const u8");
}
#[test]
fn test_doc_type_duration_all_languages() {
assert_eq!(doc_type(&TypeRef::Duration, Language::Python, TEST_PREFIX), "float");
assert_eq!(doc_type(&TypeRef::Duration, Language::Node, TEST_PREFIX), "number");
assert_eq!(doc_type(&TypeRef::Duration, Language::Go, TEST_PREFIX), "time.Duration");
assert_eq!(doc_type(&TypeRef::Duration, Language::Java, TEST_PREFIX), "Duration");
assert_eq!(doc_type(&TypeRef::Duration, Language::Csharp, TEST_PREFIX), "TimeSpan");
assert_eq!(doc_type(&TypeRef::Duration, Language::Ruby, TEST_PREFIX), "Float");
assert_eq!(doc_type(&TypeRef::Duration, Language::Php, TEST_PREFIX), "float");
assert_eq!(doc_type(&TypeRef::Duration, Language::Elixir, TEST_PREFIX), "integer()");
assert_eq!(doc_type(&TypeRef::Duration, Language::R, TEST_PREFIX), "numeric");
assert_eq!(
doc_type(&TypeRef::Duration, Language::Rust, TEST_PREFIX),
"std::time::Duration"
);
assert_eq!(doc_type(&TypeRef::Duration, Language::Ffi, TEST_PREFIX), "uint64_t");
assert_eq!(doc_type(&TypeRef::Duration, Language::Kotlin, TEST_PREFIX), "Duration");
assert_eq!(doc_type(&TypeRef::Duration, Language::Swift, TEST_PREFIX), "Duration");
assert_eq!(doc_type(&TypeRef::Duration, Language::Dart, TEST_PREFIX), "Duration");
assert_eq!(doc_type(&TypeRef::Duration, Language::Gleam, TEST_PREFIX), "Int");
assert_eq!(doc_type(&TypeRef::Duration, Language::Zig, TEST_PREFIX), "i64");
}
#[test]
fn test_doc_type_swift_dart_vec_and_map() {
let vec_string = TypeRef::Vec(Box::new(TypeRef::String));
assert_eq!(doc_type(&vec_string, Language::Swift, TEST_PREFIX), "[String]");
assert_eq!(doc_type(&vec_string, Language::Dart, TEST_PREFIX), "List<String>");
let map = TypeRef::Map(Box::new(TypeRef::String), Box::new(TypeRef::String));
assert_eq!(doc_type(&map, Language::Swift, TEST_PREFIX), "[String: String]");
assert_eq!(doc_type(&map, Language::Dart, TEST_PREFIX), "Map<String, String>");
}
#[test]
fn test_doc_type_swift_dart_path_and_unit() {
assert_eq!(doc_type(&TypeRef::Path, Language::Swift, TEST_PREFIX), "URL");
assert_eq!(doc_type(&TypeRef::Path, Language::Dart, TEST_PREFIX), "String");
assert_eq!(doc_type(&TypeRef::Unit, Language::Swift, TEST_PREFIX), "Void");
assert_eq!(doc_type(&TypeRef::Unit, Language::Dart, TEST_PREFIX), "void");
}
#[test]
fn test_doc_type_named_strips_module_path() {
let ty = TypeRef::Named("my_crate::types::OutputFormat".to_string());
assert_eq!(doc_type(&ty, Language::Python, TEST_PREFIX), "OutputFormat");
assert_eq!(doc_type(&ty, Language::Java, TEST_PREFIX), "OutputFormat");
assert_eq!(doc_type(&ty, Language::Go, TEST_PREFIX), "OutputFormat");
assert_eq!(doc_type(&ty, Language::Rust, TEST_PREFIX), "OutputFormat");
assert_eq!(doc_type(&ty, Language::Ffi, TEST_PREFIX), "HtmOutputFormat");
}
#[test]
fn test_doc_type_named_without_path() {
let ty = TypeRef::Named("ParseOptions".to_string());
assert_eq!(doc_type(&ty, Language::Python, TEST_PREFIX), "ParseOptions");
assert_eq!(doc_type(&ty, Language::Node, TEST_PREFIX), "ParseOptions");
assert_eq!(doc_type(&ty, Language::Ffi, TEST_PREFIX), "HtmParseOptions");
}
#[test]
fn test_doc_type_map_string_to_string_all_languages() {
let ty = TypeRef::Map(Box::new(TypeRef::String), Box::new(TypeRef::String));
assert_eq!(doc_type(&ty, Language::Python, TEST_PREFIX), "dict[str, str]");
assert_eq!(doc_type(&ty, Language::Node, TEST_PREFIX), "Record<string, string>");
assert_eq!(doc_type(&ty, Language::Go, TEST_PREFIX), "map[string]string");
assert_eq!(doc_type(&ty, Language::Java, TEST_PREFIX), "Map<String, String>");
assert_eq!(
doc_type(&ty, Language::Csharp, TEST_PREFIX),
"Dictionary<string, string>"
);
assert_eq!(doc_type(&ty, Language::Ruby, TEST_PREFIX), "Hash{String=>String}");
assert_eq!(doc_type(&ty, Language::Php, TEST_PREFIX), "array<string, string>");
assert_eq!(doc_type(&ty, Language::Elixir, TEST_PREFIX), "map()");
assert_eq!(doc_type(&ty, Language::R, TEST_PREFIX), "list");
assert_eq!(doc_type(&ty, Language::Rust, TEST_PREFIX), "HashMap<String, String>");
assert_eq!(doc_type(&ty, Language::Ffi, TEST_PREFIX), "void*");
}
#[test]
fn test_doc_type_map_with_primitive_value_java_boxes() {
let ty = TypeRef::Map(
Box::new(TypeRef::String),
Box::new(TypeRef::Primitive(PrimitiveType::I32)),
);
assert_eq!(doc_type(&ty, Language::Java, TEST_PREFIX), "Map<String, Integer>");
assert_eq!(doc_type(&ty, Language::Python, TEST_PREFIX), "dict[str, int]");
assert_eq!(doc_type(&ty, Language::Rust, TEST_PREFIX), "HashMap<String, i32>");
}
#[test]
fn test_doc_type_nested_vec_of_optional_string() {
let ty = TypeRef::Vec(Box::new(TypeRef::Optional(Box::new(TypeRef::String))));
assert_eq!(doc_type(&ty, Language::Python, TEST_PREFIX), "list[str | None]");
assert_eq!(doc_type(&ty, Language::Node, TEST_PREFIX), "Array<string | null>");
assert_eq!(doc_type(&ty, Language::Go, TEST_PREFIX), "[]*string");
assert_eq!(doc_type(&ty, Language::Java, TEST_PREFIX), "List<Optional<String>>");
assert_eq!(doc_type(&ty, Language::Rust, TEST_PREFIX), "Vec<Option<String>>");
}
#[test]
fn test_doc_type_nested_map_string_to_vec_u32() {
let ty = TypeRef::Map(
Box::new(TypeRef::String),
Box::new(TypeRef::Vec(Box::new(TypeRef::Primitive(PrimitiveType::U32)))),
);
assert_eq!(doc_type(&ty, Language::Python, TEST_PREFIX), "dict[str, list[int]]");
assert_eq!(
doc_type(&ty, Language::Node, TEST_PREFIX),
"Record<string, Array<number>>"
);
assert_eq!(doc_type(&ty, Language::Go, TEST_PREFIX), "map[string][]uint32");
assert_eq!(doc_type(&ty, Language::Java, TEST_PREFIX), "Map<String, List<Integer>>");
assert_eq!(doc_type(&ty, Language::Rust, TEST_PREFIX), "HashMap<String, Vec<u32>>");
}
#[test]
fn test_doc_type_optional_of_named_all_languages() {
let ty = TypeRef::Optional(Box::new(TypeRef::Named("ParseOptions".to_string())));
assert_eq!(doc_type(&ty, Language::Python, TEST_PREFIX), "ParseOptions | None");
assert_eq!(doc_type(&ty, Language::Java, TEST_PREFIX), "Optional<ParseOptions>");
assert_eq!(doc_type(&ty, Language::Csharp, TEST_PREFIX), "ParseOptions?");
assert_eq!(doc_type(&ty, Language::Go, TEST_PREFIX), "*ParseOptions");
assert_eq!(doc_type(&ty, Language::Rust, TEST_PREFIX), "Option<ParseOptions>");
assert_eq!(doc_type(&ty, Language::Ruby, TEST_PREFIX), "ParseOptions?");
assert_eq!(doc_type(&ty, Language::Php, TEST_PREFIX), "?ParseOptions");
assert_eq!(doc_type(&ty, Language::Elixir, TEST_PREFIX), "ParseOptions | nil");
assert_eq!(doc_type(&ty, Language::R, TEST_PREFIX), "ParseOptions or NULL");
}
#[test]
fn test_doc_type_all_go_primitives() {
let cases: &[(PrimitiveType, &str)] = &[
(PrimitiveType::Bool, "bool"),
(PrimitiveType::U8, "uint8"),
(PrimitiveType::U16, "uint16"),
(PrimitiveType::U32, "uint32"),
(PrimitiveType::U64, "uint64"),
(PrimitiveType::I8, "int8"),
(PrimitiveType::I16, "int16"),
(PrimitiveType::I32, "int32"),
(PrimitiveType::I64, "int64"),
(PrimitiveType::F32, "float32"),
(PrimitiveType::F64, "float64"),
(PrimitiveType::Usize, "int"),
(PrimitiveType::Isize, "int"),
];
for (prim, expected) in cases {
assert_eq!(
doc_type(&TypeRef::Primitive(prim.clone()), Language::Go, TEST_PREFIX),
*expected,
"Go primitive {prim:?}"
);
}
}
#[test]
fn test_doc_type_all_java_primitives() {
let cases: &[(PrimitiveType, &str)] = &[
(PrimitiveType::Bool, "boolean"),
(PrimitiveType::U8, "byte"),
(PrimitiveType::I8, "byte"),
(PrimitiveType::U16, "short"),
(PrimitiveType::I16, "short"),
(PrimitiveType::U32, "int"),
(PrimitiveType::I32, "int"),
(PrimitiveType::U64, "long"),
(PrimitiveType::I64, "long"),
(PrimitiveType::Usize, "long"),
(PrimitiveType::Isize, "long"),
(PrimitiveType::F32, "float"),
(PrimitiveType::F64, "double"),
];
for (prim, expected) in cases {
assert_eq!(
doc_type(&TypeRef::Primitive(prim.clone()), Language::Java, TEST_PREFIX),
*expected,
"Java primitive {prim:?}"
);
}
}
#[test]
fn test_doc_type_all_csharp_primitives() {
let cases: &[(PrimitiveType, &str)] = &[
(PrimitiveType::Bool, "bool"),
(PrimitiveType::U8, "byte"),
(PrimitiveType::U16, "ushort"),
(PrimitiveType::U32, "uint"),
(PrimitiveType::U64, "ulong"),
(PrimitiveType::I8, "sbyte"),
(PrimitiveType::I16, "short"),
(PrimitiveType::I32, "int"),
(PrimitiveType::I64, "long"),
(PrimitiveType::Usize, "nuint"),
(PrimitiveType::Isize, "nint"),
(PrimitiveType::F32, "float"),
(PrimitiveType::F64, "double"),
];
for (prim, expected) in cases {
assert_eq!(
doc_type(&TypeRef::Primitive(prim.clone()), Language::Csharp, TEST_PREFIX),
*expected,
"C# primitive {prim:?}"
);
}
}
#[test]
fn test_doc_type_all_rust_primitives() {
let cases: &[(PrimitiveType, &str)] = &[
(PrimitiveType::Bool, "bool"),
(PrimitiveType::U8, "u8"),
(PrimitiveType::U16, "u16"),
(PrimitiveType::U32, "u32"),
(PrimitiveType::U64, "u64"),
(PrimitiveType::I8, "i8"),
(PrimitiveType::I16, "i16"),
(PrimitiveType::I32, "i32"),
(PrimitiveType::I64, "i64"),
(PrimitiveType::Usize, "usize"),
(PrimitiveType::Isize, "isize"),
(PrimitiveType::F32, "f32"),
(PrimitiveType::F64, "f64"),
];
for (prim, expected) in cases {
assert_eq!(
doc_type(&TypeRef::Primitive(prim.clone()), Language::Rust, TEST_PREFIX),
*expected,
"Rust primitive {prim:?}"
);
}
}
#[test]
fn test_doc_type_all_ffi_primitives() {
let cases: &[(PrimitiveType, &str)] = &[
(PrimitiveType::Bool, "bool"),
(PrimitiveType::U8, "uint8_t"),
(PrimitiveType::U16, "uint16_t"),
(PrimitiveType::U32, "uint32_t"),
(PrimitiveType::U64, "uint64_t"),
(PrimitiveType::I8, "int8_t"),
(PrimitiveType::I16, "int16_t"),
(PrimitiveType::I32, "int32_t"),
(PrimitiveType::I64, "int64_t"),
(PrimitiveType::Usize, "uintptr_t"),
(PrimitiveType::Isize, "intptr_t"),
(PrimitiveType::F32, "float"),
(PrimitiveType::F64, "double"),
];
for (prim, expected) in cases {
assert_eq!(
doc_type(&TypeRef::Primitive(prim.clone()), Language::Ffi, TEST_PREFIX),
*expected,
"FFI primitive {prim:?}"
);
}
}
#[test]
fn test_doc_type_all_kotlin_primitives() {
let cases: &[(PrimitiveType, &str)] = &[
(PrimitiveType::Bool, "Boolean"),
(PrimitiveType::U8, "Byte"),
(PrimitiveType::I8, "Byte"),
(PrimitiveType::U16, "Short"),
(PrimitiveType::I16, "Short"),
(PrimitiveType::U32, "Int"),
(PrimitiveType::I32, "Int"),
(PrimitiveType::U64, "Long"),
(PrimitiveType::I64, "Long"),
(PrimitiveType::Usize, "Long"),
(PrimitiveType::Isize, "Long"),
(PrimitiveType::F32, "Float"),
(PrimitiveType::F64, "Double"),
];
for (prim, expected) in cases {
assert_eq!(
doc_type(&TypeRef::Primitive(prim.clone()), Language::Kotlin, TEST_PREFIX),
*expected,
"Kotlin primitive {prim:?}"
);
}
}
#[test]
fn test_doc_type_all_gleam_primitives() {
let cases: &[(PrimitiveType, &str)] = &[
(PrimitiveType::Bool, "Bool"),
(PrimitiveType::U8, "Int"),
(PrimitiveType::U64, "Int"),
(PrimitiveType::I32, "Int"),
(PrimitiveType::Usize, "Int"),
(PrimitiveType::F32, "Float"),
(PrimitiveType::F64, "Float"),
];
for (prim, expected) in cases {
assert_eq!(
doc_type(&TypeRef::Primitive(prim.clone()), Language::Gleam, TEST_PREFIX),
*expected,
"Gleam primitive {prim:?}"
);
}
}
#[test]
fn test_doc_type_all_zig_primitives() {
let cases: &[(PrimitiveType, &str)] = &[
(PrimitiveType::Bool, "bool"),
(PrimitiveType::U8, "u8"),
(PrimitiveType::U16, "u16"),
(PrimitiveType::U32, "u32"),
(PrimitiveType::U64, "u64"),
(PrimitiveType::I8, "i8"),
(PrimitiveType::I16, "i16"),
(PrimitiveType::I32, "i32"),
(PrimitiveType::I64, "i64"),
(PrimitiveType::Usize, "u64"),
(PrimitiveType::Isize, "i64"),
(PrimitiveType::F32, "f32"),
(PrimitiveType::F64, "f64"),
];
for (prim, expected) in cases {
assert_eq!(
doc_type(&TypeRef::Primitive(prim.clone()), Language::Zig, TEST_PREFIX),
*expected,
"Zig primitive {prim:?}"
);
}
}
#[test]
fn test_java_boxed_type_all_primitives() {
let cases: &[(PrimitiveType, &str)] = &[
(PrimitiveType::Bool, "Boolean"),
(PrimitiveType::U8, "Byte"),
(PrimitiveType::I8, "Byte"),
(PrimitiveType::U16, "Short"),
(PrimitiveType::I16, "Short"),
(PrimitiveType::U32, "Integer"),
(PrimitiveType::I32, "Integer"),
(PrimitiveType::U64, "Long"),
(PrimitiveType::I64, "Long"),
(PrimitiveType::Usize, "Long"),
(PrimitiveType::Isize, "Long"),
(PrimitiveType::F32, "Float"),
(PrimitiveType::F64, "Double"),
];
for (prim, expected) in cases {
assert_eq!(
java_boxed_type(&TypeRef::Primitive(prim.clone())),
*expected,
"boxed Java type for {prim:?}"
);
}
}
#[test]
fn test_java_boxed_type_non_primitives_delegate_to_java_doc_type() {
assert_eq!(java_boxed_type(&TypeRef::String), "String");
assert_eq!(java_boxed_type(&TypeRef::Bytes), "byte[]");
assert_eq!(
java_boxed_type(&TypeRef::Named("ParseOptions".to_string())),
"ParseOptions"
);
assert_eq!(java_boxed_type(&TypeRef::Duration), "Duration");
}
}