use vize_carton::String;
use vize_carton::append;
use vize_carton::cstr;
use crate::virtual_ts::helpers::to_safe_identifier;
pub(super) fn slot_props_type(
component: Option<&str>,
slot_name: &str,
slot_name_is_static: bool,
) -> String {
match component {
Some(component) => {
let component_ref = to_safe_identifier(component);
if slot_name_is_static {
cstr!(
"typeof {component_ref} extends {{ new (): {{ $slots: infer __S }} }} ? (__S extends {{ \"{slot_name}\"?: (props: infer __P, ...args: any[]) => any }} ? __P : any) : any"
)
} else {
cstr!(
"typeof {component_ref} extends {{ new (): {{ $slots: infer __S }} }} ? ({{ [__K in keyof __S]: NonNullable<__S[__K]> extends (props: infer __P, ...args: any[]) => any ? __P : never }}[keyof __S] extends infer __P ? ([__P] extends [never] ? any : __P) : any) : any"
)
}
}
None => "any".into(),
}
}
pub(super) fn split_slot_pattern_annotation(pattern: &str) -> Option<(&str, &str)> {
let mut depth = 0i32;
let mut quote: Option<char> = None;
let mut escaped = false;
for (at, ch) in pattern.char_indices() {
if let Some(open) = quote {
if escaped {
escaped = false;
} else if ch == '\\' {
escaped = true;
} else if ch == open {
quote = None;
}
continue;
}
match ch {
'\'' | '"' | '`' => quote = Some(ch),
'{' | '[' | '(' | '<' => depth += 1,
'}' | ']' | ')' | '>' => depth -= 1,
':' if depth == 0 => {
let annotation = pattern[at + 1..].trim();
if annotation.is_empty() {
return None;
}
return Some((pattern[..at].trim_end(), annotation));
}
_ => {}
}
}
None
}
pub(super) fn emit_slot_function_open(
ts: &mut String,
indent: &str,
function_name: &str,
props_pattern: &str,
props_type: &String,
) {
if let Some((pattern, annotation)) = split_slot_pattern_annotation(props_pattern) {
append!(
*ts,
"{indent}void function {function_name}({pattern}: {annotation}) {{\n"
);
append!(
*ts,
"{indent} const __slot_annotation_check: {annotation} = undefined as unknown as ({props_type});\n{indent} void __slot_annotation_check;\n"
);
} else {
append!(
*ts,
"{indent}void function {function_name}({props_pattern}: {props_type}) {{\n"
);
}
}
pub(super) fn append_v_for_comment(
ts: &mut String,
indent: &str,
label: &str,
alias: &str,
source: &str,
) {
append!(*ts, "\n{indent}// {label}: {alias} in ");
for c in source.chars() {
if c == '\n' || c == '\r' {
ts.push(' ');
} else {
ts.push(c);
}
}
ts.push('\n');
}
pub(super) fn emit_v_for_loop_open(
ts: &mut String,
indent: &str,
value_alias: &str,
key_alias: Option<&str>,
index_alias: Option<&str>,
source: &str,
) {
append!(*ts, "{indent}__vForList({source}).forEach(([{value_alias}");
if let Some(key) = key_alias {
append!(*ts, ", {key}");
} else if index_alias.is_some() {
ts.push_str(", _key");
}
if let Some(index) = index_alias {
append!(*ts, ", {index}");
}
ts.push_str("]) => {\n");
}