browser_control/sidecar/
assets.rs1use anyhow::{Context, Result};
14use std::path::PathBuf;
15
16const SIDECAR_JS: &str = include_str!("../../assets/playwright-sidecar/sidecar.mjs");
18
19const PACKAGE_JSON: &str = include_str!("../../assets/playwright-sidecar/package.json");
22
23pub async fn ensure_sidecar_dir(playwright_version: &str) -> Result<PathBuf> {
26 let dir = cache_dir(playwright_version)?;
27 tokio::fs::create_dir_all(&dir)
28 .await
29 .with_context(|| format!("creating sidecar cache directory at {dir:?}"))?;
30
31 let js_path = dir.join("sidecar.mjs");
34 tokio::fs::write(&js_path, SIDECAR_JS)
35 .await
36 .with_context(|| format!("writing {js_path:?}"))?;
37
38 let pkg_json = patch_version(PACKAGE_JSON, playwright_version);
42 let pkg_path = dir.join("package.json");
43 tokio::fs::write(&pkg_path, pkg_json)
44 .await
45 .with_context(|| format!("writing {pkg_path:?}"))?;
46
47 Ok(dir)
48}
49
50fn cache_dir(playwright_version: &str) -> Result<PathBuf> {
51 let project = directories::ProjectDirs::from("dev", "browser-control", "browser-control")
52 .ok_or_else(|| anyhow::anyhow!("could not determine user cache directory"))?;
53 let base = project.cache_dir().to_path_buf();
54 Ok(base.join(format!("playwright-sidecar-{playwright_version}")))
55}
56
57fn patch_version(template: &str, version: &str) -> String {
62 let key = "\"playwright-core\":";
64 let Some(idx) = template.find(key) else {
65 return template.to_string();
66 };
67 let after_key = &template[idx + key.len()..];
69 let Some(open_off) = after_key.find('"') else {
70 return template.to_string();
71 };
72 let after_open = &after_key[open_off + 1..];
73 let Some(close_off) = after_open.find('"') else {
74 return template.to_string();
75 };
76 let mut out = String::with_capacity(template.len() + version.len());
77 out.push_str(&template[..idx + key.len() + open_off + 1]);
78 out.push_str(version);
79 out.push_str(&after_open[close_off..]);
80 out
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86
87 #[test]
88 fn patch_version_rewrites_known_template() {
89 let t = r#"{
90 "name": "x",
91 "dependencies": {
92 "playwright-core": "1.49.1"
93 }
94}"#;
95 let out = patch_version(t, "1.55.0");
96 assert!(out.contains("\"playwright-core\": \"1.55.0\""));
97 assert!(!out.contains("1.49.1"));
98 }
99
100 #[test]
101 fn patch_version_keeps_input_when_key_missing() {
102 let t = r#"{ "name": "x" }"#;
103 let out = patch_version(t, "1.55.0");
104 assert_eq!(out, t);
105 }
106}