mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(resolver): implement restrictions (path only) (#693)
This commit is contained in:
parent
38fb4c296a
commit
59f5dc1906
6 changed files with 76 additions and 3 deletions
|
|
@ -29,7 +29,7 @@
|
|||
| | resolveToContext | false | Resolve to a context instead of a file |
|
||||
| ✅ | preferRelative | false | Prefer to resolve module requests as relative request and fallback to resolving as module |
|
||||
| ✅ | preferAbsolute | false | Prefer to resolve server-relative urls as absolute paths before falling back to resolve in roots |
|
||||
| | restrictions | [] | A list of resolve restrictions |
|
||||
| ✅ | restrictions | [] | A list of resolve restrictions |
|
||||
| ✅ | roots | [] | A list of root paths |
|
||||
| ✅ | symlinks | true | Whether to resolve symlinks to their symlinked location |
|
||||
| | unsafeCache | false | Use this cache object to unsafely cache the successful requests
|
||||
|
|
@ -62,7 +62,7 @@ Crossed out test files are irrelevant.
|
|||
- [ ] pnp.test.js
|
||||
- [x] ~pr-53.test.js~
|
||||
- [x] resolve.test.js (need to add resolveToContext)
|
||||
- [ ] restrictions.test.js
|
||||
- [x] restrictions.test.js (partially done, regex is not supported yet)
|
||||
- [x] roots.test.js (need to add resolveToContext)
|
||||
- [x] scoped-packages.test.js
|
||||
- [x] simple.test.js
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@ pub enum ResolveError {
|
|||
/// JSON parse error
|
||||
JSON(JSONError),
|
||||
|
||||
/// Restricted by `ResolveOptions::restrictions`
|
||||
Restriction(PathBuf),
|
||||
|
||||
// TODO: TypeError [ERR_INVALID_MODULE_SPECIFIER]: Invalid module "./dist/../../../a.js" specifier is not a valid subpath for the "exports" resolution of /xxx/package.json
|
||||
InvalidModuleSpecifier(String),
|
||||
|
||||
|
|
@ -47,6 +50,8 @@ pub enum ResolveError {
|
|||
InvalidPackageConfigDirectory(PathBuf),
|
||||
|
||||
PackageImportNotDefined(String),
|
||||
|
||||
Unimplemented(&'static str),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ use crate::{
|
|||
pub use crate::{
|
||||
error::{JSONError, ResolveError},
|
||||
file_system::{FileMetadata, FileSystem},
|
||||
options::{Alias, AliasValue, ResolveOptions},
|
||||
options::{Alias, AliasValue, ResolveOptions, Restriction},
|
||||
resolution::Resolution,
|
||||
};
|
||||
|
||||
|
|
@ -138,6 +138,8 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
|
|||
.and_then(|value| value.ok_or(err))
|
||||
})?;
|
||||
let path = self.load_realpath(&cached_path).unwrap_or_else(|| cached_path.to_path_buf());
|
||||
// enhanced_resolve: restrictions
|
||||
self.check_restrictions(&path)?;
|
||||
let ctx = ctx.borrow();
|
||||
Ok(Resolution {
|
||||
path,
|
||||
|
|
@ -361,6 +363,34 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_restrictions(&self, path: &Path) -> Result<(), ResolveError> {
|
||||
// https://github.com/webpack/enhanced-resolve/blob/a998c7d218b7a9ec2461fc4fddd1ad5dd7687485/lib/RestrictionsPlugin.js#L19-L24
|
||||
fn is_inside(path: &Path, parent: &Path) -> bool {
|
||||
if !path.starts_with(parent) {
|
||||
return false;
|
||||
}
|
||||
if path.as_os_str().len() == parent.as_os_str().len() {
|
||||
return true;
|
||||
}
|
||||
path.strip_prefix(parent).is_ok_and(|p| p == Path::new("./"))
|
||||
}
|
||||
for restriction in &self.options.restrictions {
|
||||
match restriction {
|
||||
Restriction::Path(restricted_path) => {
|
||||
if !is_inside(path, restricted_path) {
|
||||
return Err(ResolveError::Restriction(path.to_path_buf()));
|
||||
}
|
||||
}
|
||||
Restriction::RegExp(_) => {
|
||||
return Err(ResolveError::Unimplemented(
|
||||
"Restriction with regex is unimplemented.",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn load_index(&self, cached_path: &CachedPath, ctx: &ResolveContext) -> ResolveState {
|
||||
for main_file in &self.options.main_files {
|
||||
let main_path = cached_path.path().join(main_file);
|
||||
|
|
|
|||
|
|
@ -84,6 +84,11 @@ pub struct ResolveOptions {
|
|||
/// Default `false`
|
||||
pub prefer_absolute: bool,
|
||||
|
||||
/// A list of resolve restrictions to restrict the paths that a request can be resolved on.
|
||||
///
|
||||
/// Default `[]`
|
||||
pub restrictions: Vec<Restriction>,
|
||||
|
||||
/// A list of directories where requests of server-relative URLs (starting with '/') are resolved.
|
||||
/// On non-Windows systems these requests are resolved as an absolute path first.
|
||||
///
|
||||
|
|
@ -111,6 +116,12 @@ pub enum AliasValue {
|
|||
Ignore,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Restriction {
|
||||
Path(PathBuf),
|
||||
RegExp(String),
|
||||
}
|
||||
|
||||
impl Default for ResolveOptions {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
|
|
@ -127,6 +138,7 @@ impl Default for ResolveOptions {
|
|||
modules: vec!["node_modules".into()],
|
||||
prefer_relative: false,
|
||||
prefer_absolute: false,
|
||||
restrictions: vec![],
|
||||
roots: vec![],
|
||||
symlinks: true,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ mod imports_field;
|
|||
mod incorrect_description_file;
|
||||
mod memory_fs;
|
||||
mod resolve;
|
||||
mod restrictions;
|
||||
mod roots;
|
||||
mod scoped_packages;
|
||||
mod simple;
|
||||
|
|
|
|||
25
crates/oxc_resolver/src/tests/restrictions.rs
Normal file
25
crates/oxc_resolver/src/tests/restrictions.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
//! <https://github.com/webpack/enhanced-resolve/blob/main/test/restrictions.test.js>
|
||||
|
||||
use crate::{ResolveError, ResolveOptions, Resolver, Restriction};
|
||||
|
||||
// TODO: regex
|
||||
// * should respect RegExp restriction
|
||||
// * should try to find alternative #1
|
||||
// * should try to find alternative #2
|
||||
// * should try to find alternative #3
|
||||
|
||||
#[test]
|
||||
// should respect string restriction
|
||||
fn restriction1() {
|
||||
let fixture = super::fixture();
|
||||
let f = fixture.join("restrictions");
|
||||
|
||||
let resolver = Resolver::new(ResolveOptions {
|
||||
extensions: vec![".js".into()],
|
||||
restrictions: vec![Restriction::Path(f.clone())],
|
||||
..ResolveOptions::default()
|
||||
});
|
||||
|
||||
let resolution = resolver.resolve(&f, "pck2");
|
||||
assert_eq!(resolution, Err(ResolveError::Restriction(fixture.join("c.js"))));
|
||||
}
|
||||
Loading…
Reference in a new issue