Skip to content

Commit edf4f8e

Browse files
committed
feat: implement visitor
1 parent 255ab77 commit edf4f8e

File tree

4 files changed

+415
-4
lines changed

4 files changed

+415
-4
lines changed

lib/fixtures/fake-service-code.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
export const returnStringServiceCode = `
2+
import { HttpInterface, GetExchange } from '@r2don/nest-http-interface';
3+
4+
@HttpInterface()
5+
class TextService {
6+
constructor() {}
7+
8+
@GetExchange()
9+
async getText(): Promise<string> {
10+
return 'text';
11+
}
12+
}`;
13+
14+
export const hasResponseBodyServiceCode = `
15+
import { HttpInterface, PostExchange, ResponseBody } from '@r2don/nest-http-interface';
16+
import { User } from './user.entity';
17+
18+
@HttpInterface()
19+
class UserService {
20+
@PostExchange()
21+
@ResponseBody(User)
22+
async getUser(): Promise<any> {
23+
throw new Error('not implemented');
24+
}
25+
}`;
26+
27+
export const notPromiseServiceCode = `
28+
import { HttpInterface, GetExchange, ResponseBody } from '@r2don/nest-http-interface';
29+
30+
@HttpInterface()
31+
class UserService {
32+
@GetExchange()
33+
getUser(): string {
34+
throw new Error('not implemented');
35+
}
36+
}`;
37+
38+
export const needResponseBodyServiceCode = `
39+
import { HttpInterface, GraphQLExchange } from '@r2don/nest-http-interface';
40+
41+
class ResponseClass {}
42+
43+
@HttpInterface()
44+
class UserService {
45+
@GraphQLExchange()
46+
async getUser(): Promise<ResponseClass> {
47+
throw new Error('not implemented');
48+
}
49+
}`;
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2+
3+
exports[`HttpInterfaceVisitor > should ignore if file name is not match 1`] = `
4+
"import { HttpInterface, GraphQLExchange } from '@r2don/nest-http-interface';
5+
class ResponseClass {
6+
}
7+
let UserService = class UserService {
8+
async getUser() {
9+
throw new Error('not implemented');
10+
}
11+
};
12+
__decorate([
13+
GraphQLExchange()
14+
], UserService.prototype, \\"getUser\\", null);
15+
UserService = __decorate([
16+
HttpInterface()
17+
], UserService);
18+
"
19+
`;
20+
21+
exports[`HttpInterfaceVisitor > should ignore if method has ResponseBody decorator 1`] = `
22+
"import { HttpInterface, PostExchange, ResponseBody } from '@r2don/nest-http-interface';
23+
import { User } from './user.entity';
24+
let UserService = class UserService {
25+
async getUser() {
26+
throw new Error('not implemented');
27+
}
28+
};
29+
__decorate([
30+
PostExchange(),
31+
ResponseBody(User)
32+
], UserService.prototype, \\"getUser\\", null);
33+
UserService = __decorate([
34+
HttpInterface()
35+
], UserService);
36+
"
37+
`;
38+
39+
exports[`HttpInterfaceVisitor > should ignore if return type if not a promise 1`] = `
40+
"import { HttpInterface, GetExchange } from '@r2don/nest-http-interface';
41+
let UserService = class UserService {
42+
getUser() {
43+
throw new Error('not implemented');
44+
}
45+
};
46+
__decorate([
47+
GetExchange()
48+
], UserService.prototype, \\"getUser\\", null);
49+
UserService = __decorate([
50+
HttpInterface()
51+
], UserService);
52+
"
53+
`;
54+
55+
exports[`HttpInterfaceVisitor > should ignore if return type is not a class 1`] = `
56+
"import { HttpInterface, GetExchange } from '@r2don/nest-http-interface';
57+
let TextService = class TextService {
58+
constructor() { }
59+
async getText() {
60+
return 'text';
61+
}
62+
};
63+
__decorate([
64+
GetExchange()
65+
], TextService.prototype, \\"getText\\", null);
66+
TextService = __decorate([
67+
HttpInterface()
68+
], TextService);
69+
"
70+
`;
71+
72+
exports[`HttpInterfaceVisitor > should override plugin suffix option 1`] = `
73+
"import { HttpInterface, GraphQLExchange } from '@r2don/nest-http-interface';
74+
class ResponseClass {
75+
}
76+
let UserService = class UserService {
77+
async getUser() {
78+
throw new Error('not implemented');
79+
}
80+
};
81+
__decorate([
82+
GraphQLExchange(),
83+
ResponseBody(ResponseClass)
84+
], UserService.prototype, \\"getUser\\", null);
85+
UserService = __decorate([
86+
HttpInterface()
87+
], UserService);
88+
"
89+
`;
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import * as ts from 'typescript';
2+
import { describe, expect, test } from 'vitest';
3+
import {
4+
returnStringServiceCode,
5+
hasResponseBodyServiceCode,
6+
needResponseBodyServiceCode,
7+
notPromiseServiceCode,
8+
} from '../../fixtures/fake-service-code';
9+
import { before } from '../compiler-plugin';
10+
11+
describe('HttpInterfaceVisitor', () => {
12+
test('should ignore if file name is not match', () => {
13+
// given
14+
const options: ts.CompilerOptions = {
15+
module: ts.ModuleKind.ES2020,
16+
target: ts.ScriptTarget.ES2020,
17+
newLine: ts.NewLineKind.LineFeed,
18+
noEmitHelpers: true,
19+
experimentalDecorators: true,
20+
strict: true,
21+
};
22+
const filename = 'not-match.ts';
23+
const fakeProgram = ts.createProgram([filename], options);
24+
25+
// when
26+
const result = ts.transpileModule(needResponseBodyServiceCode, {
27+
compilerOptions: options,
28+
fileName: filename,
29+
transformers: { before: [before({}, fakeProgram)] },
30+
});
31+
32+
// then
33+
expect(result.outputText).toMatchSnapshot();
34+
});
35+
36+
test('should ignore if return type is not a class', () => {
37+
// given
38+
const options: ts.CompilerOptions = {
39+
module: ts.ModuleKind.ES2020,
40+
target: ts.ScriptTarget.ES2020,
41+
newLine: ts.NewLineKind.LineFeed,
42+
noEmitHelpers: true,
43+
experimentalDecorators: true,
44+
strict: true,
45+
};
46+
const filename = 'text.service.ts';
47+
const fakeProgram = ts.createProgram([filename], options);
48+
49+
// when
50+
const result = ts.transpileModule(returnStringServiceCode, {
51+
compilerOptions: options,
52+
fileName: filename,
53+
transformers: {
54+
before: [before(undefined, fakeProgram)],
55+
},
56+
});
57+
58+
// then
59+
expect(result.outputText).toMatchSnapshot();
60+
});
61+
62+
test('should ignore if method has ResponseBody decorator', () => {
63+
// given
64+
const options: ts.CompilerOptions = {
65+
module: ts.ModuleKind.ES2020,
66+
target: ts.ScriptTarget.ES2020,
67+
newLine: ts.NewLineKind.LineFeed,
68+
noEmitHelpers: true,
69+
experimentalDecorators: true,
70+
strict: true,
71+
};
72+
const filename = 'text.service.ts';
73+
const fakeProgram = ts.createProgram([filename], options);
74+
75+
// when
76+
const result = ts.transpileModule(hasResponseBodyServiceCode, {
77+
compilerOptions: options,
78+
fileName: filename,
79+
transformers: { before: [before({}, fakeProgram)] },
80+
});
81+
82+
// then
83+
expect(result.outputText).toMatchSnapshot();
84+
});
85+
86+
test('should ignore if return type if not a promise ', () => {
87+
// given
88+
const options: ts.CompilerOptions = {
89+
module: ts.ModuleKind.ES2020,
90+
target: ts.ScriptTarget.ES2020,
91+
newLine: ts.NewLineKind.LineFeed,
92+
noEmitHelpers: true,
93+
experimentalDecorators: true,
94+
strict: true,
95+
};
96+
const filename = 'text.service.ts';
97+
const fakeProgram = ts.createProgram([filename], options);
98+
99+
// when
100+
const result = ts.transpileModule(notPromiseServiceCode, {
101+
compilerOptions: options,
102+
fileName: filename,
103+
transformers: { before: [before({}, fakeProgram)] },
104+
});
105+
106+
// then
107+
expect(result.outputText).toMatchSnapshot();
108+
});
109+
110+
test('should override plugin suffix option', () => {
111+
// given
112+
const options: ts.CompilerOptions = {
113+
module: ts.ModuleKind.ES2020,
114+
target: ts.ScriptTarget.ES2020,
115+
newLine: ts.NewLineKind.LineFeed,
116+
noEmitHelpers: true,
117+
experimentalDecorators: true,
118+
strict: true,
119+
};
120+
const filename = '.custom.ts';
121+
const fakeProgram = ts.createProgram([filename], options);
122+
123+
// when
124+
const result = ts.transpileModule(needResponseBodyServiceCode, {
125+
compilerOptions: options,
126+
fileName: filename,
127+
transformers: {
128+
before: [
129+
before({ interfaceFilenameSuffix: '.custom.ts' }, fakeProgram),
130+
],
131+
},
132+
});
133+
134+
// then
135+
expect(result.outputText).toMatchSnapshot();
136+
});
137+
});

0 commit comments

Comments
 (0)