feat(resolver): implement enforceExtension (#566)

This commit is contained in:
Boshen 2023-07-18 15:05:02 +08:00 committed by GitHub
parent e5de977279
commit c32dd32bad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 34 additions and 22 deletions

View file

@ -16,7 +16,7 @@
| | cacheWithContext | true | If unsafe cache is enabled, includes `request.context` in the cache key |
| | conditionNames | [] | A list of exports field condition names |
| ✅ | descriptionFiles | ["package.json"] | A list of description files to read from |
| | enforceExtension | false | Enforce that a extension from extensions must be used |
| | enforceExtension | false | Enforce that a extension from extensions must be used |
| | exportsFields | ["exports"] | A list of exports fields in description files |
| ✅ | extensions | [".js", ".json", ".node"] | A list of extensions which should be tried for files |
| | fallback | [] | Same as `alias`, but only used if default resolving fails |

View file

@ -170,7 +170,7 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
fn load_index(&self, path: &Path) -> ResolveState {
for main_field in &self.options.main_files {
let main_path = path.join(main_field);
if !self.options.enforce_extension && self.cache.is_file(&main_path) {
if self.options.enforce_extension == Some(false) && self.cache.is_file(&main_path) {
return Ok(Some(main_path));
}
// 1. If X/index.js is a file, load X/index.js as JavaScript text. STOP

View file

@ -25,8 +25,12 @@ pub struct ResolveOptions {
/// Enforce that a extension from extensions must be used.
///
/// Default `false`
pub enforce_extension: bool,
/// Default to `true` when [ResolveOptions::extensions] contains an empty string.
/// Use `Some(false)` to disable the behavior.
/// See <https://github.com/webpack/enhanced-resolve/pull/285>
///
/// Default None, which is the same as `Some(false)` when the above empty rule is not applied.
pub enforce_extension: Option<bool>,
/// An object which maps extension to extension aliases.
///
@ -55,7 +59,7 @@ impl Default for ResolveOptions {
alias: vec![],
alias_fields: vec![],
description_files: vec!["package.json".into()],
enforce_extension: false,
enforce_extension: None,
extension_alias: vec![],
extensions: vec![".js".into(), ".json".into(), ".node".into()],
main_files: vec!["index".into()],
@ -66,6 +70,15 @@ impl Default for ResolveOptions {
impl ResolveOptions {
pub(crate) fn sanitize(mut self) -> Self {
if self.enforce_extension.is_none() {
self.enforce_extension = Some(false);
// Set `enforceExtension` to `true` when [ResolveOptions::extensions] contains an empty string.
// See <https://github.com/webpack/enhanced-resolve/pull/285>
if self.extensions.iter().any(String::is_empty) {
self.enforce_extension = Some(true);
self.extensions.retain(String::is_empty);
}
}
self.extensions = Self::remove_leading_dots(self.extensions);
self.extension_alias = self
.extension_alias

View file

@ -2,7 +2,7 @@
use std::path::PathBuf;
use oxc_resolver::{ResolveError, ResolveOptions, Resolver};
use oxc_resolver::{Resolution, ResolveError, ResolveOptions, Resolver};
fn fixture() -> PathBuf {
super::fixture().join("extensions")
@ -48,32 +48,31 @@ fn extensions() -> Result<(), ResolveError> {
}
#[test]
#[ignore = "need to match missingDependencies returned from the resolve function"]
// should default enforceExtension to true when extensions includes an empty string
fn default_enforce_extension() {
// should default enforceExtension to true when extensions includes an empty string
let fixture = fixture();
let f = fixture();
let options = ResolveOptions {
let resolved = Resolver::new(ResolveOptions {
extensions: vec![".ts".into(), String::new(), ".js".into()],
..ResolveOptions::default()
};
})
.resolve(&f, "./foo");
let resolver = Resolver::new(options);
let _resolved = resolver.resolve(fixture, "./foo");
assert_eq!(resolved, Err(ResolveError::NotFound(f.join("foo").into_boxed_path())));
// TODO: need to match missingDependencies returned from the resolve function
}
#[test]
#[ignore = "need to match missingDependencies returned from the resolve function"]
// should respect enforceExtension when extensions includes an empty string
fn respect_enforce_extension() {
// should respect enforceExtension when extensions includes an empty string
let fixture = fixture();
let f = fixture();
let options = ResolveOptions {
enforce_extension: false,
let resolved = Resolver::new(ResolveOptions {
enforce_extension: Some(false),
extensions: vec![".ts".into(), String::new(), ".js".into()],
..ResolveOptions::default()
};
let resolver = Resolver::new(options);
let _resolved = resolver.resolve(fixture, "./foo");
})
.resolve(&f, "./foo");
assert_eq!(resolved.map(Resolution::into_path_buf), Ok(f.join("foo.ts")));
// TODO: need to match missingDependencies returned from the resolve function
}