@geekmidas/cli 0.1.0 → 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.
- package/README.md +63 -13
- package/dist/{CronGenerator-Ctl4USy4.cjs → CronGenerator-1PflEYe2.cjs} +8 -7
- package/dist/CronGenerator-1PflEYe2.cjs.map +1 -0
- package/dist/{CronGenerator-ClbRcmz_.mjs → CronGenerator-DXRfHQcV.mjs} +6 -5
- package/dist/CronGenerator-DXRfHQcV.mjs.map +1 -0
- package/dist/{EndpointGenerator-Dj7AumHi.cjs → EndpointGenerator-BbGrDiCP.cjs} +134 -34
- package/dist/EndpointGenerator-BbGrDiCP.cjs.map +1 -0
- package/dist/{EndpointGenerator-uBA1ixUw.mjs → EndpointGenerator-BmZ9BxbO.mjs} +132 -32
- package/dist/EndpointGenerator-BmZ9BxbO.mjs.map +1 -0
- package/dist/{FunctionGenerator-DN681IUn.cjs → FunctionGenerator-Clw64SwQ.cjs} +8 -7
- package/dist/FunctionGenerator-Clw64SwQ.cjs.map +1 -0
- package/dist/{FunctionGenerator-crAa-JC7.mjs → FunctionGenerator-DOEB_yPh.mjs} +6 -5
- package/dist/FunctionGenerator-DOEB_yPh.mjs.map +1 -0
- package/dist/{Generator-C3tYSTQY.cjs → Generator-CDoEXCDg.cjs} +2 -2
- package/dist/Generator-CDoEXCDg.cjs.map +1 -0
- package/dist/{Generator-CDt4pB3W.mjs → Generator-UanJW0_V.mjs} +1 -1
- package/dist/Generator-UanJW0_V.mjs.map +1 -0
- package/dist/SubscriberGenerator-BfMZCVNy.cjs +204 -0
- package/dist/SubscriberGenerator-BfMZCVNy.cjs.map +1 -0
- package/dist/SubscriberGenerator-D2u00NI3.mjs +198 -0
- package/dist/SubscriberGenerator-D2u00NI3.mjs.map +1 -0
- package/dist/build/index.cjs +10 -9
- package/dist/build/index.mjs +8 -7
- package/dist/build/manifests.cjs +1 -1
- package/dist/build/manifests.mjs +1 -1
- package/dist/build/providerResolver.cjs +1 -1
- package/dist/build-BBhlEjf5.cjs +89 -0
- package/dist/build-BBhlEjf5.cjs.map +1 -0
- package/dist/build-kY-lG30Q.mjs +83 -0
- package/dist/build-kY-lG30Q.mjs.map +1 -0
- package/dist/{chunk-CsX-DzYB.cjs → chunk-CUT6urMc.cjs} +0 -12
- package/dist/{config-RcNESK0T.cjs → config-D1EpSGk6.cjs} +2 -2
- package/dist/{config-RcNESK0T.cjs.map → config-D1EpSGk6.cjs.map} +1 -1
- package/dist/{config-CXxYmz_o.mjs → config-U-mdW-7Y.mjs} +1 -1
- package/dist/{config-CXxYmz_o.mjs.map → config-U-mdW-7Y.mjs.map} +1 -1
- package/dist/config.cjs +1 -1
- package/dist/config.mjs +1 -1
- package/dist/generators/CronGenerator.cjs +2 -2
- package/dist/generators/CronGenerator.mjs +2 -2
- package/dist/generators/EndpointGenerator.cjs +2 -2
- package/dist/generators/EndpointGenerator.mjs +2 -2
- package/dist/generators/FunctionGenerator.cjs +2 -2
- package/dist/generators/FunctionGenerator.mjs +2 -2
- package/dist/generators/Generator.cjs +1 -1
- package/dist/generators/Generator.mjs +1 -1
- package/dist/generators/SubscriberGenerator.cjs +4 -0
- package/dist/generators/SubscriberGenerator.mjs +4 -0
- package/dist/generators/index.cjs +8 -6
- package/dist/generators/index.mjs +6 -5
- package/dist/index.cjs +18 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +15 -11
- package/dist/index.mjs.map +1 -1
- package/dist/{manifests-HX4z4kkz.mjs → manifests-BrJXpHrf.mjs} +5 -4
- package/dist/manifests-BrJXpHrf.mjs.map +1 -0
- package/dist/{manifests-BTtfDMX8.cjs → manifests-D0saShvH.cjs} +6 -5
- package/dist/manifests-D0saShvH.cjs.map +1 -0
- package/dist/{openapi-BivnatiC.mjs → openapi-BQx3_JbM.mjs} +4 -4
- package/dist/openapi-BQx3_JbM.mjs.map +1 -0
- package/dist/{openapi-DW-qF3oW.cjs → openapi-CMLr04cz.cjs} +6 -6
- package/dist/openapi-CMLr04cz.cjs.map +1 -0
- package/dist/{openapi-react-query-lgS7AVEz.mjs → openapi-react-query-DbrWwQzb.mjs} +3 -2
- package/dist/openapi-react-query-DbrWwQzb.mjs.map +1 -0
- package/dist/{openapi-react-query-J0BzBHhN.cjs → openapi-react-query-Dvjqx_Eo.cjs} +4 -3
- package/dist/openapi-react-query-Dvjqx_Eo.cjs.map +1 -0
- package/dist/openapi-react-query.cjs +1 -1
- package/dist/openapi-react-query.mjs +1 -1
- package/dist/openapi.cjs +4 -4
- package/dist/openapi.mjs +4 -4
- package/dist/{providerResolver-Cs-0YCaP.cjs → providerResolver-DgvzNfP4.cjs} +1 -1
- package/dist/{providerResolver-Cs-0YCaP.cjs.map → providerResolver-DgvzNfP4.cjs.map} +1 -1
- package/examples/cron-example.ts +1 -1
- package/examples/function-example.ts +1 -1
- package/examples/logger.ts +1 -1
- package/package.json +6 -3
- package/src/__tests__/openapi-react-query.spec.ts +506 -0
- package/src/__tests__/openapi.spec.ts +362 -0
- package/src/__tests__/test-helpers.ts +10 -8
- package/src/build/__tests__/index-new.spec.ts +41 -42
- package/src/build/index.ts +89 -28
- package/src/build/manifests.ts +4 -1
- package/src/build/types.ts +2 -2
- package/src/generators/CronGenerator.ts +3 -2
- package/src/generators/EndpointGenerator.ts +141 -42
- package/src/generators/FunctionGenerator.ts +3 -2
- package/src/generators/Generator.ts +1 -1
- package/src/generators/SubscriberGenerator.ts +271 -0
- package/src/generators/__tests__/CronGenerator.spec.ts +1 -1
- package/src/generators/__tests__/EndpointGenerator.spec.ts +33 -11
- package/src/generators/__tests__/FunctionGenerator.spec.ts +21 -22
- package/src/generators/__tests__/SubscriberGenerator.spec.ts +341 -0
- package/src/generators/index.ts +1 -0
- package/src/openapi-react-query.ts +2 -1
- package/src/openapi.ts +1 -1
- package/src/types.ts +18 -0
- package/dist/CronGenerator-ClbRcmz_.mjs.map +0 -1
- package/dist/CronGenerator-Ctl4USy4.cjs.map +0 -1
- package/dist/EndpointGenerator-Dj7AumHi.cjs.map +0 -1
- package/dist/EndpointGenerator-uBA1ixUw.mjs.map +0 -1
- package/dist/FunctionGenerator-DN681IUn.cjs.map +0 -1
- package/dist/FunctionGenerator-crAa-JC7.mjs.map +0 -1
- package/dist/Generator-C3tYSTQY.cjs.map +0 -1
- package/dist/Generator-CDt4pB3W.mjs.map +0 -1
- package/dist/__tests__/config.spec.cjs +0 -98
- package/dist/__tests__/config.spec.cjs.map +0 -1
- package/dist/__tests__/config.spec.mjs +0 -97
- package/dist/__tests__/config.spec.mjs.map +0 -1
- package/dist/__tests__/test-helpers.cjs +0 -14
- package/dist/__tests__/test-helpers.mjs +0 -4
- package/dist/build/__tests__/index-new.spec.cjs +0 -286
- package/dist/build/__tests__/index-new.spec.cjs.map +0 -1
- package/dist/build/__tests__/index-new.spec.mjs +0 -285
- package/dist/build/__tests__/index-new.spec.mjs.map +0 -1
- package/dist/build-BZdwxCLW.mjs +0 -64
- package/dist/build-BZdwxCLW.mjs.map +0 -1
- package/dist/build-BfQFnU5-.cjs +0 -70
- package/dist/build-BfQFnU5-.cjs.map +0 -1
- package/dist/esm-9eeZntth.mjs +0 -3777
- package/dist/esm-9eeZntth.mjs.map +0 -1
- package/dist/esm-Crmo4h9t.cjs +0 -4392
- package/dist/esm-Crmo4h9t.cjs.map +0 -1
- package/dist/esm-CsJbr7gi.mjs +0 -3
- package/dist/esm-w09tAC4l.cjs +0 -8
- package/dist/generators/__tests__/CronGenerator.spec.cjs +0 -216
- package/dist/generators/__tests__/CronGenerator.spec.cjs.map +0 -1
- package/dist/generators/__tests__/CronGenerator.spec.mjs +0 -215
- package/dist/generators/__tests__/CronGenerator.spec.mjs.map +0 -1
- package/dist/generators/__tests__/EndpointGenerator.spec.cjs +0 -182
- package/dist/generators/__tests__/EndpointGenerator.spec.cjs.map +0 -1
- package/dist/generators/__tests__/EndpointGenerator.spec.mjs +0 -181
- package/dist/generators/__tests__/EndpointGenerator.spec.mjs.map +0 -1
- package/dist/generators/__tests__/FunctionGenerator.spec.cjs +0 -152
- package/dist/generators/__tests__/FunctionGenerator.spec.cjs.map +0 -1
- package/dist/generators/__tests__/FunctionGenerator.spec.mjs +0 -151
- package/dist/generators/__tests__/FunctionGenerator.spec.mjs.map +0 -1
- package/dist/manifests-BTtfDMX8.cjs.map +0 -1
- package/dist/manifests-HX4z4kkz.mjs.map +0 -1
- package/dist/openapi-BivnatiC.mjs.map +0 -1
- package/dist/openapi-DW-qF3oW.cjs.map +0 -1
- package/dist/openapi-react-query-J0BzBHhN.cjs.map +0 -1
- package/dist/openapi-react-query-lgS7AVEz.mjs.map +0 -1
- package/dist/test-helpers-ARd8GDgx.cjs +0 -199
- package/dist/test-helpers-ARd8GDgx.cjs.map +0 -1
- package/dist/test-helpers-DdVBk23F.mjs +0 -133
- package/dist/test-helpers-DdVBk23F.mjs.map +0 -1
- /package/dist/{generators-_pY7sHy1.cjs → generators-CEKtVh81.cjs} +0 -0
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import { openapiCommand } from '../openapi';
|
|
6
|
+
import {
|
|
7
|
+
cleanupDir,
|
|
8
|
+
createMockEndpointFile,
|
|
9
|
+
createTempDir,
|
|
10
|
+
createTestFile,
|
|
11
|
+
} from './test-helpers';
|
|
12
|
+
|
|
13
|
+
describe('OpenAPI Generation', () => {
|
|
14
|
+
let tempDir: string;
|
|
15
|
+
|
|
16
|
+
beforeEach(async () => {
|
|
17
|
+
tempDir = await createTempDir('openapi-test-');
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
afterEach(async () => {
|
|
21
|
+
await cleanupDir(tempDir);
|
|
22
|
+
vi.restoreAllMocks();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe('openapiCommand', () => {
|
|
26
|
+
it('should generate OpenAPI spec for endpoints', async () => {
|
|
27
|
+
// Create endpoint file
|
|
28
|
+
await createMockEndpointFile(
|
|
29
|
+
tempDir,
|
|
30
|
+
'getUser.ts',
|
|
31
|
+
'getUser',
|
|
32
|
+
'/users/:id',
|
|
33
|
+
'GET',
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
// Create config file
|
|
37
|
+
await createTestFile(
|
|
38
|
+
tempDir,
|
|
39
|
+
'gkm.config.json',
|
|
40
|
+
JSON.stringify({
|
|
41
|
+
routes: [`${tempDir}/**/*.ts`],
|
|
42
|
+
}),
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const outputPath = join(tempDir, 'openapi.json');
|
|
46
|
+
|
|
47
|
+
// Mock process.cwd
|
|
48
|
+
vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
|
|
49
|
+
|
|
50
|
+
await openapiCommand({ output: outputPath });
|
|
51
|
+
|
|
52
|
+
// Verify file was created
|
|
53
|
+
expect(existsSync(outputPath)).toBe(true);
|
|
54
|
+
|
|
55
|
+
// Verify content
|
|
56
|
+
const content = await readFile(outputPath, 'utf-8');
|
|
57
|
+
const spec = JSON.parse(content);
|
|
58
|
+
|
|
59
|
+
expect(spec).toHaveProperty('openapi');
|
|
60
|
+
expect(spec).toHaveProperty('info');
|
|
61
|
+
expect(spec.info.title).toBe('API Documentation');
|
|
62
|
+
expect(spec).toHaveProperty('paths');
|
|
63
|
+
expect(Object.keys(spec.paths).length).toBeGreaterThan(0);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should handle no endpoints found', async () => {
|
|
67
|
+
// Create config with no matching files
|
|
68
|
+
await createTestFile(
|
|
69
|
+
tempDir,
|
|
70
|
+
'gkm.config.json',
|
|
71
|
+
JSON.stringify({
|
|
72
|
+
routes: [`${tempDir}/nonexistent/**/*.ts`],
|
|
73
|
+
}),
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
|
|
77
|
+
const consoleSpy = vi.spyOn(console, 'log');
|
|
78
|
+
|
|
79
|
+
await openapiCommand({ output: join(tempDir, 'openapi.json') });
|
|
80
|
+
|
|
81
|
+
expect(consoleSpy).toHaveBeenCalledWith('No valid endpoints found');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should use default output path when not specified', async () => {
|
|
85
|
+
// Create endpoint file
|
|
86
|
+
await createMockEndpointFile(
|
|
87
|
+
tempDir,
|
|
88
|
+
'endpoint.ts',
|
|
89
|
+
'testEndpoint',
|
|
90
|
+
'/test',
|
|
91
|
+
'GET',
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
// Create config
|
|
95
|
+
await createTestFile(
|
|
96
|
+
tempDir,
|
|
97
|
+
'gkm.config.json',
|
|
98
|
+
JSON.stringify({
|
|
99
|
+
routes: [`${tempDir}/**/*.ts`],
|
|
100
|
+
}),
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
|
|
104
|
+
|
|
105
|
+
await openapiCommand();
|
|
106
|
+
|
|
107
|
+
// Should create openapi.json in current directory
|
|
108
|
+
expect(existsSync(join(tempDir, 'openapi.json'))).toBe(true);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should generate spec with multiple endpoints', async () => {
|
|
112
|
+
// Create multiple endpoint files
|
|
113
|
+
await createMockEndpointFile(
|
|
114
|
+
tempDir,
|
|
115
|
+
'getUsers.ts',
|
|
116
|
+
'getUsers',
|
|
117
|
+
'/users',
|
|
118
|
+
'GET',
|
|
119
|
+
);
|
|
120
|
+
await createMockEndpointFile(
|
|
121
|
+
tempDir,
|
|
122
|
+
'createUser.ts',
|
|
123
|
+
'createUser',
|
|
124
|
+
'/users',
|
|
125
|
+
'POST',
|
|
126
|
+
);
|
|
127
|
+
await createMockEndpointFile(
|
|
128
|
+
tempDir,
|
|
129
|
+
'deleteUser.ts',
|
|
130
|
+
'deleteUser',
|
|
131
|
+
'/users/:id',
|
|
132
|
+
'DELETE',
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
// Create config
|
|
136
|
+
await createTestFile(
|
|
137
|
+
tempDir,
|
|
138
|
+
'gkm.config.json',
|
|
139
|
+
JSON.stringify({
|
|
140
|
+
routes: [`${tempDir}/**/*.ts`],
|
|
141
|
+
}),
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
const outputPath = join(tempDir, 'openapi.json');
|
|
145
|
+
vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
|
|
146
|
+
|
|
147
|
+
await openapiCommand({ output: outputPath });
|
|
148
|
+
|
|
149
|
+
const content = await readFile(outputPath, 'utf-8');
|
|
150
|
+
const spec = JSON.parse(content);
|
|
151
|
+
|
|
152
|
+
// Should have multiple paths
|
|
153
|
+
expect(Object.keys(spec.paths).length).toBeGreaterThanOrEqual(1);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('should create output directory if it does not exist', async () => {
|
|
157
|
+
// Create endpoint file
|
|
158
|
+
await createMockEndpointFile(
|
|
159
|
+
tempDir,
|
|
160
|
+
'endpoint.ts',
|
|
161
|
+
'testEndpoint',
|
|
162
|
+
'/test',
|
|
163
|
+
'GET',
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
// Create config
|
|
167
|
+
await createTestFile(
|
|
168
|
+
tempDir,
|
|
169
|
+
'gkm.config.json',
|
|
170
|
+
JSON.stringify({
|
|
171
|
+
routes: [`${tempDir}/**/*.ts`],
|
|
172
|
+
}),
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
const outputPath = join(tempDir, 'nested', 'dir', 'openapi.json');
|
|
176
|
+
vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
|
|
177
|
+
|
|
178
|
+
await openapiCommand({ output: outputPath });
|
|
179
|
+
|
|
180
|
+
expect(existsSync(outputPath)).toBe(true);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('should include API metadata in spec', async () => {
|
|
184
|
+
// Create endpoint
|
|
185
|
+
await createMockEndpointFile(
|
|
186
|
+
tempDir,
|
|
187
|
+
'endpoint.ts',
|
|
188
|
+
'testEndpoint',
|
|
189
|
+
'/test',
|
|
190
|
+
'GET',
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
// Create config
|
|
194
|
+
await createTestFile(
|
|
195
|
+
tempDir,
|
|
196
|
+
'gkm.config.json',
|
|
197
|
+
JSON.stringify({
|
|
198
|
+
routes: [`${tempDir}/**/*.ts`],
|
|
199
|
+
}),
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
const outputPath = join(tempDir, 'openapi.json');
|
|
203
|
+
vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
|
|
204
|
+
|
|
205
|
+
await openapiCommand({ output: outputPath });
|
|
206
|
+
|
|
207
|
+
const content = await readFile(outputPath, 'utf-8');
|
|
208
|
+
const spec = JSON.parse(content);
|
|
209
|
+
|
|
210
|
+
expect(spec.info).toEqual({
|
|
211
|
+
title: 'API Documentation',
|
|
212
|
+
version: '1.0.0',
|
|
213
|
+
description: 'Auto-generated API documentation from endpoints',
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it('should log generation success', async () => {
|
|
218
|
+
// Create endpoint
|
|
219
|
+
await createMockEndpointFile(
|
|
220
|
+
tempDir,
|
|
221
|
+
'endpoint.ts',
|
|
222
|
+
'testEndpoint',
|
|
223
|
+
'/test',
|
|
224
|
+
'GET',
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
// Create config
|
|
228
|
+
await createTestFile(
|
|
229
|
+
tempDir,
|
|
230
|
+
'gkm.config.json',
|
|
231
|
+
JSON.stringify({
|
|
232
|
+
routes: [`${tempDir}/**/*.ts`],
|
|
233
|
+
}),
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
const outputPath = join(tempDir, 'openapi.json');
|
|
237
|
+
vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
|
|
238
|
+
const consoleSpy = vi.spyOn(console, 'log');
|
|
239
|
+
|
|
240
|
+
await openapiCommand({ output: outputPath });
|
|
241
|
+
|
|
242
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
243
|
+
expect.stringContaining('OpenAPI spec generated'),
|
|
244
|
+
);
|
|
245
|
+
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Found'));
|
|
246
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
247
|
+
expect.stringContaining('endpoints'),
|
|
248
|
+
);
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it('should throw error when config loading fails', async () => {
|
|
252
|
+
// No config file created
|
|
253
|
+
vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
|
|
254
|
+
|
|
255
|
+
await expect(openapiCommand()).rejects.toThrow(
|
|
256
|
+
/OpenAPI generation failed/,
|
|
257
|
+
);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it('should throw error for invalid TypeScript files', async () => {
|
|
261
|
+
// Create invalid TS file
|
|
262
|
+
await createTestFile(
|
|
263
|
+
tempDir,
|
|
264
|
+
'invalid.ts',
|
|
265
|
+
'this is not valid typescript {[}]',
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
// Create config
|
|
269
|
+
await createTestFile(
|
|
270
|
+
tempDir,
|
|
271
|
+
'gkm.config.json',
|
|
272
|
+
JSON.stringify({
|
|
273
|
+
routes: [`${tempDir}/**/*.ts`],
|
|
274
|
+
}),
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
|
|
278
|
+
|
|
279
|
+
// Should throw error for syntax errors
|
|
280
|
+
await expect(
|
|
281
|
+
openapiCommand({ output: join(tempDir, 'openapi.json') }),
|
|
282
|
+
).rejects.toThrow(/OpenAPI generation failed/);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it('should generate valid JSON format', async () => {
|
|
286
|
+
// Create endpoint
|
|
287
|
+
await createMockEndpointFile(
|
|
288
|
+
tempDir,
|
|
289
|
+
'endpoint.ts',
|
|
290
|
+
'testEndpoint',
|
|
291
|
+
'/test',
|
|
292
|
+
'GET',
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
// Create config
|
|
296
|
+
await createTestFile(
|
|
297
|
+
tempDir,
|
|
298
|
+
'gkm.config.json',
|
|
299
|
+
JSON.stringify({
|
|
300
|
+
routes: [`${tempDir}/**/*.ts`],
|
|
301
|
+
}),
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
const outputPath = join(tempDir, 'openapi.json');
|
|
305
|
+
vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
|
|
306
|
+
|
|
307
|
+
await openapiCommand({ output: outputPath });
|
|
308
|
+
|
|
309
|
+
const content = await readFile(outputPath, 'utf-8');
|
|
310
|
+
|
|
311
|
+
// Should be valid JSON and properly formatted
|
|
312
|
+
expect(() => JSON.parse(content)).not.toThrow();
|
|
313
|
+
expect(content).toContain('\n'); // Formatted with indentation
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
it('should handle endpoints with complex schemas', async () => {
|
|
317
|
+
// Create endpoint with complex schema
|
|
318
|
+
const complexEndpointContent = `
|
|
319
|
+
import { e } from '@geekmidas/constructs/endpoints';
|
|
320
|
+
import { z } from 'zod';
|
|
321
|
+
|
|
322
|
+
export const complexEndpoint = e
|
|
323
|
+
.post('/complex')
|
|
324
|
+
.body(z.object({
|
|
325
|
+
user: z.object({
|
|
326
|
+
name: z.string(),
|
|
327
|
+
email: z.string().email(),
|
|
328
|
+
age: z.number().optional(),
|
|
329
|
+
}),
|
|
330
|
+
tags: z.array(z.string()),
|
|
331
|
+
}))
|
|
332
|
+
.output(z.object({
|
|
333
|
+
id: z.string(),
|
|
334
|
+
status: z.enum(['active', 'inactive']),
|
|
335
|
+
}))
|
|
336
|
+
.handle(async () => ({ id: '123', status: 'active' as const }));
|
|
337
|
+
`;
|
|
338
|
+
|
|
339
|
+
await createTestFile(tempDir, 'complex.ts', complexEndpointContent);
|
|
340
|
+
|
|
341
|
+
// Create config
|
|
342
|
+
await createTestFile(
|
|
343
|
+
tempDir,
|
|
344
|
+
'gkm.config.json',
|
|
345
|
+
JSON.stringify({
|
|
346
|
+
routes: [`${tempDir}/**/*.ts`],
|
|
347
|
+
}),
|
|
348
|
+
);
|
|
349
|
+
|
|
350
|
+
const outputPath = join(tempDir, 'openapi.json');
|
|
351
|
+
vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
|
|
352
|
+
|
|
353
|
+
await openapiCommand({ output: outputPath });
|
|
354
|
+
|
|
355
|
+
const content = await readFile(outputPath, 'utf-8');
|
|
356
|
+
const spec = JSON.parse(content);
|
|
357
|
+
|
|
358
|
+
// Should have generated schema for complex types
|
|
359
|
+
expect(spec.paths).toBeDefined();
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
});
|
|
@@ -3,10 +3,9 @@ import { tmpdir } from 'node:os';
|
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import {
|
|
5
5
|
CronBuilder,
|
|
6
|
-
FunctionBuilder,
|
|
7
6
|
type ScheduleExpression,
|
|
8
|
-
} from '@geekmidas/
|
|
9
|
-
import { e } from '@geekmidas/
|
|
7
|
+
} from '@geekmidas/constructs/crons';
|
|
8
|
+
import { e } from '@geekmidas/constructs/endpoints';
|
|
10
9
|
import { z } from 'zod';
|
|
11
10
|
|
|
12
11
|
/**
|
|
@@ -57,7 +56,7 @@ export async function createMockEndpointFile(
|
|
|
57
56
|
method: string = 'GET',
|
|
58
57
|
): Promise<string> {
|
|
59
58
|
const content = `
|
|
60
|
-
import { e } from '@geekmidas/
|
|
59
|
+
import { e } from '@geekmidas/constructs/endpoints';
|
|
61
60
|
import { z } from 'zod';
|
|
62
61
|
|
|
63
62
|
export const ${exportName} = e
|
|
@@ -78,10 +77,10 @@ export async function createMockFunctionFile(
|
|
|
78
77
|
timeout = 30,
|
|
79
78
|
): Promise<string> {
|
|
80
79
|
const content = `
|
|
81
|
-
import {
|
|
80
|
+
import { f } from '@geekmidas/constructs/functions';
|
|
82
81
|
import { z } from 'zod';
|
|
83
82
|
|
|
84
|
-
export const ${exportName} =
|
|
83
|
+
export const ${exportName} = f
|
|
85
84
|
.input(z.object({ name: z.string() }))
|
|
86
85
|
.output(z.object({ greeting: z.string() }))
|
|
87
86
|
.timeout(${timeout})
|
|
@@ -100,7 +99,7 @@ export async function createMockCronFile(
|
|
|
100
99
|
schedule = 'rate(1 hour)',
|
|
101
100
|
): Promise<string> {
|
|
102
101
|
const content = `
|
|
103
|
-
import { CronBuilder } from '@geekmidas/
|
|
102
|
+
import { CronBuilder } from '@geekmidas/constructs/crons';
|
|
104
103
|
import { z } from 'zod';
|
|
105
104
|
|
|
106
105
|
export const ${exportName} = new CronBuilder()
|
|
@@ -129,7 +128,9 @@ export function createTestFunction(timeout: number = 30) {
|
|
|
129
128
|
builder.input(z.object({ name: z.string() }));
|
|
130
129
|
builder.output(z.object({ greeting: z.string() }));
|
|
131
130
|
builder.timeout(timeout);
|
|
132
|
-
return builder.handle(async ({ input }: any) => ({
|
|
131
|
+
return builder.handle(async ({ input }: any) => ({
|
|
132
|
+
greeting: `Hello, ${input.name}!`,
|
|
133
|
+
}));
|
|
133
134
|
}
|
|
134
135
|
|
|
135
136
|
export function createTestCron(
|
|
@@ -175,4 +176,5 @@ export async function waitFor(
|
|
|
175
176
|
}
|
|
176
177
|
|
|
177
178
|
import { dirname } from 'node:path';
|
|
179
|
+
import { FunctionBuilder } from '@geekmidas/constructs/functions';
|
|
178
180
|
import type { HttpMethod } from '../../../api/src/constructs/types';
|
|
@@ -69,9 +69,19 @@ export default {
|
|
|
69
69
|
|
|
70
70
|
// Check that output directories were created
|
|
71
71
|
const serverDir = join(dir, '.gkm', 'server');
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
|
|
73
|
+
// Check app.ts has the createApp function with new API
|
|
74
|
+
const appContent = await readFile(join(serverDir, 'app.ts'), 'utf-8');
|
|
75
|
+
expect(appContent).toContain('function createApp');
|
|
76
|
+
expect(appContent).toContain('interface ServerApp');
|
|
77
|
+
expect(appContent).toContain('async start(options');
|
|
78
|
+
|
|
79
|
+
// Check endpoints.ts has the HonoEndpoint setup
|
|
80
|
+
const endpointsContent = await readFile(
|
|
81
|
+
join(serverDir, 'endpoints.ts'),
|
|
82
|
+
'utf-8',
|
|
74
83
|
);
|
|
84
|
+
expect(endpointsContent).toContain('HonoEndpoint');
|
|
75
85
|
} finally {
|
|
76
86
|
process.chdir(originalCwd);
|
|
77
87
|
}
|
|
@@ -192,29 +202,38 @@ export default {
|
|
|
192
202
|
),
|
|
193
203
|
).toContain('AmazonApiGatewayV2Endpoint');
|
|
194
204
|
|
|
195
|
-
// Verify unified
|
|
196
|
-
const
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
const lambdaManifest = JSON.parse(
|
|
200
|
-
await readFile(lambdaManifestPath, 'utf-8'),
|
|
201
|
-
);
|
|
202
|
-
const apiGatewayManifest = JSON.parse(
|
|
203
|
-
await readFile(apiGatewayManifestPath, 'utf-8'),
|
|
204
|
-
);
|
|
205
|
+
// Verify unified manifest was created at root .gkm directory
|
|
206
|
+
const manifestPath = join(dir, '.gkm', 'manifest.json');
|
|
207
|
+
const manifest = JSON.parse(await readFile(manifestPath, 'utf-8'));
|
|
205
208
|
|
|
206
|
-
// Verify
|
|
207
|
-
expect(
|
|
209
|
+
// Verify manifest structure includes all routes from both providers
|
|
210
|
+
expect(manifest).toMatchObject({
|
|
208
211
|
routes: expect.arrayContaining([
|
|
212
|
+
// Routes from aws-lambda provider
|
|
209
213
|
expect.objectContaining({
|
|
210
214
|
path: '/users',
|
|
211
215
|
method: 'GET',
|
|
212
|
-
handler: expect.stringContaining(
|
|
216
|
+
handler: expect.stringContaining(
|
|
217
|
+
'routes/getUsersEndpoint.handler',
|
|
218
|
+
),
|
|
213
219
|
}),
|
|
214
220
|
expect.objectContaining({
|
|
215
221
|
path: '/posts',
|
|
216
222
|
method: 'POST',
|
|
217
|
-
handler: expect.stringContaining(
|
|
223
|
+
handler: expect.stringContaining(
|
|
224
|
+
'routes/getPostsEndpoint.handler',
|
|
225
|
+
),
|
|
226
|
+
}),
|
|
227
|
+
// Routes from aws-apigatewayv2 provider
|
|
228
|
+
expect.objectContaining({
|
|
229
|
+
path: '/users',
|
|
230
|
+
method: 'GET',
|
|
231
|
+
handler: expect.stringContaining('getUsersEndpoint.handler'),
|
|
232
|
+
}),
|
|
233
|
+
expect.objectContaining({
|
|
234
|
+
path: '/posts',
|
|
235
|
+
method: 'POST',
|
|
236
|
+
handler: expect.stringContaining('getPostsEndpoint.handler'),
|
|
218
237
|
}),
|
|
219
238
|
]),
|
|
220
239
|
functions: expect.arrayContaining([
|
|
@@ -251,31 +270,10 @@ export default {
|
|
|
251
270
|
]),
|
|
252
271
|
});
|
|
253
272
|
|
|
254
|
-
// Verify
|
|
255
|
-
expect(
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
path: '/users',
|
|
259
|
-
method: 'GET',
|
|
260
|
-
handler: expect.stringContaining('getUsersEndpoint.handler'),
|
|
261
|
-
}),
|
|
262
|
-
expect.objectContaining({
|
|
263
|
-
path: '/posts',
|
|
264
|
-
method: 'POST',
|
|
265
|
-
handler: expect.stringContaining('getPostsEndpoint.handler'),
|
|
266
|
-
}),
|
|
267
|
-
]),
|
|
268
|
-
functions: [],
|
|
269
|
-
crons: [],
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
// Verify counts
|
|
273
|
-
expect(lambdaManifest.routes).toHaveLength(2);
|
|
274
|
-
expect(lambdaManifest.functions).toHaveLength(2);
|
|
275
|
-
expect(lambdaManifest.crons).toHaveLength(2);
|
|
276
|
-
expect(apiGatewayManifest.routes).toHaveLength(2);
|
|
277
|
-
expect(apiGatewayManifest.functions).toHaveLength(0);
|
|
278
|
-
expect(apiGatewayManifest.crons).toHaveLength(0);
|
|
273
|
+
// Verify counts - should have duplicated routes (one for each provider)
|
|
274
|
+
expect(manifest.routes).toHaveLength(4); // 2 routes x 2 providers
|
|
275
|
+
expect(manifest.functions).toHaveLength(2);
|
|
276
|
+
expect(manifest.crons).toHaveLength(2);
|
|
279
277
|
} finally {
|
|
280
278
|
process.chdir(originalCwd);
|
|
281
279
|
}
|
|
@@ -313,8 +311,9 @@ export default {
|
|
|
313
311
|
expect(logSpy).toHaveBeenCalledWith('Found 0 endpoints');
|
|
314
312
|
expect(logSpy).toHaveBeenCalledWith('Found 0 functions');
|
|
315
313
|
expect(logSpy).toHaveBeenCalledWith('Found 0 crons');
|
|
314
|
+
expect(logSpy).toHaveBeenCalledWith('Found 0 subscribers');
|
|
316
315
|
expect(logSpy).toHaveBeenCalledWith(
|
|
317
|
-
'No endpoints, functions, or
|
|
316
|
+
'No endpoints, functions, crons, or subscribers found to process',
|
|
318
317
|
);
|
|
319
318
|
} finally {
|
|
320
319
|
process.chdir(originalCwd);
|