@devbro/pashmak 0.1.27 → 0.1.28

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.
@@ -32,6 +32,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
32
32
  // src/app/console/generate/index.mts
33
33
  var generate_exports = {};
34
34
  __export(generate_exports, {
35
+ GenerateApiDocsCommand: () => GenerateApiDocsCommand,
35
36
  GenerateControllerCommand: () => GenerateControllerCommand
36
37
  });
37
38
  module.exports = __toCommonJS(generate_exports);
@@ -217,46 +218,46 @@ var Route = class {
217
218
  static {
218
219
  __name(this, "Route");
219
220
  }
220
- constructor(methods, path3, handler) {
221
+ constructor(methods, path4, handler) {
221
222
  this.methods = methods;
222
- this.path = path3;
223
+ this.path = path4;
223
224
  this.handler = handler;
224
- this.urlRegex = this.pathToRegex(path3);
225
+ this.urlRegex = this.pathToRegex(path4);
225
226
  }
226
227
  middlewares = [];
227
228
  urlRegex;
228
- pathToRegex(path3) {
229
- const lex = this.lexUrlPath(path3);
229
+ pathToRegex(path4) {
230
+ const lex = this.lexUrlPath(path4);
230
231
  return this.tokensToRegex(lex);
231
232
  }
232
- lexUrlPath(path3) {
233
+ lexUrlPath(path4) {
233
234
  const tokens = [];
234
235
  let i = 0;
235
- while (i < path3.length) {
236
- const char = path3[i];
236
+ while (i < path4.length) {
237
+ const char = path4[i];
237
238
  if (char === "/") {
238
239
  tokens.push({ type: "SLASH", value: "/" });
239
240
  i++;
240
241
  } else if (char === ":") {
241
242
  let start = i + 1;
242
- while (start < path3.length && /[a-zA-Z0-9_]/.test(path3[start])) {
243
+ while (start < path4.length && /[a-zA-Z0-9_]/.test(path4[start])) {
243
244
  start++;
244
245
  }
245
- tokens.push({ type: "PARAM", value: path3.slice(i + 1, start) });
246
+ tokens.push({ type: "PARAM", value: path4.slice(i + 1, start) });
246
247
  i = start;
247
248
  } else if (char === "*") {
248
249
  let start = i + 1;
249
- while (start < path3.length && /[a-zA-Z0-9_\.]/.test(path3[start])) {
250
+ while (start < path4.length && /[a-zA-Z0-9_\.]/.test(path4[start])) {
250
251
  start++;
251
252
  }
252
- tokens.push({ type: "WILDCARD", value: path3.slice(i + 1, start) });
253
+ tokens.push({ type: "WILDCARD", value: path4.slice(i + 1, start) });
253
254
  i = start;
254
255
  } else {
255
256
  let start = i;
256
- while (start < path3.length && !["/", ":", "*"].includes(path3[start])) {
257
+ while (start < path4.length && !["/", ":", "*"].includes(path4[start])) {
257
258
  start++;
258
259
  }
259
- tokens.push({ type: "TEXT", value: path3.slice(i, start) });
260
+ tokens.push({ type: "TEXT", value: path4.slice(i, start) });
260
261
  i = start;
261
262
  }
262
263
  }
@@ -803,7 +804,120 @@ var GenerateControllerCommand = class extends import_clipanion2.Command {
803
804
  }
804
805
  };
805
806
  cli().register(GenerateControllerCommand);
807
+
808
+ // src/app/console/generate/GenerateApiDocsCommand.mts
809
+ var import_clipanion3 = require("clipanion");
810
+ var import_path3 = __toESM(require("path"), 1);
811
+ var fs2 = __toESM(require("fs/promises"), 1);
812
+ var GenerateApiDocsCommand = class extends import_clipanion3.Command {
813
+ static {
814
+ __name(this, "GenerateApiDocsCommand");
815
+ }
816
+ static paths = [
817
+ [`make`, `apidocs`],
818
+ [`generate`, `apidocs`]
819
+ ];
820
+ async execute() {
821
+ const rootDir = process.cwd();
822
+ this.context.stdout.write(`Generating OpenAPI documentation...
823
+ `);
824
+ const routes = router().routes;
825
+ const openApiSpec = {
826
+ openapi: "3.0.0",
827
+ info: {
828
+ title: "API Documentation",
829
+ version: "1.0.0",
830
+ description: "Auto-generated API documentation"
831
+ },
832
+ servers: [
833
+ {
834
+ url: "/",
835
+ description: "Local server"
836
+ }
837
+ ],
838
+ paths: {}
839
+ };
840
+ for (const route of routes) {
841
+ const routePath = route.path;
842
+ const openApiPath = routePath.replace(/:([a-zA-Z0-9_]+)/g, "{$1}");
843
+ if (!openApiSpec.paths[openApiPath]) {
844
+ openApiSpec.paths[openApiPath] = {};
845
+ }
846
+ for (const method of route.methods) {
847
+ const lowerMethod = method.toLowerCase();
848
+ if (lowerMethod === "head") {
849
+ continue;
850
+ }
851
+ openApiSpec.paths[openApiPath][lowerMethod] = {
852
+ summary: `${method} ${routePath}`,
853
+ description: `Endpoint for ${method} ${routePath}`,
854
+ parameters: this.extractParameters(routePath),
855
+ responses: {
856
+ "200": {
857
+ description: "Successful response",
858
+ content: {
859
+ "application/json": {
860
+ schema: {
861
+ type: "object"
862
+ }
863
+ }
864
+ }
865
+ },
866
+ "500": {
867
+ description: "Internal server error"
868
+ }
869
+ }
870
+ };
871
+ if (["post", "put", "patch"].includes(lowerMethod)) {
872
+ openApiSpec.paths[openApiPath][lowerMethod].requestBody = {
873
+ required: true,
874
+ content: {
875
+ "application/json": {
876
+ schema: {
877
+ type: "object"
878
+ }
879
+ }
880
+ }
881
+ };
882
+ }
883
+ }
884
+ }
885
+ const publicDir = import_path3.default.join(rootDir, "public");
886
+ await fs2.mkdir(publicDir, { recursive: true });
887
+ const outputPath = import_path3.default.join(publicDir, "openapi.json");
888
+ await fs2.writeFile(
889
+ outputPath,
890
+ JSON.stringify(openApiSpec, null, 2),
891
+ "utf-8"
892
+ );
893
+ this.context.stdout.write(
894
+ `OpenAPI documentation generated at: ${outputPath}
895
+ `
896
+ );
897
+ this.context.stdout.write(`Total routes documented: ${routes.length}
898
+ `);
899
+ }
900
+ extractParameters(routePath) {
901
+ const paramRegex = /:([a-zA-Z0-9_]+)/g;
902
+ const parameters = [];
903
+ let match;
904
+ while ((match = paramRegex.exec(routePath)) !== null) {
905
+ parameters.push({
906
+ name: match[1],
907
+ in: "path",
908
+ required: true,
909
+ schema: {
910
+ type: "string"
911
+ },
912
+ description: `Path parameter ${match[1]}`
913
+ });
914
+ }
915
+ return parameters;
916
+ }
917
+ };
918
+ cli().register(GenerateApiDocsCommand);
806
919
  // Annotate the CommonJS export names for ESM import in node:
807
920
  0 && (module.exports = {
921
+ GenerateApiDocsCommand,
808
922
  GenerateControllerCommand
809
923
  });
@@ -1189,6 +1189,7 @@ var console_exports = {};
1189
1189
  __export(console_exports, {
1190
1190
  CreateProjectCommand: () => CreateProjectCommand,
1191
1191
  DefaultCommand: () => DefaultCommand,
1192
+ GenerateApiDocsCommand: () => GenerateApiDocsCommand,
1192
1193
  GenerateControllerCommand: () => GenerateControllerCommand,
1193
1194
  GenerateMigrateCommand: () => GenerateMigrateCommand,
1194
1195
  GenerateQueueMigrateCommand: () => GenerateQueueMigrateCommand,
@@ -1380,46 +1381,46 @@ var Route = class {
1380
1381
  static {
1381
1382
  __name(this, "Route");
1382
1383
  }
1383
- constructor(methods, path9, handler) {
1384
+ constructor(methods, path10, handler) {
1384
1385
  this.methods = methods;
1385
- this.path = path9;
1386
+ this.path = path10;
1386
1387
  this.handler = handler;
1387
- this.urlRegex = this.pathToRegex(path9);
1388
+ this.urlRegex = this.pathToRegex(path10);
1388
1389
  }
1389
1390
  middlewares = [];
1390
1391
  urlRegex;
1391
- pathToRegex(path9) {
1392
- const lex = this.lexUrlPath(path9);
1392
+ pathToRegex(path10) {
1393
+ const lex = this.lexUrlPath(path10);
1393
1394
  return this.tokensToRegex(lex);
1394
1395
  }
1395
- lexUrlPath(path9) {
1396
+ lexUrlPath(path10) {
1396
1397
  const tokens = [];
1397
1398
  let i = 0;
1398
- while (i < path9.length) {
1399
- const char = path9[i];
1399
+ while (i < path10.length) {
1400
+ const char = path10[i];
1400
1401
  if (char === "/") {
1401
1402
  tokens.push({ type: "SLASH", value: "/" });
1402
1403
  i++;
1403
1404
  } else if (char === ":") {
1404
1405
  let start = i + 1;
1405
- while (start < path9.length && /[a-zA-Z0-9_]/.test(path9[start])) {
1406
+ while (start < path10.length && /[a-zA-Z0-9_]/.test(path10[start])) {
1406
1407
  start++;
1407
1408
  }
1408
- tokens.push({ type: "PARAM", value: path9.slice(i + 1, start) });
1409
+ tokens.push({ type: "PARAM", value: path10.slice(i + 1, start) });
1409
1410
  i = start;
1410
1411
  } else if (char === "*") {
1411
1412
  let start = i + 1;
1412
- while (start < path9.length && /[a-zA-Z0-9_\.]/.test(path9[start])) {
1413
+ while (start < path10.length && /[a-zA-Z0-9_\.]/.test(path10[start])) {
1413
1414
  start++;
1414
1415
  }
1415
- tokens.push({ type: "WILDCARD", value: path9.slice(i + 1, start) });
1416
+ tokens.push({ type: "WILDCARD", value: path10.slice(i + 1, start) });
1416
1417
  i = start;
1417
1418
  } else {
1418
1419
  let start = i;
1419
- while (start < path9.length && !["/", ":", "*"].includes(path9[start])) {
1420
+ while (start < path10.length && !["/", ":", "*"].includes(path10[start])) {
1420
1421
  start++;
1421
1422
  }
1422
- tokens.push({ type: "TEXT", value: path9.slice(i, start) });
1423
+ tokens.push({ type: "TEXT", value: path10.slice(i, start) });
1423
1424
  i = start;
1424
1425
  }
1425
1426
  }
@@ -2328,21 +2329,133 @@ var GenerateControllerCommand = class extends import_clipanion8.Command {
2328
2329
  };
2329
2330
  cli().register(GenerateControllerCommand);
2330
2331
 
2331
- // src/app/console/project/CreateProjectCommand.mts
2332
+ // src/app/console/generate/GenerateApiDocsCommand.mts
2332
2333
  var import_clipanion9 = require("clipanion");
2333
- var import_change_case_all3 = require("change-case-all");
2334
2334
  var import_path7 = __toESM(require("path"), 1);
2335
2335
  var fs6 = __toESM(require("fs/promises"), 1);
2336
+ var GenerateApiDocsCommand = class extends import_clipanion9.Command {
2337
+ static {
2338
+ __name(this, "GenerateApiDocsCommand");
2339
+ }
2340
+ static paths = [
2341
+ [`make`, `apidocs`],
2342
+ [`generate`, `apidocs`]
2343
+ ];
2344
+ async execute() {
2345
+ const rootDir = process.cwd();
2346
+ this.context.stdout.write(`Generating OpenAPI documentation...
2347
+ `);
2348
+ const routes = router().routes;
2349
+ const openApiSpec = {
2350
+ openapi: "3.0.0",
2351
+ info: {
2352
+ title: "API Documentation",
2353
+ version: "1.0.0",
2354
+ description: "Auto-generated API documentation"
2355
+ },
2356
+ servers: [
2357
+ {
2358
+ url: "/",
2359
+ description: "Local server"
2360
+ }
2361
+ ],
2362
+ paths: {}
2363
+ };
2364
+ for (const route of routes) {
2365
+ const routePath = route.path;
2366
+ const openApiPath = routePath.replace(/:([a-zA-Z0-9_]+)/g, "{$1}");
2367
+ if (!openApiSpec.paths[openApiPath]) {
2368
+ openApiSpec.paths[openApiPath] = {};
2369
+ }
2370
+ for (const method of route.methods) {
2371
+ const lowerMethod = method.toLowerCase();
2372
+ if (lowerMethod === "head") {
2373
+ continue;
2374
+ }
2375
+ openApiSpec.paths[openApiPath][lowerMethod] = {
2376
+ summary: `${method} ${routePath}`,
2377
+ description: `Endpoint for ${method} ${routePath}`,
2378
+ parameters: this.extractParameters(routePath),
2379
+ responses: {
2380
+ "200": {
2381
+ description: "Successful response",
2382
+ content: {
2383
+ "application/json": {
2384
+ schema: {
2385
+ type: "object"
2386
+ }
2387
+ }
2388
+ }
2389
+ },
2390
+ "500": {
2391
+ description: "Internal server error"
2392
+ }
2393
+ }
2394
+ };
2395
+ if (["post", "put", "patch"].includes(lowerMethod)) {
2396
+ openApiSpec.paths[openApiPath][lowerMethod].requestBody = {
2397
+ required: true,
2398
+ content: {
2399
+ "application/json": {
2400
+ schema: {
2401
+ type: "object"
2402
+ }
2403
+ }
2404
+ }
2405
+ };
2406
+ }
2407
+ }
2408
+ }
2409
+ const publicDir = import_path7.default.join(rootDir, "public");
2410
+ await fs6.mkdir(publicDir, { recursive: true });
2411
+ const outputPath = import_path7.default.join(publicDir, "openapi.json");
2412
+ await fs6.writeFile(
2413
+ outputPath,
2414
+ JSON.stringify(openApiSpec, null, 2),
2415
+ "utf-8"
2416
+ );
2417
+ this.context.stdout.write(
2418
+ `OpenAPI documentation generated at: ${outputPath}
2419
+ `
2420
+ );
2421
+ this.context.stdout.write(`Total routes documented: ${routes.length}
2422
+ `);
2423
+ }
2424
+ extractParameters(routePath) {
2425
+ const paramRegex = /:([a-zA-Z0-9_]+)/g;
2426
+ const parameters = [];
2427
+ let match;
2428
+ while ((match = paramRegex.exec(routePath)) !== null) {
2429
+ parameters.push({
2430
+ name: match[1],
2431
+ in: "path",
2432
+ required: true,
2433
+ schema: {
2434
+ type: "string"
2435
+ },
2436
+ description: `Path parameter ${match[1]}`
2437
+ });
2438
+ }
2439
+ return parameters;
2440
+ }
2441
+ };
2442
+ cli().register(GenerateApiDocsCommand);
2443
+
2444
+ // src/app/console/project/CreateProjectCommand.mts
2445
+ var import_clipanion10 = require("clipanion");
2446
+ var import_change_case_all3 = require("change-case-all");
2447
+ var import_path8 = __toESM(require("path"), 1);
2448
+ var fs7 = __toESM(require("fs/promises"), 1);
2336
2449
  var import_url3 = require("url");
2337
2450
  var import_handlebars3 = __toESM(require("handlebars"), 1);
2338
2451
  var import_child_process = require("child_process");
2339
2452
  var import_meta3 = {};
2340
- var CreateProjectCommand = class extends import_clipanion9.Command {
2453
+ var CreateProjectCommand = class extends import_clipanion10.Command {
2341
2454
  static {
2342
2455
  __name(this, "CreateProjectCommand");
2343
2456
  }
2344
2457
  static paths = [[`create`, `project`]];
2345
- static usage = import_clipanion9.Command.Usage({
2458
+ static usage = import_clipanion10.Command.Usage({
2346
2459
  category: `Project`,
2347
2460
  description: `Create a new project`,
2348
2461
  details: `
@@ -2360,13 +2473,13 @@ var CreateProjectCommand = class extends import_clipanion9.Command {
2360
2473
  ]
2361
2474
  ]
2362
2475
  });
2363
- projectPath = import_clipanion9.Option.String("--path", { required: true });
2364
- git = import_clipanion9.Option.Boolean(`--git`, false, {
2476
+ projectPath = import_clipanion10.Option.String("--path", { required: true });
2477
+ git = import_clipanion10.Option.Boolean(`--git`, false, {
2365
2478
  description: `Initialize a git repository in the new project`
2366
2479
  });
2367
2480
  async folderExists(folderPath) {
2368
2481
  try {
2369
- const stats = await fs6.stat(folderPath);
2482
+ const stats = await fs7.stat(folderPath);
2370
2483
  return stats.isDirectory();
2371
2484
  } catch (error) {
2372
2485
  if (error.code === "ENOENT") {
@@ -2376,28 +2489,28 @@ var CreateProjectCommand = class extends import_clipanion9.Command {
2376
2489
  }
2377
2490
  }
2378
2491
  async execute() {
2379
- const projectPath = import_path7.default.join(this.projectPath);
2492
+ const projectPath = import_path8.default.join(this.projectPath);
2380
2493
  try {
2381
- await fs6.access(projectPath);
2494
+ await fs7.access(projectPath);
2382
2495
  console.error(`Error: Directory ${projectPath} already exists.`);
2383
2496
  return 1;
2384
2497
  } catch {
2385
2498
  }
2386
- await fs6.mkdir(projectPath, { recursive: true });
2499
+ await fs7.mkdir(projectPath, { recursive: true });
2387
2500
  console.log(`Created project directory at: ${projectPath}`);
2388
- const dirname = typeof __dirname === "undefined" ? import_path7.default.dirname((0, import_url3.fileURLToPath)(import_meta3.url)) : __dirname;
2389
- let basePath = import_path7.default.join(dirname, `./base_project`);
2501
+ const dirname = typeof __dirname === "undefined" ? import_path8.default.dirname((0, import_url3.fileURLToPath)(import_meta3.url)) : __dirname;
2502
+ let basePath = import_path8.default.join(dirname, `./base_project`);
2390
2503
  if (await this.folderExists(basePath) === false) {
2391
- basePath = import_path7.default.join(dirname, `../app/console/project/base_project`);
2504
+ basePath = import_path8.default.join(dirname, `../app/console/project/base_project`);
2392
2505
  }
2393
2506
  console.log(`Using base project path: ${basePath}`);
2394
2507
  const baseProjectPath = basePath;
2395
2508
  await this.processTplFolder(baseProjectPath, projectPath, {});
2396
2509
  console.log(`Copied base project files to: ${projectPath}`);
2397
- const packageJsonPath = import_path7.default.join(projectPath, `package.json`);
2398
- const packageJson = JSON.parse(await fs6.readFile(packageJsonPath, `utf-8`));
2399
- packageJson.name = import_change_case_all3.Case.snake(import_path7.default.basename(projectPath));
2400
- await fs6.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
2510
+ const packageJsonPath = import_path8.default.join(projectPath, `package.json`);
2511
+ const packageJson = JSON.parse(await fs7.readFile(packageJsonPath, `utf-8`));
2512
+ packageJson.name = import_change_case_all3.Case.snake(import_path8.default.basename(projectPath));
2513
+ await fs7.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
2401
2514
  console.log(`Updated package.json with project name: ${packageJson.name}`);
2402
2515
  if (this.git) {
2403
2516
  try {
@@ -2414,12 +2527,12 @@ var CreateProjectCommand = class extends import_clipanion9.Command {
2414
2527
  }
2415
2528
  }
2416
2529
  async processTplFolder(src, dest, data = {}) {
2417
- const files = await fs6.readdir(src, { withFileTypes: true });
2530
+ const files = await fs7.readdir(src, { withFileTypes: true });
2418
2531
  for (const file of files) {
2419
- const srcPath = import_path7.default.join(src, file.name);
2420
- const destPath = file.isFile() && file.name.endsWith(".tpl") ? import_path7.default.join(dest, file.name.substring(0, file.name.length - 4)) : import_path7.default.join(dest, file.name);
2532
+ const srcPath = import_path8.default.join(src, file.name);
2533
+ const destPath = file.isFile() && file.name.endsWith(".tpl") ? import_path8.default.join(dest, file.name.substring(0, file.name.length - 4)) : import_path8.default.join(dest, file.name);
2421
2534
  if (file.isDirectory()) {
2422
- await fs6.mkdir(destPath, { recursive: true });
2535
+ await fs7.mkdir(destPath, { recursive: true });
2423
2536
  await this.processTplFolder(srcPath, destPath, data);
2424
2537
  } else if (file.name.endsWith(".tpl")) {
2425
2538
  await this.processTplFile(srcPath, destPath, {});
@@ -2432,23 +2545,23 @@ var CreateProjectCommand = class extends import_clipanion9.Command {
2432
2545
  }
2433
2546
  async processTplFile(src, dest, data = {}) {
2434
2547
  const compiledTemplate = import_handlebars3.default.compile(
2435
- (await fs6.readFile(src)).toString()
2548
+ (await fs7.readFile(src)).toString()
2436
2549
  );
2437
2550
  const template = await compiledTemplate(data);
2438
- await fs6.writeFile(dest, template);
2551
+ await fs7.writeFile(dest, template);
2439
2552
  }
2440
2553
  };
2441
2554
 
2442
2555
  // src/app/console/queue/GenerateQueueMigrateCommand.mts
2443
- var import_clipanion10 = require("clipanion");
2556
+ var import_clipanion11 = require("clipanion");
2444
2557
  var import_change_case_all4 = require("change-case-all");
2445
- var import_path8 = __toESM(require("path"), 1);
2446
- var fs7 = __toESM(require("fs/promises"), 1);
2558
+ var import_path9 = __toESM(require("path"), 1);
2559
+ var fs8 = __toESM(require("fs/promises"), 1);
2447
2560
  var import_neko_config7 = require("@devbro/neko-config");
2448
2561
  var import_handlebars4 = __toESM(require("handlebars"), 1);
2449
2562
  var import_url4 = require("url");
2450
2563
  var import_meta4 = {};
2451
- var GenerateQueueMigrateCommand = class extends import_clipanion10.Command {
2564
+ var GenerateQueueMigrateCommand = class extends import_clipanion11.Command {
2452
2565
  static {
2453
2566
  __name(this, "GenerateQueueMigrateCommand");
2454
2567
  }
@@ -2466,20 +2579,20 @@ var GenerateQueueMigrateCommand = class extends import_clipanion10.Command {
2466
2579
  const filename = `${year}_${month}_${day}_${secondsOfDay}_${fixed_name}.ts`;
2467
2580
  this.context.stdout.write(`creating migration file ${filename}
2468
2581
  `);
2469
- await fs7.mkdir(import_neko_config7.config.get("migration.path"), { recursive: true });
2582
+ await fs8.mkdir(import_neko_config7.config.get("migration.path"), { recursive: true });
2470
2583
  let dirname = typeof __dirname === "string" ? __dirname : void 0;
2471
2584
  if (!dirname) {
2472
- dirname = import_path8.default.dirname((0, import_url4.fileURLToPath)(import_meta4.url));
2585
+ dirname = import_path9.default.dirname((0, import_url4.fileURLToPath)(import_meta4.url));
2473
2586
  }
2474
2587
  const compiledTemplate = import_handlebars4.default.compile(
2475
- (await fs7.readFile(import_path8.default.join(dirname, "./queue_migration.tpl"))).toString()
2588
+ (await fs8.readFile(import_path9.default.join(dirname, "./queue_migration.tpl"))).toString()
2476
2589
  );
2477
2590
  const template = await compiledTemplate({
2478
2591
  className: import_change_case_all4.Case.pascal(this.name) + "Migration",
2479
2592
  tableName: import_change_case_all4.Case.snake(this.name)
2480
2593
  });
2481
- await fs7.writeFile(
2482
- import_path8.default.join(import_neko_config7.config.get("migration.path"), filename),
2594
+ await fs8.writeFile(
2595
+ import_path9.default.join(import_neko_config7.config.get("migration.path"), filename),
2483
2596
  template
2484
2597
  );
2485
2598
  }
@@ -2492,6 +2605,7 @@ cli().register(CreateProjectCommand);
2492
2605
  0 && (module.exports = {
2493
2606
  CreateProjectCommand,
2494
2607
  DefaultCommand,
2608
+ GenerateApiDocsCommand,
2495
2609
  GenerateControllerCommand,
2496
2610
  GenerateMigrateCommand,
2497
2611
  GenerateQueueMigrateCommand,