Skip to content
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

fix(es/modules): Support jsc.baseUrl without jsc.paths #7302

Merged
merged 20 commits into from
Apr 20, 2023
11 changes: 6 additions & 5 deletions crates/swc/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1438,10 +1438,11 @@ impl ModuleConfig {
}
_ => base.clone(),
};
let skip_resolver = base_url.as_os_str().is_empty() && paths.is_empty();

match config {
None | Some(ModuleConfig::Es6) | Some(ModuleConfig::NodeNext) => {
if paths.is_empty() {
if skip_resolver {
Box::new(noop())
} else {
let resolver = build_resolver(base_url, paths);
Expand All @@ -1450,7 +1451,7 @@ impl ModuleConfig {
}
}
Some(ModuleConfig::CommonJs(config)) => {
if paths.is_empty() {
if skip_resolver {
Box::new(modules::common_js::common_js(
unresolved_mark,
config,
Expand All @@ -1470,7 +1471,7 @@ impl ModuleConfig {
}
}
Some(ModuleConfig::Umd(config)) => {
if paths.is_empty() {
if skip_resolver {
Box::new(modules::umd::umd(
cm,
unresolved_mark,
Expand All @@ -1493,7 +1494,7 @@ impl ModuleConfig {
}
}
Some(ModuleConfig::Amd(config)) => {
if paths.is_empty() {
if skip_resolver {
Box::new(modules::amd::amd(
unresolved_mark,
config,
Expand All @@ -1514,7 +1515,7 @@ impl ModuleConfig {
}
}
Some(ModuleConfig::SystemJs(config)) => {
if paths.is_empty() {
if skip_resolver {
Box::new(modules::system_js::system_js(unresolved_mark, config))
} else {
let resolver = build_resolver(base_url, paths);
Expand Down
2 changes: 1 addition & 1 deletion crates/swc_ecma_loader/src/resolvers/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ impl Resolve for NodeModulesResolver {
} else {
self.resolve_node_modules(base_dir, target)
.and_then(|path| {
let file_path = path.context("Impossible to get the node_modules path");
let file_path = path.context("failed to get the node_modules path");
let current_directory = current_dir()?;
let relative_path = diff_paths(file_path?, current_directory);
self.wrap(relative_path)
Expand Down
32 changes: 22 additions & 10 deletions crates/swc_ecma_loader/src/resolvers/tsc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ where
{
inner: R,
base_url: PathBuf,
base_url_filename: FileName,
paths: Vec<(Pattern, Vec<String>)>,
}

Expand Down Expand Up @@ -93,6 +94,7 @@ where

Self {
inner,
base_url_filename: FileName::Real(base_url.clone()),
base_url,
paths,
}
Expand All @@ -103,27 +105,30 @@ impl<R> Resolve for TsConfigResolver<R>
where
R: Resolve,
{
fn resolve(&self, base: &FileName, src: &str) -> Result<FileName, Error> {
fn resolve(&self, base: &FileName, module_specifier: &str) -> Result<FileName, Error> {
let _tracing = if cfg!(debug_assertions) {
Some(
tracing::span!(
Level::ERROR,
"tsc.resolve",
base_url = tracing::field::display(self.base_url.display()),
base = tracing::field::display(base),
src = tracing::field::display(src),
src = tracing::field::display(module_specifier),
)
.entered(),
)
} else {
None
};

if src.starts_with('.') && (src == ".." || src.starts_with("./") || src.starts_with("../"))
if module_specifier.starts_with('.')
&& (module_specifier == ".."
|| module_specifier.starts_with("./")
|| module_specifier.starts_with("../"))
{
return self
.inner
.resolve(base, src)
.resolve(base, module_specifier)
.context("not processed by tsc resolver because it's relative import");
}

Expand All @@ -136,17 +141,24 @@ where
Component::Normal(v) => v == "node_modules",
_ => false,
}) {
return self.inner.resolve(base, src).context(
return self.inner.resolve(base, module_specifier).context(
"not processed by tsc resolver because base module is in node_modules",
);
}
}

if let Ok(v) = self
.inner
.resolve(&self.base_url_filename, module_specifier)
{
return Ok(v);
}

// https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping
for (from, to) in &self.paths {
match from {
Pattern::Wildcard { prefix } => {
let extra = src.strip_prefix(prefix);
let extra = module_specifier.strip_prefix(prefix);
let extra = match extra {
Some(v) => v,
None => {
Expand All @@ -169,7 +181,7 @@ where
let res = self.inner.resolve(base, &rel).with_context(|| {
format!(
"failed to resolve `{}`, which is expanded from `{}`",
replaced, src
replaced, module_specifier
)
});

Expand All @@ -192,14 +204,14 @@ where

bail!(
"`{}` matched `{}` (from tsconfig.paths) but failed to resolve:\n{:?}",
src,
module_specifier,
prefix,
errors
)
}
Pattern::Exact(from) => {
// Should be exactly matched
if src == from {
if module_specifier == from {
let replaced = self.base_url.join(&to[0]);
if replaced.exists() {
return Ok(FileName::Real(replaced));
Expand All @@ -219,6 +231,6 @@ where
}
}

self.inner.resolve(base, src)
self.inner.resolve(base, module_specifier)
}
}
34 changes: 26 additions & 8 deletions crates/swc_ecma_transforms_module/tests/path_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::{
};

use indexmap::IndexMap;
use serde::Deserialize;
use swc_common::FileName;
use swc_ecma_loader::resolvers::{node::NodeModulesResolver, tsc::TsConfigResolver};
use swc_ecma_parser::Syntax;
Expand Down Expand Up @@ -96,29 +97,46 @@ fn paths_resolver(
base_url: impl AsRef<Path>,
rules: Vec<(String, Vec<String>)>,
) -> JscPathsProvider {
let base_url = base_url.as_ref().to_path_buf();
dbg!(&base_url);

NodeImportResolver::new(TsConfigResolver::new(
NodeModulesResolver::new(swc_ecma_loader::TargetEnv::Node, Default::default(), true),
base_url.as_ref().to_path_buf(),
base_url,
rules,
))
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct TestConfig {
#[serde(default)]
base_url: Option<PathBuf>,

#[serde(default)]
input_file: Option<String>,

#[serde(default)]
paths: IndexMap<String, Vec<String>>,
}

#[testing::fixture("tests/paths/**/input")]
fn fixture(input_dir: PathBuf) {
let output_dir = input_dir.parent().unwrap().join("output");

let index_path = input_dir.join("index.ts");
let paths_json_path = input_dir.join("config.json");
let paths_json = std::fs::read_to_string(paths_json_path).unwrap();
let config = serde_json::from_str::<TestConfig>(&paths_json).unwrap();

let index_path = input_dir.join(config.input_file.as_deref().unwrap_or("index.ts"));

test_fixture(
Syntax::default(),
&|_| {
let paths_json_path = input_dir.join("paths.json");
let paths_json = std::fs::read_to_string(paths_json_path).unwrap();
let paths = serde_json::from_str::<IndexMap<String, Vec<String>>>(&paths_json).unwrap();

let rules = paths.into_iter().collect();
let rules = config.paths.clone().into_iter().collect();

let resolver = paths_resolver(&input_dir, rules);
let resolver =
paths_resolver(config.base_url.clone().unwrap_or(input_dir.clone()), rules);

import_rewriter(FileName::Real(index_path.clone()), resolver)
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"baseUrl": "src",
"inputFile": "src/index.ts"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import jq from "jquery";
import file from "folder/file2";
console.log(jq, file);
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default 'used'
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import jq from "jquery";
import file from "./folder/file2";
console.log(jq, file);
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"baseUrl": "src",
"inputFile": "src/index.ts"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import jq from "../jquery";
import file from "./file2";
console.log(jq, file);
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default 'used'
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import jq from "./jquery";
import file from "./folder/file2";
console.log(jq, file);
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"baseUrl": "src",
"inputFile": "src/index.ts"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import jq from 'jquery';
import file from "folder/file2";

console.log(jq, file)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"paths": {
"@src/*": ["./*"]
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"paths": {
"@lib/*": ["./src/*"]
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"paths": {
"@src/*": ["./src/*"]
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"paths": {
"@src/*": ["./src/*"]
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"paths": {
"shared/*": ["./src/shared/*"],
"utils/*": ["./src/utils/*"]
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"paths": {
"@src/*": ["./src/*"]
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"paths": {
"@src/*": ["./src/*"]
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"paths": {
"@/*": ["./src/*"]
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"paths": {
"@/utils/*": ["./*"]
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"paths": {
"@/utils/*": ["./*"]
}
}

This file was deleted.