pharos_runtime_compiler/
component_properties.rs1use std::{fs, io, path::Path};
3
4pub fn compile(root: &Path) -> io::Result<()> {
6 let target = root.join("static/pharos/component-properties.js");
7 fs::create_dir_all(target.parent().ok_or(io::ErrorKind::InvalidInput)?)?;
8 fs::write(target, include_bytes!("../assets/component-properties.js"))?;
9 let metadata = root.join("static/architect-preview-overrides.json");
10 if !metadata.is_file() {
11 return Ok(());
12 }
13 if fs::metadata(&metadata)?.len() > 65536 {
14 return Err(io::ErrorKind::InvalidData.into());
15 }
16 install_in_templates(&root.join("templates"), 0)
17}
18
19fn install_in_templates(directory: &Path, depth: usize) -> io::Result<()> {
21 if !directory.exists() {
22 return Ok(());
23 }
24 if depth > 32 {
25 return Err(io::ErrorKind::InvalidData.into());
26 }
27 for entry in fs::read_dir(directory)? {
28 let entry = entry?;
29 let kind = entry.file_type()?;
30 if kind.is_symlink() {
31 return Err(io::ErrorKind::InvalidInput.into());
32 }
33 if kind.is_dir() {
34 install_in_templates(&entry.path(), depth + 1)?;
35 continue;
36 }
37 if entry
38 .path()
39 .extension()
40 .is_none_or(|extension| extension != "html")
41 {
42 continue;
43 }
44 if entry.metadata()?.len() > 8 * 1024 * 1024 {
45 return Err(io::ErrorKind::InvalidData.into());
46 }
47 let source = fs::read_to_string(entry.path())?;
48 if source.contains("data-pharos-component-properties") {
49 continue;
50 }
51 if let Some(index) = source.to_ascii_lowercase().find("</head>") {
52 let mut result = source;
53 result.insert_str(index, include_str!("../assets/component-properties.html"));
54 fs::write(entry.path(), result)?;
55 }
56 }
57 Ok(())
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63 #[test]
65 fn renderer_is_opt_in_and_idempotent() {
66 let root = std::env::temp_dir().join(format!("pharos-properties-{}", std::process::id()));
67 fs::create_dir_all(root.join("templates")).unwrap();
68 fs::create_dir_all(root.join("static")).unwrap();
69 fs::write(
70 root.join("templates/layout.html"),
71 "<head></head><body></body>",
72 )
73 .unwrap();
74 fs::write(root.join("templates/partial.html"), "<div>partial</div>").unwrap();
75 compile(&root).unwrap();
76 assert!(
77 !fs::read_to_string(root.join("templates/layout.html"))
78 .unwrap()
79 .contains("data-pharos-component-properties")
80 );
81 fs::write(root.join("static/architect-preview-overrides.json"), "{}").unwrap();
82 compile(&root).unwrap();
83 compile(&root).unwrap();
84 assert_eq!(
85 fs::read_to_string(root.join("templates/layout.html"))
86 .unwrap()
87 .matches("data-pharos-component-properties")
88 .count(),
89 1
90 );
91 assert_eq!(
92 fs::read_to_string(root.join("templates/partial.html")).unwrap(),
93 "<div>partial</div>"
94 );
95 fs::remove_dir_all(root).unwrap();
96 }
97}