Skip to content

Instantly share code, notes, and snippets.

@snuffyDev
Created April 17, 2022 06:02
Show Gist options
  • Select an option

  • Save snuffyDev/a736f604c1c03bf722de2da7b196d2b7 to your computer and use it in GitHub Desktop.

Select an option

Save snuffyDev/a736f604c1c03bf722de2da7b196d2b7 to your computer and use it in GitHub Desktop.
use super::fs::{FSMethods, FileMetadata, FileSystem, Folder};
use std::{
io::{Error, ErrorKind},
path::{Component, Path, PathBuf},
};
use serde_json::Value;
#[derive(Default)]
pub struct Resolver {
modules: Vec<Module>,
}
pub trait GetFileSystem {
fn get_file_system(&self) -> FileSystem;
}
impl Resolver {
pub fn new() -> Self {
Self { modules: vec![] }
}
}
#[derive(Debug, serde::Serialize, Clone)]
pub struct Module {
pub contents: String,
pub file_path: String,
pub metadata: Option<FileMetadata>,
}
impl Module {
pub fn new(file_path: String) -> Module {
let contents = FileSystem.read_file(&file_path).unwrap();
Module {
contents: contents.contents,
file_path,
metadata: Some(contents.metadata),
}
}
}
pub fn resolve(name: String, base: &Path) -> Result<Module, Error> {
let root = base.parent().unwrap();
let path = Path::new(&name);
if path.starts_with("../") || path.starts_with("./") {
let normalized_path = normalize(&root.join(path));
get_module(&normalized_path)
} else if path.is_absolute() {
get_module(path)
} else if name.is_empty() {
get_module(root)
} else {
let node_modules = base.join("node_modules").join(&path);
get_module(&node_modules).or_else(|_| resolve(name, root))
}
}
fn normalize(file_path: &Path) -> PathBuf {
file_path
.components()
.fold(PathBuf::from(""), |path, c| match c {
Component::Prefix(ref prefix) => PathBuf::from(prefix.as_os_str().to_owned()),
Component::RootDir | Component::CurDir => path.join("/"),
Component::Normal(comp) => path.join(comp),
Component::ParentDir => match path.parent() {
Some(path) => path.to_owned(),
_ => path,
},
})
}
fn get_module(path: &Path) -> Result<Module, Error> {
if path.is_file() {
return Ok(Module::new(path.display().to_string()));
}
let file_exts = vec!["js", "mjs", "json"];
for ext in file_exts {
let this_path = path.with_extension(ext);
if this_path.is_file() {
return Ok(Module::new(this_path.clone().display().to_string()));
}
}
let pkg_path = &path.join("package.json").display().to_string();
if let Ok(data) = FileSystem.read_file(&pkg_path) {
let pkg_info: Value = serde_json::from_str(&data.contents)?;
if let Some(main) = pkg_info["main"].as_str() {
if main != "." && main != ".." {
return get_module(&path.join(main));
}
}
}
if path.is_dir() {
return get_module(&path.join("index"));
}
Err(Error::new(
ErrorKind::NotFound,
format!("Error resolving {}", path.display()),
))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment