@geekmidas/cli 0.9.0 → 0.12.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 (146) hide show
  1. package/README.md +525 -0
  2. package/dist/bundler-DRXCw_YR.mjs +70 -0
  3. package/dist/bundler-DRXCw_YR.mjs.map +1 -0
  4. package/dist/bundler-WsEvH_b2.cjs +71 -0
  5. package/dist/bundler-WsEvH_b2.cjs.map +1 -0
  6. package/dist/{config-CFls09Ey.cjs → config-AmInkU7k.cjs} +10 -8
  7. package/dist/config-AmInkU7k.cjs.map +1 -0
  8. package/dist/{config-Bq72aj8e.mjs → config-DYULeEv8.mjs} +6 -4
  9. package/dist/config-DYULeEv8.mjs.map +1 -0
  10. package/dist/config.cjs +1 -1
  11. package/dist/config.d.cts +2 -1
  12. package/dist/config.d.cts.map +1 -0
  13. package/dist/config.d.mts +2 -1
  14. package/dist/config.d.mts.map +1 -0
  15. package/dist/config.mjs +1 -1
  16. package/dist/encryption-C8H-38Yy.mjs +42 -0
  17. package/dist/encryption-C8H-38Yy.mjs.map +1 -0
  18. package/dist/encryption-Dyf_r1h-.cjs +44 -0
  19. package/dist/encryption-Dyf_r1h-.cjs.map +1 -0
  20. package/dist/index.cjs +2125 -184
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.mjs +2143 -197
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/{openapi--vOy9mo4.mjs → openapi-BfFlOBCG.mjs} +812 -49
  25. package/dist/openapi-BfFlOBCG.mjs.map +1 -0
  26. package/dist/{openapi-CHhTPief.cjs → openapi-Bt_1FDpT.cjs} +805 -42
  27. package/dist/openapi-Bt_1FDpT.cjs.map +1 -0
  28. package/dist/{openapi-react-query-o5iMi8tz.cjs → openapi-react-query-B-sNWHFU.cjs} +5 -5
  29. package/dist/openapi-react-query-B-sNWHFU.cjs.map +1 -0
  30. package/dist/{openapi-react-query-CcciaVu5.mjs → openapi-react-query-B6XTeGqS.mjs} +5 -5
  31. package/dist/openapi-react-query-B6XTeGqS.mjs.map +1 -0
  32. package/dist/openapi-react-query.cjs +1 -1
  33. package/dist/openapi-react-query.d.cts.map +1 -0
  34. package/dist/openapi-react-query.d.mts.map +1 -0
  35. package/dist/openapi-react-query.mjs +1 -1
  36. package/dist/openapi.cjs +2 -2
  37. package/dist/openapi.d.cts +1 -1
  38. package/dist/openapi.d.cts.map +1 -0
  39. package/dist/openapi.d.mts +1 -1
  40. package/dist/openapi.d.mts.map +1 -0
  41. package/dist/openapi.mjs +2 -2
  42. package/dist/storage-BUYQJgz7.cjs +4 -0
  43. package/dist/storage-BXoJvmv2.cjs +149 -0
  44. package/dist/storage-BXoJvmv2.cjs.map +1 -0
  45. package/dist/storage-C9PU_30f.mjs +101 -0
  46. package/dist/storage-C9PU_30f.mjs.map +1 -0
  47. package/dist/storage-DLJAYxzJ.mjs +3 -0
  48. package/dist/{types-b-vwGpqc.d.cts → types-BR0M2v_c.d.mts} +100 -1
  49. package/dist/types-BR0M2v_c.d.mts.map +1 -0
  50. package/dist/{types-DXgiA1sF.d.mts → types-BhkZc-vm.d.cts} +100 -1
  51. package/dist/types-BhkZc-vm.d.cts.map +1 -0
  52. package/examples/cron-example.ts +27 -27
  53. package/examples/env.ts +27 -27
  54. package/examples/function-example.ts +31 -31
  55. package/examples/gkm.config.json +20 -20
  56. package/examples/gkm.config.ts +8 -8
  57. package/examples/gkm.minimal.config.json +5 -5
  58. package/examples/gkm.production.config.json +25 -25
  59. package/examples/logger.ts +2 -2
  60. package/package.json +6 -6
  61. package/src/__tests__/EndpointGenerator.hooks.spec.ts +191 -191
  62. package/src/__tests__/config.spec.ts +55 -55
  63. package/src/__tests__/loadEnvFiles.spec.ts +93 -93
  64. package/src/__tests__/normalizeHooksConfig.spec.ts +58 -58
  65. package/src/__tests__/openapi-react-query.spec.ts +497 -497
  66. package/src/__tests__/openapi.spec.ts +428 -428
  67. package/src/__tests__/test-helpers.ts +77 -76
  68. package/src/auth/__tests__/credentials.spec.ts +204 -0
  69. package/src/auth/__tests__/index.spec.ts +168 -0
  70. package/src/auth/credentials.ts +187 -0
  71. package/src/auth/index.ts +226 -0
  72. package/src/build/__tests__/index-new.spec.ts +474 -474
  73. package/src/build/__tests__/manifests.spec.ts +333 -333
  74. package/src/build/bundler.ts +141 -0
  75. package/src/build/endpoint-analyzer.ts +236 -0
  76. package/src/build/handler-templates.ts +1253 -0
  77. package/src/build/index.ts +250 -179
  78. package/src/build/manifests.ts +52 -52
  79. package/src/build/providerResolver.ts +145 -145
  80. package/src/build/types.ts +64 -43
  81. package/src/config.ts +39 -37
  82. package/src/deploy/__tests__/docker.spec.ts +111 -0
  83. package/src/deploy/__tests__/dokploy.spec.ts +245 -0
  84. package/src/deploy/__tests__/init.spec.ts +662 -0
  85. package/src/deploy/docker.ts +128 -0
  86. package/src/deploy/dokploy.ts +204 -0
  87. package/src/deploy/index.ts +136 -0
  88. package/src/deploy/init.ts +484 -0
  89. package/src/deploy/types.ts +48 -0
  90. package/src/dev/__tests__/index.spec.ts +266 -266
  91. package/src/dev/index.ts +647 -593
  92. package/src/docker/__tests__/compose.spec.ts +531 -0
  93. package/src/docker/__tests__/templates.spec.ts +280 -0
  94. package/src/docker/compose.ts +273 -0
  95. package/src/docker/index.ts +230 -0
  96. package/src/docker/templates.ts +446 -0
  97. package/src/generators/CronGenerator.ts +72 -72
  98. package/src/generators/EndpointGenerator.ts +699 -398
  99. package/src/generators/FunctionGenerator.ts +84 -84
  100. package/src/generators/Generator.ts +72 -72
  101. package/src/generators/OpenApiTsGenerator.ts +589 -589
  102. package/src/generators/SubscriberGenerator.ts +124 -124
  103. package/src/generators/__tests__/CronGenerator.spec.ts +433 -433
  104. package/src/generators/__tests__/EndpointGenerator.spec.ts +532 -382
  105. package/src/generators/__tests__/FunctionGenerator.spec.ts +244 -244
  106. package/src/generators/__tests__/SubscriberGenerator.spec.ts +397 -382
  107. package/src/generators/index.ts +4 -4
  108. package/src/index.ts +628 -206
  109. package/src/init/__tests__/generators.spec.ts +334 -334
  110. package/src/init/__tests__/init.spec.ts +332 -332
  111. package/src/init/__tests__/utils.spec.ts +89 -89
  112. package/src/init/generators/config.ts +175 -175
  113. package/src/init/generators/docker.ts +41 -41
  114. package/src/init/generators/env.ts +72 -72
  115. package/src/init/generators/index.ts +1 -1
  116. package/src/init/generators/models.ts +64 -64
  117. package/src/init/generators/monorepo.ts +161 -161
  118. package/src/init/generators/package.ts +71 -71
  119. package/src/init/generators/source.ts +6 -6
  120. package/src/init/index.ts +203 -208
  121. package/src/init/templates/api.ts +115 -115
  122. package/src/init/templates/index.ts +75 -75
  123. package/src/init/templates/minimal.ts +98 -98
  124. package/src/init/templates/serverless.ts +89 -89
  125. package/src/init/templates/worker.ts +98 -98
  126. package/src/init/utils.ts +54 -56
  127. package/src/openapi-react-query.ts +194 -194
  128. package/src/openapi.ts +63 -63
  129. package/src/secrets/__tests__/encryption.spec.ts +226 -0
  130. package/src/secrets/__tests__/generator.spec.ts +319 -0
  131. package/src/secrets/__tests__/index.spec.ts +91 -0
  132. package/src/secrets/__tests__/storage.spec.ts +403 -0
  133. package/src/secrets/encryption.ts +91 -0
  134. package/src/secrets/generator.ts +164 -0
  135. package/src/secrets/index.ts +383 -0
  136. package/src/secrets/storage.ts +134 -0
  137. package/src/secrets/types.ts +53 -0
  138. package/src/types.ts +295 -176
  139. package/tsconfig.json +9 -0
  140. package/tsdown.config.ts +11 -8
  141. package/dist/config-Bq72aj8e.mjs.map +0 -1
  142. package/dist/config-CFls09Ey.cjs.map +0 -1
  143. package/dist/openapi--vOy9mo4.mjs.map +0 -1
  144. package/dist/openapi-CHhTPief.cjs.map +0 -1
  145. package/dist/openapi-react-query-CcciaVu5.mjs.map +0 -1
  146. package/dist/openapi-react-query-o5iMi8tz.cjs.map +0 -1
@@ -11,356 +11,356 @@ import { serverlessTemplate } from '../templates/serverless.js';
11
11
  import { workerTemplate } from '../templates/worker.js';
12
12
 
13
13
  const baseOptions: TemplateOptions = {
14
- name: 'test-project',
15
- template: 'minimal',
16
- telescope: true,
17
- database: true,
18
- routeStyle: 'file-based',
19
- monorepo: false,
20
- apiPath: '',
14
+ name: 'test-project',
15
+ template: 'minimal',
16
+ telescope: true,
17
+ database: true,
18
+ routeStyle: 'file-based',
19
+ monorepo: false,
20
+ apiPath: '',
21
21
  };
22
22
 
23
23
  describe('generatePackageJson', () => {
24
- it('should generate package.json with correct name', () => {
25
- const files = generatePackageJson(baseOptions, minimalTemplate);
26
- expect(files).toHaveLength(1);
27
- expect(files[0].path).toBe('package.json');
28
-
29
- const pkg = JSON.parse(files[0].content);
30
- expect(pkg.name).toBe('test-project');
31
- expect(pkg.type).toBe('module');
32
- expect(pkg.private).toBe(true);
33
- });
34
-
35
- it('should include telescope when enabled', () => {
36
- const files = generatePackageJson(baseOptions, minimalTemplate);
37
- const pkg = JSON.parse(files[0].content);
38
- expect(pkg.dependencies['@geekmidas/telescope']).toBe('workspace:*');
39
- });
40
-
41
- it('should include database dependencies when enabled', () => {
42
- const files = generatePackageJson(baseOptions, minimalTemplate);
43
- const pkg = JSON.parse(files[0].content);
44
- expect(pkg.dependencies['@geekmidas/db']).toBe('workspace:*');
45
- expect(pkg.dependencies['kysely']).toBeDefined();
46
- expect(pkg.dependencies['pg']).toBeDefined();
47
- });
48
-
49
- it('should exclude telescope when disabled', () => {
50
- const options = { ...baseOptions, telescope: false };
51
- const files = generatePackageJson(options, minimalTemplate);
52
- const pkg = JSON.parse(files[0].content);
53
- expect(pkg.dependencies['@geekmidas/telescope']).toBeUndefined();
54
- });
55
-
56
- it('should use workspace:* for @geekmidas packages', () => {
57
- const files = generatePackageJson(baseOptions, minimalTemplate);
58
- const pkg = JSON.parse(files[0].content);
59
- expect(pkg.dependencies['@geekmidas/constructs']).toBe('workspace:*');
60
- expect(pkg.dependencies['@geekmidas/envkit']).toBe('workspace:*');
61
- expect(pkg.dependencies['@geekmidas/logger']).toBe('workspace:*');
62
- });
63
-
64
- it('should use tilde versions for external packages', () => {
65
- const files = generatePackageJson(baseOptions, minimalTemplate);
66
- const pkg = JSON.parse(files[0].content);
67
- expect(pkg.dependencies['hono']).toMatch(/^~/);
68
- expect(pkg.dependencies['pino']).toMatch(/^~/);
69
- expect(pkg.devDependencies['typescript']).toMatch(/^~/);
70
- });
71
-
72
- it('should include biome and turbo for non-monorepo', () => {
73
- const files = generatePackageJson(baseOptions, minimalTemplate);
74
- const pkg = JSON.parse(files[0].content);
75
- expect(pkg.devDependencies['@biomejs/biome']).toBeDefined();
76
- expect(pkg.devDependencies['turbo']).toBeDefined();
77
- expect(pkg.scripts['lint']).toBeDefined();
78
- expect(pkg.scripts['fmt']).toBeDefined();
79
- });
80
-
81
- it('should exclude biome and turbo for monorepo apps', () => {
82
- const options: TemplateOptions = {
83
- ...baseOptions,
84
- monorepo: true,
85
- apiPath: 'apps/api',
86
- };
87
- const files = generatePackageJson(options, minimalTemplate);
88
- const pkg = JSON.parse(files[0].content);
89
- expect(pkg.devDependencies['@biomejs/biome']).toBeUndefined();
90
- expect(pkg.devDependencies['turbo']).toBeUndefined();
91
- expect(pkg.scripts['lint']).toBeUndefined();
92
- expect(pkg.scripts['fmt']).toBeUndefined();
93
- });
94
-
95
- it('should include models package for monorepo apps', () => {
96
- const options: TemplateOptions = {
97
- ...baseOptions,
98
- monorepo: true,
99
- apiPath: 'apps/api',
100
- };
101
- const files = generatePackageJson(options, minimalTemplate);
102
- const pkg = JSON.parse(files[0].content);
103
- expect(pkg.dependencies['@test-project/models']).toBe('workspace:*');
104
- expect(pkg.dependencies['zod']).toBeUndefined(); // zod is in models
105
- });
106
-
107
- it('should use scoped package name for monorepo apps', () => {
108
- const options: TemplateOptions = {
109
- ...baseOptions,
110
- monorepo: true,
111
- apiPath: 'apps/api',
112
- };
113
- const files = generatePackageJson(options, minimalTemplate);
114
- const pkg = JSON.parse(files[0].content);
115
- expect(pkg.name).toBe('@test-project/api');
116
- });
24
+ it('should generate package.json with correct name', () => {
25
+ const files = generatePackageJson(baseOptions, minimalTemplate);
26
+ expect(files).toHaveLength(1);
27
+ expect(files[0].path).toBe('package.json');
28
+
29
+ const pkg = JSON.parse(files[0].content);
30
+ expect(pkg.name).toBe('test-project');
31
+ expect(pkg.type).toBe('module');
32
+ expect(pkg.private).toBe(true);
33
+ });
34
+
35
+ it('should include telescope when enabled', () => {
36
+ const files = generatePackageJson(baseOptions, minimalTemplate);
37
+ const pkg = JSON.parse(files[0].content);
38
+ expect(pkg.dependencies['@geekmidas/telescope']).toBe('workspace:*');
39
+ });
40
+
41
+ it('should include database dependencies when enabled', () => {
42
+ const files = generatePackageJson(baseOptions, minimalTemplate);
43
+ const pkg = JSON.parse(files[0].content);
44
+ expect(pkg.dependencies['@geekmidas/db']).toBe('workspace:*');
45
+ expect(pkg.dependencies.kysely).toBeDefined();
46
+ expect(pkg.dependencies.pg).toBeDefined();
47
+ });
48
+
49
+ it('should exclude telescope when disabled', () => {
50
+ const options = { ...baseOptions, telescope: false };
51
+ const files = generatePackageJson(options, minimalTemplate);
52
+ const pkg = JSON.parse(files[0].content);
53
+ expect(pkg.dependencies['@geekmidas/telescope']).toBeUndefined();
54
+ });
55
+
56
+ it('should use workspace:* for @geekmidas packages', () => {
57
+ const files = generatePackageJson(baseOptions, minimalTemplate);
58
+ const pkg = JSON.parse(files[0].content);
59
+ expect(pkg.dependencies['@geekmidas/constructs']).toBe('workspace:*');
60
+ expect(pkg.dependencies['@geekmidas/envkit']).toBe('workspace:*');
61
+ expect(pkg.dependencies['@geekmidas/logger']).toBe('workspace:*');
62
+ });
63
+
64
+ it('should use tilde versions for external packages', () => {
65
+ const files = generatePackageJson(baseOptions, minimalTemplate);
66
+ const pkg = JSON.parse(files[0].content);
67
+ expect(pkg.dependencies.hono).toMatch(/^~/);
68
+ expect(pkg.dependencies.pino).toMatch(/^~/);
69
+ expect(pkg.devDependencies.typescript).toMatch(/^~/);
70
+ });
71
+
72
+ it('should include biome and turbo for non-monorepo', () => {
73
+ const files = generatePackageJson(baseOptions, minimalTemplate);
74
+ const pkg = JSON.parse(files[0].content);
75
+ expect(pkg.devDependencies['@biomejs/biome']).toBeDefined();
76
+ expect(pkg.devDependencies.turbo).toBeDefined();
77
+ expect(pkg.scripts.lint).toBeDefined();
78
+ expect(pkg.scripts.fmt).toBeDefined();
79
+ });
80
+
81
+ it('should exclude biome and turbo for monorepo apps', () => {
82
+ const options: TemplateOptions = {
83
+ ...baseOptions,
84
+ monorepo: true,
85
+ apiPath: 'apps/api',
86
+ };
87
+ const files = generatePackageJson(options, minimalTemplate);
88
+ const pkg = JSON.parse(files[0].content);
89
+ expect(pkg.devDependencies['@biomejs/biome']).toBeUndefined();
90
+ expect(pkg.devDependencies.turbo).toBeUndefined();
91
+ expect(pkg.scripts.lint).toBeUndefined();
92
+ expect(pkg.scripts.fmt).toBeUndefined();
93
+ });
94
+
95
+ it('should include models package for monorepo apps', () => {
96
+ const options: TemplateOptions = {
97
+ ...baseOptions,
98
+ monorepo: true,
99
+ apiPath: 'apps/api',
100
+ };
101
+ const files = generatePackageJson(options, minimalTemplate);
102
+ const pkg = JSON.parse(files[0].content);
103
+ expect(pkg.dependencies['@test-project/models']).toBe('workspace:*');
104
+ expect(pkg.dependencies.zod).toBeUndefined(); // zod is in models
105
+ });
106
+
107
+ it('should use scoped package name for monorepo apps', () => {
108
+ const options: TemplateOptions = {
109
+ ...baseOptions,
110
+ monorepo: true,
111
+ apiPath: 'apps/api',
112
+ };
113
+ const files = generatePackageJson(options, minimalTemplate);
114
+ const pkg = JSON.parse(files[0].content);
115
+ expect(pkg.name).toBe('@test-project/api');
116
+ });
117
117
  });
118
118
 
119
119
  describe('generateConfigFiles', () => {
120
- it('should generate gkm.config.ts and tsconfig.json for non-monorepo', () => {
121
- const files = generateConfigFiles(baseOptions, minimalTemplate);
122
- const paths = files.map((f) => f.path);
123
- expect(paths).toContain('gkm.config.ts');
124
- expect(paths).toContain('tsconfig.json');
125
- expect(paths).toContain('biome.json');
126
- expect(paths).toContain('turbo.json');
127
- });
128
-
129
- it('should only generate gkm.config.ts and tsconfig.json for monorepo', () => {
130
- const options: TemplateOptions = {
131
- ...baseOptions,
132
- monorepo: true,
133
- apiPath: 'apps/api',
134
- };
135
- const files = generateConfigFiles(options, minimalTemplate);
136
- const paths = files.map((f) => f.path);
137
- expect(paths).toContain('gkm.config.ts');
138
- expect(paths).toContain('tsconfig.json');
139
- expect(paths).not.toContain('biome.json');
140
- expect(paths).not.toContain('turbo.json');
141
- });
142
-
143
- it('should include telescope config when enabled', () => {
144
- const files = generateConfigFiles(baseOptions, minimalTemplate);
145
- const gkmConfig = files.find((f) => f.path === 'gkm.config.ts');
146
- expect(gkmConfig?.content).toContain('telescope');
147
- });
148
-
149
- it('should include functions config for serverless template', () => {
150
- const options = { ...baseOptions, template: 'serverless' as const };
151
- const files = generateConfigFiles(options, serverlessTemplate);
152
- const gkmConfig = files.find((f) => f.path === 'gkm.config.ts');
153
- expect(gkmConfig?.content).toContain('functions');
154
- });
155
-
156
- it('should include paths config for monorepo apps', () => {
157
- const options: TemplateOptions = {
158
- ...baseOptions,
159
- monorepo: true,
160
- apiPath: 'apps/api',
161
- };
162
- const files = generateConfigFiles(options, minimalTemplate);
163
- const tsConfig = files.find((f) => f.path === 'tsconfig.json');
164
- const config = JSON.parse(tsConfig!.content);
165
- expect(config.extends).toBe('../../tsconfig.json');
166
- expect(config.compilerOptions.paths).toBeDefined();
167
- expect(config.compilerOptions.paths['@test-project/*']).toBeDefined();
168
- });
120
+ it('should generate gkm.config.ts and tsconfig.json for non-monorepo', () => {
121
+ const files = generateConfigFiles(baseOptions, minimalTemplate);
122
+ const paths = files.map((f) => f.path);
123
+ expect(paths).toContain('gkm.config.ts');
124
+ expect(paths).toContain('tsconfig.json');
125
+ expect(paths).toContain('biome.json');
126
+ expect(paths).toContain('turbo.json');
127
+ });
128
+
129
+ it('should only generate gkm.config.ts and tsconfig.json for monorepo', () => {
130
+ const options: TemplateOptions = {
131
+ ...baseOptions,
132
+ monorepo: true,
133
+ apiPath: 'apps/api',
134
+ };
135
+ const files = generateConfigFiles(options, minimalTemplate);
136
+ const paths = files.map((f) => f.path);
137
+ expect(paths).toContain('gkm.config.ts');
138
+ expect(paths).toContain('tsconfig.json');
139
+ expect(paths).not.toContain('biome.json');
140
+ expect(paths).not.toContain('turbo.json');
141
+ });
142
+
143
+ it('should include telescope config when enabled', () => {
144
+ const files = generateConfigFiles(baseOptions, minimalTemplate);
145
+ const gkmConfig = files.find((f) => f.path === 'gkm.config.ts');
146
+ expect(gkmConfig?.content).toContain('telescope');
147
+ });
148
+
149
+ it('should include functions config for serverless template', () => {
150
+ const options = { ...baseOptions, template: 'serverless' as const };
151
+ const files = generateConfigFiles(options, serverlessTemplate);
152
+ const gkmConfig = files.find((f) => f.path === 'gkm.config.ts');
153
+ expect(gkmConfig?.content).toContain('functions');
154
+ });
155
+
156
+ it('should include paths config for monorepo apps', () => {
157
+ const options: TemplateOptions = {
158
+ ...baseOptions,
159
+ monorepo: true,
160
+ apiPath: 'apps/api',
161
+ };
162
+ const files = generateConfigFiles(options, minimalTemplate);
163
+ const tsConfig = files.find((f) => f.path === 'tsconfig.json');
164
+ const config = JSON.parse(tsConfig?.content);
165
+ expect(config.extends).toBe('../../tsconfig.json');
166
+ expect(config.compilerOptions.paths).toBeDefined();
167
+ expect(config.compilerOptions.paths['@test-project/*']).toBeDefined();
168
+ });
169
169
  });
170
170
 
171
171
  describe('generateEnvFiles', () => {
172
- it('should generate all env files for non-monorepo', () => {
173
- const files = generateEnvFiles(baseOptions, minimalTemplate);
174
- const paths = files.map((f) => f.path);
175
- expect(paths).toContain('.env');
176
- expect(paths).toContain('.env.example');
177
- expect(paths).toContain('.env.development');
178
- expect(paths).toContain('.env.test');
179
- expect(paths).toContain('.gitignore');
180
- });
181
-
182
- it('should not generate .gitignore for monorepo', () => {
183
- const options: TemplateOptions = {
184
- ...baseOptions,
185
- monorepo: true,
186
- apiPath: 'apps/api',
187
- };
188
- const files = generateEnvFiles(options, minimalTemplate);
189
- const paths = files.map((f) => f.path);
190
- expect(paths).not.toContain('.gitignore');
191
- });
192
-
193
- it('should include DATABASE_URL when database is enabled', () => {
194
- const files = generateEnvFiles(baseOptions, minimalTemplate);
195
- const envFile = files.find((f) => f.path === '.env');
196
- expect(envFile?.content).toContain('DATABASE_URL');
197
- });
198
-
199
- it('should include RABBITMQ_URL for worker template', () => {
200
- const options = { ...baseOptions, template: 'worker' as const };
201
- const files = generateEnvFiles(options, workerTemplate);
202
- const envFile = files.find((f) => f.path === '.env');
203
- expect(envFile?.content).toContain('RABBITMQ_URL');
204
- });
172
+ it('should generate all env files for non-monorepo', () => {
173
+ const files = generateEnvFiles(baseOptions, minimalTemplate);
174
+ const paths = files.map((f) => f.path);
175
+ expect(paths).toContain('.env');
176
+ expect(paths).toContain('.env.example');
177
+ expect(paths).toContain('.env.development');
178
+ expect(paths).toContain('.env.test');
179
+ expect(paths).toContain('.gitignore');
180
+ });
181
+
182
+ it('should not generate .gitignore for monorepo', () => {
183
+ const options: TemplateOptions = {
184
+ ...baseOptions,
185
+ monorepo: true,
186
+ apiPath: 'apps/api',
187
+ };
188
+ const files = generateEnvFiles(options, minimalTemplate);
189
+ const paths = files.map((f) => f.path);
190
+ expect(paths).not.toContain('.gitignore');
191
+ });
192
+
193
+ it('should include DATABASE_URL when database is enabled', () => {
194
+ const files = generateEnvFiles(baseOptions, minimalTemplate);
195
+ const envFile = files.find((f) => f.path === '.env');
196
+ expect(envFile?.content).toContain('DATABASE_URL');
197
+ });
198
+
199
+ it('should include RABBITMQ_URL for worker template', () => {
200
+ const options = { ...baseOptions, template: 'worker' as const };
201
+ const files = generateEnvFiles(options, workerTemplate);
202
+ const envFile = files.find((f) => f.path === '.env');
203
+ expect(envFile?.content).toContain('RABBITMQ_URL');
204
+ });
205
205
  });
206
206
 
207
207
  describe('generateDockerFiles', () => {
208
- it('should generate docker-compose.yml', () => {
209
- const files = generateDockerFiles(baseOptions, minimalTemplate);
210
- expect(files).toHaveLength(1);
211
- expect(files[0].path).toBe('docker-compose.yml');
212
- });
213
-
214
- it('should include postgres when database is enabled', () => {
215
- const files = generateDockerFiles(baseOptions, minimalTemplate);
216
- expect(files[0].content).toContain('postgres');
217
- expect(files[0].content).toContain('5432');
218
- });
219
-
220
- it('should include redis', () => {
221
- const files = generateDockerFiles(baseOptions, minimalTemplate);
222
- expect(files[0].content).toContain('redis');
223
- expect(files[0].content).toContain('6379');
224
- });
225
-
226
- it('should include serverless-redis-http for serverless template', () => {
227
- const options = { ...baseOptions, template: 'serverless' as const };
228
- const files = generateDockerFiles(options, serverlessTemplate);
229
- expect(files[0].content).toContain('hiett/serverless-redis-http');
230
- expect(files[0].content).toContain('8079');
231
- });
232
-
233
- it('should include rabbitmq for worker template', () => {
234
- const options = { ...baseOptions, template: 'worker' as const };
235
- const files = generateDockerFiles(options, workerTemplate);
236
- expect(files[0].content).toContain('rabbitmq');
237
- expect(files[0].content).toContain('5672');
238
- expect(files[0].content).toContain('15672');
239
- });
208
+ it('should generate docker-compose.yml', () => {
209
+ const files = generateDockerFiles(baseOptions, minimalTemplate);
210
+ expect(files).toHaveLength(1);
211
+ expect(files[0].path).toBe('docker-compose.yml');
212
+ });
213
+
214
+ it('should include postgres when database is enabled', () => {
215
+ const files = generateDockerFiles(baseOptions, minimalTemplate);
216
+ expect(files[0].content).toContain('postgres');
217
+ expect(files[0].content).toContain('5432');
218
+ });
219
+
220
+ it('should include redis', () => {
221
+ const files = generateDockerFiles(baseOptions, minimalTemplate);
222
+ expect(files[0].content).toContain('redis');
223
+ expect(files[0].content).toContain('6379');
224
+ });
225
+
226
+ it('should include serverless-redis-http for serverless template', () => {
227
+ const options = { ...baseOptions, template: 'serverless' as const };
228
+ const files = generateDockerFiles(options, serverlessTemplate);
229
+ expect(files[0].content).toContain('hiett/serverless-redis-http');
230
+ expect(files[0].content).toContain('8079');
231
+ });
232
+
233
+ it('should include rabbitmq for worker template', () => {
234
+ const options = { ...baseOptions, template: 'worker' as const };
235
+ const files = generateDockerFiles(options, workerTemplate);
236
+ expect(files[0].content).toContain('rabbitmq');
237
+ expect(files[0].content).toContain('5672');
238
+ expect(files[0].content).toContain('15672');
239
+ });
240
240
  });
241
241
 
242
242
  describe('generateMonorepoFiles', () => {
243
- it('should return empty array for non-monorepo', () => {
244
- const files = generateMonorepoFiles(baseOptions, minimalTemplate);
245
- expect(files).toHaveLength(0);
246
- });
247
-
248
- it('should generate root files for monorepo', () => {
249
- const options: TemplateOptions = {
250
- ...baseOptions,
251
- monorepo: true,
252
- apiPath: 'apps/api',
253
- };
254
- const files = generateMonorepoFiles(options, minimalTemplate);
255
- const paths = files.map((f) => f.path);
256
- expect(paths).toContain('package.json');
257
- expect(paths).toContain('pnpm-workspace.yaml');
258
- expect(paths).toContain('tsconfig.json');
259
- expect(paths).toContain('biome.json');
260
- expect(paths).toContain('turbo.json');
261
- expect(paths).toContain('.gitignore');
262
- });
263
-
264
- it('should include correct workspace paths', () => {
265
- const options: TemplateOptions = {
266
- ...baseOptions,
267
- monorepo: true,
268
- apiPath: 'apps/api',
269
- };
270
- const files = generateMonorepoFiles(options, minimalTemplate);
271
- const workspace = files.find((f) => f.path === 'pnpm-workspace.yaml');
272
- expect(workspace?.content).toContain("'apps/*'");
273
- expect(workspace?.content).toContain("'packages/*'");
274
- });
275
-
276
- it('should include root scripts', () => {
277
- const options: TemplateOptions = {
278
- ...baseOptions,
279
- monorepo: true,
280
- apiPath: 'apps/api',
281
- };
282
- const files = generateMonorepoFiles(options, minimalTemplate);
283
- const pkgJson = files.find((f) => f.path === 'package.json');
284
- const pkg = JSON.parse(pkgJson!.content);
285
- expect(pkg.scripts.dev).toBe('turbo dev');
286
- expect(pkg.scripts.build).toBe('turbo build');
287
- expect(pkg.scripts.lint).toBe('biome lint .');
288
- });
243
+ it('should return empty array for non-monorepo', () => {
244
+ const files = generateMonorepoFiles(baseOptions, minimalTemplate);
245
+ expect(files).toHaveLength(0);
246
+ });
247
+
248
+ it('should generate root files for monorepo', () => {
249
+ const options: TemplateOptions = {
250
+ ...baseOptions,
251
+ monorepo: true,
252
+ apiPath: 'apps/api',
253
+ };
254
+ const files = generateMonorepoFiles(options, minimalTemplate);
255
+ const paths = files.map((f) => f.path);
256
+ expect(paths).toContain('package.json');
257
+ expect(paths).toContain('pnpm-workspace.yaml');
258
+ expect(paths).toContain('tsconfig.json');
259
+ expect(paths).toContain('biome.json');
260
+ expect(paths).toContain('turbo.json');
261
+ expect(paths).toContain('.gitignore');
262
+ });
263
+
264
+ it('should include correct workspace paths', () => {
265
+ const options: TemplateOptions = {
266
+ ...baseOptions,
267
+ monorepo: true,
268
+ apiPath: 'apps/api',
269
+ };
270
+ const files = generateMonorepoFiles(options, minimalTemplate);
271
+ const workspace = files.find((f) => f.path === 'pnpm-workspace.yaml');
272
+ expect(workspace?.content).toContain("'apps/*'");
273
+ expect(workspace?.content).toContain("'packages/*'");
274
+ });
275
+
276
+ it('should include root scripts', () => {
277
+ const options: TemplateOptions = {
278
+ ...baseOptions,
279
+ monorepo: true,
280
+ apiPath: 'apps/api',
281
+ };
282
+ const files = generateMonorepoFiles(options, minimalTemplate);
283
+ const pkgJson = files.find((f) => f.path === 'package.json');
284
+ const pkg = JSON.parse(pkgJson?.content);
285
+ expect(pkg.scripts.dev).toBe('turbo dev');
286
+ expect(pkg.scripts.build).toBe('turbo build');
287
+ expect(pkg.scripts.lint).toBe('biome lint .');
288
+ });
289
289
  });
290
290
 
291
291
  describe('generateModelsPackage', () => {
292
- it('should return empty array for non-monorepo', () => {
293
- const files = generateModelsPackage(baseOptions);
294
- expect(files).toHaveLength(0);
295
- });
296
-
297
- it('should generate models package for monorepo', () => {
298
- const options: TemplateOptions = {
299
- ...baseOptions,
300
- monorepo: true,
301
- apiPath: 'apps/api',
302
- };
303
- const files = generateModelsPackage(options);
304
- const paths = files.map((f) => f.path);
305
- expect(paths).toContain('packages/models/package.json');
306
- expect(paths).toContain('packages/models/tsconfig.json');
307
- expect(paths).toContain('packages/models/src/index.ts');
308
- });
309
-
310
- it('should use correct package name', () => {
311
- const options: TemplateOptions = {
312
- ...baseOptions,
313
- monorepo: true,
314
- apiPath: 'apps/api',
315
- };
316
- const files = generateModelsPackage(options);
317
- const pkgJson = files.find(
318
- (f) => f.path === 'packages/models/package.json',
319
- );
320
- const pkg = JSON.parse(pkgJson!.content);
321
- expect(pkg.name).toBe('@test-project/models');
322
- });
323
-
324
- it('should include zod as dependency', () => {
325
- const options: TemplateOptions = {
326
- ...baseOptions,
327
- monorepo: true,
328
- apiPath: 'apps/api',
329
- };
330
- const files = generateModelsPackage(options);
331
- const pkgJson = files.find(
332
- (f) => f.path === 'packages/models/package.json',
333
- );
334
- const pkg = JSON.parse(pkgJson!.content);
335
- expect(pkg.dependencies.zod).toBeDefined();
336
- });
337
-
338
- it('should include example schemas', () => {
339
- const options: TemplateOptions = {
340
- ...baseOptions,
341
- monorepo: true,
342
- apiPath: 'apps/api',
343
- };
344
- const files = generateModelsPackage(options);
345
- const indexTs = files.find(
346
- (f) => f.path === 'packages/models/src/index.ts',
347
- );
348
- expect(indexTs?.content).toContain('userSchema');
349
- expect(indexTs?.content).toContain('paginationSchema');
350
- expect(indexTs?.content).toContain("import { z } from 'zod'");
351
- });
352
-
353
- it('should extend root tsconfig', () => {
354
- const options: TemplateOptions = {
355
- ...baseOptions,
356
- monorepo: true,
357
- apiPath: 'apps/api',
358
- };
359
- const files = generateModelsPackage(options);
360
- const tsConfig = files.find(
361
- (f) => f.path === 'packages/models/tsconfig.json',
362
- );
363
- const config = JSON.parse(tsConfig!.content);
364
- expect(config.extends).toBe('../../tsconfig.json');
365
- });
292
+ it('should return empty array for non-monorepo', () => {
293
+ const files = generateModelsPackage(baseOptions);
294
+ expect(files).toHaveLength(0);
295
+ });
296
+
297
+ it('should generate models package for monorepo', () => {
298
+ const options: TemplateOptions = {
299
+ ...baseOptions,
300
+ monorepo: true,
301
+ apiPath: 'apps/api',
302
+ };
303
+ const files = generateModelsPackage(options);
304
+ const paths = files.map((f) => f.path);
305
+ expect(paths).toContain('packages/models/package.json');
306
+ expect(paths).toContain('packages/models/tsconfig.json');
307
+ expect(paths).toContain('packages/models/src/index.ts');
308
+ });
309
+
310
+ it('should use correct package name', () => {
311
+ const options: TemplateOptions = {
312
+ ...baseOptions,
313
+ monorepo: true,
314
+ apiPath: 'apps/api',
315
+ };
316
+ const files = generateModelsPackage(options);
317
+ const pkgJson = files.find(
318
+ (f) => f.path === 'packages/models/package.json',
319
+ );
320
+ const pkg = JSON.parse(pkgJson?.content);
321
+ expect(pkg.name).toBe('@test-project/models');
322
+ });
323
+
324
+ it('should include zod as dependency', () => {
325
+ const options: TemplateOptions = {
326
+ ...baseOptions,
327
+ monorepo: true,
328
+ apiPath: 'apps/api',
329
+ };
330
+ const files = generateModelsPackage(options);
331
+ const pkgJson = files.find(
332
+ (f) => f.path === 'packages/models/package.json',
333
+ );
334
+ const pkg = JSON.parse(pkgJson?.content);
335
+ expect(pkg.dependencies.zod).toBeDefined();
336
+ });
337
+
338
+ it('should include example schemas', () => {
339
+ const options: TemplateOptions = {
340
+ ...baseOptions,
341
+ monorepo: true,
342
+ apiPath: 'apps/api',
343
+ };
344
+ const files = generateModelsPackage(options);
345
+ const indexTs = files.find(
346
+ (f) => f.path === 'packages/models/src/index.ts',
347
+ );
348
+ expect(indexTs?.content).toContain('userSchema');
349
+ expect(indexTs?.content).toContain('paginationSchema');
350
+ expect(indexTs?.content).toContain("import { z } from 'zod'");
351
+ });
352
+
353
+ it('should extend root tsconfig', () => {
354
+ const options: TemplateOptions = {
355
+ ...baseOptions,
356
+ monorepo: true,
357
+ apiPath: 'apps/api',
358
+ };
359
+ const files = generateModelsPackage(options);
360
+ const tsConfig = files.find(
361
+ (f) => f.path === 'packages/models/tsconfig.json',
362
+ );
363
+ const config = JSON.parse(tsConfig?.content);
364
+ expect(config.extends).toBe('../../tsconfig.json');
365
+ });
366
366
  });