Skip to content

Commit

Permalink
feat: consider array return type in visitor
Browse files Browse the repository at this point in the history
  • Loading branch information
jbl428 committed May 7, 2023
1 parent d7fa31e commit 99c88a5
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 1 deletion.
23 changes: 23 additions & 0 deletions lib/fixtures/fake-service-code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,26 @@ class UserService {
throw new Error('not implemented');
}
}`;

export const arrayResponseBodyServiceCode = `
import { HttpInterface, GetExchange } from '@r2don/nest-http-interface';
class ResponseClass {}
@HttpInterface()
class UserService {
@GetExchange()
async getUsers(): Promise<ResponseClass[]> {
throw new Error('not implemented');
}
@GetExchange()
async getUserList(): Promise<Array<ResponseClass>> {
throw new Error('not implemented');
}
@GetExchange()
async getUsersReadonly(): Promise<readonly ResponseClass[]> {
throw new Error('not implemented');
}
}`;
Original file line number Diff line number Diff line change
@@ -1,5 +1,38 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`HttpInterfaceVisitor > should handle array return type 1`] = `
"import { HttpInterface, GetExchange } from '@r2don/nest-http-interface';
class ResponseClass {
}
let UserService = class UserService {
async getUsers() {
throw new Error('not implemented');
}
async getUserList() {
throw new Error('not implemented');
}
async getUsersReadonly() {
throw new Error('not implemented');
}
};
__decorate([
GetExchange(),
ResponseBody(ResponseClass)
], UserService.prototype, \\"getUsers\\", null);
__decorate([
GetExchange(),
ResponseBody(ResponseClass)
], UserService.prototype, \\"getUserList\\", null);
__decorate([
GetExchange(),
ResponseBody(ResponseClass)
], UserService.prototype, \\"getUsersReadonly\\", null);
UserService = __decorate([
HttpInterface()
], UserService);
"
`;

exports[`HttpInterfaceVisitor > should ignore if file name is not match 1`] = `
"import { HttpInterface, GraphQLExchange } from '@r2don/nest-http-interface';
class ResponseClass {
Expand Down
19 changes: 19 additions & 0 deletions lib/plugin/visitors/http-interface.visitor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
hasResponseBodyServiceCode,
needResponseBodyServiceCode,
notPromiseServiceCode,
arrayResponseBodyServiceCode,
} from '../../fixtures/fake-service-code';
import { before } from '../compiler-plugin';

Expand Down Expand Up @@ -103,4 +104,22 @@ describe('HttpInterfaceVisitor', () => {
// then
expect(result.outputText).toMatchSnapshot();
});

test('should handle array return type', () => {
// given
const filename = 'text.service.ts';
const fakeProgram = ts.createProgram([filename], compilerOptions);

// when
const result = ts.transpileModule(arrayResponseBodyServiceCode, {
compilerOptions,
fileName: filename,
transformers: {
before: [before({}, fakeProgram)],
},
});

// then
expect(result.outputText).toMatchSnapshot();
});
});
30 changes: 29 additions & 1 deletion lib/plugin/visitors/http-interface.visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export class HttpInterfaceVisitor {
return undefined;
}

const innerType = node.type.typeArguments?.[0];
const innerType = this.getInnerType(node.type.typeArguments?.[0]);
if (
innerType == null ||
!ts.isTypeReferenceNode(innerType) ||
Expand All @@ -119,6 +119,34 @@ export class HttpInterfaceVisitor {
return innerType.typeName.text;
}

private getInnerType(node?: ts.TypeNode): ts.TypeNode | undefined {
/* c8 ignore next 3 */
if (node == null) {
return undefined;
}

if (ts.isArrayTypeNode(node)) {
return this.getInnerType(node.elementType);
}

if (
ts.isTypeReferenceNode(node) &&
ts.isIdentifier(node.typeName) &&
node.typeName.text === 'Array'
) {
return this.getInnerType(node.typeArguments?.[0]);
}

if (
ts.isTypeOperatorNode(node) &&
node.operator === ts.SyntaxKind.ReadonlyKeyword
) {
return this.getInnerType(node.type);
}

return node;
}

private isExchangeMethod(
member: ts.ClassElement,
): member is ts.MethodDeclaration {
Expand Down

0 comments on commit 99c88a5

Please sign in to comment.