mirror of
https://github.com/swc-project/swc.git
synced 2025-01-08 23:10:13 +03:00
fix(es/loader): Fix traversal of node modules resolver (#4327)
This commit is contained in:
parent
bef183e74a
commit
780de7095e
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -3228,11 +3228,13 @@ dependencies = [
|
||||
"ahash",
|
||||
"anyhow",
|
||||
"dashmap",
|
||||
"lazy_static",
|
||||
"lru",
|
||||
"normpath",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"path-clean",
|
||||
"pathdiff",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"swc_cached",
|
||||
|
@ -27,18 +27,20 @@ tsc = ["dashmap", "once_cell", "swc_cached"]
|
||||
[dependencies]
|
||||
ahash = "0.7.4"
|
||||
anyhow = "1.0.41"
|
||||
dashmap = {version = "5.1.0", optional = true}
|
||||
lru = {version = "0.7.1", optional = true}
|
||||
once_cell = {version = "1.9.0", optional = true}
|
||||
parking_lot = {version = "0.12.0", optional = true}
|
||||
path-clean = {version = "=0.1.0", optional = true}
|
||||
serde = {version = "1", features = ["derive"]}
|
||||
serde_json = {version = "1.0.64", optional = true}
|
||||
swc_cached = {version = "0.1.0", optional = true, path = "../swc_cached"}
|
||||
swc_common = { version = "0.17.20", path = "../swc_common"}
|
||||
dashmap = { version = "5.1.0", optional = true }
|
||||
lru = { version = "0.7.1", optional = true }
|
||||
once_cell = { version = "1.9.0", optional = true }
|
||||
parking_lot = { version = "0.12.0", optional = true }
|
||||
path-clean = { version = "=0.1.0", optional = true }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = { version = "1.0.64", optional = true }
|
||||
swc_cached = { version = "0.1.0", optional = true, path = "../swc_cached" }
|
||||
swc_common = { version = "0.17.20", path = "../swc_common" }
|
||||
tracing = "0.1.32"
|
||||
pathdiff = "0.2.1"
|
||||
|
||||
[dev-dependencies]
|
||||
lazy_static = "1.4.0"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
normpath = {version = "0.2", optional = true}
|
||||
normpath = { version = "0.2", optional = true }
|
||||
|
@ -3,6 +3,7 @@
|
||||
//! See: https://github.com/goto-bus-stop/node-resolve
|
||||
|
||||
use std::{
|
||||
env::current_dir,
|
||||
fs::File,
|
||||
io::BufReader,
|
||||
path::{Component, Path, PathBuf},
|
||||
@ -14,6 +15,7 @@ use dashmap::{DashMap, DashSet};
|
||||
use normpath::BasePath;
|
||||
use once_cell::sync::Lazy;
|
||||
use path_clean::PathClean;
|
||||
use pathdiff::diff_paths;
|
||||
use serde::Deserialize;
|
||||
use swc_common::{collections::AHashMap, FileName};
|
||||
use tracing::debug;
|
||||
@ -53,6 +55,19 @@ fn find_package_root(path: &Path) -> Option<PathBuf> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn to_absolute_path(path: impl AsRef<Path>) -> Result<PathBuf, Error> {
|
||||
let path = path.as_ref();
|
||||
|
||||
let absolute_path = if path.is_absolute() {
|
||||
path.to_path_buf()
|
||||
} else {
|
||||
current_dir()?.join(path)
|
||||
}
|
||||
.clean();
|
||||
|
||||
Ok(absolute_path)
|
||||
}
|
||||
|
||||
pub(crate) fn is_core_module(s: &str) -> bool {
|
||||
NODE_BUILTINS.contains(&s)
|
||||
}
|
||||
@ -294,14 +309,17 @@ impl NodeModulesResolver {
|
||||
base_dir: &Path,
|
||||
target: &str,
|
||||
) -> Result<Option<PathBuf>, Error> {
|
||||
let mut path = Some(base_dir);
|
||||
let absolute_path = to_absolute_path(base_dir)?;
|
||||
let mut path = Some(&*absolute_path);
|
||||
while let Some(dir) = path {
|
||||
let node_modules = dir.join("node_modules");
|
||||
if node_modules.is_dir() {
|
||||
let path = node_modules.join(target);
|
||||
if let Some(result) = self
|
||||
.resolve_as_file(&path)
|
||||
.or_else(|_| self.resolve_as_directory(&path))?
|
||||
.ok()
|
||||
.or_else(|| self.resolve_as_directory(&path).ok())
|
||||
.flatten()
|
||||
{
|
||||
return Ok(Some(result));
|
||||
}
|
||||
@ -391,7 +409,12 @@ impl Resolve for NodeModulesResolver {
|
||||
.and_then(|p| self.wrap(p))
|
||||
} else {
|
||||
self.resolve_node_modules(base_dir, target)
|
||||
.and_then(|p| self.wrap(p))
|
||||
.and_then(|path| {
|
||||
let file_path = path.context("Impossible to get the node_modules path");
|
||||
let current_directory = current_dir()?;
|
||||
let relative_path = diff_paths(file_path?, current_directory);
|
||||
self.wrap(relative_path)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
1
crates/swc_ecma_loader/tests/.gitignore
vendored
Normal file
1
crates/swc_ecma_loader/tests/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
!node_modules
|
1
crates/swc_ecma_loader/tests/basic_import/node_modules/jquery/index.js
generated
vendored
Normal file
1
crates/swc_ecma_loader/tests/basic_import/node_modules/jquery/index.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
console.log("hello world!");
|
4
crates/swc_ecma_loader/tests/basic_import/node_modules/jquery/package.json
generated
vendored
Normal file
4
crates/swc_ecma_loader/tests/basic_import/node_modules/jquery/package.json
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "jquery",
|
||||
"main": "index.js"
|
||||
}
|
1
crates/swc_ecma_loader/tests/hoisting/node_modules/jquery/index.js
generated
vendored
Normal file
1
crates/swc_ecma_loader/tests/hoisting/node_modules/jquery/index.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
console.log("hello world!");
|
4
crates/swc_ecma_loader/tests/hoisting/node_modules/jquery/package.json
generated
vendored
Normal file
4
crates/swc_ecma_loader/tests/hoisting/node_modules/jquery/package.json
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "jquery",
|
||||
"main": "index.js"
|
||||
}
|
1
crates/swc_ecma_loader/tests/hoisting/packages/app/node_modules/example/index.js
generated
vendored
Normal file
1
crates/swc_ecma_loader/tests/hoisting/packages/app/node_modules/example/index.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
console.log("hello world!");
|
4
crates/swc_ecma_loader/tests/hoisting/packages/app/node_modules/example/package.json
generated
vendored
Normal file
4
crates/swc_ecma_loader/tests/hoisting/packages/app/node_modules/example/package.json
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "example",
|
||||
"main": "index.js"
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "app",
|
||||
"main": "file.js"
|
||||
}
|
68
crates/swc_ecma_loader/tests/node_resolver.rs
Normal file
68
crates/swc_ecma_loader/tests/node_resolver.rs
Normal file
@ -0,0 +1,68 @@
|
||||
#![cfg(feature = "node")]
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
env::{current_dir, set_current_dir},
|
||||
path::PathBuf,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use anyhow::{anyhow, Error};
|
||||
use lazy_static::lazy_static;
|
||||
use swc_common::{collections::AHashMap, FileName};
|
||||
extern crate swc_ecma_loader;
|
||||
use swc_ecma_loader::{resolve::Resolve, resolvers::node::NodeModulesResolver, TargetEnv};
|
||||
|
||||
lazy_static! {
|
||||
static ref UPDATE_DIR_MUTEX: Arc<Mutex<()>> = Arc::new(Mutex::new(()));
|
||||
}
|
||||
|
||||
fn inside_directory(dir: &str, callback: fn()) {
|
||||
let arc = Arc::clone(&UPDATE_DIR_MUTEX);
|
||||
let _lock = arc.lock().expect("could not lock");
|
||||
|
||||
let initial_current_dir = current_dir().unwrap();
|
||||
let new_current_dir = format!("{}{}", initial_current_dir.display(), dir);
|
||||
|
||||
set_current_dir(new_current_dir).unwrap();
|
||||
callback();
|
||||
set_current_dir(initial_current_dir).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_import() {
|
||||
inside_directory("/tests/basic_import", || {
|
||||
// Given
|
||||
let node_resolver = NodeModulesResolver::new(TargetEnv::Node, Default::default(), true);
|
||||
|
||||
// When
|
||||
let resolved = node_resolver
|
||||
.resolve(&FileName::Real(PathBuf::from(&"jquery")), &"jquery")
|
||||
.expect("should resolve");
|
||||
|
||||
// Expect
|
||||
assert_eq!(
|
||||
resolved,
|
||||
FileName::Real(PathBuf::from("node_modules/jquery/index.js"))
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hoisting() {
|
||||
inside_directory("/tests/hoisting/packages/app", || {
|
||||
// Given
|
||||
let node_resolver = NodeModulesResolver::new(TargetEnv::Node, Default::default(), true);
|
||||
|
||||
// When
|
||||
let resolved = node_resolver
|
||||
.resolve(&FileName::Real(PathBuf::from(&"jquery")), &"jquery")
|
||||
.expect("should resolve");
|
||||
|
||||
// Expect
|
||||
assert_eq!(
|
||||
resolved,
|
||||
FileName::Real(PathBuf::from("../../node_modules/jquery/index.js"))
|
||||
);
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue
Block a user