hyperlight_js/script.rs
1/*
2Copyright 2026 The Hyperlight Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16use std::path::{Path, PathBuf};
17use std::sync::Arc;
18
19use crate::{new_error, Result};
20
21/// Represents a JavaScript immutable handler script with metadata about its source location.
22/// The source location metadata is required to resolve relative locations when the script imports
23/// other modules using relative paths.
24#[derive(Debug, Clone)]
25pub struct Script {
26 /// The script content
27 content: Arc<str>,
28 /// base path for resolving module imports
29 base_path: Option<PathBuf>,
30}
31
32impl Script {
33 /// Create a script from a string with no base path for module resolution
34 pub fn from_content(content: impl Into<String>) -> Self {
35 // TODO(tandr): Consider validating the script content using oxc_parser or similar
36 Self {
37 content: Arc::from(content.into()),
38 base_path: None,
39 }
40 }
41
42 /// Create a script by reading from a file
43 ///
44 /// The base path is automatically set to the directory containing the file
45 pub fn from_file(path: impl AsRef<Path>) -> Result<Self> {
46 let path = path.as_ref();
47
48 let content = std::fs::read_to_string(path)
49 .map_err(|e| new_error!("Failed to read script from '{}': {}", path.display(), e))?;
50
51 let base_path = path.parent().map(|p| p.to_path_buf());
52 Ok(Self {
53 content: Arc::from(content),
54 base_path,
55 })
56 }
57
58 /// Set a virtual base path for module resolution.
59 pub fn with_virtual_base(mut self, path: impl AsRef<str>) -> Self {
60 self.base_path = Some(PathBuf::from(path.as_ref()));
61 self
62 }
63
64 /// Get the script content
65 pub fn content(&self) -> &str {
66 &self.content
67 }
68
69 /// Get the base path for module resolution, if any
70 pub fn base_path(&self) -> Option<&Path> {
71 self.base_path.as_deref()
72 }
73}
74
75impl From<String> for Script {
76 fn from(content: String) -> Self {
77 Self::from_content(content)
78 }
79}
80
81impl From<&str> for Script {
82 fn from(content: &str) -> Self {
83 Self::from_content(content)
84 }
85}
86
87impl TryFrom<&Path> for Script {
88 type Error = hyperlight_host::HyperlightError;
89 fn try_from(path: &Path) -> Result<Self> {
90 Self::from_file(path)
91 }
92}