use std::path::{Path, PathBuf};
const BUILTINS: &[&str] = &[
"http",
"https",
"fs",
"child_process",
"net",
"dns",
"vm",
"os",
"path",
];
pub fn resolve_require(from_file: &Path, specifier: &str) -> Option<PathBuf> {
if BUILTINS.contains(&specifier) {
return None;
}
if specifier.starts_with('.') {
let dir = from_file.parent().unwrap_or_else(|| Path::new("."));
let resolved = dir.join(specifier);
if resolved.extension().is_none() {
for ext in ["js", "json", "node"] {
let with_ext = resolved.with_extension(ext);
if with_ext.exists() {
return with_ext.canonicalize().ok();
}
}
}
if resolved.exists() {
return resolved.canonicalize().ok();
}
}
None
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn builtin_returns_none() {
assert_eq!(resolve_require(Path::new("/pkg/index.js"), "fs"), None);
assert_eq!(resolve_require(Path::new("/pkg/index.js"), "http"), None);
}
#[test]
fn relative_with_extension() {
let dir = tempfile::tempdir().unwrap();
let target = dir.path().join("helper.js");
std::fs::File::create(&target).unwrap();
let from = dir.path().join("index.js");
assert_eq!(
resolve_require(&from, "./helper.js"),
Some(target)
);
}
#[test]
fn relative_without_extension() {
let dir = tempfile::tempdir().unwrap();
let target = dir.path().join("helper.js");
std::fs::File::create(&target).unwrap();
let from = dir.path().join("index.js");
assert_eq!(
resolve_require(&from, "./helper"),
Some(target)
);
}
#[test]
fn parent_relative() {
let dir = tempfile::tempdir().unwrap();
let target = dir.path().join("parent.js");
std::fs::File::create(&target).unwrap();
let sub = dir.path().join("sub");
std::fs::create_dir(&sub).unwrap();
let from = sub.join("index.js");
assert_eq!(
resolve_require(&from, "../parent"),
Some(target)
);
}
#[test]
fn external_returns_none() {
assert_eq!(
resolve_require(Path::new("/pkg/index.js"), "express"),
None
);
}
}