alexis-cli 1.0.4 → 1.0.5
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/commands/make-swagger.js +99 -167
- package/package.json +1 -1
package/commands/make-swagger.js
CHANGED
|
@@ -96,7 +96,7 @@ const buildSchemaFromEntity = (entity) => {
|
|
|
96
96
|
return {
|
|
97
97
|
type: 'object',
|
|
98
98
|
properties,
|
|
99
|
-
required
|
|
99
|
+
...(required.length ? { required } : {})
|
|
100
100
|
};
|
|
101
101
|
};
|
|
102
102
|
|
|
@@ -126,6 +126,13 @@ module.exports = () => {
|
|
|
126
126
|
const projectRoot = process.cwd();
|
|
127
127
|
const srcDir = path.join(projectRoot, 'src');
|
|
128
128
|
const swaggerDir = path.join(srcDir, 'swagger');
|
|
129
|
+
const entitiesDir = path.join(srcDir, 'entities');
|
|
130
|
+
const modulesDir = path.join(srcDir, 'modules/v1');
|
|
131
|
+
|
|
132
|
+
if (!fs.existsSync(entitiesDir) || !fs.existsSync(modulesDir)) {
|
|
133
|
+
console.warn('⚠️ Missing entities or modules directory → Swagger skipped');
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
129
136
|
|
|
130
137
|
if (!fs.existsSync(swaggerDir)) {
|
|
131
138
|
fs.mkdirSync(swaggerDir, { recursive: true });
|
|
@@ -136,7 +143,7 @@ module.exports = () => {
|
|
|
136
143
|
info: {
|
|
137
144
|
title: 'Express API',
|
|
138
145
|
version: '1.0.0',
|
|
139
|
-
description: '
|
|
146
|
+
description: 'Swagger généré automatiquement'
|
|
140
147
|
},
|
|
141
148
|
servers: [{ url: 'http://localhost:3000/api/v1' }],
|
|
142
149
|
paths: {},
|
|
@@ -152,46 +159,35 @@ module.exports = () => {
|
|
|
152
159
|
}
|
|
153
160
|
};
|
|
154
161
|
|
|
155
|
-
/*
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
if (!fs.existsSync(entitiesDir)) {
|
|
159
|
-
console.warn('⚠️ No entities directory found, skipping Swagger generation');
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const modulesDir = path.join(srcDir, 'modules/v1');
|
|
164
|
-
if (!fs.existsSync(modulesDir)) {
|
|
165
|
-
console.warn('⚠️ No modules directory found, skipping Swagger generation');
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
|
|
162
|
+
/* ======================================================
|
|
163
|
+
ENTITIES → SCHEMAS
|
|
164
|
+
====================================================== */
|
|
169
165
|
|
|
170
166
|
fs.readdirSync(entitiesDir).forEach((file) => {
|
|
171
167
|
if (!file.endsWith('.entity.js')) return;
|
|
172
168
|
|
|
173
|
-
let entity;
|
|
174
169
|
try {
|
|
175
|
-
entity = require(path.join(entitiesDir, file));
|
|
170
|
+
const entity = require(path.join(entitiesDir, file));
|
|
171
|
+
if (entity.options?.swagger === false) return;
|
|
172
|
+
|
|
173
|
+
const name = entity.options.name;
|
|
174
|
+
swagger.components.schemas[name] = buildSchemaFromEntity(entity);
|
|
176
175
|
} catch {
|
|
177
176
|
console.warn(`⚠️ Cannot load entity ${file}`);
|
|
178
|
-
return;
|
|
179
177
|
}
|
|
180
|
-
|
|
181
|
-
if (entity.options?.swagger === false) return;
|
|
182
|
-
|
|
183
|
-
const entityName = entity.options.name;
|
|
184
|
-
swagger.components.schemas[entityName] = buildSchemaFromEntity(entity);
|
|
185
178
|
});
|
|
186
179
|
|
|
187
|
-
/*
|
|
180
|
+
/* ======================================================
|
|
181
|
+
AUTH (only if module exists)
|
|
182
|
+
====================================================== */
|
|
183
|
+
|
|
184
|
+
const authDir = path.join(modulesDir, 'auth');
|
|
188
185
|
|
|
189
|
-
|
|
186
|
+
if (fs.existsSync(authDir) && fs.existsSync(path.join(authDir, 'auth.routes.js'))) {
|
|
190
187
|
swagger.paths['/auth/register'] = {
|
|
191
188
|
post: {
|
|
192
189
|
tags: ['Auth'],
|
|
193
190
|
summary: 'Register',
|
|
194
|
-
description: 'Create a new user account',
|
|
195
191
|
requestBody: {
|
|
196
192
|
required: true,
|
|
197
193
|
content: {
|
|
@@ -207,10 +203,7 @@ module.exports = () => {
|
|
|
207
203
|
}
|
|
208
204
|
}
|
|
209
205
|
},
|
|
210
|
-
responses: {
|
|
211
|
-
201: { description: 'User created' },
|
|
212
|
-
400: { description: 'User already exists' }
|
|
213
|
-
}
|
|
206
|
+
responses: { 201: { description: 'User created' } }
|
|
214
207
|
}
|
|
215
208
|
};
|
|
216
209
|
|
|
@@ -218,7 +211,6 @@ module.exports = () => {
|
|
|
218
211
|
post: {
|
|
219
212
|
tags: ['Auth'],
|
|
220
213
|
summary: 'Login',
|
|
221
|
-
description: 'Authenticate user and return JWT token',
|
|
222
214
|
requestBody: {
|
|
223
215
|
required: true,
|
|
224
216
|
content: {
|
|
@@ -227,17 +219,14 @@ module.exports = () => {
|
|
|
227
219
|
type: 'object',
|
|
228
220
|
required: ['email', 'password'],
|
|
229
221
|
properties: {
|
|
230
|
-
email: { type: 'string'
|
|
231
|
-
password: { type: 'string'
|
|
222
|
+
email: { type: 'string' },
|
|
223
|
+
password: { type: 'string' }
|
|
232
224
|
}
|
|
233
225
|
}
|
|
234
226
|
}
|
|
235
227
|
}
|
|
236
228
|
},
|
|
237
|
-
responses: {
|
|
238
|
-
200: { description: 'JWT token returned' },
|
|
239
|
-
401: { description: 'Invalid credentials' }
|
|
240
|
-
}
|
|
229
|
+
responses: { 200: { description: 'JWT token' } }
|
|
241
230
|
}
|
|
242
231
|
};
|
|
243
232
|
|
|
@@ -245,166 +234,109 @@ module.exports = () => {
|
|
|
245
234
|
get: {
|
|
246
235
|
tags: ['Auth'],
|
|
247
236
|
summary: 'Profile',
|
|
248
|
-
description: 'Get current authenticated user',
|
|
249
237
|
security: [{ bearerAuth: [] }],
|
|
250
|
-
responses: {
|
|
251
|
-
200: { description: 'User profile' },
|
|
252
|
-
401: { description: 'Unauthorized' }
|
|
253
|
-
}
|
|
238
|
+
responses: { 200: { description: 'User profile' } }
|
|
254
239
|
}
|
|
255
240
|
};
|
|
256
|
-
|
|
257
|
-
|
|
241
|
+
|
|
242
|
+
console.log('🔐 Auth Swagger added');
|
|
243
|
+
} else {
|
|
244
|
+
console.log('ℹ️ Auth module not found → skipping Auth Swagger');
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/* ======================================================
|
|
248
|
+
CRUD MODULES
|
|
249
|
+
====================================================== */
|
|
258
250
|
|
|
259
251
|
fs.readdirSync(modulesDir).forEach((moduleName) => {
|
|
260
252
|
if (moduleName === 'auth') return;
|
|
253
|
+
|
|
261
254
|
const modulePath = path.join(modulesDir, moduleName);
|
|
262
255
|
if (!fs.statSync(modulePath).isDirectory()) return;
|
|
263
256
|
|
|
264
|
-
/* ----- CRUD ----- */
|
|
265
|
-
|
|
266
257
|
const entityName =
|
|
267
258
|
moduleName.charAt(0).toUpperCase() + moduleName.slice(1);
|
|
268
259
|
|
|
269
|
-
|
|
270
|
-
$
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
const entityPath = path.join(srcDir, 'entities', `${entityName}.entity.js`);
|
|
274
|
-
const entity = fs.existsSync(entityPath)
|
|
275
|
-
? require(entityPath)
|
|
276
|
-
: null;
|
|
260
|
+
if (!swagger.components.schemas[entityName]) {
|
|
261
|
+
console.warn(`⚠️ No schema for ${entityName} → skipping`);
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
277
264
|
|
|
278
|
-
const
|
|
265
|
+
const entityPath = path.join(entitiesDir, `${entityName}.entity.js`);
|
|
266
|
+
const entity = fs.existsSync(entityPath) ? require(entityPath) : null;
|
|
279
267
|
|
|
268
|
+
const example = entity ? buildExampleFromEntity(entity) : {};
|
|
269
|
+
const schemaRef = { $ref: `#/components/schemas/${entityName}` };
|
|
280
270
|
|
|
281
271
|
const basePath = `/${moduleName}`;
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
schema: {
|
|
295
|
-
type: 'array',
|
|
296
|
-
items: schemaRef
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
},
|
|
303
|
-
|
|
304
|
-
post: {
|
|
305
|
-
tags: [entityName],
|
|
306
|
-
summary: `Create ${entityName}`,
|
|
307
|
-
description: `Create a new ${entityName}`,
|
|
308
|
-
security: [{ bearerAuth: [] }],
|
|
309
|
-
requestBody: {
|
|
310
|
-
required: true,
|
|
272
|
+
const idPath = `${basePath}/{id}`;
|
|
273
|
+
|
|
274
|
+
swagger.paths[basePath] ??= {};
|
|
275
|
+
swagger.paths[idPath] ??= {};
|
|
276
|
+
|
|
277
|
+
swagger.paths[basePath].get = {
|
|
278
|
+
tags: [entityName],
|
|
279
|
+
summary: `List ${entityName}`,
|
|
280
|
+
security: [{ bearerAuth: [] }],
|
|
281
|
+
responses: {
|
|
282
|
+
200: {
|
|
283
|
+
description: 'Success',
|
|
311
284
|
content: {
|
|
312
285
|
'application/json': {
|
|
313
|
-
schema: schemaRef
|
|
314
|
-
example: exampleBody
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
},
|
|
318
|
-
responses: {
|
|
319
|
-
201: {
|
|
320
|
-
description: `${entityName} created`,
|
|
321
|
-
content: {
|
|
322
|
-
'application/json': {
|
|
323
|
-
schema: schemaRef
|
|
324
|
-
}
|
|
286
|
+
schema: { type: 'array', items: schemaRef }
|
|
325
287
|
}
|
|
326
288
|
}
|
|
327
289
|
}
|
|
328
290
|
}
|
|
329
291
|
};
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
schema: { type: 'number' }
|
|
292
|
+
|
|
293
|
+
swagger.paths[basePath].post = {
|
|
294
|
+
tags: [entityName],
|
|
295
|
+
summary: `Create ${entityName}`,
|
|
296
|
+
security: [{ bearerAuth: [] }],
|
|
297
|
+
requestBody: {
|
|
298
|
+
required: true,
|
|
299
|
+
content: {
|
|
300
|
+
'application/json': {
|
|
301
|
+
schema: schemaRef,
|
|
302
|
+
example
|
|
342
303
|
}
|
|
343
|
-
],
|
|
344
|
-
responses: {
|
|
345
|
-
200: {
|
|
346
|
-
description: 'Entity found',
|
|
347
|
-
content: {
|
|
348
|
-
'application/json': {
|
|
349
|
-
schema: schemaRef
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
},
|
|
353
|
-
404: { description: 'Not found' }
|
|
354
304
|
}
|
|
355
305
|
},
|
|
306
|
+
responses: { 201: { description: 'Created' } }
|
|
307
|
+
};
|
|
356
308
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
},
|
|
379
|
-
responses: {
|
|
380
|
-
200: {
|
|
381
|
-
description: `${entityName} updated`,
|
|
382
|
-
content: {
|
|
383
|
-
'application/json': {
|
|
384
|
-
schema: schemaRef
|
|
385
|
-
}
|
|
386
|
-
}
|
|
309
|
+
swagger.paths[idPath].get = {
|
|
310
|
+
tags: [entityName],
|
|
311
|
+
summary: `Get ${entityName}`,
|
|
312
|
+
security: [{ bearerAuth: [] }],
|
|
313
|
+
parameters: [{ name: 'id', in: 'path', required: true, schema: { type: 'number' } }],
|
|
314
|
+
responses: { 200: { description: 'Found' } }
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
swagger.paths[idPath].put = {
|
|
318
|
+
tags: [entityName],
|
|
319
|
+
summary: `Update ${entityName}`,
|
|
320
|
+
security: [{ bearerAuth: [] }],
|
|
321
|
+
parameters: [{ name: 'id', in: 'path', required: true, schema: { type: 'number' } }],
|
|
322
|
+
requestBody: {
|
|
323
|
+
required: true,
|
|
324
|
+
content: {
|
|
325
|
+
'application/json': {
|
|
326
|
+
schema: schemaRef,
|
|
327
|
+
example
|
|
387
328
|
}
|
|
388
329
|
}
|
|
389
330
|
},
|
|
331
|
+
responses: { 200: { description: 'Updated' } }
|
|
332
|
+
};
|
|
390
333
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
{
|
|
398
|
-
name: 'id',
|
|
399
|
-
in: 'path',
|
|
400
|
-
required: true,
|
|
401
|
-
schema: { type: 'number' }
|
|
402
|
-
}
|
|
403
|
-
],
|
|
404
|
-
responses: {
|
|
405
|
-
204: { description: `${entityName} deleted` }
|
|
406
|
-
}
|
|
407
|
-
}
|
|
334
|
+
swagger.paths[idPath].delete = {
|
|
335
|
+
tags: [entityName],
|
|
336
|
+
summary: `Delete ${entityName}`,
|
|
337
|
+
security: [{ bearerAuth: [] }],
|
|
338
|
+
parameters: [{ name: 'id', in: 'path', required: true, schema: { type: 'number' } }],
|
|
339
|
+
responses: { 204: { description: 'Deleted' } }
|
|
408
340
|
};
|
|
409
341
|
});
|
|
410
342
|
|