Skip to content

Commit d37125f

Browse files
authoredMar 6, 2024··
fix(es/module): Fix relativeness check for jsc.paths (#8702)
**Related issue:** - Closes #8701
1 parent 90aaaba commit d37125f

27 files changed

+456
-31
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"$schema": "http://json.schemastore.org/swcrc",
3+
"jsc": {
4+
"baseUrl": ".",
5+
"paths": {
6+
"@app/*": [
7+
"./src/*"
8+
]
9+
},
10+
"parser": {
11+
"syntax": "typescript",
12+
"decorators": true
13+
}
14+
}
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { Test, TestingModule } from '@nestjs/testing';
2+
import { AppController } from './app.controller';
3+
import { AppService } from './app.service';
4+
5+
describe('AppController', () => {
6+
let app: TestingModule;
7+
8+
beforeAll(async () => {
9+
app = await Test.createTestingModule({
10+
controllers: [AppController],
11+
providers: [AppService],
12+
}).compile();
13+
});
14+
15+
describe('getHello', () => {
16+
it('should return "Hello World!"', () => {
17+
const appController = app.get(AppController);
18+
expect(appController.getHello()).toBe('Hello World!');
19+
});
20+
});
21+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Controller, Get } from '@nestjs/common';
2+
import { AppService } from './app.service';
3+
4+
@Controller()
5+
export class AppController {
6+
constructor(private readonly appService: AppService) {}
7+
8+
@Get()
9+
getHello(): string {
10+
return this.appService.getHello();
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { Module } from '@nestjs/common';
2+
import { AppController } from '@app/app.controller';
3+
import { AppService } from '@app/app.service';
4+
5+
@Module({
6+
imports: [],
7+
controllers: [AppController],
8+
providers: [AppService],
9+
})
10+
export class AppModule {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { Injectable } from '@nestjs/common';
2+
3+
@Injectable()
4+
export class AppService {
5+
getHello(): string {
6+
return 'Hello World!';
7+
}
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { NestFactory } from '@nestjs/core';
2+
import { AppModule } from './app.module';
3+
4+
async function bootstrap() {
5+
const app = await NestFactory.create(AppModule);
6+
await app.listen(3000);
7+
}
8+
bootstrap();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { _ as _async_to_generator } from "@swc/helpers/_/_async_to_generator";
2+
import { _ as _ts_generator } from "@swc/helpers/_/_ts_generator";
3+
import { Test } from "@nestjs/testing";
4+
import { AppController } from "./app.controller";
5+
import { AppService } from "./app.service";
6+
describe("AppController", function() {
7+
var app;
8+
beforeAll(/*#__PURE__*/ _async_to_generator(function() {
9+
return _ts_generator(this, function(_state) {
10+
switch(_state.label){
11+
case 0:
12+
return [
13+
4,
14+
Test.createTestingModule({
15+
controllers: [
16+
AppController
17+
],
18+
providers: [
19+
AppService
20+
]
21+
}).compile()
22+
];
23+
case 1:
24+
app = _state.sent();
25+
return [
26+
2
27+
];
28+
}
29+
});
30+
}));
31+
describe("getHello", function() {
32+
it('should return "Hello World!"', function() {
33+
var appController = app.get(AppController);
34+
expect(appController.getHello()).toBe("Hello World!");
35+
});
36+
});
37+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { _ as _class_call_check } from "@swc/helpers/_/_class_call_check";
2+
import { _ as _create_class } from "@swc/helpers/_/_create_class";
3+
import { _ as _define_property } from "@swc/helpers/_/_define_property";
4+
import { _ as _ts_decorate } from "@swc/helpers/_/_ts_decorate";
5+
import { Controller, Get } from "@nestjs/common";
6+
export var AppController = /*#__PURE__*/ function() {
7+
"use strict";
8+
function AppController(appService) {
9+
_class_call_check(this, AppController);
10+
_define_property(this, "appService", void 0);
11+
this.appService = appService;
12+
}
13+
_create_class(AppController, [
14+
{
15+
key: "getHello",
16+
value: function getHello() {
17+
return this.appService.getHello();
18+
}
19+
}
20+
]);
21+
return AppController;
22+
}();
23+
_ts_decorate([
24+
Get()
25+
], AppController.prototype, "getHello", null);
26+
AppController = _ts_decorate([
27+
Controller()
28+
], AppController);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { _ as _class_call_check } from "@swc/helpers/_/_class_call_check";
2+
import { _ as _ts_decorate } from "@swc/helpers/_/_ts_decorate";
3+
import { Module } from "@nestjs/common";
4+
import { AppController } from "./app.controller";
5+
import { AppService } from "./app.service";
6+
export var AppModule = function AppModule() {
7+
"use strict";
8+
_class_call_check(this, AppModule);
9+
};
10+
AppModule = _ts_decorate([
11+
Module({
12+
imports: [],
13+
controllers: [
14+
AppController
15+
],
16+
providers: [
17+
AppService
18+
]
19+
})
20+
], AppModule);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { _ as _class_call_check } from "@swc/helpers/_/_class_call_check";
2+
import { _ as _create_class } from "@swc/helpers/_/_create_class";
3+
import { _ as _ts_decorate } from "@swc/helpers/_/_ts_decorate";
4+
import { Injectable } from "@nestjs/common";
5+
export var AppService = /*#__PURE__*/ function() {
6+
"use strict";
7+
function AppService() {
8+
_class_call_check(this, AppService);
9+
}
10+
_create_class(AppService, [
11+
{
12+
key: "getHello",
13+
value: function getHello() {
14+
return "Hello World!";
15+
}
16+
}
17+
]);
18+
return AppService;
19+
}();
20+
AppService = _ts_decorate([
21+
Injectable()
22+
], AppService);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { _ as _async_to_generator } from "@swc/helpers/_/_async_to_generator";
2+
import { _ as _ts_generator } from "@swc/helpers/_/_ts_generator";
3+
import { NestFactory } from "@nestjs/core";
4+
import { AppModule } from "./app.module";
5+
function bootstrap() {
6+
return _bootstrap.apply(this, arguments);
7+
}
8+
function _bootstrap() {
9+
_bootstrap = _async_to_generator(function() {
10+
var app;
11+
return _ts_generator(this, function(_state) {
12+
switch(_state.label){
13+
case 0:
14+
return [
15+
4,
16+
NestFactory.create(AppModule)
17+
];
18+
case 1:
19+
app = _state.sent();
20+
return [
21+
4,
22+
app.listen(3000)
23+
];
24+
case 2:
25+
_state.sent();
26+
return [
27+
2
28+
];
29+
}
30+
});
31+
});
32+
return _bootstrap.apply(this, arguments);
33+
}
34+
bootstrap();

‎crates/swc/tests/projects.rs

+56-3
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ use anyhow::Context;
88
use rayon::prelude::*;
99
use swc::{
1010
config::{
11-
Config, FileMatcher, JsMinifyOptions, JscConfig, ModuleConfig, Options, SourceMapsConfig,
12-
TransformConfig,
11+
Config, FileMatcher, JsMinifyOptions, JscConfig, ModuleConfig, Options, Paths,
12+
SourceMapsConfig, TransformConfig,
1313
},
1414
try_with_handler, BoolOrDataConfig, Compiler, TransformOutput,
1515
};
@@ -65,7 +65,16 @@ fn file_with_opt(filename: &str, options: Options) -> Result<NormalizedOutput, S
6565
}
6666

6767
fn str_with_opt(content: &str, options: Options) -> Result<NormalizedOutput, StdErr> {
68-
compile_str(FileName::Anon, content, options).map(|v| v.code.into())
68+
compile_str(
69+
if options.filename.is_empty() {
70+
FileName::Anon
71+
} else {
72+
FileName::Real(PathBuf::from(&options.filename))
73+
},
74+
content,
75+
options,
76+
)
77+
.map(|v| v.code.into())
6978
}
7079

7180
fn compile_str(
@@ -1155,6 +1164,50 @@ fn issue_8674_1() {
11551164
assert_eq!(output.to_string(), "import { foo } from \"./src/foo\";\n");
11561165
}
11571166

1167+
#[test]
1168+
fn issue_8701_1() {
1169+
static INPUT: &str = "import { AppController } from '@app/app.controller';
1170+
import { AppService } from '@app/app.service';
1171+
1172+
console.log(AppController, AppService);";
1173+
1174+
let base_url = current_dir()
1175+
.unwrap()
1176+
.join("tests/projects/issue-8701")
1177+
.canonicalize()
1178+
.unwrap();
1179+
1180+
dbg!(&base_url);
1181+
1182+
let output = str_with_opt(
1183+
INPUT,
1184+
Options {
1185+
filename: "src/app.module.ts".into(),
1186+
config: Config {
1187+
jsc: JscConfig {
1188+
base_url,
1189+
paths: {
1190+
let mut paths = Paths::default();
1191+
paths.insert("@app/*".into(), vec!["./src/*".into()]);
1192+
paths
1193+
},
1194+
..Default::default()
1195+
},
1196+
..Default::default()
1197+
},
1198+
..Default::default()
1199+
},
1200+
)
1201+
.unwrap();
1202+
println!("{}", output);
1203+
1204+
assert_eq!(
1205+
output.to_string(),
1206+
"import { AppController } from \"./app.controller\";\nimport { AppService } from \
1207+
\"./app.service\";\nconsole.log(AppController, AppService);\n"
1208+
);
1209+
}
1210+
11581211
#[testing::fixture("tests/minify/**/input.js")]
11591212
fn minify(input_js: PathBuf) {
11601213
let input_dir = input_js.parent().unwrap();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { Test, TestingModule } from '@nestjs/testing';
2+
import { AppController } from './app.controller';
3+
import { AppService } from './app.service';
4+
5+
describe('AppController', () => {
6+
let app: TestingModule;
7+
8+
beforeAll(async () => {
9+
app = await Test.createTestingModule({
10+
controllers: [AppController],
11+
providers: [AppService],
12+
}).compile();
13+
});
14+
15+
describe('getHello', () => {
16+
it('should return "Hello World!"', () => {
17+
const appController = app.get(AppController);
18+
expect(appController.getHello()).toBe('Hello World!');
19+
});
20+
});
21+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Controller, Get } from '@nestjs/common';
2+
import { AppService } from './app.service';
3+
4+
@Controller()
5+
export class AppController {
6+
constructor(private readonly appService: AppService) {}
7+
8+
@Get()
9+
getHello(): string {
10+
return this.appService.getHello();
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { Module } from '@nestjs/common';
2+
import { AppController } from '@app/app.controller';
3+
import { AppService } from '@app/app.service';
4+
@Module({
5+
imports: [],
6+
controllers: [AppController],
7+
providers: [AppService],
8+
})
9+
export class AppModule { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { Injectable } from '@nestjs/common';
2+
3+
@Injectable()
4+
export class AppService {
5+
getHello(): string {
6+
return 'Hello World!';
7+
}
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { NestFactory } from '@nestjs/core';
2+
import { AppModule } from './app.module';
3+
4+
async function bootstrap() {
5+
const app = await NestFactory.create(AppModule);
6+
await app.listen(3000);
7+
}
8+
bootstrap();

‎crates/swc_ecma_transforms_module/src/path.rs

+1-8
Original file line numberDiff line numberDiff line change
@@ -259,14 +259,7 @@ where
259259
info!("Resolved as {target:?} with slug = {slug:?}");
260260

261261
let mut target = match target {
262-
FileName::Real(v) => {
263-
// @nestjs/common should be preserved as a whole
264-
if v.starts_with(".") || v.starts_with("..") || v.is_absolute() {
265-
v
266-
} else {
267-
return Ok(self.to_specifier(v, slug));
268-
}
269-
}
262+
FileName::Real(v) => v,
270263
FileName::Custom(s) => return Ok(self.to_specifier(s.into(), slug)),
271264
_ => {
272265
unreachable!(

‎crates/swc_ecma_transforms_module/tests/path_node.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -126,14 +126,19 @@ fn fixture(input_dir: PathBuf) {
126126
let config = serde_json::from_str::<TestConfig>(&paths_json).unwrap();
127127

128128
let index_path = input_dir.join(config.input_file.as_deref().unwrap_or("index.ts"));
129+
dbg!(&index_path);
129130

131+
let base_dir = input_dir
132+
.join(config.base_url.clone().unwrap_or(input_dir.clone()))
133+
.canonicalize()
134+
.unwrap();
135+
dbg!(&base_dir);
130136
test_fixture(
131137
Syntax::default(),
132138
&|_| {
133139
let rules = config.paths.clone().into_iter().collect();
134140

135-
let resolver =
136-
paths_resolver(&config.base_url.clone().unwrap_or(input_dir.clone()), rules);
141+
let resolver = paths_resolver(&base_dir, rules);
137142

138143
import_rewriter(FileName::Real(index_path.clone()), resolver)
139144
},

‎crates/swc_ecma_transforms_module/tests/paths/pack-1682/1/output/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import PrismaClientProvider from "db/PrismaClientProvider";
1+
import PrismaClientProvider from "../db/PrismaClientProvider.js";
22
export default function setupTests() {
33
const context = {};
44
beforeEach(()=>{

‎node-swc/__tests__/transform/issue_7806_test.mjs

+9-17
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,15 @@ const __filename = fileURLToPath(import.meta.url);
66

77
describe("jsc.paths", () => {
88
it("should work with process.cwd()", async () => {
9-
console.log(process.cwd());
10-
const f = path.join(
9+
const testDir = path.join(
1110
__filename,
1211
"..",
1312
"..",
1413
"..",
1514
"tests",
16-
"swc-path-bug-1",
17-
"src",
18-
"index.ts"
15+
"swc-path-bug-1"
1916
);
17+
const f = path.join(testDir, "src", "index.ts");
2018
console.log(f);
2119
expect(
2220
(
@@ -25,7 +23,7 @@ describe("jsc.paths", () => {
2523
parser: {
2624
syntax: "typescript",
2725
},
28-
baseUrl: process.cwd(),
26+
baseUrl: testDir,
2927
paths: {
3028
"@utils/*": ["src/utils/*"],
3129
},
@@ -37,21 +35,15 @@ describe("jsc.paths", () => {
3735
Object.defineProperty(exports, "__esModule", {
3836
value: true
3937
});
40-
const _helloworldutils = require("src/utils/hello-world.utils.js");
38+
const _helloworldutils = require("./utils/hello-world.utils.js");
4139
console.log((0, _helloworldutils.helloWorld)());
4240
"
4341
`);
4442
});
4543

4644
it("should work with process.cwd() and relative url", async () => {
47-
console.log(process.cwd());
48-
const f = path.join(
49-
"node-swc",
50-
"tests",
51-
"swc-path-bug-1",
52-
"src",
53-
"index.ts"
54-
);
45+
const testDir = path.join("node-swc", "tests", "swc-path-bug-1");
46+
const f = path.join(testDir, "src", "index.ts");
5547
console.log(f);
5648
expect(
5749
(
@@ -60,7 +52,7 @@ describe("jsc.paths", () => {
6052
parser: {
6153
syntax: "typescript",
6254
},
63-
baseUrl: process.cwd(),
55+
baseUrl: path.resolve(testDir),
6456
paths: {
6557
"@utils/*": ["src/utils/*"],
6658
},
@@ -72,7 +64,7 @@ describe("jsc.paths", () => {
7264
Object.defineProperty(exports, "__esModule", {
7365
value: true
7466
});
75-
const _helloworldutils = require("src/utils/hello-world.utils.js");
67+
const _helloworldutils = require("./utils/hello-world.utils.js");
7668
console.log((0, _helloworldutils.helloWorld)());
7769
"
7870
`);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import path from "node:path";
2+
import { fileURLToPath } from "node:url";
3+
import swc from "../../..";
4+
5+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
6+
7+
it("should transpile import path correctly", async () => {
8+
const baseUrl = path.resolve(__dirname, "../../tests/issue-8701");
9+
console.log("baseUrl", baseUrl);
10+
process.chdir(baseUrl);
11+
12+
const { code } = await swc.transformFile("src/app.module.ts", {
13+
jsc: {
14+
baseUrl,
15+
paths: {
16+
"@app/*": ["./src/*"],
17+
},
18+
parser: {
19+
syntax: "typescript",
20+
decorators: true,
21+
},
22+
target: "es2019",
23+
},
24+
});
25+
26+
expect(code).toMatchInlineSnapshot(`
27+
"function _ts_decorate(decorators, target, key, desc) {
28+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
29+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
30+
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
31+
return c > 3 && r && Object.defineProperty(target, key, r), r;
32+
}
33+
import { Module } from "@nestjs/common";
34+
import { AppController } from "./app.controller";
35+
import { AppService } from "./app.service";
36+
export class AppModule {
37+
}
38+
AppModule = _ts_decorate([
39+
Module({
40+
imports: [],
41+
controllers: [
42+
AppController
43+
],
44+
providers: [
45+
AppService
46+
]
47+
})
48+
], AppModule);
49+
"
50+
`);
51+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { Test, TestingModule } from '@nestjs/testing';
2+
import { AppController } from './app.controller';
3+
import { AppService } from './app.service';
4+
5+
describe('AppController', () => {
6+
let app: TestingModule;
7+
8+
beforeAll(async () => {
9+
app = await Test.createTestingModule({
10+
controllers: [AppController],
11+
providers: [AppService],
12+
}).compile();
13+
});
14+
15+
describe('getHello', () => {
16+
it('should return "Hello World!"', () => {
17+
const appController = app.get(AppController);
18+
expect(appController.getHello()).toBe('Hello World!');
19+
});
20+
});
21+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Controller, Get } from '@nestjs/common';
2+
import { AppService } from './app.service';
3+
4+
@Controller()
5+
export class AppController {
6+
constructor(private readonly appService: AppService) {}
7+
8+
@Get()
9+
getHello(): string {
10+
return this.appService.getHello();
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { Module } from '@nestjs/common';
2+
import { AppController } from '@app/app.controller';
3+
import { AppService } from '@app/app.service';
4+
@Module({
5+
imports: [],
6+
controllers: [AppController],
7+
providers: [AppService],
8+
})
9+
export class AppModule { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { Injectable } from '@nestjs/common';
2+
3+
@Injectable()
4+
export class AppService {
5+
getHello(): string {
6+
return 'Hello World!';
7+
}
8+
}

‎node-swc/tests/issue-8701/src/main.ts

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { NestFactory } from '@nestjs/core';
2+
import { AppModule } from './app.module';
3+
4+
async function bootstrap() {
5+
const app = await NestFactory.create(AppModule);
6+
await app.listen(3000);
7+
}
8+
bootstrap();

0 commit comments

Comments
 (0)
Please sign in to comment.