use serde_json::Value;
use super::helpers::{
extract_store_like_from_quote_summary_value, find_quote_summary_store_in_value,
find_quote_summary_value_in_value, normalize_store_like, truncate, wrap_store_like,
};
use crate::profile::scrape::utils::{find_matching_brace, iter_json_scripts};
pub fn try_root_app_main(body: &str, debug: bool) -> Option<String> {
if let Some(start) = body.find("root.App.main") {
let after = &body[start..];
if let Some(eq) = after.find('=') {
let mut payload = &after[eq + 1..];
payload = payload.trim_start();
let end_script = payload.find("</script>").unwrap_or(payload.len());
let segment = &payload[..end_script];
if let Some(semi) = segment.rfind(';') {
let json_str = segment[..semi].trim();
if debug {
eprintln!(
"YF_DEBUG [extract_bootstrap_json]: Strategy A preview=`{}`",
truncate(json_str, 160)
);
}
return Some(json_str.to_string());
}
}
}
None
}
pub fn try_quote_summary_store_literal(body: &str, debug: bool) -> Option<String> {
let key = "\"QuoteSummaryStore\"";
if let Some(pos) = body.find(key) {
let after = &body[pos + key.len()..];
if let Some(brace_rel) = after.find('{') {
let obj_start = pos + key.len() + brace_rel;
if let Some(obj_end) = find_matching_brace(body, obj_start) {
let obj = &body[obj_start..=obj_end];
let wrapped = format!(
r#"{{"context":{{"dispatcher":{{"stores":{{"QuoteSummaryStore":{obj}}}}}}}}}"#
);
if debug {
eprintln!(
"YF_DEBUG [extract_bootstrap_json]: Strategy B obj.len={} preview=`{}`",
obj.len(),
truncate(obj, 160)
);
}
return Some(wrapped);
} else if debug {
eprintln!(
"YF_DEBUG [extract_bootstrap_json]: Strategy B found start but failed to match closing brace."
);
}
}
}
None
}
#[allow(clippy::too_many_lines)]
pub fn try_sveltekit_json(body: &str, debug: bool) -> Option<String> {
let scripts = iter_json_scripts(body);
if debug {
eprintln!(
"YF_DEBUG [extract_bootstrap_json]: Strategy C inspecting {} JSON scripts...",
scripts.len()
);
}
for (i, (tag_attrs, inner_json)) in scripts.iter().enumerate() {
let is_svelte = tag_attrs.contains("data-sveltekit-fetched");
if !is_svelte {
continue;
}
if debug {
eprintln!(
"YF_DEBUG [extract_bootstrap_json]: C[{}] attrs=`{}` inner.len={} preview=`{}`",
i,
truncate(tag_attrs, 160),
inner_json.len(),
truncate(inner_json, 120)
);
}
if let Ok(outer_array) = serde_json::from_str::<Vec<Value>>(inner_json) {
if debug {
eprintln!(
"YF_DEBUG [extract_bootstrap_json]: C[{}] parsed as ARRAY (len={})",
i,
outer_array.len()
);
}
for (ai, outer_obj) in outer_array.into_iter().enumerate() {
if let Some(nodes) = outer_obj.get("nodes").and_then(|n| n.as_array()) {
if debug {
eprintln!(
"YF_DEBUG [extract_bootstrap_json]: C[{}][{}] nodes.len={}",
i,
ai,
nodes.len()
);
}
for (ni, node) in nodes.iter().enumerate() {
if let Some(data) = node.get("data")
&& let Some(store_like) =
extract_store_like_from_quote_summary_value(data)
&& let Ok(wrapped) = wrap_store_like(&store_like)
{
if debug {
eprintln!(
"YF_DEBUG [extract_bootstrap_json]: C[{}][{}] SUCCESS via nodes[{}].data -> wrapped.len={}",
i,
ai,
ni,
wrapped.len()
);
}
return Some(wrapped);
}
}
}
}
}
let parsed_obj = match serde_json::from_str::<Value>(inner_json) {
Ok(v @ Value::Object(_)) => Some(v),
Ok(_) => None,
Err(e) => {
if debug {
eprintln!(
"YF_DEBUG [extract_bootstrap_json]: C[{i}] parse-as-OBJECT failed: {e}"
);
}
None
}
};
if let Some(mut outer_obj) = parsed_obj {
let body_val_opt = { outer_obj.get_mut("body").map(serde_json::Value::take) };
if let Some(body_val) = body_val_opt {
let payload_opt = match body_val {
Value::String(s) => serde_json::from_str::<Value>(&s).ok(),
Value::Object(_) | Value::Array(_) => Some(body_val),
_ => None,
};
if let Some(payload) = payload_opt {
if let Some(qss) = find_quote_summary_store_in_value(&payload) {
let store_like = normalize_store_like(qss.clone());
if let Ok(wrapped) = wrap_store_like(&store_like) {
if debug {
eprintln!(
"YF_DEBUG [extract_bootstrap_json]: C[{}] SUCCESS via QuoteSummaryStore path; wrapped.len={}",
i,
wrapped.len()
);
}
return Some(wrapped);
}
}
if let Some(qs_val) = find_quote_summary_value_in_value(&payload)
&& let Some(store_like) =
extract_store_like_from_quote_summary_value(qs_val)
&& let Ok(wrapped) = wrap_store_like(&store_like)
{
if debug {
eprintln!(
"YF_DEBUG [extract_bootstrap_json]: C[{}] SUCCESS via quoteSummary->result; wrapped.len={}",
i,
wrapped.len()
);
}
return Some(wrapped);
}
}
}
}
}
None
}
pub fn try_generic_json_scripts(body: &str, debug: bool) -> Option<String> {
let scripts = iter_json_scripts(body);
for (i, (_attrs, inner_json)) in scripts.iter().enumerate() {
let val = match serde_json::from_str::<Value>(inner_json) {
Ok(v) => v,
Err(e) => {
if debug {
eprintln!(
"YF_DEBUG [extract_bootstrap_json]: D[{}] parse failed: {} (preview=`{}`)",
i,
e,
if inner_json.len() > 120 {
&inner_json[..120]
} else {
inner_json
}
);
}
continue;
}
};
if let Some(qss) = find_quote_summary_store_in_value(&val) {
let store_like = normalize_store_like(qss.clone());
if let Ok(wrapped) = wrap_store_like(&store_like) {
if debug {
eprintln!(
"YF_DEBUG [extract_bootstrap_json]: D[{}] SUCCESS via QuoteSummaryStore; wrapped.len={}",
i,
wrapped.len()
);
}
return Some(wrapped);
}
}
if let Some(qs_val) = find_quote_summary_value_in_value(&val)
&& let Some(store_like) = extract_store_like_from_quote_summary_value(qs_val)
&& let Ok(wrapped) = wrap_store_like(&store_like)
{
if debug {
eprintln!(
"YF_DEBUG [extract_bootstrap_json]: D[{}] SUCCESS via quoteSummary->result; wrapped.len={}",
i,
wrapped.len()
);
}
return Some(wrapped);
}
if let Some(body_val) = val.get("body") {
let payload_opt = match body_val {
Value::String(s) => serde_json::from_str::<Value>(s).ok(),
Value::Object(_) | Value::Array(_) => Some(body_val.clone()),
_ => None,
};
if let Some(payload) = payload_opt {
if let Some(qss) = find_quote_summary_store_in_value(&payload) {
let store_like = normalize_store_like(qss.clone());
if let Ok(wrapped) = wrap_store_like(&store_like) {
if debug {
eprintln!(
"YF_DEBUG [extract_bootstrap_json]: D[{}] SUCCESS via body->QuoteSummaryStore; wrapped.len={}",
i,
wrapped.len()
);
}
return Some(wrapped);
}
}
if let Some(qs_val) = find_quote_summary_value_in_value(&payload)
&& let Some(store_like) = extract_store_like_from_quote_summary_value(qs_val)
&& let Ok(wrapped) = wrap_store_like(&store_like)
{
if debug {
eprintln!(
"YF_DEBUG [extract_bootstrap_json]: D[{}] SUCCESS via body->quoteSummary->result; wrapped.len={}",
i,
wrapped.len()
);
}
return Some(wrapped);
}
}
}
}
None
}