use anyhow::{Context, Result};
use std::path::PathBuf;
const SIDECAR_JS: &str = include_str!("../../assets/playwright-sidecar/sidecar.mjs");
const PACKAGE_JSON: &str = include_str!("../../assets/playwright-sidecar/package.json");
pub async fn ensure_sidecar_dir(playwright_version: &str) -> Result<PathBuf> {
let dir = cache_dir(playwright_version)?;
tokio::fs::create_dir_all(&dir)
.await
.with_context(|| format!("creating sidecar cache directory at {dir:?}"))?;
let js_path = dir.join("sidecar.mjs");
tokio::fs::write(&js_path, SIDECAR_JS)
.await
.with_context(|| format!("writing {js_path:?}"))?;
let pkg_json = patch_version(PACKAGE_JSON, playwright_version);
let pkg_path = dir.join("package.json");
tokio::fs::write(&pkg_path, pkg_json)
.await
.with_context(|| format!("writing {pkg_path:?}"))?;
Ok(dir)
}
fn cache_dir(playwright_version: &str) -> Result<PathBuf> {
let project = directories::ProjectDirs::from("dev", "browser-control", "browser-control")
.ok_or_else(|| anyhow::anyhow!("could not determine user cache directory"))?;
let base = project.cache_dir().to_path_buf();
Ok(base.join(format!("playwright-sidecar-{playwright_version}")))
}
fn patch_version(template: &str, version: &str) -> String {
let key = "\"playwright-core\":";
let Some(idx) = template.find(key) else {
return template.to_string();
};
let after_key = &template[idx + key.len()..];
let Some(open_off) = after_key.find('"') else {
return template.to_string();
};
let after_open = &after_key[open_off + 1..];
let Some(close_off) = after_open.find('"') else {
return template.to_string();
};
let mut out = String::with_capacity(template.len() + version.len());
out.push_str(&template[..idx + key.len() + open_off + 1]);
out.push_str(version);
out.push_str(&after_open[close_off..]);
out
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn patch_version_rewrites_known_template() {
let t = r#"{
"name": "x",
"dependencies": {
"playwright-core": "1.49.1"
}
}"#;
let out = patch_version(t, "1.55.0");
assert!(out.contains("\"playwright-core\": \"1.55.0\""));
assert!(!out.contains("1.49.1"));
}
#[test]
fn patch_version_keeps_input_when_key_missing() {
let t = r#"{ "name": "x" }"#;
let out = patch_version(t, "1.55.0");
assert_eq!(out, t);
}
}