@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.
- package/README.md +96 -21
- package/dist/create/index.d.ts.map +1 -1
- package/dist/create/index.js +12 -1
- package/dist/create/index.js.map +1 -1
- package/dist/create/scaffold.d.ts.map +1 -1
- package/dist/create/scaffold.js +11 -2
- package/dist/create/scaffold.js.map +1 -1
- package/dist/create/scaffolders/api-nestjs-graphql.d.ts +3 -0
- package/dist/create/scaffolders/api-nestjs-graphql.d.ts.map +1 -0
- package/dist/create/scaffolders/api-nestjs-graphql.js +44 -0
- package/dist/create/scaffolders/api-nestjs-graphql.js.map +1 -0
- package/dist/create/scaffolders/api-nestjs-rest.d.ts.map +1 -1
- package/dist/create/scaffolders/api-nestjs-rest.js +11 -1
- package/dist/create/scaffolders/api-nestjs-rest.js.map +1 -1
- package/dist/create/scaffolders/wire-client.d.ts +3 -0
- package/dist/create/scaffolders/wire-client.d.ts.map +1 -0
- package/dist/create/scaffolders/wire-client.js +77 -0
- package/dist/create/scaffolders/wire-client.js.map +1 -0
- package/dist/create/types.d.ts +1 -1
- package/dist/create/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/templates/api-nestjs-graphql/.prettierrc +4 -0
- package/templates/api-nestjs-graphql/eslint.config.mjs +34 -0
- package/templates/api-nestjs-graphql/nest-cli.json +8 -0
- package/templates/api-nestjs-graphql/package.json +81 -0
- package/templates/api-nestjs-graphql/project.json +21 -0
- package/templates/api-nestjs-graphql/src/app.module.ts +21 -0
- package/templates/api-nestjs-graphql/src/common/entities/base.entity.ts +21 -0
- package/templates/api-nestjs-graphql/src/common/repositories/entity.repository.ts +21 -0
- package/templates/api-nestjs-graphql/src/common/repositories/readonly-entity.repository.ts +22 -0
- package/templates/api-nestjs-graphql/src/common/services/entity.service.ts +24 -0
- package/templates/api-nestjs-graphql/src/common/services/readonly-entity.service.ts +23 -0
- package/templates/api-nestjs-graphql/src/main.ts +8 -0
- package/templates/api-nestjs-graphql/src/modules/database/database.module.ts +18 -0
- package/templates/api-nestjs-graphql/src/modules/health/__tests__/health.controller.spec.ts +20 -0
- package/templates/api-nestjs-graphql/src/modules/health/__tests__/health.service.spec.ts +18 -0
- package/templates/api-nestjs-graphql/src/modules/health/health.controller.ts +12 -0
- package/templates/api-nestjs-graphql/src/modules/health/health.module.ts +9 -0
- package/templates/api-nestjs-graphql/src/modules/health/health.service.ts +8 -0
- package/templates/api-nestjs-graphql/test/app.e2e-spec.ts +29 -0
- package/templates/api-nestjs-graphql/test/jest-e2e.json +9 -0
- package/templates/api-nestjs-graphql/tsconfig.build.json +4 -0
- package/templates/api-nestjs-graphql/tsconfig.json +21 -0
- package/templates/api-nestjs-rest/package.json +1 -0
- package/templates/api-nestjs-rest/src/main.ts +11 -0
- package/templates/base/package.json +5 -1
- package/templates/base/packages/types/package.json +10 -0
- package/templates/base/packages/types/tsconfig.json +10 -0
- package/templates/base/tools/generators/controller/index.js +22 -0
- package/templates/base/tools/generators/controller/schema.json +18 -0
- package/templates/base/tools/generators/generators.json +11 -1
- package/templates/base/tools/generators/module/graphql-files/__fileName__.model.ts__tmpl__ +11 -0
- package/templates/base/tools/generators/module/index.js +4 -22
- package/templates/base/tools/generators/module/schema.json +4 -5
- package/templates/base/tools/generators/resolver/files/__fileName__.resolver.ts__tmpl__ +28 -0
- package/templates/base/tools/generators/resolver/index.js +22 -0
- package/templates/base/tools/generators/resolver/schema.json +18 -0
- package/templates/types-graphql/codegen.ts +17 -0
- package/templates/types-graphql/project.json +19 -0
- package/templates/types-rest/openapi-ts.config.ts +10 -0
- package/templates/types-rest/project.json +19 -0
- /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,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,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,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
|
+
}
|
|
@@ -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,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.
|
|
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
|
-
|
|
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
|
-
"
|
|
16
|
+
"graphql": {
|
|
17
17
|
"type": "boolean",
|
|
18
|
-
"description": "
|
|
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
|
+
}
|