use crate::builtin::derive_common::{
collection_element_type, is_primitive_type, standalone_fn_name, type_has_derive,
};
use crate::ts_syn::abi::ir::type_registry::{ResolvedTypeRef, TypeRegistry};
use super::types::EqField;
pub fn generate_field_equality_for_interface(
field: &EqField,
self_var: &str,
other_var: &str,
resolved: Option<&ResolvedTypeRef>,
registry: Option<&TypeRegistry>,
) -> String {
let field_name = &field.name;
let ts_type = &field.ts_type;
if let (Some(resolved), Some(registry)) = (resolved, registry) {
if !resolved.is_collection
&& resolved.registry_key.is_some()
&& type_has_derive(registry, &resolved.base_type_name, "PartialEq")
{
let fn_name = standalone_fn_name(&resolved.base_type_name, "Equals");
return format!("{fn_name}({self_var}.{field_name}, {other_var}.{field_name})");
}
if resolved.is_collection
&& let Some(elem) = collection_element_type(resolved)
&& elem.registry_key.is_some()
&& type_has_derive(registry, &elem.base_type_name, "PartialEq")
{
let elem_fn = standalone_fn_name(&elem.base_type_name, "Equals");
let base = resolved.base_type_name.as_str();
match base {
"Map" => {
return format!(
"({self_var}.{field_name} instanceof Map && {other_var}.{field_name} instanceof Map && \
{self_var}.{field_name}.size === {other_var}.{field_name}.size && \
Array.from({self_var}.{field_name}.entries()).every(([k, v]) => \
{other_var}.{field_name}.has(k) && \
{elem_fn}(v, {other_var}.{field_name}.get(k))))"
);
}
"Set" => {
}
_ => {
return format!(
"(Array.isArray({self_var}.{field_name}) && Array.isArray({other_var}.{field_name}) && \
{self_var}.{field_name}.length === {other_var}.{field_name}.length && \
{self_var}.{field_name}.every((v, i) => \
{elem_fn}(v, {other_var}.{field_name}[i])))"
);
}
}
}
}
if is_primitive_type(ts_type) {
format!("{self_var}.{field_name} === {other_var}.{field_name}")
} else if ts_type.ends_with("[]")
|| ts_type.starts_with("Array<")
|| ts_type.starts_with("ReadonlyArray<")
{
format!(
"(Array.isArray({self_var}.{field_name}) && Array.isArray({other_var}.{field_name}) && \
{self_var}.{field_name}.length === {other_var}.{field_name}.length && \
{self_var}.{field_name}.every((v, i) => \
typeof (v as any)?.equals === 'function' \
? (v as any).equals({other_var}.{field_name}[i]) \
: v === {other_var}.{field_name}[i]))"
)
} else if ts_type == "Date" {
format!(
"({self_var}.{field_name} instanceof Date && {other_var}.{field_name} instanceof Date \
? {self_var}.{field_name}.getTime() === {other_var}.{field_name}.getTime() \
: {self_var}.{field_name} === {other_var}.{field_name})"
)
} else if ts_type == "RegExp" {
format!(
"({self_var}.{field_name}.source === {other_var}.{field_name}.source && \
{self_var}.{field_name}.flags === {other_var}.{field_name}.flags)"
)
} else if ts_type == "URL" {
format!("{self_var}.{field_name}.href === {other_var}.{field_name}.href")
} else if ts_type == "URLSearchParams" {
format!("{self_var}.{field_name}.toString() === {other_var}.{field_name}.toString()")
} else if matches!(
ts_type.as_str(),
"Uint8Array"
| "Int8Array"
| "Uint16Array"
| "Int16Array"
| "Uint32Array"
| "Int32Array"
| "Float32Array"
| "Float64Array"
| "BigInt64Array"
| "BigUint64Array"
| "Uint8ClampedArray"
) {
format!(
"({self_var}.{field_name}.length === {other_var}.{field_name}.length && \
{self_var}.{field_name}.every((v, i) => v === {other_var}.{field_name}[i]))"
)
} else if ts_type == "ArrayBuffer" || ts_type == "SharedArrayBuffer" {
format!(
"(new Uint8Array({self_var}.{field_name}).every((v, i) => \
v === new Uint8Array({other_var}.{field_name})[i]))"
)
} else if matches!(
ts_type.as_str(),
"Error"
| "TypeError"
| "RangeError"
| "SyntaxError"
| "ReferenceError"
| "URIError"
| "EvalError"
) {
format!(
"({self_var}.{field_name}.message === {other_var}.{field_name}.message && \
{self_var}.{field_name}.constructor === {other_var}.{field_name}.constructor)"
)
} else if ts_type.starts_with("Map<") {
format!(
"({self_var}.{field_name} instanceof Map && {other_var}.{field_name} instanceof Map && \
{self_var}.{field_name}.size === {other_var}.{field_name}.size && \
Array.from({self_var}.{field_name}.entries()).every(([k, v]) => \
{other_var}.{field_name}.has(k) && \
(typeof (v as any)?.equals === 'function' \
? (v as any).equals({other_var}.{field_name}.get(k)) \
: v === {other_var}.{field_name}.get(k))))"
)
} else if ts_type.starts_with("Set<") {
format!(
"({self_var}.{field_name} instanceof Set && {other_var}.{field_name} instanceof Set && \
{self_var}.{field_name}.size === {other_var}.{field_name}.size && \
Array.from({self_var}.{field_name}).every(v => {other_var}.{field_name}.has(v)))"
)
} else {
format!(
"(typeof ({self_var}.{field_name} as any)?.equals === 'function' \
? ({self_var}.{field_name} as any).equals({other_var}.{field_name}) \
: {self_var}.{field_name} === {other_var}.{field_name})"
)
}
}