Skip to content

feat: add file_dependencies and missing_dependencies API #50

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ Test cases are located in `./src/tests`, fixtures are located in `./tests`

- [x] alias.test.js
- [x] browserField.test.js
- [ ] dependencies.test.js
- [x] dependencies.test.js
- [x] exportsField.test.js
- [x] extension-alias.test.js
- [x] extensions.test.js
Expand All @@ -97,7 +97,7 @@ Test cases are located in `./src/tests`, fixtures are located in `./tests`
- [x] identifier.test.js (see unit test in `crates/oxc_resolver/src/request.rs`)
- [x] importsField.test.js
- [x] incorrect-description-file.test.js (need to add ctx.fileDependencies)
- [ ] missing.test.js
- [x] missing.test.js
- [x] path.test.js (see unit test in `crates/oxc_resolver/src/path.rs`)
- [ ] plugins.test.js
- [ ] pnp.test.js
Expand Down
59 changes: 47 additions & 12 deletions src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ use dashmap::{DashMap, DashSet};
use rustc_hash::FxHasher;

use crate::{
package_json::PackageJson, path::PathUtil, FileMetadata, FileSystem, ResolveError,
ResolveOptions, TsConfig,
context::ResolveContext as Ctx, package_json::PackageJson, path::PathUtil, FileMetadata,
FileSystem, ResolveError, ResolveOptions, TsConfig,
};

#[derive(Default)]
Expand Down Expand Up @@ -176,12 +176,24 @@ impl CachedPathImpl {
*self.meta.get_or_init(|| fs.metadata(&self.path).ok())
}

pub fn is_file<Fs: FileSystem>(&self, fs: &Fs) -> bool {
self.meta(fs).is_some_and(|meta| meta.is_file)
pub fn is_file<Fs: FileSystem>(&self, fs: &Fs, ctx: &mut Ctx) -> bool {
if let Some(meta) = self.meta(fs) {
ctx.add_file_dependency(self.path());
meta.is_file
} else {
ctx.add_missing_dependency(self.path());
false
}
}

pub fn is_dir<Fs: FileSystem>(&self, fs: &Fs) -> bool {
self.meta(fs).is_some_and(|meta| meta.is_dir)
pub fn is_dir<Fs: FileSystem>(&self, fs: &Fs, ctx: &mut Ctx) -> bool {
self.meta(fs).map_or_else(
|| {
ctx.add_missing_dependency(self.path());
false
},
|meta| meta.is_dir,
)
}

fn symlink<Fs: FileSystem>(&self, fs: &Fs) -> io::Result<Option<PathBuf>> {
Expand Down Expand Up @@ -219,16 +231,18 @@ impl CachedPathImpl {
&self,
module_name: &str,
cache: &Cache<Fs>,
ctx: &mut Ctx,
) -> Option<CachedPath> {
let cached_path = cache.value(&self.path.join(module_name));
cached_path.is_dir(&cache.fs).then(|| cached_path)
cached_path.is_dir(&cache.fs, ctx).then(|| cached_path)
}

pub fn cached_node_modules<Fs: FileSystem + Default>(
&self,
cache: &Cache<Fs>,
ctx: &mut Ctx,
) -> Option<CachedPath> {
self.node_modules.get_or_init(|| self.module_directory("node_modules", cache)).clone()
self.node_modules.get_or_init(|| self.module_directory("node_modules", cache, ctx)).clone()
}

/// Find package.json of a path by traversing parent directories.
Expand All @@ -240,10 +254,11 @@ impl CachedPathImpl {
&self,
fs: &Fs,
options: &ResolveOptions,
ctx: &mut Ctx,
) -> Result<Option<Arc<PackageJson>>, ResolveError> {
let mut cache_value = self;
// Go up directories when the querying path is not a directory
while !cache_value.is_dir(fs) {
while !cache_value.is_dir(fs, ctx) {
if let Some(cv) = &cache_value.parent {
cache_value = cv.as_ref();
} else {
Expand All @@ -252,7 +267,7 @@ impl CachedPathImpl {
}
let mut cache_value = Some(cache_value);
while let Some(cv) = cache_value {
if let Some(package_json) = cv.package_json(fs, options)? {
if let Some(package_json) = cv.package_json(fs, options, ctx)? {
return Ok(Some(Arc::clone(&package_json)));
}
cache_value = cv.parent.as_deref();
Expand All @@ -269,9 +284,11 @@ impl CachedPathImpl {
&self,
fs: &Fs,
options: &ResolveOptions,
ctx: &mut Ctx,
) -> Result<Option<Arc<PackageJson>>, ResolveError> {
// Change to `std::sync::OnceLock::get_or_try_init` when it is stable.
self.package_json
let result = self
.package_json
.get_or_try_init(|| {
let package_json_path = self.path.join("package.json");
let Ok(package_json_string) = fs.read_to_string(&package_json_path) else {
Expand All @@ -292,7 +309,25 @@ impl CachedPathImpl {
.map(Some)
.map_err(|error| ResolveError::from_serde_json_error(package_json_path, &error))
})
.cloned()
.cloned();
// https://github.com/webpack/enhanced-resolve/blob/58464fc7cb56673c9aa849e68e6300239601e615/lib/DescriptionFileUtils.js#L68-L82
match &result {
Ok(Some(package_json)) => {
ctx.add_file_dependency(&package_json.path);
}
Ok(None) => {
// Avoid an allocation by making this lazy
if let Some(deps) = &mut ctx.missing_dependencies {
deps.push(self.path.join("package.json"));
}
}
Err(_) => {
if let Some(deps) = &mut ctx.file_dependencies {
deps.push(self.path.join("package.json"));
}
}
}
result
}
}

Expand Down
32 changes: 31 additions & 1 deletion src/context.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::ops::{Deref, DerefMut};
use std::{
ops::{Deref, DerefMut},
path::{Path, PathBuf},
};

use crate::error::ResolveError;

Expand All @@ -8,10 +11,20 @@ pub struct ResolveContext(ResolveContextImpl);
#[derive(Debug, Default, Clone)]
pub struct ResolveContextImpl {
pub fully_specified: bool,

pub query: Option<String>,

pub fragment: Option<String>,

/// Files that was found on file system
pub file_dependencies: Option<Vec<PathBuf>>,

/// Files that was found on file system
pub missing_dependencies: Option<Vec<PathBuf>>,

/// The current resolving alias for bailing recursion alias.
pub resolving_alias: Option<String>,

/// For avoiding infinite recursion, which will cause stack overflow.
depth: u8,
}
Expand Down Expand Up @@ -44,6 +57,23 @@ impl ResolveContext {
}
}

pub fn init_file_dependencies(&mut self) {
self.file_dependencies.replace(vec![]);
self.missing_dependencies.replace(vec![]);
}

pub fn add_file_dependency(&mut self, dep: &Path) {
if let Some(deps) = &mut self.file_dependencies {
deps.push(dep.to_path_buf());
}
}

pub fn add_missing_dependency(&mut self, dep: &Path) {
if let Some(deps) = &mut self.missing_dependencies {
deps.push(dep.to_path_buf());
}
}

pub fn with_resolving_alias(&mut self, alias: String) {
self.resolving_alias = Some(alias);
}
Expand Down
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy