use vize_carton::ToCompactString;
use crate::script::resolve_type_to_object_body;
use crate::types::BindingType;
use super::super::MacroCall;
use super::ScriptCompileContext;
fn is_valid_identifier(s: &str) -> bool {
if s.is_empty() {
return false;
}
let mut chars = s.chars();
let first = chars.next().unwrap();
if !first.is_ascii_alphabetic() && first != '_' && first != '$' {
return false;
}
chars.all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '$')
}
impl ScriptCompileContext {
pub(super) fn extract_props_bindings(&mut self, call: &MacroCall) {
if let Some(ref type_args) = call.type_args {
self.extract_props_from_type_args(type_args);
return;
}
let args = call.args.trim();
if args.starts_with('[') && args.ends_with(']') {
let inner = &args[1..args.len() - 1];
for part in inner.split(',') {
let part = part.trim();
if (part.starts_with('\'') && part.ends_with('\''))
|| (part.starts_with('"') && part.ends_with('"'))
{
let name = &part[1..part.len() - 1];
self.bindings
.bindings
.insert(name.to_compact_string(), BindingType::Props);
}
}
} else if args.starts_with('{') && args.ends_with('}') {
let inner = &args[1..args.len() - 1];
for part in inner.split(',') {
let part = part.trim();
if let Some(colon_pos) = part.find(':') {
let key = part[..colon_pos].trim();
if !key.is_empty() && is_valid_identifier(key) {
self.bindings
.bindings
.insert(key.to_compact_string(), BindingType::Props);
}
} else if is_valid_identifier(part) {
self.bindings
.bindings
.insert(part.to_compact_string(), BindingType::Props);
}
}
}
}
fn extract_props_from_type_args(&mut self, type_args: &str) {
let content = type_args.trim();
let Some(resolved_content) =
resolve_type_to_object_body(content, &self.interfaces, &self.type_aliases)
else {
return;
};
let mut depth = 0;
let mut current = vize_carton::String::default();
for c in resolved_content.chars() {
match c {
'{' | '<' | '(' | '[' => {
depth += 1;
current.push(c);
}
'}' | '>' | ')' | ']' => {
depth -= 1;
current.push(c);
}
',' | ';' | '\n' if depth == 0 => {
self.extract_single_prop_from_type(¤t);
current.clear();
}
_ => current.push(c),
}
}
self.extract_single_prop_from_type(¤t);
}
fn extract_single_prop_from_type(&mut self, segment: &str) {
let trimmed = segment.trim();
if trimmed.is_empty() {
return;
}
if let Some(colon_pos) = trimmed.find(':') {
let name_part = &trimmed[..colon_pos];
let name = name_part.trim().trim_end_matches('?').trim();
if !name.is_empty() && is_valid_identifier(name) {
self.bindings
.bindings
.insert(name.to_compact_string(), BindingType::Props);
}
}
}
}