use std::{collections::HashMap, path::PathBuf, sync::Arc};
use fancy_regex::Regex;
use napi::Either;
use napi_derive::napi;
#[derive(Debug, Clone)]
#[napi(object)]
pub struct NapiResolveOptions {
#[napi(ts_type = "'auto' | TsconfigOptions")]
pub tsconfig: Option<Either<String, TsconfigOptions>>,
pub alias: Option<HashMap<String, Vec<Option<String>>>>,
#[napi(ts_type = "(string | string[])[]")]
pub alias_fields: Option<Vec<StrOrStrListType>>,
pub condition_names: Option<Vec<String>>,
pub enforce_extension: Option<EnforceExtension>,
#[napi(ts_type = "(string | string[])[]")]
pub exports_fields: Option<Vec<StrOrStrListType>>,
#[napi(ts_type = "(string | string[])[]")]
pub imports_fields: Option<Vec<StrOrStrListType>>,
pub extension_alias: Option<HashMap<String, Vec<String>>>,
pub extensions: Option<Vec<String>>,
pub fallback: Option<HashMap<String, Vec<Option<String>>>>,
pub fully_specified: Option<bool>,
#[napi(ts_type = "string | string[]")]
pub main_fields: Option<StrOrStrListType>,
pub main_files: Option<Vec<String>>,
#[napi(ts_type = "string | string[]")]
pub modules: Option<StrOrStrListType>,
pub resolve_to_context: Option<bool>,
pub prefer_relative: Option<bool>,
pub prefer_absolute: Option<bool>,
pub restrictions: Option<Vec<Restriction>>,
pub roots: Option<Vec<String>>,
pub symlinks: Option<bool>,
pub builtin_modules: Option<bool>,
pub module_type: Option<bool>,
pub allow_package_exports_in_directory_resolve: Option<bool>,
}
#[napi]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EnforceExtension {
Auto,
Enabled,
Disabled,
}
impl EnforceExtension {
pub fn is_auto(&self) -> bool {
*self == Self::Auto
}
pub fn is_enabled(&self) -> bool {
*self == Self::Enabled
}
pub fn is_disabled(&self) -> bool {
*self == Self::Disabled
}
}
#[napi(object)]
#[derive(Debug, Clone)]
pub struct Restriction {
pub path: Option<String>,
pub regex: Option<String>,
}
#[napi(object)]
#[derive(Debug, Clone)]
pub struct TsconfigOptions {
pub config_file: String,
#[napi(ts_type = "'auto'")]
pub references: Option<String>,
}
impl From<Restriction> for oxc_resolver::Restriction {
fn from(val: Restriction) -> Self {
match (val.path, val.regex) {
(None, None) => {
panic!("Should specify path or regex")
}
(None, Some(regex)) => {
let re = Regex::new(®ex).unwrap();
oxc_resolver::Restriction::Fn(Arc::new(move |path| {
re.is_match(path.to_str().unwrap_or_default()).unwrap_or(false)
}))
}
(Some(path), None) => oxc_resolver::Restriction::Path(PathBuf::from(path)),
(Some(_), Some(_)) => {
panic!("Restriction can't be path and regex at the same time")
}
}
}
}
impl From<EnforceExtension> for oxc_resolver::EnforceExtension {
fn from(val: EnforceExtension) -> Self {
match val {
EnforceExtension::Auto => oxc_resolver::EnforceExtension::Auto,
EnforceExtension::Enabled => oxc_resolver::EnforceExtension::Enabled,
EnforceExtension::Disabled => oxc_resolver::EnforceExtension::Disabled,
}
}
}
impl From<TsconfigOptions> for oxc_resolver::TsconfigOptions {
fn from(val: TsconfigOptions) -> Self {
oxc_resolver::TsconfigOptions {
config_file: PathBuf::from(val.config_file),
references: match val.references {
Some(string) if string.as_str() == "auto" => oxc_resolver::TsconfigReferences::Auto,
Some(opt) => {
panic!("`{}` is not a valid option for tsconfig references", opt)
}
None => oxc_resolver::TsconfigReferences::Disabled,
},
}
}
}
type StrOrStrListType = Either<String, Vec<String>>;
pub struct StrOrStrList(pub StrOrStrListType);
impl From<StrOrStrList> for Vec<String> {
fn from(val: StrOrStrList) -> Self {
match val {
StrOrStrList(Either::A(s)) => Vec::from([s]),
StrOrStrList(Either::B(a)) => a,
}
}
}