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.
@@ -96,7 +96,7 @@ const buildSchemaFromEntity = (entity) => {
96
96
  return {
97
97
  type: 'object',
98
98
  properties,
99
- required: required.length ? required : undefined
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: 'API générée automatiquement'
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
- /* ========= ENTITIES → SCHEMAS ========= */
156
-
157
- const entitiesDir = path.join(srcDir, 'entities');
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
- /* ========= MODULES / ROUTES ========= */
180
+ /* ======================================================
181
+ AUTH (only if module exists)
182
+ ====================================================== */
183
+
184
+ const authDir = path.join(modulesDir, 'auth');
188
185
 
189
- const generateAuthSwagger = (swagger) => {
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', example: 'user@example.com' },
231
- password: { type: 'string', example: 'password123' }
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
- generateAuthSwagger(swagger);
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
- const schemaRef = {
270
- $ref: `#/components/schemas/${entityName}`
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 exampleBody = entity ? buildExampleFromEntity(entity) : {};
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
- swagger.paths[basePath] = {
284
- get: {
285
- tags: [entityName],
286
- summary: `List ${entityName}`,
287
- description: `Retrieve all ${entityName}`,
288
- security: [{ bearerAuth: [] }],
289
- responses: {
290
- 200: {
291
- description: 'List retrieved',
292
- content: {
293
- 'application/json': {
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
- swagger.paths[`${basePath}/{id}`] = {
331
- get: {
332
- tags: [entityName],
333
- summary: `Get ${entityName}`,
334
- description: `Retrieve a ${entityName} by ID`,
335
- security: [{ bearerAuth: [] }],
336
- parameters: [
337
- {
338
- name: 'id',
339
- in: 'path',
340
- required: true,
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
- put: {
358
- tags: [entityName],
359
- summary: `Update ${entityName}`,
360
- description: `Update an existing ${entityName}`,
361
- security: [{ bearerAuth: [] }],
362
- parameters: [
363
- {
364
- name: 'id',
365
- in: 'path',
366
- required: true,
367
- schema: { type: 'number' }
368
- }
369
- ],
370
- requestBody: {
371
- required: true,
372
- content: {
373
- 'application/json': {
374
- schema: schemaRef,
375
- example: exampleBody
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
- delete: {
392
- tags: [entityName],
393
- summary: `Delete ${entityName}`,
394
- description: `Delete a ${entityName}`,
395
- security: [{ bearerAuth: [] }],
396
- parameters: [
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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alexis-cli",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "main": "index.js",
5
5
  "bin": {
6
6
  "alexis": "bin/alexis.js"