use super::types::RN_PLATFORM_PREFIXES;
pub(super) fn has_react_native_plugin(active_plugins: &[String]) -> bool {
active_plugins
.iter()
.any(|p| p == "react-native" || p == "expo")
}
pub(super) fn build_extensions(active_plugins: &[String]) -> Vec<String> {
let base: Vec<String> = vec![
".ts".into(),
".tsx".into(),
".mts".into(),
".cts".into(),
".js".into(),
".jsx".into(),
".mjs".into(),
".cjs".into(),
".d.ts".into(),
".d.mts".into(),
".d.cts".into(),
".json".into(),
".vue".into(),
".svelte".into(),
".astro".into(),
".mdx".into(),
".css".into(),
".scss".into(),
];
if has_react_native_plugin(active_plugins) {
let source_exts = [".ts", ".tsx", ".js", ".jsx"];
let mut rn_extensions: Vec<String> = Vec::new();
for platform in RN_PLATFORM_PREFIXES {
for ext in &source_exts {
rn_extensions.push(format!("{platform}{ext}"));
}
}
rn_extensions.extend(base);
rn_extensions
} else {
base
}
}
pub(super) fn build_condition_names(
active_plugins: &[String],
extra_conditions: &[String],
) -> Vec<String> {
let mut names = vec![
"development".into(),
"import".into(),
"require".into(),
"default".into(),
"types".into(),
"node".into(),
];
if has_react_native_plugin(active_plugins) {
names.insert(0, "react-native".into());
names.insert(1, "browser".into());
}
for extra in extra_conditions.iter().rev() {
names.insert(0, extra.clone());
}
let mut seen: rustc_hash::FxHashSet<String> = rustc_hash::FxHashSet::default();
names.retain(|name| seen.insert(name.clone()));
names
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_has_react_native_plugin_active() {
let plugins = vec!["react-native".to_string(), "typescript".to_string()];
assert!(has_react_native_plugin(&plugins));
}
#[test]
fn test_has_expo_plugin_active() {
let plugins = vec!["expo".to_string(), "typescript".to_string()];
assert!(has_react_native_plugin(&plugins));
}
#[test]
fn test_has_react_native_plugin_inactive() {
let plugins = vec!["nextjs".to_string(), "typescript".to_string()];
assert!(!has_react_native_plugin(&plugins));
}
#[test]
fn test_rn_platform_extensions_prepended() {
let no_rn = build_extensions(&[]);
let rn_plugins = vec!["react-native".to_string()];
let with_rn = build_extensions(&rn_plugins);
assert_eq!(no_rn[0], ".ts");
assert_eq!(with_rn[0], ".web.ts");
assert_eq!(with_rn[1], ".web.tsx");
assert_eq!(with_rn[2], ".web.js");
assert_eq!(with_rn[3], ".web.jsx");
assert!(with_rn.len() > no_rn.len());
assert_eq!(
with_rn.len(),
no_rn.len() + 16,
"should add 16 platform extensions (4 platforms x 4 exts)"
);
}
#[test]
fn test_rn_condition_names_prepended() {
let no_rn = build_condition_names(&[], &[]);
let rn_plugins = vec!["react-native".to_string()];
let with_rn = build_condition_names(&rn_plugins, &[]);
assert_eq!(no_rn[0], "development");
assert_eq!(with_rn[0], "react-native");
assert_eq!(with_rn[1], "browser");
assert_eq!(with_rn[2], "development");
}
#[test]
fn test_development_condition_in_baseline() {
let names = build_condition_names(&[], &[]);
assert!(
names.contains(&"development".to_string()),
"`development` must be part of the default condition set"
);
}
#[test]
fn test_extra_conditions_prepended_before_baseline() {
let names = build_condition_names(&[], &["worker".to_string(), "edge-light".to_string()]);
assert_eq!(names[0], "worker");
assert_eq!(names[1], "edge-light");
assert_eq!(names[2], "development");
}
#[test]
fn test_extra_conditions_prepended_before_rn() {
let rn_plugins = vec!["react-native".to_string()];
let names = build_condition_names(&rn_plugins, &["worker".to_string()]);
assert_eq!(names[0], "worker");
assert_eq!(names[1], "react-native");
assert_eq!(names[2], "browser");
assert_eq!(names[3], "development");
}
#[test]
fn test_duplicate_baseline_condition_from_user_is_deduped() {
let names = build_condition_names(&[], &["development".to_string()]);
let dev_count = names.iter().filter(|n| *n == "development").count();
assert_eq!(dev_count, 1, "`development` should appear exactly once");
assert_eq!(
names[0], "development",
"user-supplied entry keeps its position"
);
}
#[test]
fn test_duplicate_user_conditions_are_deduped_preserving_first() {
let names = build_condition_names(
&[],
&[
"worker".to_string(),
"edge-light".to_string(),
"worker".to_string(),
],
);
let worker_count = names.iter().filter(|n| *n == "worker").count();
assert_eq!(worker_count, 1);
assert_eq!(names[0], "worker");
assert_eq!(names[1], "edge-light");
}
}