use std::fmt::Write;
use oxc_coverage_types::FileCoverage;
pub struct PreambleInputs<'a> {
pub coverage: &'a FileCoverage,
pub coverage_json: &'a str,
pub coverage_hash: &'a str,
pub coverage_var: &'a str,
pub cov_fn_name: &'a str,
pub report_logic: bool,
pub needs_optional_chain_helper: bool,
}
pub fn generate_preamble_source(inputs: &PreambleInputs<'_>) -> String {
let PreambleInputs {
coverage,
coverage_json,
coverage_hash,
coverage_var,
cov_fn_name,
report_logic,
needs_optional_chain_helper,
} = *inputs;
let mut buf = String::with_capacity(256 + coverage_json.len());
let _ = write!(buf, "var {cov_fn_name} = (function () {{ var path = ");
buf.push_str(
&serde_json::to_string(&coverage.path).expect("serializing a String to JSON is infallible"),
);
let _ = write!(buf, "; var hash = ");
buf.push_str(
&serde_json::to_string(coverage_hash).expect("serializing a &str to JSON is infallible"),
);
let _ = write!(buf, "; var gcv = '{coverage_var}'; var coverageData = ");
buf.push_str(coverage_json);
let _ = writeln!(
buf,
"; coverageData.hash = hash; var coverage = typeof globalThis !== 'undefined' ? globalThis : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : this; if (!coverage[gcv]) {{ coverage[gcv] = {{}}; }} if (!coverage[gcv][path] || coverage[gcv][path].hash !== hash) {{ coverage[gcv][path] = coverageData; }} var actualCoverage = coverage[gcv][path]; return actualCoverage; }})();"
);
if report_logic {
append_logic_helper(&mut buf, cov_fn_name);
}
if needs_optional_chain_helper {
append_optional_chain_helper(&mut buf, cov_fn_name);
}
buf
}
fn append_logic_helper(buf: &mut String, cov_fn_name: &str) {
let _ = writeln!(buf, "var {cov_fn_name}_temp;");
let _ = writeln!(
buf,
"function {cov_fn_name}_bt(val, id, idx) {{ {cov_fn_name}_temp = val; if ({cov_fn_name}_temp && (!Array.isArray({cov_fn_name}_temp) || {cov_fn_name}_temp.length) && (Object.getPrototypeOf({cov_fn_name}_temp) !== Object.prototype || Object.values({cov_fn_name}_temp).length)) {{ ++{cov_fn_name}.bT[id][idx]; }} return {cov_fn_name}_temp; }}"
);
}
fn append_optional_chain_helper(buf: &mut String, cov_fn_name: &str) {
let _ = writeln!(
buf,
"function {cov_fn_name}_oc(val, id) {{ ++{cov_fn_name}.b[id][val == null ? 0 : 1]; return val; }}"
);
}
pub fn djb31_hex(input: &str) -> String {
let mut hash: u64 = 0;
for byte in input.bytes() {
hash = hash.wrapping_mul(31).wrapping_add(u64::from(byte));
}
format!("{hash:x}")
}
pub fn generate_cov_fn_name(file_path: &str) -> String {
format!("cov_{}", djb31_hex(file_path))
}