Skip to content

Commit 7e73515

Browse files
committed
fix: resolve file path in require
1 parent b95a530 commit 7e73515

File tree

3 files changed

+103
-14
lines changed

3 files changed

+103
-14
lines changed

lib/plugin/utils/plugin-utils.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/* c8 ignore start */
2+
/**
3+
* codes are from '@nestjs/swagger' package
4+
*/
5+
6+
import { isAbsolute, posix } from 'path';
7+
8+
export function replaceImportPath(
9+
typeReference: string,
10+
fileName: string,
11+
): string | undefined {
12+
if (!typeReference.includes('import')) {
13+
return typeReference;
14+
}
15+
let importPath = /\("([^)]).+(")/.exec(typeReference)?.[0];
16+
if (importPath == null) {
17+
return undefined;
18+
}
19+
importPath = convertPath(importPath);
20+
importPath = importPath.slice(2, importPath.length - 1);
21+
22+
try {
23+
if (isAbsolute(importPath)) {
24+
throw new Error();
25+
}
26+
require.resolve(importPath);
27+
return typeReference.replace('import', 'require');
28+
} catch (_error) {
29+
let relativePath = posix.relative(posix.dirname(fileName), importPath);
30+
relativePath = relativePath[0] !== '.' ? './' + relativePath : relativePath;
31+
32+
const nodeModulesText = 'node_modules';
33+
const nodeModulePos = relativePath.indexOf(nodeModulesText);
34+
if (nodeModulePos >= 0) {
35+
relativePath = relativePath.slice(
36+
nodeModulePos + nodeModulesText.length + 1, // slash
37+
);
38+
39+
const typesText = '@types';
40+
const typesPos = relativePath.indexOf(typesText);
41+
if (typesPos >= 0) {
42+
relativePath = relativePath.slice(
43+
typesPos + typesText.length + 1, // slash
44+
);
45+
}
46+
47+
const indexText = '/index';
48+
const indexPos = relativePath.indexOf(indexText);
49+
if (indexPos >= 0) {
50+
relativePath = relativePath.slice(0, indexPos);
51+
}
52+
}
53+
54+
typeReference = typeReference.replace(importPath, relativePath);
55+
return typeReference.replace('import', 'require');
56+
}
57+
}
58+
59+
/**
60+
* Converts Windows specific file paths to posix
61+
* @param windowsPath
62+
*/
63+
function convertPath(windowsPath: string): string {
64+
return windowsPath
65+
.replace(/^\\\\\?\\/, '')
66+
.replace(/\\/g, '/')
67+
.replace(/\/\/+/g, '/');
68+
}
69+
70+
/* c8 ignore end */

lib/plugin/visitors/__snapshots__/http-interface.visitor.spec.ts.snap

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
exports[`HttpInterfaceVisitor > should handle array return type 1`] = `
44
"\\"use strict\\";
55
Object.defineProperty(exports, \\"__esModule\\", { value: true });
6-
const eager_module_1 = require(\\"@r2don/nest-http-interface\\");
6+
const r2don_http_module_1 = require(\\"@r2don/nest-http-interface\\");
77
const nest_http_interface_1 = require(\\"@r2don/nest-http-interface\\");
88
class ResponseClass {
99
}
@@ -20,15 +20,15 @@ let UserService = class UserService {
2020
};
2121
__decorate([
2222
(0, nest_http_interface_1.GetExchange)(),
23-
eager_module_1.ResponseBody(ResponseClass)
23+
r2don_http_module_1.ResponseBody(ResponseClass)
2424
], UserService.prototype, \\"getUsers\\", null);
2525
__decorate([
2626
(0, nest_http_interface_1.GetExchange)(),
27-
eager_module_1.ResponseBody(ResponseClass)
27+
r2don_http_module_1.ResponseBody(ResponseClass)
2828
], UserService.prototype, \\"getUserList\\", null);
2929
__decorate([
3030
(0, nest_http_interface_1.GetExchange)(),
31-
eager_module_1.ResponseBody(ResponseClass)
31+
r2don_http_module_1.ResponseBody(ResponseClass)
3232
], UserService.prototype, \\"getUsersReadonly\\", null);
3333
UserService = __decorate([
3434
(0, nest_http_interface_1.HttpInterface)()
@@ -116,7 +116,7 @@ TextService = __decorate([
116116
exports[`HttpInterfaceVisitor > should override plugin suffix option 1`] = `
117117
"\\"use strict\\";
118118
Object.defineProperty(exports, \\"__esModule\\", { value: true });
119-
const eager_module_1 = require(\\"@r2don/nest-http-interface\\");
119+
const r2don_http_module_1 = require(\\"@r2don/nest-http-interface\\");
120120
const nest_http_interface_1 = require(\\"@r2don/nest-http-interface\\");
121121
class ResponseClass {
122122
}
@@ -127,7 +127,7 @@ let UserService = class UserService {
127127
};
128128
__decorate([
129129
(0, nest_http_interface_1.GraphQLExchange)(),
130-
eager_module_1.ResponseBody(ResponseClass)
130+
r2don_http_module_1.ResponseBody(ResponseClass)
131131
], UserService.prototype, \\"getUser\\", null);
132132
UserService = __decorate([
133133
(0, nest_http_interface_1.HttpInterface)()

lib/plugin/visitors/http-interface.visitor.ts

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
GraphQLExchange,
1212
ResponseBody,
1313
} from '../../decorators';
14+
import { replaceImportPath } from '../utils/plugin-utils';
1415

1516
export class HttpInterfaceVisitor {
1617
HTTP_INTERFACE_DECORATOR = HttpInterface.name;
@@ -26,7 +27,7 @@ export class HttpInterfaceVisitor {
2627
GraphQLExchange.name,
2728
];
2829

29-
libModuleAlias = 'eager_module_1';
30+
libModuleAlias = 'r2don_http_module_1';
3031
libName = '@r2don/nest-http-interface';
3132
importSet = new Set<string>();
3233
typeFormatFlag =
@@ -45,7 +46,12 @@ export class HttpInterfaceVisitor {
4546
const typeChecker = program.getTypeChecker();
4647
const visitNode = (node: ts.Node): ts.Node => {
4748
if (this.isHttpInterfaceClass(node)) {
48-
return this.visitMethods(node, factory, typeChecker);
49+
return this.visitMethods(
50+
node,
51+
factory,
52+
typeChecker,
53+
sourceFile.fileName,
54+
);
4955
}
5056

5157
if (ts.isSourceFile(node)) {
@@ -91,13 +97,19 @@ export class HttpInterfaceVisitor {
9197
node: ts.ClassDeclaration,
9298
factory: ts.NodeFactory,
9399
typeChecker: ts.TypeChecker,
100+
hostFilename: string,
94101
): ts.ClassDeclaration {
95102
const updatedMembers = node.members.map((member) => {
96103
if (!this.isExchangeMethod(member)) {
97104
return member;
98105
}
99106

100-
return this.appendResponseBodyDecorator(member, factory, typeChecker);
107+
return this.appendResponseBodyDecorator(
108+
member,
109+
factory,
110+
typeChecker,
111+
hostFilename,
112+
);
101113
});
102114

103115
return factory.updateClassDeclaration(
@@ -121,8 +133,13 @@ export class HttpInterfaceVisitor {
121133
node: ts.MethodDeclaration,
122134
factory: ts.NodeFactory,
123135
typeChecker: ts.TypeChecker,
136+
hostFilename: string,
124137
): ts.MethodDeclaration {
125-
const returnType = this.getReturnTypeAsText(node, typeChecker);
138+
const returnType = this.getReturnTypeAsText(
139+
node,
140+
typeChecker,
141+
hostFilename,
142+
);
126143

127144
if (returnType == null) {
128145
return node;
@@ -157,6 +174,7 @@ export class HttpInterfaceVisitor {
157174
private getReturnTypeAsText(
158175
node: ts.MethodDeclaration,
159176
typeChecker: ts.TypeChecker,
177+
hostFilename: string,
160178
): string | undefined {
161179
if (
162180
node.type == null ||
@@ -176,13 +194,14 @@ export class HttpInterfaceVisitor {
176194
return undefined;
177195
}
178196

179-
return typeChecker
180-
.typeToString(
197+
return replaceImportPath(
198+
typeChecker.typeToString(
181199
typeChecker.getTypeAtLocation(innerType),
182200
undefined,
183201
this.typeFormatFlag,
184-
)
185-
.replace('import', 'require');
202+
),
203+
hostFilename,
204+
);
186205
}
187206

188207
private getInnerType(node?: ts.TypeNode): ts.TypeNode | undefined {

0 commit comments

Comments
 (0)