use vize_carton::{String, ToCompactString};
use super::string_tracking::{
compact_render_body, count_braces_with_state, count_parens_with_state, StringTrackState,
};
fn is_vapor_template_declaration(line: &str) -> bool {
line.starts_with("const t") && line.contains("_template(")
}
fn detect_render_export_name(trimmed: &str) -> Option<&'static str> {
if trimmed.starts_with("export function render(") || trimmed.starts_with("function render(") {
Some("render")
} else if trimmed.starts_with("export function ssrRender(")
|| trimmed.starts_with("function ssrRender(")
{
Some("ssrRender")
} else {
None
}
}
fn finalize_render_body(render_body: &mut String) {
while render_body.ends_with([' ', '\t', '\n', '\r']) {
render_body.pop();
}
if render_body.ends_with(';') {
render_body.pop();
}
}
pub(crate) fn extract_template_parts_full(
template_code: &str,
) -> (String, String, String, &'static str) {
let mut imports = String::default();
let mut hoisted = String::default();
let mut render_fn = String::default();
let mut render_fn_name = "";
let mut in_render = false;
let mut brace_depth = 0;
let mut brace_state = StringTrackState::default();
for line in template_code.lines() {
let trimmed = line.trim();
if trimmed.starts_with("import ") {
imports.push_str(line);
imports.push('\n');
} else if let Some(name) = detect_render_export_name(trimmed) {
in_render = true;
render_fn_name = name;
brace_depth = 0;
brace_state = StringTrackState::default();
brace_depth += count_braces_with_state(line, &mut brace_state);
render_fn.push_str(line);
render_fn.push('\n');
} else if trimmed.starts_with("const _hoisted_")
|| is_vapor_template_declaration(trimmed)
|| (!trimmed.is_empty() && !in_render)
{
hoisted.push_str(line);
hoisted.push('\n');
} else if in_render {
brace_depth += count_braces_with_state(line, &mut brace_state);
render_fn.push_str(line);
render_fn.push('\n');
if brace_depth == 0 {
in_render = false;
}
}
}
(imports, hoisted, render_fn, render_fn_name)
}
#[allow(dead_code)]
pub(crate) fn extract_template_parts(
template_code: &str,
) -> (String, String, String, String, &'static str) {
let mut imports = String::default();
let mut hoisted = String::default();
let mut preamble = String::default(); let mut render_body = String::default();
let mut render_fn_name = "";
let mut in_render = false;
let mut in_block_render = false;
let mut saw_block_render = false;
let mut in_return = false;
let mut brace_depth = 0;
let mut brace_state = StringTrackState::default();
let mut paren_state = StringTrackState::default();
let mut return_paren_depth = 0;
let mut pending_ternary_continuation = false;
for line in template_code.lines() {
let trimmed = line.trim();
if trimmed.starts_with("import ") {
imports.push_str(line);
imports.push('\n');
} else if trimmed.starts_with("const _hoisted_") || is_vapor_template_declaration(trimmed) {
hoisted.push_str(line);
hoisted.push('\n');
} else if let Some(name) = detect_render_export_name(trimmed) {
in_render = true;
render_fn_name = name;
in_block_render = trimmed.starts_with("function render(") && trimmed.contains("$props");
saw_block_render = saw_block_render || in_block_render;
brace_depth = 0;
brace_state = StringTrackState::default();
paren_state = StringTrackState::default();
brace_depth += count_braces_with_state(line, &mut brace_state);
} else if in_render {
let brace_delta = count_braces_with_state(line, &mut brace_state);
let next_brace_depth = brace_depth + brace_delta;
if in_block_render {
if !(next_brace_depth == 0 && trimmed == "}") {
if !render_body.is_empty() {
render_body.push('\n');
}
render_body.push_str(line);
}
brace_depth = next_brace_depth;
if brace_depth == 0 {
in_render = false;
in_block_render = false;
}
continue;
}
brace_depth = next_brace_depth;
if pending_ternary_continuation && !trimmed.is_empty() {
if trimmed.starts_with('?') || trimmed.starts_with(':') {
pending_ternary_continuation = false;
} else {
pending_ternary_continuation = false;
in_return = false;
finalize_render_body(&mut render_body);
}
}
if in_return {
render_body.push('\n');
render_body.push_str(line);
return_paren_depth += count_parens_with_state(line, &mut paren_state);
if return_paren_depth <= 0 {
pending_ternary_continuation = true;
}
} else if let Some(stripped) = trimmed.strip_prefix("return ") {
render_body = stripped.to_compact_string();
paren_state = StringTrackState::default();
return_paren_depth = count_parens_with_state(stripped, &mut paren_state);
if return_paren_depth > 0 {
in_return = true;
} else {
in_return = true;
pending_ternary_continuation = true;
}
} else if trimmed.starts_with("const _component_")
|| trimmed.starts_with("const _directive_")
{
preamble.push_str(trimmed);
preamble.push('\n');
}
if brace_depth == 0 {
in_render = false;
}
}
}
if in_return {
finalize_render_body(&mut render_body);
}
let compacted = if saw_block_render {
render_body
} else {
compact_render_body(&render_body)
};
(imports, hoisted, preamble, compacted, render_fn_name)
}