use anyhow::{bail, Context, Result};
use std::path::Path;
use std::process::Command;
pub fn check_types(entry_path: &Path) -> Result<()> {
let tsc_check = Command::new("tsc").arg("--version").output();
if tsc_check.is_err() {
eprintln!("[type-check] Warning: tsc not found, skipping type check");
eprintln!("[type-check] Install TypeScript: npm install -g typescript");
return Ok(()); }
let project_root = entry_path
.parent()
.with_context(|| "Cannot determine project directory")?;
let tsconfig_path = find_tsconfig(project_root);
eprintln!("[type-check] Running TypeScript type checker...");
let mut cmd = Command::new("tsc");
cmd.arg("--noEmit")
.arg("--pretty")
.current_dir(project_root);
if tsconfig_path.is_none() {
cmd.arg("--target").arg("ES2020")
.arg("--lib").arg("ES2020,DOM")
.arg("--module").arg("ESNext")
.arg("--moduleResolution").arg("node")
.arg("--allowImportingTsExtensions")
.arg("--skipLibCheck")
.arg(entry_path);
}
let output = cmd.output().with_context(|| "Failed to run tsc")?;
if !output.status.success() {
eprintln!("{}", String::from_utf8_lossy(&output.stdout));
eprintln!("{}", String::from_utf8_lossy(&output.stderr));
bail!(
"\n❌ Type checking failed!\n\
Fix the type errors above before running.\n\
\n\
To skip type checking (not recommended):\n\
export ARCANE_SKIP_TYPE_CHECK=1"
);
}
eprintln!("[type-check] ✅ No type errors found");
Ok(())
}
fn find_tsconfig(start_dir: &Path) -> Option<std::path::PathBuf> {
let mut current = start_dir;
loop {
let tsconfig = current.join("tsconfig.json");
if tsconfig.exists() {
return Some(tsconfig);
}
current = current.parent()?;
}
}
pub fn should_skip_type_check() -> bool {
std::env::var("ARCANE_SKIP_TYPE_CHECK").is_ok()
}