infinity_build_js/
config.rs1use infinity_build_core::{BuildError, BuildResult};
2use serde::{Deserialize, Serialize};
3use std::path::{Path, PathBuf};
4
5#[derive(Debug, Clone, Deserialize, Serialize)]
6pub struct JsBuildConfig {
7 #[serde(flatten)]
8 pub package: PackageSpec,
9
10 #[serde(default)]
11 pub instruments: Vec<Instrument>,
12}
13
14#[derive(Debug, Clone, Deserialize, Serialize)]
15pub struct PackageSpec {
16 pub package_name: String,
17
18 #[serde(default = "default_package_dir")]
19 pub package_dir: PathBuf,
20}
21
22fn default_package_dir() -> PathBuf {
23 PathBuf::from("PackageSources")
24}
25
26#[derive(Debug, Clone, Deserialize, Serialize)]
27pub struct Instrument {
28 pub name: String,
29 pub index: PathBuf,
30
31 #[serde(default)]
32 pub simulator_package: Option<SimulatorPackage>,
33
34 #[serde(default)]
35 pub modules: Vec<ModuleAlias>,
36}
37
38#[derive(Debug, Clone, Deserialize, Serialize)]
39pub struct ModuleAlias {
40 pub resolve: String,
41 pub index: PathBuf,
42}
43
44#[derive(Debug, Clone, Deserialize, Serialize)]
45#[serde(tag = "type", rename_all = "camelCase")]
46pub enum SimulatorPackage {
47 React {
48 #[serde(default)]
49 file_name: Option<String>,
50
51 #[serde(default)]
52 template_id: Option<String>,
53
54 #[serde(default = "default_true")]
55 is_interactive: bool,
56
57 #[serde(default)]
58 imports: Vec<String>,
59
60 #[serde(default)]
61 html_template: Option<PathBuf>,
62
63 #[serde(default)]
64 js_template: Option<PathBuf>,
65 },
66
67 BaseInstrument {
68 #[serde(default)]
69 file_name: Option<String>,
70
71 template_id: String,
73 mount_element_id: String,
75
76 #[serde(default)]
77 imports: Vec<String>,
78
79 #[serde(default)]
80 html_template: Option<PathBuf>,
81 },
82}
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq)]
85pub enum SimulatorPackageKind {
86 React,
87 BaseInstrument,
88}
89
90fn default_true() -> bool {
91 true
92}
93
94impl SimulatorPackage {
95 pub fn kind(&self) -> SimulatorPackageKind {
96 match self {
97 SimulatorPackage::React { .. } => SimulatorPackageKind::React,
98 SimulatorPackage::BaseInstrument { .. } => SimulatorPackageKind::BaseInstrument,
99 }
100 }
101
102 pub fn file_name(&self) -> &str {
103 match self {
104 SimulatorPackage::React { file_name, .. }
105 | SimulatorPackage::BaseInstrument { file_name, .. } => {
106 file_name.as_deref().unwrap_or("instrument")
107 }
108 }
109 }
110
111 pub fn imports(&self) -> &[String] {
112 match self {
113 SimulatorPackage::React { imports, .. }
114 | SimulatorPackage::BaseInstrument { imports, .. } => imports,
115 }
116 }
117}
118
119#[cfg(windows)]
123fn strip_verbatim_prefix(path: PathBuf) -> PathBuf {
124 let s = path.as_os_str().to_string_lossy();
125 if let Some(rest) = s.strip_prefix(r"\\?\") {
126 if let Some(unc) = rest.strip_prefix(r"UNC\") {
128 return PathBuf::from(format!(r"\\{unc}"));
129 }
130 return PathBuf::from(rest.to_string());
131 }
132 path
133}
134
135#[cfg(not(windows))]
136fn strip_verbatim_prefix(path: PathBuf) -> PathBuf {
137 path
138}
139
140impl Instrument {
141 pub fn resolved_index(&self, project_root: &Path) -> BuildResult<PathBuf> {
142 let abs = project_root.join(&self.index);
143 let canonical = std::fs::canonicalize(&abs)
144 .map_err(|e| BuildError::invalid_path(abs, format!("entrypoint not found: {e}")))?;
145 Ok(strip_verbatim_prefix(canonical))
146 }
147}