@exanderal/stackcraft 0.1.2 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +96 -21
  2. package/dist/create/index.d.ts.map +1 -1
  3. package/dist/create/index.js +12 -1
  4. package/dist/create/index.js.map +1 -1
  5. package/dist/create/scaffold.d.ts.map +1 -1
  6. package/dist/create/scaffold.js +11 -2
  7. package/dist/create/scaffold.js.map +1 -1
  8. package/dist/create/scaffolders/api-nestjs-graphql.d.ts +3 -0
  9. package/dist/create/scaffolders/api-nestjs-graphql.d.ts.map +1 -0
  10. package/dist/create/scaffolders/api-nestjs-graphql.js +44 -0
  11. package/dist/create/scaffolders/api-nestjs-graphql.js.map +1 -0
  12. package/dist/create/scaffolders/api-nestjs-rest.d.ts.map +1 -1
  13. package/dist/create/scaffolders/api-nestjs-rest.js +11 -1
  14. package/dist/create/scaffolders/api-nestjs-rest.js.map +1 -1
  15. package/dist/create/scaffolders/wire-client.d.ts +3 -0
  16. package/dist/create/scaffolders/wire-client.d.ts.map +1 -0
  17. package/dist/create/scaffolders/wire-client.js +77 -0
  18. package/dist/create/scaffolders/wire-client.js.map +1 -0
  19. package/dist/create/types.d.ts +1 -1
  20. package/dist/create/types.d.ts.map +1 -1
  21. package/package.json +1 -1
  22. package/templates/api-nestjs-graphql/.prettierrc +4 -0
  23. package/templates/api-nestjs-graphql/eslint.config.mjs +34 -0
  24. package/templates/api-nestjs-graphql/nest-cli.json +8 -0
  25. package/templates/api-nestjs-graphql/package.json +81 -0
  26. package/templates/api-nestjs-graphql/project.json +21 -0
  27. package/templates/api-nestjs-graphql/src/app.module.ts +21 -0
  28. package/templates/api-nestjs-graphql/src/common/entities/base.entity.ts +21 -0
  29. package/templates/api-nestjs-graphql/src/common/repositories/entity.repository.ts +21 -0
  30. package/templates/api-nestjs-graphql/src/common/repositories/readonly-entity.repository.ts +22 -0
  31. package/templates/api-nestjs-graphql/src/common/services/entity.service.ts +24 -0
  32. package/templates/api-nestjs-graphql/src/common/services/readonly-entity.service.ts +23 -0
  33. package/templates/api-nestjs-graphql/src/main.ts +8 -0
  34. package/templates/api-nestjs-graphql/src/modules/database/database.module.ts +18 -0
  35. package/templates/api-nestjs-graphql/src/modules/health/__tests__/health.controller.spec.ts +20 -0
  36. package/templates/api-nestjs-graphql/src/modules/health/__tests__/health.service.spec.ts +18 -0
  37. package/templates/api-nestjs-graphql/src/modules/health/health.controller.ts +12 -0
  38. package/templates/api-nestjs-graphql/src/modules/health/health.module.ts +9 -0
  39. package/templates/api-nestjs-graphql/src/modules/health/health.service.ts +8 -0
  40. package/templates/api-nestjs-graphql/test/app.e2e-spec.ts +29 -0
  41. package/templates/api-nestjs-graphql/test/jest-e2e.json +9 -0
  42. package/templates/api-nestjs-graphql/tsconfig.build.json +4 -0
  43. package/templates/api-nestjs-graphql/tsconfig.json +21 -0
  44. package/templates/api-nestjs-rest/package.json +1 -0
  45. package/templates/api-nestjs-rest/src/main.ts +11 -0
  46. package/templates/base/package.json +5 -1
  47. package/templates/base/packages/types/package.json +10 -0
  48. package/templates/base/packages/types/tsconfig.json +10 -0
  49. package/templates/base/tools/generators/controller/index.js +22 -0
  50. package/templates/base/tools/generators/controller/schema.json +18 -0
  51. package/templates/base/tools/generators/generators.json +11 -1
  52. package/templates/base/tools/generators/module/graphql-files/__fileName__.model.ts__tmpl__ +11 -0
  53. package/templates/base/tools/generators/module/index.js +4 -22
  54. package/templates/base/tools/generators/module/schema.json +4 -5
  55. package/templates/base/tools/generators/resolver/files/__fileName__.resolver.ts__tmpl__ +28 -0
  56. package/templates/base/tools/generators/resolver/index.js +22 -0
  57. package/templates/base/tools/generators/resolver/schema.json +18 -0
  58. package/templates/types-graphql/codegen.ts +17 -0
  59. package/templates/types-graphql/project.json +19 -0
  60. package/templates/types-rest/openapi-ts.config.ts +10 -0
  61. package/templates/types-rest/project.json +19 -0
  62. /package/templates/base/tools/generators/{module/crud-files → controller/files}/__fileName__.controller.ts__tmpl__ +0 -0
@@ -0,0 +1,21 @@
1
+ import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
2
+ import { Module } from '@nestjs/common';
3
+ import { ConfigModule } from '@nestjs/config';
4
+ import { GraphQLModule } from '@nestjs/graphql';
5
+ import { join } from 'node:path';
6
+ import { DatabaseModule } from './modules/database/database.module';
7
+ import { HealthModule } from './modules/health/health.module';
8
+
9
+ @Module({
10
+ imports: [
11
+ ConfigModule.forRoot({ isGlobal: true }),
12
+ GraphQLModule.forRoot<ApolloDriverConfig>({
13
+ driver: ApolloDriver,
14
+ autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
15
+ sortSchema: true,
16
+ }),
17
+ DatabaseModule,
18
+ HealthModule,
19
+ ],
20
+ })
21
+ export class AppModule {}
@@ -0,0 +1,21 @@
1
+ import { Field, ID, ObjectType } from '@nestjs/graphql';
2
+ import {
3
+ CreateDateColumn,
4
+ PrimaryGeneratedColumn,
5
+ UpdateDateColumn,
6
+ } from 'typeorm';
7
+
8
+ @ObjectType({ isAbstract: true })
9
+ export abstract class BaseEntity {
10
+ @Field(() => ID)
11
+ @PrimaryGeneratedColumn('uuid')
12
+ id: string;
13
+
14
+ @Field()
15
+ @CreateDateColumn()
16
+ createdAt: Date;
17
+
18
+ @Field()
19
+ @UpdateDateColumn()
20
+ updatedAt: Date;
21
+ }
@@ -0,0 +1,21 @@
1
+ import { DeepPartial } from 'typeorm';
2
+ import { BaseEntity } from '../entities/base.entity';
3
+ import { ReadonlyEntityRepository } from './readonly-entity.repository';
4
+
5
+ export abstract class EntityRepository<
6
+ T extends BaseEntity,
7
+ > extends ReadonlyEntityRepository<T> {
8
+ async create(data: DeepPartial<T>): Promise<T> {
9
+ const entity = this.repo.create(data);
10
+ return this.repo.save(entity);
11
+ }
12
+
13
+ async update(id: string, data: DeepPartial<T>): Promise<T> {
14
+ await this.repo.update(id, data as any);
15
+ return this.findById(id) as Promise<T>;
16
+ }
17
+
18
+ async remove(id: string): Promise<void> {
19
+ await this.repo.delete(id);
20
+ }
21
+ }
@@ -0,0 +1,22 @@
1
+ import { FindManyOptions, FindOptionsWhere, In, Repository } from 'typeorm';
2
+ import { BaseEntity } from '../entities/base.entity';
3
+
4
+ export abstract class ReadonlyEntityRepository<T extends BaseEntity> {
5
+ constructor(protected readonly repo: Repository<T>) {}
6
+
7
+ findAll(options?: FindManyOptions<T>): Promise<T[]> {
8
+ return this.repo.find(options);
9
+ }
10
+
11
+ findByIds(ids: string[]): Promise<T[]> {
12
+ return this.repo.findBy({ id: In(ids) } as FindOptionsWhere<T>);
13
+ }
14
+
15
+ findById(id: string): Promise<T | null> {
16
+ return this.repo.findOneBy({ id } as FindOptionsWhere<T>);
17
+ }
18
+
19
+ findOne(where: FindOptionsWhere<T>): Promise<T | null> {
20
+ return this.repo.findOneBy(where);
21
+ }
22
+ }
@@ -0,0 +1,24 @@
1
+ import { DeepPartial } from 'typeorm';
2
+ import { BaseEntity } from '../entities/base.entity';
3
+ import { EntityRepository } from '../repositories/entity.repository';
4
+ import { ReadonlyEntityService } from './readonly-entity.service';
5
+
6
+ export abstract class EntityService<
7
+ T extends BaseEntity,
8
+ > extends ReadonlyEntityService<T> {
9
+ constructor(protected readonly repository: EntityRepository<T>) {
10
+ super(repository);
11
+ }
12
+
13
+ create(data: DeepPartial<T>): Promise<T> {
14
+ return this.repository.create(data);
15
+ }
16
+
17
+ update(id: string, data: DeepPartial<T>): Promise<T> {
18
+ return this.repository.update(id, data);
19
+ }
20
+
21
+ remove(id: string): Promise<void> {
22
+ return this.repository.remove(id);
23
+ }
24
+ }
@@ -0,0 +1,23 @@
1
+ import { FindManyOptions, FindOptionsWhere } from 'typeorm';
2
+ import { BaseEntity } from '../entities/base.entity';
3
+ import { ReadonlyEntityRepository } from '../repositories/readonly-entity.repository';
4
+
5
+ export abstract class ReadonlyEntityService<T extends BaseEntity> {
6
+ constructor(protected readonly repository: ReadonlyEntityRepository<T>) {}
7
+
8
+ findAll(options?: FindManyOptions<T>): Promise<T[]> {
9
+ return this.repository.findAll(options);
10
+ }
11
+
12
+ findByIds(ids: string[]): Promise<T[]> {
13
+ return this.repository.findByIds(ids);
14
+ }
15
+
16
+ findById(id: string): Promise<T | null> {
17
+ return this.repository.findById(id);
18
+ }
19
+
20
+ findOne(where: FindOptionsWhere<T>): Promise<T | null> {
21
+ return this.repository.findOne(where);
22
+ }
23
+ }
@@ -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(process.env.PORT ?? 3000);
7
+ }
8
+ bootstrap();
@@ -0,0 +1,18 @@
1
+ import { Module } from '@nestjs/common';
2
+ import { TypeOrmModule } from '@nestjs/typeorm';
3
+
4
+ @Module({
5
+ imports: [
6
+ TypeOrmModule.forRoot({
7
+ type: '{{dbType}}' as 'postgres' | 'mysql',
8
+ host: process.env.DB_HOST ?? 'localhost',
9
+ port: parseInt(process.env.DB_PORT ?? '{{dbPort}}', 10),
10
+ username: process.env.DB_USER ?? 'postgres',
11
+ password: process.env.DB_PASSWORD ?? '',
12
+ database: process.env.DB_NAME ?? '{{projectName}}',
13
+ entities: [],
14
+ synchronize: process.env.NODE_ENV !== 'production',
15
+ }),
16
+ ],
17
+ })
18
+ export class DatabaseModule {}
@@ -0,0 +1,20 @@
1
+ import { Test, TestingModule } from '@nestjs/testing';
2
+ import { HealthController } from './health.controller';
3
+ import { HealthService } from './health.service';
4
+
5
+ describe('HealthController', () => {
6
+ let controller: HealthController;
7
+
8
+ beforeEach(async () => {
9
+ const module: TestingModule = await Test.createTestingModule({
10
+ controllers: [HealthController],
11
+ providers: [HealthService],
12
+ }).compile();
13
+
14
+ controller = module.get<HealthController>(HealthController);
15
+ });
16
+
17
+ it('returns ok status', () => {
18
+ expect(controller.check()).toEqual({ status: 'ok' });
19
+ });
20
+ });
@@ -0,0 +1,18 @@
1
+ import { Test, TestingModule } from '@nestjs/testing';
2
+ import { HealthService } from './health.service';
3
+
4
+ describe('HealthService', () => {
5
+ let service: HealthService;
6
+
7
+ beforeEach(async () => {
8
+ const module: TestingModule = await Test.createTestingModule({
9
+ providers: [HealthService],
10
+ }).compile();
11
+
12
+ service = module.get<HealthService>(HealthService);
13
+ });
14
+
15
+ it('returns ok status', () => {
16
+ expect(service.check()).toEqual({ status: 'ok' });
17
+ });
18
+ });
@@ -0,0 +1,12 @@
1
+ import { Controller, Get } from '@nestjs/common';
2
+ import { HealthService } from './health.service';
3
+
4
+ @Controller('health')
5
+ export class HealthController {
6
+ constructor(private readonly healthService: HealthService) {}
7
+
8
+ @Get()
9
+ check() {
10
+ return this.healthService.check();
11
+ }
12
+ }
@@ -0,0 +1,9 @@
1
+ import { Module } from '@nestjs/common';
2
+ import { HealthController } from './health.controller';
3
+ import { HealthService } from './health.service';
4
+
5
+ @Module({
6
+ controllers: [HealthController],
7
+ providers: [HealthService],
8
+ })
9
+ export class HealthModule {}
@@ -0,0 +1,8 @@
1
+ import { Injectable } from '@nestjs/common';
2
+
3
+ @Injectable()
4
+ export class HealthService {
5
+ check() {
6
+ return { status: 'ok' };
7
+ }
8
+ }
@@ -0,0 +1,29 @@
1
+ import { INestApplication } from '@nestjs/common';
2
+ import { Test, TestingModule } from '@nestjs/testing';
3
+ import * as request from 'supertest';
4
+ import { App } from 'supertest/types';
5
+ import { AppModule } from './../src/app.module';
6
+
7
+ describe('App (e2e)', () => {
8
+ let app: INestApplication<App>;
9
+
10
+ beforeEach(async () => {
11
+ const moduleFixture: TestingModule = await Test.createTestingModule({
12
+ imports: [AppModule],
13
+ }).compile();
14
+
15
+ app = moduleFixture.createNestApplication();
16
+ await app.init();
17
+ });
18
+
19
+ afterEach(async () => {
20
+ await app.close();
21
+ });
22
+
23
+ it('/health (GET)', () => {
24
+ return request(app.getHttpServer())
25
+ .get('/health')
26
+ .expect(200)
27
+ .expect({ status: 'ok' });
28
+ });
29
+ });
@@ -0,0 +1,9 @@
1
+ {
2
+ "moduleFileExtensions": ["js", "json", "ts"],
3
+ "rootDir": ".",
4
+ "testEnvironment": "node",
5
+ "testRegex": ".e2e-spec.ts$",
6
+ "transform": {
7
+ "^.+\\.(t|j)s$": "ts-jest"
8
+ }
9
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
4
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "commonjs",
4
+ "declaration": true,
5
+ "removeComments": true,
6
+ "emitDecoratorMetadata": true,
7
+ "experimentalDecorators": true,
8
+ "allowSyntheticDefaultImports": true,
9
+ "target": "ES2023",
10
+ "sourceMap": true,
11
+ "outDir": "./dist",
12
+ "baseUrl": "./",
13
+ "incremental": true,
14
+ "skipLibCheck": true,
15
+ "strictNullChecks": true,
16
+ "forceConsistentCasingInFileNames": true,
17
+ "noImplicitAny": false,
18
+ "strictBindCallApply": false,
19
+ "noFallthroughCasesInSwitch": false
20
+ }
21
+ }
@@ -25,6 +25,7 @@
25
25
  "@nestjs/config": "^3.0.0",
26
26
  "@nestjs/core": "^11.0.1",
27
27
  "@nestjs/platform-express": "^11.0.1",
28
+ "@nestjs/swagger": "^11.0.0",
28
29
  "@nestjs/typeorm": "^10.0.0",
29
30
  "reflect-metadata": "^0.2.2",
30
31
  "rxjs": "^7.8.1",
@@ -1,8 +1,19 @@
1
+ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
1
2
  import { NestFactory } from '@nestjs/core';
3
+ import { writeFileSync } from 'node:fs';
2
4
  import { AppModule } from './app.module';
3
5
 
4
6
  async function bootstrap() {
5
7
  const app = await NestFactory.create(AppModule);
8
+
9
+ const config = new DocumentBuilder()
10
+ .setTitle('{{projectName}}')
11
+ .setVersion('1.0')
12
+ .build();
13
+ const document = SwaggerModule.createDocument(app, config);
14
+ SwaggerModule.setup('api', app, document);
15
+ writeFileSync('./swagger.json', JSON.stringify(document, null, 2));
16
+
6
17
  await app.listen(process.env.PORT ?? 3000);
7
18
  }
8
19
  bootstrap();
@@ -7,7 +7,11 @@
7
7
  "build": "nx run-many -t build",
8
8
  "test": "nx run-many -t test",
9
9
  "lint": "nx run-many -t lint",
10
- "generate:module": "nx g @local/generators:module"
10
+ "generate:module": "nx g @local/generators:module",
11
+ "generate:resolver": "nx g @local/generators:resolver",
12
+ "generate:controller": "nx g @local/generators:controller",
13
+ "codegen": "nx run types:codegen",
14
+ "codegen:watch": "nx run types:codegen:watch"
11
15
  },
12
16
  "devDependencies": {
13
17
  "@nx/devkit": "^20.0.0",
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "@local/types",
3
+ "version": "0.0.1",
4
+ "private": true,
5
+ "exports": {
6
+ "./rest": "./src/rest/index.ts",
7
+ "./graphql": "./src/graphql/index.ts"
8
+ },
9
+ "devDependencies": {}
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "NodeNext",
4
+ "moduleResolution": "NodeNext",
5
+ "target": "ES2022",
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true
9
+ }
10
+ }
@@ -0,0 +1,22 @@
1
+ const { formatFiles, generateFiles, names } = require('@nx/devkit');
2
+ const { execSync } = require('node:child_process');
3
+ const { join } = require('node:path');
4
+
5
+ module.exports = async function (tree, options) {
6
+ const n = names(options.name);
7
+ const controllerPath = `apps/backend/src/api/${n.fileName}`;
8
+
9
+ generateFiles(tree, join(__dirname, 'files'), controllerPath, { ...n, tmpl: '' });
10
+
11
+ await formatFiles(tree);
12
+
13
+ console.log(`\n✓ Controller created at ${controllerPath}/`);
14
+ console.log(` → Import ${n.className}Module and register ${n.className}Controller in your module\n`);
15
+
16
+ return () => {
17
+ execSync(`npx prettier --write ${controllerPath}`, {
18
+ cwd: tree.root,
19
+ stdio: 'inherit',
20
+ });
21
+ };
22
+ };
@@ -0,0 +1,18 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "cli": "nx",
4
+ "id": "controller",
5
+ "title": "Create a REST controller",
6
+ "type": "object",
7
+ "properties": {
8
+ "name": {
9
+ "type": "string",
10
+ "description": "Module name to generate a controller for (e.g. trainer)",
11
+ "$default": {
12
+ "$source": "argv",
13
+ "index": 0
14
+ }
15
+ }
16
+ },
17
+ "required": ["name"]
18
+ }
@@ -3,7 +3,17 @@
3
3
  "module": {
4
4
  "factory": "./module/index",
5
5
  "schema": "./module/schema.json",
6
- "description": "Create a NestJS module"
6
+ "description": "Create a NestJS domain module (model, repository, service)"
7
+ },
8
+ "resolver": {
9
+ "factory": "./resolver/index",
10
+ "schema": "./resolver/schema.json",
11
+ "description": "Create a GraphQL resolver in src/resolvers/"
12
+ },
13
+ "controller": {
14
+ "factory": "./controller/index",
15
+ "schema": "./controller/schema.json",
16
+ "description": "Create a REST controller in src/api/"
7
17
  }
8
18
  }
9
19
  }
@@ -0,0 +1,11 @@
1
+ import { ObjectType } from '@nestjs/graphql';
2
+ import { Entity } from 'typeorm';
3
+ import { BaseEntity } from '../../common/entities/base.entity';
4
+
5
+ @ObjectType()
6
+ @Entity('<%= fileName %>s')
7
+ export class <%= className %>Model extends BaseEntity {
8
+ // @Field()
9
+ // @Column()
10
+ // name: string;
11
+ }
@@ -6,20 +6,10 @@ module.exports = async function (tree, options) {
6
6
  const n = names(options.name);
7
7
  const modulePath = `apps/backend/src/modules/${n.fileName}`;
8
8
 
9
- generateFiles(
10
- tree,
11
- join(__dirname, 'files'),
12
- modulePath,
13
- { ...n, tmpl: '' },
14
- );
9
+ generateFiles(tree, join(__dirname, 'files'), modulePath, { ...n, tmpl: '' });
15
10
 
16
- if (options.crud) {
17
- generateFiles(
18
- tree,
19
- join(__dirname, 'crud-files'),
20
- `apps/backend/src/api/${n.fileName}`,
21
- { ...n, tmpl: '' },
22
- );
11
+ if (options.graphql) {
12
+ generateFiles(tree, join(__dirname, 'graphql-files'), modulePath, { ...n, tmpl: '' });
23
13
  }
24
14
 
25
15
  await formatFiles(tree);
@@ -27,16 +17,8 @@ module.exports = async function (tree, options) {
27
17
  console.log(`\n✓ Module created at ${modulePath}/`);
28
18
  console.log(` → Import ${n.className}Module in app.module.ts\n`);
29
19
 
30
- if (options.crud) {
31
- console.log(`✓ Controller created at apps/backend/src/api/${n.fileName}/`);
32
- console.log(` → Add ${n.className}Controller to a module and import ${n.className}Module there\n`);
33
- }
34
-
35
20
  return () => {
36
- const targets = [modulePath];
37
- if (options.crud) targets.push(`apps/backend/src/api/${n.fileName}`);
38
-
39
- execSync(`npx prettier --write ${targets.join(' ')}`, {
21
+ execSync(`npx prettier --write ${modulePath}`, {
40
22
  cwd: tree.root,
41
23
  stdio: 'inherit',
42
24
  });
@@ -2,7 +2,7 @@
2
2
  "$schema": "http://json-schema.org/schema",
3
3
  "cli": "nx",
4
4
  "id": "module",
5
- "title": "Create a NestJS module",
5
+ "title": "Create a NestJS domain module",
6
6
  "type": "object",
7
7
  "properties": {
8
8
  "name": {
@@ -13,11 +13,10 @@
13
13
  "index": 0
14
14
  }
15
15
  },
16
- "crud": {
16
+ "graphql": {
17
17
  "type": "boolean",
18
- "description": "Generate a CRUD controller in src/api/<name>/",
19
- "default": false,
20
- "x-prompt": "Generate a CRUD controller?"
18
+ "description": "Add @ObjectType() to the model (required for GraphQL resolvers)",
19
+ "default": false
21
20
  }
22
21
  },
23
22
  "required": ["name"]
@@ -0,0 +1,28 @@
1
+ import {
2
+ Args,
3
+ Mutation,
4
+ Query,
5
+ Resolver,
6
+ } from '@nestjs/graphql';
7
+ import { <%= className %>Model } from '../../modules/<%= fileName %>/<%= fileName %>.model';
8
+ import { <%= className %>Service } from '../../modules/<%= fileName %>/<%= fileName %>.service';
9
+
10
+ @Resolver(() => <%= className %>Model)
11
+ export class <%= className %>Resolver {
12
+ constructor(private readonly service: <%= className %>Service) {}
13
+
14
+ @Query(() => [<%= className %>Model])
15
+ <%= propertyName %>s() {
16
+ return this.service.findAll();
17
+ }
18
+
19
+ @Query(() => <%= className %>Model, { nullable: true })
20
+ <%= propertyName %>(@Args('id') id: string) {
21
+ return this.service.findById(id);
22
+ }
23
+
24
+ @Mutation(() => Boolean)
25
+ remove<%= className %>(@Args('id') id: string) {
26
+ return this.service.remove(id).then(() => true);
27
+ }
28
+ }
@@ -0,0 +1,22 @@
1
+ const { formatFiles, generateFiles, names } = require('@nx/devkit');
2
+ const { execSync } = require('node:child_process');
3
+ const { join } = require('node:path');
4
+
5
+ module.exports = async function (tree, options) {
6
+ const n = names(options.name);
7
+ const resolverPath = `apps/backend/src/resolvers/${n.fileName}`;
8
+
9
+ generateFiles(tree, join(__dirname, 'files'), resolverPath, { ...n, tmpl: '' });
10
+
11
+ await formatFiles(tree);
12
+
13
+ console.log(`\n✓ Resolver created at ${resolverPath}/`);
14
+ console.log(` → Import ${n.className}Module and register ${n.className}Resolver in your module\n`);
15
+
16
+ return () => {
17
+ execSync(`npx prettier --write ${resolverPath}`, {
18
+ cwd: tree.root,
19
+ stdio: 'inherit',
20
+ });
21
+ };
22
+ };
@@ -0,0 +1,18 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "cli": "nx",
4
+ "id": "resolver",
5
+ "title": "Create a GraphQL resolver",
6
+ "type": "object",
7
+ "properties": {
8
+ "name": {
9
+ "type": "string",
10
+ "description": "Module name to generate a resolver for (e.g. trainer)",
11
+ "$default": {
12
+ "$source": "argv",
13
+ "index": 0
14
+ }
15
+ }
16
+ },
17
+ "required": ["name"]
18
+ }
@@ -0,0 +1,17 @@
1
+ import type { CodegenConfig } from '@graphql-codegen/cli';
2
+
3
+ const config: CodegenConfig = {
4
+ schema: '../../apps/backend/src/schema.gql',
5
+ documents: ['../../apps/web/src/**/*.graphql'],
6
+ generates: {
7
+ './src/graphql/index.ts': {
8
+ plugins: [
9
+ 'typescript',
10
+ 'typescript-operations',
11
+ 'typescript-react-apollo',
12
+ ],
13
+ },
14
+ },
15
+ };
16
+
17
+ export default config;
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "types",
3
+ "targets": {
4
+ "codegen": {
5
+ "executor": "nx:run-commands",
6
+ "options": {
7
+ "command": "graphql-codegen --config codegen.ts",
8
+ "cwd": "{projectRoot}"
9
+ }
10
+ },
11
+ "codegen:watch": {
12
+ "executor": "nx:run-commands",
13
+ "options": {
14
+ "command": "graphql-codegen --config codegen.ts --watch",
15
+ "cwd": "{projectRoot}"
16
+ }
17
+ }
18
+ }
19
+ }
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from '@hey-api/openapi-ts';
2
+
3
+ export default defineConfig({
4
+ input: '../../apps/backend/swagger.json',
5
+ output: {
6
+ path: './src/rest',
7
+ format: 'prettier',
8
+ },
9
+ plugins: ['@hey-api/typescript'],
10
+ });