use std::path::{Path, PathBuf};
use std::sync::Mutex;
use oj_resolver::OjResolver;
pub const PLUGIN_HOST_JS: &str = include_str!("../assets/plugin-host.mjs");
pub const DISCOVERED_DEPS_JS: &str = include_str!("../assets/discovered-deps.mjs");
pub(crate) fn ensure_asset(dir: &Path, name: &str, bytes: &str) -> std::io::Result<()> {
let path = dir.join(name);
if std::fs::read(&path).ok().as_deref() == Some(bytes.as_bytes()) {
return Ok(());
}
std::fs::create_dir_all(dir)?;
let tmp = dir.join(format!("{name}.tmp-{}", std::process::id()));
std::fs::write(&tmp, bytes)?;
std::fs::rename(&tmp, &path)
}
pub const VITE_EXTRACT_JS: &str = include_str!("../assets/vite-extract.mjs");
#[derive(Debug, Default, Clone, Copy)]
pub struct ServeInfo {
pub middleware_port: Option<u16>,
pub runner_environments: bool,
}
impl ServeInfo {
pub(crate) fn from_json(v: &serde_json::Value) -> ServeInfo {
ServeInfo {
middleware_port: v
.get("middlewarePort")
.and_then(|p| p.as_u64())
.and_then(|p| u16::try_from(p).ok()),
runner_environments: v
.get("runnerEnvironments")
.and_then(|b| b.as_bool())
.unwrap_or(false),
}
}
}
#[derive(Debug)]
pub struct EmittedFile {
pub file_name: String,
pub source: String,
}
#[derive(Debug, Clone)]
pub struct ChunkEmit {
pub ref_id: String,
pub id: String,
pub name: Option<String>,
pub file_name: Option<String>,
}
impl ChunkEmit {
fn from_value(m: &serde_json::Value) -> Option<Self> {
Some(Self {
ref_id: m.get("referenceId")?.as_str()?.to_string(),
id: m.get("id")?.as_str()?.to_string(),
name: m.get("name").and_then(|x| x.as_str()).map(str::to_string),
file_name: m
.get("fileName")
.and_then(|x| x.as_str())
.map(str::to_string),
})
}
}
#[inline]
pub fn plugins_file(root: &Path) -> Option<std::path::PathBuf> {
["oj.plugins.mjs", "oj.plugins.js"]
.into_iter()
.map(|f| root.join(f))
.find(|p| p.is_file())
}
pub enum PluginSource {
OjPlugins(std::path::PathBuf),
ViteConfig(std::path::PathBuf),
}
#[inline]
pub fn vite_config_file(root: &Path, config: Option<&Path>) -> Option<std::path::PathBuf> {
if let Some(p) = config {
return p.is_file().then(|| p.to_path_buf());
}
[
"vite.config.js",
"vite.config.mjs",
"vite.config.ts",
"vite.config.cjs",
"vite.config.mts",
"vite.config.cts",
]
.into_iter()
.map(|f| root.join(f))
.find(|p| p.is_file())
}
#[inline]
pub fn plugin_source(root: &Path, config: Option<&Path>) -> Option<PluginSource> {
if config.is_some() {
return vite_config_file(root, config).map(PluginSource::ViteConfig);
}
if let Some(p) = plugins_file(root) {
return Some(PluginSource::OjPlugins(p));
}
vite_config_file(root, config).map(PluginSource::ViteConfig)
}
mod extract;
mod hook_plan;
mod host;
pub use self::extract::*;
pub use self::hook_plan::*;
pub use self::host::*;
#[cfg(test)]
mod engine_extraction_tests;
#[cfg(test)]
mod hook_plan_tests;
#[cfg(test)]
mod vite_values_tests;