@geekmidas/cli 0.10.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 (145) 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-C9aXOHBe.cjs → config-AmInkU7k.cjs} +8 -8
  7. package/dist/config-AmInkU7k.cjs.map +1 -0
  8. package/dist/{config-BrkUalUh.mjs → config-DYULeEv8.mjs} +3 -3
  9. package/dist/config-DYULeEv8.mjs.map +1 -0
  10. package/dist/config.cjs +1 -1
  11. package/dist/config.d.cts +1 -1
  12. package/dist/config.d.mts +1 -1
  13. package/dist/config.mjs +1 -1
  14. package/dist/encryption-C8H-38Yy.mjs +42 -0
  15. package/dist/encryption-C8H-38Yy.mjs.map +1 -0
  16. package/dist/encryption-Dyf_r1h-.cjs +44 -0
  17. package/dist/encryption-Dyf_r1h-.cjs.map +1 -0
  18. package/dist/index.cjs +2116 -179
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.mjs +2134 -192
  21. package/dist/index.mjs.map +1 -1
  22. package/dist/{openapi-CZLI4QTr.mjs → openapi-BfFlOBCG.mjs} +801 -38
  23. package/dist/openapi-BfFlOBCG.mjs.map +1 -0
  24. package/dist/{openapi-BeHLKcwP.cjs → openapi-Bt_1FDpT.cjs} +794 -31
  25. package/dist/openapi-Bt_1FDpT.cjs.map +1 -0
  26. package/dist/{openapi-react-query-o5iMi8tz.cjs → openapi-react-query-B-sNWHFU.cjs} +5 -5
  27. package/dist/openapi-react-query-B-sNWHFU.cjs.map +1 -0
  28. package/dist/{openapi-react-query-CcciaVu5.mjs → openapi-react-query-B6XTeGqS.mjs} +5 -5
  29. package/dist/openapi-react-query-B6XTeGqS.mjs.map +1 -0
  30. package/dist/openapi-react-query.cjs +1 -1
  31. package/dist/openapi-react-query.d.cts.map +1 -1
  32. package/dist/openapi-react-query.d.mts.map +1 -1
  33. package/dist/openapi-react-query.mjs +1 -1
  34. package/dist/openapi.cjs +2 -2
  35. package/dist/openapi.d.cts +1 -1
  36. package/dist/openapi.d.cts.map +1 -1
  37. package/dist/openapi.d.mts +1 -1
  38. package/dist/openapi.d.mts.map +1 -1
  39. package/dist/openapi.mjs +2 -2
  40. package/dist/storage-BUYQJgz7.cjs +4 -0
  41. package/dist/storage-BXoJvmv2.cjs +149 -0
  42. package/dist/storage-BXoJvmv2.cjs.map +1 -0
  43. package/dist/storage-C9PU_30f.mjs +101 -0
  44. package/dist/storage-C9PU_30f.mjs.map +1 -0
  45. package/dist/storage-DLJAYxzJ.mjs +3 -0
  46. package/dist/{types-b-vwGpqc.d.cts → types-BR0M2v_c.d.mts} +100 -1
  47. package/dist/types-BR0M2v_c.d.mts.map +1 -0
  48. package/dist/{types-DXgiA1sF.d.mts → types-BhkZc-vm.d.cts} +100 -1
  49. package/dist/types-BhkZc-vm.d.cts.map +1 -0
  50. package/examples/cron-example.ts +27 -27
  51. package/examples/env.ts +27 -27
  52. package/examples/function-example.ts +31 -31
  53. package/examples/gkm.config.json +20 -20
  54. package/examples/gkm.config.ts +8 -8
  55. package/examples/gkm.minimal.config.json +5 -5
  56. package/examples/gkm.production.config.json +25 -25
  57. package/examples/logger.ts +2 -2
  58. package/package.json +6 -6
  59. package/src/__tests__/EndpointGenerator.hooks.spec.ts +191 -191
  60. package/src/__tests__/config.spec.ts +55 -55
  61. package/src/__tests__/loadEnvFiles.spec.ts +93 -93
  62. package/src/__tests__/normalizeHooksConfig.spec.ts +58 -58
  63. package/src/__tests__/openapi-react-query.spec.ts +497 -497
  64. package/src/__tests__/openapi.spec.ts +428 -428
  65. package/src/__tests__/test-helpers.ts +76 -76
  66. package/src/auth/__tests__/credentials.spec.ts +204 -0
  67. package/src/auth/__tests__/index.spec.ts +168 -0
  68. package/src/auth/credentials.ts +187 -0
  69. package/src/auth/index.ts +226 -0
  70. package/src/build/__tests__/index-new.spec.ts +474 -474
  71. package/src/build/__tests__/manifests.spec.ts +333 -333
  72. package/src/build/bundler.ts +141 -0
  73. package/src/build/endpoint-analyzer.ts +236 -0
  74. package/src/build/handler-templates.ts +1253 -0
  75. package/src/build/index.ts +250 -179
  76. package/src/build/manifests.ts +52 -52
  77. package/src/build/providerResolver.ts +145 -145
  78. package/src/build/types.ts +64 -43
  79. package/src/config.ts +39 -39
  80. package/src/deploy/__tests__/docker.spec.ts +111 -0
  81. package/src/deploy/__tests__/dokploy.spec.ts +245 -0
  82. package/src/deploy/__tests__/init.spec.ts +662 -0
  83. package/src/deploy/docker.ts +128 -0
  84. package/src/deploy/dokploy.ts +204 -0
  85. package/src/deploy/index.ts +136 -0
  86. package/src/deploy/init.ts +484 -0
  87. package/src/deploy/types.ts +48 -0
  88. package/src/dev/__tests__/index.spec.ts +266 -266
  89. package/src/dev/index.ts +647 -601
  90. package/src/docker/__tests__/compose.spec.ts +531 -0
  91. package/src/docker/__tests__/templates.spec.ts +280 -0
  92. package/src/docker/compose.ts +273 -0
  93. package/src/docker/index.ts +230 -0
  94. package/src/docker/templates.ts +446 -0
  95. package/src/generators/CronGenerator.ts +72 -72
  96. package/src/generators/EndpointGenerator.ts +699 -398
  97. package/src/generators/FunctionGenerator.ts +84 -84
  98. package/src/generators/Generator.ts +72 -72
  99. package/src/generators/OpenApiTsGenerator.ts +577 -577
  100. package/src/generators/SubscriberGenerator.ts +124 -124
  101. package/src/generators/__tests__/CronGenerator.spec.ts +433 -433
  102. package/src/generators/__tests__/EndpointGenerator.spec.ts +532 -382
  103. package/src/generators/__tests__/FunctionGenerator.spec.ts +244 -244
  104. package/src/generators/__tests__/SubscriberGenerator.spec.ts +397 -382
  105. package/src/generators/index.ts +4 -4
  106. package/src/index.ts +623 -201
  107. package/src/init/__tests__/generators.spec.ts +334 -334
  108. package/src/init/__tests__/init.spec.ts +332 -332
  109. package/src/init/__tests__/utils.spec.ts +89 -89
  110. package/src/init/generators/config.ts +175 -175
  111. package/src/init/generators/docker.ts +41 -41
  112. package/src/init/generators/env.ts +72 -72
  113. package/src/init/generators/index.ts +1 -1
  114. package/src/init/generators/models.ts +64 -64
  115. package/src/init/generators/monorepo.ts +161 -161
  116. package/src/init/generators/package.ts +71 -71
  117. package/src/init/generators/source.ts +6 -6
  118. package/src/init/index.ts +203 -208
  119. package/src/init/templates/api.ts +115 -115
  120. package/src/init/templates/index.ts +75 -75
  121. package/src/init/templates/minimal.ts +98 -98
  122. package/src/init/templates/serverless.ts +89 -89
  123. package/src/init/templates/worker.ts +98 -98
  124. package/src/init/utils.ts +54 -56
  125. package/src/openapi-react-query.ts +194 -194
  126. package/src/openapi.ts +63 -63
  127. package/src/secrets/__tests__/encryption.spec.ts +226 -0
  128. package/src/secrets/__tests__/generator.spec.ts +319 -0
  129. package/src/secrets/__tests__/index.spec.ts +91 -0
  130. package/src/secrets/__tests__/storage.spec.ts +403 -0
  131. package/src/secrets/encryption.ts +91 -0
  132. package/src/secrets/generator.ts +164 -0
  133. package/src/secrets/index.ts +383 -0
  134. package/src/secrets/storage.ts +134 -0
  135. package/src/secrets/types.ts +53 -0
  136. package/src/types.ts +295 -176
  137. package/tsdown.config.ts +11 -8
  138. package/dist/config-BrkUalUh.mjs.map +0 -1
  139. package/dist/config-C9aXOHBe.cjs.map +0 -1
  140. package/dist/openapi-BeHLKcwP.cjs.map +0 -1
  141. package/dist/openapi-CZLI4QTr.mjs.map +0 -1
  142. package/dist/openapi-react-query-CcciaVu5.mjs.map +0 -1
  143. package/dist/openapi-react-query-o5iMi8tz.cjs.map +0 -1
  144. package/dist/types-DXgiA1sF.d.mts.map +0 -1
  145. package/dist/types-b-vwGpqc.d.cts.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
  });