service-ref.ts 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. import { ClassDeclaration, Node, Type } from 'ts-morph';
  2. import { EntityRef } from './entity-ref';
  3. export interface ServiceFeatures {
  4. findOne: boolean;
  5. findAll: boolean;
  6. create: boolean;
  7. update: boolean;
  8. delete: boolean;
  9. }
  10. export class ServiceRef {
  11. readonly features: ServiceFeatures;
  12. readonly crudEntityRef?: EntityRef;
  13. get name(): string {
  14. return this.classDeclaration.getName() as string;
  15. }
  16. get nameCamelCase(): string {
  17. return this.name.charAt(0).toLowerCase() + this.name.slice(1);
  18. }
  19. get isCrudService(): boolean {
  20. return this.crudEntityRef !== undefined;
  21. }
  22. constructor(public readonly classDeclaration: ClassDeclaration) {
  23. this.features = {
  24. findOne: !!this.classDeclaration.getMethod('findOne'),
  25. findAll: !!this.classDeclaration.getMethod('findAll'),
  26. create: !!this.classDeclaration.getMethod('create'),
  27. update: !!this.classDeclaration.getMethod('update'),
  28. delete: !!this.classDeclaration.getMethod('delete'),
  29. };
  30. this.crudEntityRef = this.getEntityRef();
  31. }
  32. private getEntityRef(): EntityRef | undefined {
  33. if (this.features.findOne) {
  34. const potentialCrudMethodNames = ['findOne', 'findAll', 'create', 'update', 'delete'];
  35. for (const methodName of potentialCrudMethodNames) {
  36. const findOneMethod = this.classDeclaration.getMethod(methodName);
  37. const returnType = findOneMethod?.getReturnType();
  38. if (returnType) {
  39. const unwrappedReturnType = this.unwrapReturnType(returnType);
  40. const typeDeclaration = unwrappedReturnType.getSymbolOrThrow().getDeclarations()[0];
  41. if (typeDeclaration && Node.isClassDeclaration(typeDeclaration)) {
  42. if (typeDeclaration.getExtends()?.getText() === 'VendureEntity') {
  43. return new EntityRef(typeDeclaration);
  44. }
  45. }
  46. }
  47. }
  48. }
  49. return;
  50. }
  51. private unwrapReturnType(returnType: Type): Type {
  52. if (returnType.isUnion()) {
  53. // get the non-null part of the union
  54. const nonNullType = returnType.getUnionTypes().find(t => !t.isNull() && !t.isUndefined());
  55. if (!nonNullType) {
  56. throw new Error('Could not find non-null type in union');
  57. }
  58. return this.unwrapReturnType(nonNullType);
  59. }
  60. const typeArguments = returnType.getTypeArguments();
  61. if (typeArguments.length) {
  62. return this.unwrapReturnType(typeArguments[0]);
  63. }
  64. const aliasTypeArguments = returnType.getAliasTypeArguments();
  65. if (aliasTypeArguments.length) {
  66. return this.unwrapReturnType(aliasTypeArguments[0]);
  67. }
  68. return returnType;
  69. }
  70. }