Skip to main content

hyperlight_js/
script.rs

1use std::path::{Path, PathBuf};
2use std::sync::Arc;
3
4use crate::{new_error, Result};
5
6/// Represents a JavaScript immutable handler script with metadata about its source location.
7/// The source location metadata is required to resolve relative locations when the script imports
8/// other modules using relative paths.
9#[derive(Debug, Clone)]
10pub struct Script {
11    /// The script content
12    content: Arc<str>,
13    /// base path for resolving module imports
14    base_path: Option<PathBuf>,
15}
16
17impl Script {
18    /// Create a script from a string with no base path for module resolution
19    pub fn from_content(content: impl Into<String>) -> Self {
20        // TODO(tandr): Consider validating the script content using oxc_parser or similar
21        Self {
22            content: Arc::from(content.into()),
23            base_path: None,
24        }
25    }
26
27    /// Create a script by reading from a file
28    ///
29    /// The base path is automatically set to the directory containing the file
30    pub fn from_file(path: impl AsRef<Path>) -> Result<Self> {
31        let path = path.as_ref();
32
33        let content = std::fs::read_to_string(path)
34            .map_err(|e| new_error!("Failed to read script from '{}': {}", path.display(), e))?;
35
36        let base_path = path.parent().map(|p| p.to_path_buf());
37        Ok(Self {
38            content: Arc::from(content),
39            base_path,
40        })
41    }
42
43    /// Set a virtual base path for module resolution.
44    pub fn with_virtual_base(mut self, path: impl AsRef<str>) -> Self {
45        self.base_path = Some(PathBuf::from(path.as_ref()));
46        self
47    }
48
49    /// Get the script content
50    pub fn content(&self) -> &str {
51        &self.content
52    }
53
54    /// Get the base path for module resolution, if any
55    pub fn base_path(&self) -> Option<&Path> {
56        self.base_path.as_deref()
57    }
58}
59
60impl From<String> for Script {
61    fn from(content: String) -> Self {
62        Self::from_content(content)
63    }
64}
65
66impl From<&str> for Script {
67    fn from(content: &str) -> Self {
68        Self::from_content(content)
69    }
70}
71
72impl TryFrom<&Path> for Script {
73    type Error = hyperlight_host::HyperlightError;
74    fn try_from(path: &Path) -> Result<Self> {
75        Self::from_file(path)
76    }
77}