diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 1047aea7d5f6..b08ed4d14b20 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -19,6 +19,10 @@ env: # https://github.com/actions/setup-node/issues/899#issuecomment-1819151595 SKIP_YARN_COREPACK_CHECK: 1 +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: "${{ github.event_name == 'pull_request' }}" + jobs: cargo-fmt: name: Cargo fmt diff --git a/crates/swc/tests/fixture/issues-8xxx/8674/input/.swcrc b/crates/swc/tests/fixture/issues-8xxx/8674/input/.swcrc new file mode 100644 index 000000000000..0620ec21b573 --- /dev/null +++ b/crates/swc/tests/fixture/issues-8xxx/8674/input/.swcrc @@ -0,0 +1,6 @@ +{ + "$schema": "http://json.schemastore.org/swcrc", + "jsc": { + "baseUrl": "." + } +} \ No newline at end of file diff --git a/crates/swc/tests/fixture/issues-8xxx/8674/input/index.ts b/crates/swc/tests/fixture/issues-8xxx/8674/input/index.ts new file mode 100644 index 000000000000..87a1949d3304 --- /dev/null +++ b/crates/swc/tests/fixture/issues-8xxx/8674/input/index.ts @@ -0,0 +1,2 @@ +import { foo } from "src/foo" +console.log(foo) \ No newline at end of file diff --git a/crates/swc/tests/fixture/issues-8xxx/8674/input/src/foo.ts b/crates/swc/tests/fixture/issues-8xxx/8674/input/src/foo.ts new file mode 100644 index 000000000000..3deda8047e15 --- /dev/null +++ b/crates/swc/tests/fixture/issues-8xxx/8674/input/src/foo.ts @@ -0,0 +1 @@ +export { } \ No newline at end of file diff --git a/crates/swc/tests/fixture/issues-8xxx/8674/output/index.ts b/crates/swc/tests/fixture/issues-8xxx/8674/output/index.ts new file mode 100644 index 000000000000..ec453b47e021 --- /dev/null +++ b/crates/swc/tests/fixture/issues-8xxx/8674/output/index.ts @@ -0,0 +1,2 @@ +import { foo } from "./src/foo"; +console.log(foo); diff --git a/crates/swc/tests/fixture/issues-8xxx/8674/output/src/foo.ts b/crates/swc/tests/fixture/issues-8xxx/8674/output/src/foo.ts new file mode 100644 index 000000000000..2234b9cae16d --- /dev/null +++ b/crates/swc/tests/fixture/issues-8xxx/8674/output/src/foo.ts @@ -0,0 +1 @@ +export { }; diff --git a/crates/swc/tests/projects.rs b/crates/swc/tests/projects.rs index a8381e71bb53..c95aea9c2c08 100644 --- a/crates/swc/tests/projects.rs +++ b/crates/swc/tests/projects.rs @@ -1,4 +1,5 @@ use std::{ + env::current_dir, fs::create_dir_all, path::{Path, PathBuf}, }; @@ -1123,6 +1124,37 @@ fn issue_7513_2() { ); } +#[test] +fn issue_8674_1() { + static INPUT: &str = "import { foo } from 'src/foo'"; + + let base_url = current_dir() + .unwrap() + .join("../../node-swc/tests/issue-8674") + .canonicalize() + .unwrap(); + + dbg!(&base_url); + + let output = str_with_opt( + INPUT, + Options { + config: Config { + jsc: JscConfig { + base_url, + ..Default::default() + }, + ..Default::default() + }, + ..Default::default() + }, + ) + .unwrap(); + println!("{}", output); + + assert_eq!(output.to_string(), "import { foo } from \"./src/foo\";\n"); +} + #[testing::fixture("tests/minify/**/input.js")] fn minify(input_js: PathBuf) { let input_dir = input_js.parent().unwrap(); diff --git a/crates/swc_ecma_loader/src/resolvers/node.rs b/crates/swc_ecma_loader/src/resolvers/node.rs index e08a8bd1b4b5..eb44710a4075 100644 --- a/crates/swc_ecma_loader/src/resolvers/node.rs +++ b/crates/swc_ecma_loader/src/resolvers/node.rs @@ -413,12 +413,27 @@ impl NodeModulesResolver { Ok(None) } - fn resolve_filename(&self, base: &FileName, target: &str) -> Result { + fn resolve_filename(&self, base: &FileName, module_specifier: &str) -> Result { debug!( "Resolving {} from {:#?} for {:#?}", - target, base, self.target_env + module_specifier, base, self.target_env ); + { + // Handle absolute path + + let path = Path::new(module_specifier); + + if let Ok(file) = self + .resolve_as_file(path) + .or_else(|_| self.resolve_as_directory(path, false)) + { + if let Ok(file) = self.wrap(file) { + return Ok(file); + } + } + } + let base = match base { FileName::Real(v) => v, _ => bail!("node-resolver supports only files"), @@ -437,10 +452,10 @@ impl NodeModulesResolver { if let Some(pkg_base) = find_package_root(base) { if let Some(item) = BROWSER_CACHE.get(&pkg_base) { let value = item.value(); - if value.module_ignores.contains(target) { - return Ok(FileName::Custom(target.into())); + if value.module_ignores.contains(module_specifier) { + return Ok(FileName::Custom(module_specifier.into())); } - if let Some(rewrite) = value.module_rewrites.get(target) { + if let Some(rewrite) = value.module_rewrites.get(module_specifier) { return self.wrap(Some(rewrite.to_path_buf())); } } @@ -449,21 +464,21 @@ impl NodeModulesResolver { // Handle builtin modules for nodejs if let TargetEnv::Node = self.target_env { - if target.starts_with("node:") { - return Ok(FileName::Custom(target.into())); + if module_specifier.starts_with("node:") { + return Ok(FileName::Custom(module_specifier.into())); } - if is_core_module(target) { - return Ok(FileName::Custom(format!("node:{}", target))); + if is_core_module(module_specifier) { + return Ok(FileName::Custom(format!("node:{}", module_specifier))); } } // Aliases allow browser shims to be renamed so we can // map `stream` to `stream-browserify` for example - let target = if let Some(alias) = self.alias.get(target) { + let target = if let Some(alias) = self.alias.get(module_specifier) { &alias[..] } else { - target + module_specifier }; let target_path = Path::new(target); diff --git a/crates/swc_ecma_loader/src/resolvers/tsc.rs b/crates/swc_ecma_loader/src/resolvers/tsc.rs index 357ea3961af8..b8b1ef2d7c27 100644 --- a/crates/swc_ecma_loader/src/resolvers/tsc.rs +++ b/crates/swc_ecma_loader/src/resolvers/tsc.rs @@ -320,13 +320,9 @@ where } let path = self.base_url.join(module_specifier); - #[cfg(windows)] - let path_string: String = path.to_string_lossy().replace("\\", "/"); - #[cfg(not(windows))] - let path_string: String = path.to_string_lossy().to_string(); // https://www.typescriptlang.org/docs/handbook/modules/reference.html#baseurl - if let Ok(v) = self.invoke_inner_resolver(base, path_string.as_str()) { + if let Ok(v) = self.invoke_inner_resolver(base, &path.to_string_lossy()) { return Ok(v); } diff --git a/crates/swc_ecma_loader/tests/tsc_resolver.rs b/crates/swc_ecma_loader/tests/tsc_resolver.rs index 9cef9faf5ab5..a8cebfa6a926 100644 --- a/crates/swc_ecma_loader/tests/tsc_resolver.rs +++ b/crates/swc_ecma_loader/tests/tsc_resolver.rs @@ -193,8 +193,10 @@ struct TestResolver(AHashMap); impl Resolve for TestResolver { fn resolve(&self, _: &FileName, src: &str) -> Result { + let src = src.replace('\\', "/"); + self.0 - .get(src) + .get(&src) .cloned() .map(FileName::Custom) .map(|v| Resolution { diff --git a/crates/swc_ecma_transforms_module/src/path.rs b/crates/swc_ecma_transforms_module/src/path.rs index 3df6d962f8bb..a7a23766a851 100644 --- a/crates/swc_ecma_transforms_module/src/path.rs +++ b/crates/swc_ecma_transforms_module/src/path.rs @@ -280,13 +280,16 @@ where v.parent() .ok_or_else(|| anyhow!("failed to get parent of {:?}", v))?, ), - FileName::Anon => { - if cfg!(target_arch = "wasm32") { - panic!("Please specify `filename`") - } else { - Cow::Owned(current_dir().expect("failed to get current directory")) + FileName::Anon => match &self.config.base_dir { + Some(v) => Cow::Borrowed(&**v), + None => { + if cfg!(target_arch = "wasm32") { + panic!("Please specify `filename`") + } else { + Cow::Owned(current_dir().expect("failed to get current directory")) + } } - } + }, _ => { unreachable!( "Node path provider does not support using `{:?}` as a base file name", diff --git a/node-swc/__tests__/transform/issue_8674_test.mjs b/node-swc/__tests__/transform/issue_8674_test.mjs new file mode 100644 index 000000000000..e823bb3f8f49 --- /dev/null +++ b/node-swc/__tests__/transform/issue_8674_test.mjs @@ -0,0 +1,29 @@ +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import swc from "../../.."; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +it("should transpile import path correctly", async () => { + const baseUrl = path.resolve(__dirname, "../../tests/issue-8674"); + console.log("baseUrl", baseUrl); + process.chdir(baseUrl); + + const { code } = await swc.transform( + ` + import { foo } from "src/foo" + console.log(foo) + `, + { + jsc: { + baseUrl, + }, + } + ); + + expect(code).toMatchInlineSnapshot(` + "import { foo } from "./src/foo"; + console.log(foo); + " + `); +}); diff --git a/node-swc/tests/issue-8674/src/bar.ts b/node-swc/tests/issue-8674/src/bar.ts new file mode 100644 index 000000000000..4548a26ba14d --- /dev/null +++ b/node-swc/tests/issue-8674/src/bar.ts @@ -0,0 +1 @@ +export default 'bar' diff --git a/node-swc/tests/issue-8674/src/foo.ts b/node-swc/tests/issue-8674/src/foo.ts new file mode 100644 index 000000000000..7e942cf45c8a --- /dev/null +++ b/node-swc/tests/issue-8674/src/foo.ts @@ -0,0 +1 @@ +export default 'foo'