@exanderal/stackcraft 0.1.1 → 0.2.0

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 (91) hide show
  1. package/README.md +79 -8
  2. package/dist/create/index.d.ts.map +1 -1
  3. package/dist/create/index.js +24 -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 +8 -2
  7. package/dist/create/scaffold.js.map +1 -1
  8. package/dist/create/scaffolders/__tests__/web-vite.test.js +1 -0
  9. package/dist/create/scaffolders/__tests__/web-vite.test.js.map +1 -1
  10. package/dist/create/scaffolders/api-nestjs-graphql.d.ts +3 -0
  11. package/dist/create/scaffolders/api-nestjs-graphql.d.ts.map +1 -0
  12. package/dist/create/scaffolders/api-nestjs-graphql.js +31 -0
  13. package/dist/create/scaffolders/api-nestjs-graphql.js.map +1 -0
  14. package/dist/create/scaffolders/api-nestjs-rest.d.ts.map +1 -1
  15. package/dist/create/scaffolders/api-nestjs-rest.js +19 -2
  16. package/dist/create/scaffolders/api-nestjs-rest.js.map +1 -1
  17. package/dist/create/types.d.ts +3 -1
  18. package/dist/create/types.d.ts.map +1 -1
  19. package/package.json +1 -1
  20. package/templates/api-nestjs-graphql/.prettierrc +4 -0
  21. package/templates/api-nestjs-graphql/eslint.config.mjs +34 -0
  22. package/templates/api-nestjs-graphql/nest-cli.json +8 -0
  23. package/templates/api-nestjs-graphql/package.json +81 -0
  24. package/templates/api-nestjs-graphql/project.json +21 -0
  25. package/templates/api-nestjs-graphql/src/app.module.ts +21 -0
  26. package/templates/api-nestjs-graphql/src/common/entities/base.entity.ts +21 -0
  27. package/templates/api-nestjs-graphql/src/common/repositories/entity.repository.ts +21 -0
  28. package/templates/api-nestjs-graphql/src/common/repositories/readonly-entity.repository.ts +22 -0
  29. package/templates/api-nestjs-graphql/src/common/services/entity.service.ts +24 -0
  30. package/templates/api-nestjs-graphql/src/common/services/readonly-entity.service.ts +23 -0
  31. package/templates/api-nestjs-graphql/src/main.ts +8 -0
  32. package/templates/api-nestjs-graphql/src/modules/database/database.module.ts +18 -0
  33. package/templates/api-nestjs-graphql/src/modules/health/__tests__/health.controller.spec.ts +20 -0
  34. package/templates/api-nestjs-graphql/src/modules/health/__tests__/health.service.spec.ts +18 -0
  35. package/templates/api-nestjs-graphql/src/modules/health/health.controller.ts +12 -0
  36. package/templates/api-nestjs-graphql/src/modules/health/health.module.ts +9 -0
  37. package/templates/api-nestjs-graphql/src/modules/health/health.service.ts +8 -0
  38. package/templates/api-nestjs-graphql/test/app.e2e-spec.ts +29 -0
  39. package/templates/api-nestjs-graphql/test/jest-e2e.json +9 -0
  40. package/templates/api-nestjs-graphql/tsconfig.build.json +4 -0
  41. package/templates/api-nestjs-graphql/tsconfig.json +21 -0
  42. package/templates/api-nestjs-rest/package.json +5 -2
  43. package/templates/api-nestjs-rest/project.json +1 -1
  44. package/templates/api-nestjs-rest/src/app.module.ts +8 -5
  45. package/templates/api-nestjs-rest/src/common/entities/base.entity.ts +16 -0
  46. package/templates/api-nestjs-rest/src/common/repositories/entity.repository.ts +21 -0
  47. package/templates/api-nestjs-rest/src/common/repositories/readonly-entity.repository.ts +22 -0
  48. package/templates/api-nestjs-rest/src/common/services/entity.service.ts +24 -0
  49. package/templates/api-nestjs-rest/src/common/services/readonly-entity.service.ts +23 -0
  50. package/templates/api-nestjs-rest/src/modules/database/database.module.ts +18 -0
  51. package/templates/api-nestjs-rest/src/modules/health/__tests__/health.controller.spec.ts +20 -0
  52. package/templates/api-nestjs-rest/src/modules/health/__tests__/health.service.spec.ts +18 -0
  53. package/templates/api-nestjs-rest/src/modules/health/health.controller.ts +12 -0
  54. package/templates/api-nestjs-rest/src/modules/health/health.module.ts +9 -0
  55. package/templates/api-nestjs-rest/src/modules/health/health.service.ts +8 -0
  56. package/templates/api-nestjs-rest/test/app.e2e-spec.ts +9 -5
  57. package/templates/base/package.json +5 -1
  58. package/templates/base/pnpm-workspace.yaml +1 -0
  59. package/templates/base/tools/generators/controller/files/__fileName__.controller.ts__tmpl__ +36 -0
  60. package/templates/base/tools/generators/controller/index.js +22 -0
  61. package/templates/base/tools/generators/controller/schema.json +18 -0
  62. package/templates/base/tools/generators/generators.json +19 -0
  63. package/templates/base/tools/generators/module/files/__fileName__.model.ts__tmpl__ +8 -0
  64. package/templates/base/tools/generators/module/files/__fileName__.module.ts__tmpl__ +12 -0
  65. package/templates/base/tools/generators/module/files/__fileName__.repository.ts__tmpl__ +15 -0
  66. package/templates/base/tools/generators/module/files/__fileName__.service.ts__tmpl__ +11 -0
  67. package/templates/base/tools/generators/module/files/__tests__/__fileName__.integration.spec.ts__tmpl__ +31 -0
  68. package/templates/base/tools/generators/module/graphql-files/__fileName__.model.ts__tmpl__ +11 -0
  69. package/templates/base/tools/generators/module/index.js +26 -0
  70. package/templates/base/tools/generators/module/schema.json +23 -0
  71. package/templates/base/tools/generators/package.json +6 -0
  72. package/templates/base/tools/generators/resolver/files/__fileName__.resolver.ts__tmpl__ +28 -0
  73. package/templates/base/tools/generators/resolver/index.js +22 -0
  74. package/templates/base/tools/generators/resolver/schema.json +18 -0
  75. package/templates/web-nextjs/package.json +3 -0
  76. package/templates/web-nextjs/postcss.config.mjs +7 -0
  77. package/templates/web-nextjs/src/app/globals.css +1 -0
  78. package/templates/web-nextjs/src/components/TemplateComponent/TemplateComponent.behaviour.ts +39 -0
  79. package/templates/web-nextjs/src/components/TemplateComponent/TemplateComponent.tsx +14 -0
  80. package/templates/web-vite/package.json +2 -0
  81. package/templates/web-vite/src/components/TemplateComponent/TemplateComponent.behaviour.ts +39 -0
  82. package/templates/web-vite/src/components/TemplateComponent/TemplateComponent.tsx +14 -0
  83. package/templates/web-vite/src/index.css +1 -8
  84. package/templates/web-vite/vite.config.ts +3 -3
  85. package/templates/api-nestjs-rest/src/app.controller.spec.ts +0 -22
  86. package/templates/api-nestjs-rest/src/app.controller.ts +0 -12
  87. package/templates/api-nestjs-rest/src/app.service.ts +0 -8
  88. package/templates/web-nextjs/app/globals.css +0 -10
  89. /package/templates/web-nextjs/{app → src/app}/favicon.ico +0 -0
  90. /package/templates/web-nextjs/{app → src/app}/layout.tsx +0 -0
  91. /package/templates/web-nextjs/{app → src/app}/page.tsx +0 -0
@@ -0,0 +1,31 @@
1
+ import { Test } from '@nestjs/testing';
2
+ import { getRepositoryToken } from '@nestjs/typeorm';
3
+ import { Repository } from 'typeorm';
4
+ import { <%= className %>Model } from '../<%= fileName %>.model';
5
+ import { <%= className %>Module } from '../<%= fileName %>.module';
6
+ import { <%= className %>Service } from '../<%= fileName %>.service';
7
+
8
+ describe('<%= className %>Service', () => {
9
+ let service: <%= className %>Service;
10
+
11
+ beforeAll(async () => {
12
+ const module = await Test.createTestingModule({
13
+ imports: [<%= className %>Module],
14
+ })
15
+ .overrideProvider(getRepositoryToken(<%= className %>Model))
16
+ .useValue({
17
+ find: jest.fn(),
18
+ findOne: jest.fn(),
19
+ findOneBy: jest.fn(),
20
+ save: jest.fn(),
21
+ delete: jest.fn(),
22
+ } satisfies Partial<Repository<<%= className %>Model>>)
23
+ .compile();
24
+
25
+ service = module.get(<%= className %>Service);
26
+ });
27
+
28
+ it('is defined', () => {
29
+ expect(service).toBeDefined();
30
+ });
31
+ });
@@ -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
+ }
@@ -0,0 +1,26 @@
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 modulePath = `apps/backend/src/modules/${n.fileName}`;
8
+
9
+ generateFiles(tree, join(__dirname, 'files'), modulePath, { ...n, tmpl: '' });
10
+
11
+ if (options.graphql) {
12
+ generateFiles(tree, join(__dirname, 'graphql-files'), modulePath, { ...n, tmpl: '' });
13
+ }
14
+
15
+ await formatFiles(tree);
16
+
17
+ console.log(`\n✓ Module created at ${modulePath}/`);
18
+ console.log(` → Import ${n.className}Module in app.module.ts\n`);
19
+
20
+ return () => {
21
+ execSync(`npx prettier --write ${modulePath}`, {
22
+ cwd: tree.root,
23
+ stdio: 'inherit',
24
+ });
25
+ };
26
+ };
@@ -0,0 +1,23 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "cli": "nx",
4
+ "id": "module",
5
+ "title": "Create a NestJS domain module",
6
+ "type": "object",
7
+ "properties": {
8
+ "name": {
9
+ "type": "string",
10
+ "description": "Module name, singular lowercase (e.g. trainer)",
11
+ "$default": {
12
+ "$source": "argv",
13
+ "index": 0
14
+ }
15
+ },
16
+ "graphql": {
17
+ "type": "boolean",
18
+ "description": "Add @ObjectType() to the model (required for GraphQL resolvers)",
19
+ "default": false
20
+ }
21
+ },
22
+ "required": ["name"]
23
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "@local/generators",
3
+ "version": "0.0.1",
4
+ "private": true,
5
+ "generators": "./generators.json"
6
+ }
@@ -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
+ }
@@ -14,10 +14,13 @@
14
14
  "react-dom": "19.2.4"
15
15
  },
16
16
  "devDependencies": {
17
+ "@tailwindcss/postcss": "^4.0.0",
17
18
  "@types/node": "^20",
18
19
  "@types/react": "^19",
19
20
  "@types/react-dom": "^19",
20
21
  "babel-plugin-react-compiler": "1.0.0",
22
+ "postcss": "^8.0.0",
23
+ "tailwindcss": "^4.0.0",
21
24
  "typescript": "^5"
22
25
  }
23
26
  }
@@ -0,0 +1,7 @@
1
+ const config = {
2
+ plugins: {
3
+ '@tailwindcss/postcss': {},
4
+ },
5
+ }
6
+
7
+ export default config
@@ -0,0 +1 @@
1
+ @import "tailwindcss";
@@ -0,0 +1,39 @@
1
+ import { useState } from "react";
2
+
3
+ type UseTemplateComponent = {
4
+ state: {
5
+ count: number;
6
+ };
7
+ handlers: {
8
+ handleCountIncrement: () => void;
9
+ handleCountDecrement: () => void;
10
+ handleCountReset: () => void;
11
+ };
12
+ };
13
+
14
+ export const useTemplateComponent = (): UseTemplateComponent => {
15
+ const [count, setCount] = useState<number>(0);
16
+
17
+ const handleCountIncrement = () => {
18
+ setCount((prev) => prev + 1);
19
+ };
20
+
21
+ const handleCountDecrement = () => {
22
+ setCount((prev) => prev - 1);
23
+ };
24
+
25
+ const handleCountReset = () => {
26
+ setCount(0);
27
+ };
28
+
29
+ return {
30
+ state: {
31
+ count,
32
+ },
33
+ handlers: {
34
+ handleCountIncrement,
35
+ handleCountDecrement,
36
+ handleCountReset,
37
+ },
38
+ };
39
+ };
@@ -0,0 +1,14 @@
1
+ import React from "react";
2
+ import { useTemplateComponent } from "./TemplateComponent.behaviour";
3
+
4
+ export const TemplateComponent = () => {
5
+ const { state, handlers } = useTemplateComponent();
6
+ return (
7
+ <div>
8
+ <div>Count: {state.count}</div>
9
+ <button onClick={handlers.handleCountIncrement}>Increment</button>
10
+ <button onClick={handlers.handleCountDecrement}>Decrement</button>
11
+ <button onClick={handlers.handleCountReset}>Reset</button>
12
+ </div>
13
+ );
14
+ };
@@ -25,6 +25,8 @@
25
25
  "globals": "^17.4.0",
26
26
  "typescript": "~5.9.3",
27
27
  "typescript-eslint": "^8.57.0",
28
+ "@tailwindcss/vite": "^4.0.0",
29
+ "tailwindcss": "^4.0.0",
28
30
  "vite": "^8.0.1"
29
31
  }
30
32
  }
@@ -0,0 +1,39 @@
1
+ import { useState } from "react";
2
+
3
+ type UseTemplateComponent = {
4
+ state: {
5
+ count: number;
6
+ };
7
+ handlers: {
8
+ handleCountIncrement: () => void;
9
+ handleCountDecrement: () => void;
10
+ handleCountReset: () => void;
11
+ };
12
+ };
13
+
14
+ export const useTemplateComponent = (): UseTemplateComponent => {
15
+ const [count, setCount] = useState<number>(0);
16
+
17
+ const handleCountIncrement = () => {
18
+ setCount((prev) => prev + 1);
19
+ };
20
+
21
+ const handleCountDecrement = () => {
22
+ setCount((prev) => prev - 1);
23
+ };
24
+
25
+ const handleCountReset = () => {
26
+ setCount(0);
27
+ };
28
+
29
+ return {
30
+ state: {
31
+ count,
32
+ },
33
+ handlers: {
34
+ handleCountIncrement,
35
+ handleCountDecrement,
36
+ handleCountReset,
37
+ },
38
+ };
39
+ };
@@ -0,0 +1,14 @@
1
+ import React from "react";
2
+ import { useTemplateComponent } from "./TemplateComponent.behaviour";
3
+
4
+ export const TemplateComponent = () => {
5
+ const { state, handlers } = useTemplateComponent();
6
+ return (
7
+ <div>
8
+ <div>Count: {state.count}</div>
9
+ <button onClick={handlers.handleCountIncrement}>Increment</button>
10
+ <button onClick={handlers.handleCountDecrement}>Decrement</button>
11
+ <button onClick={handlers.handleCountReset}>Reset</button>
12
+ </div>
13
+ );
14
+ };
@@ -1,8 +1 @@
1
- *, *::before, *::after {
2
- box-sizing: border-box;
3
- }
4
-
5
- body {
6
- margin: 0;
7
- font-family: system-ui, sans-serif;
8
- }
1
+ @import "tailwindcss";
@@ -1,7 +1,7 @@
1
- import { defineConfig } from 'vite'
1
+ import tailwindcss from '@tailwindcss/vite'
2
2
  import react from '@vitejs/plugin-react'
3
+ import { defineConfig } from 'vite'
3
4
 
4
- // https://vite.dev/config/
5
5
  export default defineConfig({
6
- plugins: [react()],
6
+ plugins: [react(), tailwindcss()],
7
7
  })
@@ -1,22 +0,0 @@
1
- import { Test, TestingModule } from '@nestjs/testing';
2
- import { AppController } from './app.controller';
3
- import { AppService } from './app.service';
4
-
5
- describe('AppController', () => {
6
- let appController: AppController;
7
-
8
- beforeEach(async () => {
9
- const app: TestingModule = await Test.createTestingModule({
10
- controllers: [AppController],
11
- providers: [AppService],
12
- }).compile();
13
-
14
- appController = app.get<AppController>(AppController);
15
- });
16
-
17
- describe('root', () => {
18
- it('should return "Hello World!"', () => {
19
- expect(appController.getHello()).toBe('Hello World!');
20
- });
21
- });
22
- });
@@ -1,12 +0,0 @@
1
- import { Controller, Get } from '@nestjs/common';
2
- import { AppService } from './app.service';
3
-
4
- @Controller()
5
- export class AppController {
6
- constructor(private readonly appService: AppService) {}
7
-
8
- @Get()
9
- getHello(): string {
10
- return this.appService.getHello();
11
- }
12
- }
@@ -1,8 +0,0 @@
1
- import { Injectable } from '@nestjs/common';
2
-
3
- @Injectable()
4
- export class AppService {
5
- getHello(): string {
6
- return 'Hello World!';
7
- }
8
- }
@@ -1,10 +0,0 @@
1
- *, *::before, *::after {
2
- box-sizing: border-box;
3
- padding: 0;
4
- margin: 0;
5
- }
6
-
7
- body {
8
- font-family: system-ui, sans-serif;
9
- -webkit-font-smoothing: antialiased;
10
- }
File without changes