@igniter-js/cli 0.4.93 → 0.4.96
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 +20 -10
- package/dist/index.mjs +522 -231
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -14,11 +14,11 @@ import { Command } from "commander";
|
|
|
14
14
|
|
|
15
15
|
// src/commands/init/action.ts
|
|
16
16
|
import * as p5 from "@clack/prompts";
|
|
17
|
-
import * as
|
|
17
|
+
import * as path11 from "path";
|
|
18
18
|
|
|
19
19
|
// src/commands/init/prompts.ts
|
|
20
20
|
import * as p2 from "@clack/prompts";
|
|
21
|
-
import * as
|
|
21
|
+
import * as path10 from "path";
|
|
22
22
|
|
|
23
23
|
// src/core/package-manager.ts
|
|
24
24
|
function getInstallCommand(pm) {
|
|
@@ -84,9 +84,6 @@ var StarterRegistry = class _StarterRegistry {
|
|
|
84
84
|
}
|
|
85
85
|
};
|
|
86
86
|
|
|
87
|
-
// src/registry/starters/nextjs-starter.ts
|
|
88
|
-
import path2 from "path";
|
|
89
|
-
|
|
90
87
|
// src/core/registry/starters/base-starter.ts
|
|
91
88
|
import * as path from "path";
|
|
92
89
|
import * as fs from "fs/promises";
|
|
@@ -123,11 +120,11 @@ function registerHandlebarsHelpers() {
|
|
|
123
120
|
handlebars.registerHelper("capitalizeSlug", function(slug) {
|
|
124
121
|
return slug.replace(/-/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
|
|
125
122
|
});
|
|
126
|
-
handlebars.registerHelper("get", function(obj,
|
|
127
|
-
if (!
|
|
123
|
+
handlebars.registerHelper("get", function(obj, path23) {
|
|
124
|
+
if (!path23 || typeof path23 !== "string") {
|
|
128
125
|
return void 0;
|
|
129
126
|
}
|
|
130
|
-
const pathArray =
|
|
127
|
+
const pathArray = path23.split(".");
|
|
131
128
|
let current = obj;
|
|
132
129
|
for (let i = 0; i < pathArray.length; i++) {
|
|
133
130
|
if (current === null || current === void 0) {
|
|
@@ -181,39 +178,69 @@ function registerHandlebarsHelpers() {
|
|
|
181
178
|
}
|
|
182
179
|
|
|
183
180
|
// src/core/registry/starters/base-starter.ts
|
|
181
|
+
import { fileURLToPath } from "url";
|
|
182
|
+
var __filename = fileURLToPath(import.meta?.url);
|
|
183
|
+
var __dirname = path.dirname(__filename);
|
|
184
|
+
function resolveTemplatesDir() {
|
|
185
|
+
const candidates = [
|
|
186
|
+
// Bundled: dist/index.mjs -> dist/../templates/ (templates at package root)
|
|
187
|
+
path.resolve(__dirname, "..", "templates"),
|
|
188
|
+
// Bundled: dist/index.mjs -> dist/templates/ (if copied to dist)
|
|
189
|
+
path.resolve(__dirname, "templates"),
|
|
190
|
+
// Development: when running from source (src/core/registry/starters/)
|
|
191
|
+
path.resolve(__dirname, "..", "..", "..", "..", "templates"),
|
|
192
|
+
// Installed via npm: node_modules/@igniter-js/cli/templates
|
|
193
|
+
path.resolve(process.cwd(), "node_modules", "@igniter-js", "cli", "templates")
|
|
194
|
+
];
|
|
195
|
+
for (const candidate of candidates) {
|
|
196
|
+
if (existsSync(candidate)) {
|
|
197
|
+
return candidate;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
throw new Error(
|
|
201
|
+
[
|
|
202
|
+
"Could not locate the CLI templates directory.",
|
|
203
|
+
"Looked in the following locations:",
|
|
204
|
+
...candidates.map((candidate) => `- ${candidate}`)
|
|
205
|
+
].join("\n")
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
function resolveTemplatePath(relativePath) {
|
|
209
|
+
return path.resolve(resolveTemplatesDir(), relativePath);
|
|
210
|
+
}
|
|
184
211
|
var BaseStarter = class {
|
|
185
212
|
constructor() {
|
|
186
213
|
this.templates = [
|
|
187
214
|
{
|
|
188
|
-
template:
|
|
215
|
+
template: resolveTemplatePath("starters/igniter.router.hbs"),
|
|
189
216
|
outputPath: "src/igniter.router.ts"
|
|
190
217
|
},
|
|
191
218
|
{
|
|
192
|
-
template:
|
|
219
|
+
template: resolveTemplatePath("starters/igniter.client.hbs"),
|
|
193
220
|
outputPath: "src/igniter.client.ts"
|
|
194
221
|
},
|
|
195
222
|
{
|
|
196
|
-
template:
|
|
223
|
+
template: resolveTemplatePath("starters/igniter.context.hbs"),
|
|
197
224
|
outputPath: "src/igniter.context.ts"
|
|
198
225
|
},
|
|
199
226
|
{
|
|
200
|
-
template:
|
|
227
|
+
template: resolveTemplatePath("starters/igniter.hbs"),
|
|
201
228
|
outputPath: "src/igniter.ts"
|
|
202
229
|
},
|
|
203
230
|
{
|
|
204
|
-
template:
|
|
231
|
+
template: resolveTemplatePath("scaffold/example-feature/example.controller.hbs"),
|
|
205
232
|
outputPath: "src/features/example/controllers/example.controller.ts"
|
|
206
233
|
},
|
|
207
234
|
{
|
|
208
|
-
template:
|
|
235
|
+
template: resolveTemplatePath("scaffold/example-feature/example.procedure.hbs"),
|
|
209
236
|
outputPath: "src/features/example/procedures/example.procedure.ts"
|
|
210
237
|
},
|
|
211
238
|
{
|
|
212
|
-
template:
|
|
239
|
+
template: resolveTemplatePath("scaffold/example-feature/example.interfaces.hbs"),
|
|
213
240
|
outputPath: "src/features/example/example.interfaces.ts"
|
|
214
241
|
},
|
|
215
242
|
{
|
|
216
|
-
template:
|
|
243
|
+
template: resolveTemplatePath("starters/open-api.hbs"),
|
|
217
244
|
outputPath: "src/docs/openapi.json"
|
|
218
245
|
}
|
|
219
246
|
];
|
|
@@ -431,43 +458,43 @@ var NextJsStarter = class extends BaseStarter {
|
|
|
431
458
|
this.repository = "starter-nextjs";
|
|
432
459
|
this.templates = [
|
|
433
460
|
{
|
|
434
|
-
template:
|
|
461
|
+
template: resolveTemplatePath("starters/nextjs/route-handler.hbs"),
|
|
435
462
|
outputPath: "src/app/api/v1/[[...all]]/route.ts"
|
|
436
463
|
},
|
|
437
464
|
{
|
|
438
|
-
template:
|
|
465
|
+
template: resolveTemplatePath("starters/igniter.router.hbs"),
|
|
439
466
|
outputPath: "src/igniter.router.ts"
|
|
440
467
|
},
|
|
441
468
|
{
|
|
442
|
-
template:
|
|
469
|
+
template: resolveTemplatePath("starters/igniter.client.hbs"),
|
|
443
470
|
outputPath: "src/igniter.client.ts"
|
|
444
471
|
},
|
|
445
472
|
{
|
|
446
|
-
template:
|
|
473
|
+
template: resolveTemplatePath("starters/igniter.context.hbs"),
|
|
447
474
|
outputPath: "src/igniter.context.ts"
|
|
448
475
|
},
|
|
449
476
|
{
|
|
450
|
-
template:
|
|
477
|
+
template: resolveTemplatePath("starters/igniter.hbs"),
|
|
451
478
|
outputPath: "src/igniter.ts"
|
|
452
479
|
},
|
|
453
480
|
{
|
|
454
|
-
template:
|
|
481
|
+
template: resolveTemplatePath("scaffold/example-feature/example.controller.hbs"),
|
|
455
482
|
outputPath: "src/features/example/controllers/example.controller.ts"
|
|
456
483
|
},
|
|
457
484
|
{
|
|
458
|
-
template:
|
|
485
|
+
template: resolveTemplatePath("scaffold/example-feature/example.procedure.hbs"),
|
|
459
486
|
outputPath: "src/features/example/procedures/example.procedure.ts"
|
|
460
487
|
},
|
|
461
488
|
{
|
|
462
|
-
template:
|
|
489
|
+
template: resolveTemplatePath("scaffold/example-feature/example.interfaces.hbs"),
|
|
463
490
|
outputPath: "src/features/example/example.interfaces.ts"
|
|
464
491
|
},
|
|
465
492
|
{
|
|
466
|
-
template:
|
|
493
|
+
template: resolveTemplatePath("starters/nextjs/tsconfig.hbs"),
|
|
467
494
|
outputPath: "tsconfig.json"
|
|
468
495
|
},
|
|
469
496
|
{
|
|
470
|
-
template:
|
|
497
|
+
template: resolveTemplatePath("starters/open-api.hbs"),
|
|
471
498
|
outputPath: "src/docs/openapi.json"
|
|
472
499
|
}
|
|
473
500
|
];
|
|
@@ -574,7 +601,6 @@ var BunReactStarter = class extends BaseStarter {
|
|
|
574
601
|
};
|
|
575
602
|
|
|
576
603
|
// src/registry/starters/tanstack-start-starter.ts
|
|
577
|
-
import path3 from "path";
|
|
578
604
|
var TanStackStartStarter = class extends BaseStarter {
|
|
579
605
|
constructor() {
|
|
580
606
|
super(...arguments);
|
|
@@ -585,43 +611,43 @@ var TanStackStartStarter = class extends BaseStarter {
|
|
|
585
611
|
this.repository = "starter-tanstack-start";
|
|
586
612
|
this.templates = [
|
|
587
613
|
{
|
|
588
|
-
template:
|
|
614
|
+
template: resolveTemplatePath("starters/tanstack-start/route-handler.hbs"),
|
|
589
615
|
outputPath: "src/routes/api/v1/$.ts"
|
|
590
616
|
},
|
|
591
617
|
{
|
|
592
|
-
template:
|
|
618
|
+
template: resolveTemplatePath("starters/igniter.router.hbs"),
|
|
593
619
|
outputPath: "src/igniter.router.ts"
|
|
594
620
|
},
|
|
595
621
|
{
|
|
596
|
-
template:
|
|
622
|
+
template: resolveTemplatePath("starters/igniter.client.hbs"),
|
|
597
623
|
outputPath: "src/igniter.client.ts"
|
|
598
624
|
},
|
|
599
625
|
{
|
|
600
|
-
template:
|
|
626
|
+
template: resolveTemplatePath("starters/igniter.context.hbs"),
|
|
601
627
|
outputPath: "src/igniter.context.ts"
|
|
602
628
|
},
|
|
603
629
|
{
|
|
604
|
-
template:
|
|
630
|
+
template: resolveTemplatePath("starters/igniter.hbs"),
|
|
605
631
|
outputPath: "src/igniter.ts"
|
|
606
632
|
},
|
|
607
633
|
{
|
|
608
|
-
template:
|
|
634
|
+
template: resolveTemplatePath("scaffold/example-feature/example.controller.hbs"),
|
|
609
635
|
outputPath: "src/features/example/controllers/example.controller.ts"
|
|
610
636
|
},
|
|
611
637
|
{
|
|
612
|
-
template:
|
|
638
|
+
template: resolveTemplatePath("scaffold/example-feature/example.procedure.hbs"),
|
|
613
639
|
outputPath: "src/features/example/procedures/example.procedure.ts"
|
|
614
640
|
},
|
|
615
641
|
{
|
|
616
|
-
template:
|
|
642
|
+
template: resolveTemplatePath("scaffold/example-feature/example.interfaces.hbs"),
|
|
617
643
|
outputPath: "src/features/example/example.interfaces.ts"
|
|
618
644
|
},
|
|
619
645
|
{
|
|
620
|
-
template:
|
|
646
|
+
template: resolveTemplatePath("starters/tanstack-start/tsconfig.hbs"),
|
|
621
647
|
outputPath: "tsconfig.json"
|
|
622
648
|
},
|
|
623
649
|
{
|
|
624
|
-
template:
|
|
650
|
+
template: resolveTemplatePath("starters/open-api.hbs"),
|
|
625
651
|
outputPath: "src/docs/openapi.json"
|
|
626
652
|
}
|
|
627
653
|
];
|
|
@@ -670,7 +696,7 @@ var AddOnRegistry = class _AddOnRegistry {
|
|
|
670
696
|
};
|
|
671
697
|
|
|
672
698
|
// src/registry/add-ons/store.ts
|
|
673
|
-
import
|
|
699
|
+
import path2 from "path";
|
|
674
700
|
|
|
675
701
|
// src/core/registry/add-ons/base-addon.ts
|
|
676
702
|
import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
@@ -1028,14 +1054,14 @@ var RedisStoreAddOn = class extends BaseAddOn {
|
|
|
1028
1054
|
this.hint = "Recommended";
|
|
1029
1055
|
this.templates = [
|
|
1030
1056
|
{
|
|
1031
|
-
template:
|
|
1057
|
+
template: path2.resolve(
|
|
1032
1058
|
process.cwd(),
|
|
1033
1059
|
"templates/add-ons/store/redis.ts.hbs"
|
|
1034
1060
|
),
|
|
1035
1061
|
outputPath: "src/services/redis.ts"
|
|
1036
1062
|
},
|
|
1037
1063
|
{
|
|
1038
|
-
template:
|
|
1064
|
+
template: path2.resolve(
|
|
1039
1065
|
process.cwd(),
|
|
1040
1066
|
"templates/add-ons/store/store.ts.hbs"
|
|
1041
1067
|
),
|
|
@@ -1096,7 +1122,7 @@ var RedisStoreAddOn = class extends BaseAddOn {
|
|
|
1096
1122
|
};
|
|
1097
1123
|
|
|
1098
1124
|
// src/registry/add-ons/jobs.ts
|
|
1099
|
-
import
|
|
1125
|
+
import path3 from "path";
|
|
1100
1126
|
var JobsAddOn = class extends BaseAddOn {
|
|
1101
1127
|
constructor() {
|
|
1102
1128
|
super(...arguments);
|
|
@@ -1106,21 +1132,21 @@ var JobsAddOn = class extends BaseAddOn {
|
|
|
1106
1132
|
this.hint = "For background processing";
|
|
1107
1133
|
this.templates = [
|
|
1108
1134
|
{
|
|
1109
|
-
template:
|
|
1135
|
+
template: path3.resolve(
|
|
1110
1136
|
process.cwd(),
|
|
1111
1137
|
"templates/add-ons/jobs/jobs.ts.hbs"
|
|
1112
1138
|
),
|
|
1113
1139
|
outputPath: "src/services/jobs.ts"
|
|
1114
1140
|
},
|
|
1115
1141
|
{
|
|
1116
|
-
template:
|
|
1142
|
+
template: path3.resolve(
|
|
1117
1143
|
process.cwd(),
|
|
1118
1144
|
"templates/add-ons/jobs/redis.ts.hbs"
|
|
1119
1145
|
),
|
|
1120
1146
|
outputPath: "src/services/redis.ts"
|
|
1121
1147
|
},
|
|
1122
1148
|
{
|
|
1123
|
-
template:
|
|
1149
|
+
template: path3.resolve(
|
|
1124
1150
|
process.cwd(),
|
|
1125
1151
|
"templates/add-ons/jobs/store.ts.hbs"
|
|
1126
1152
|
),
|
|
@@ -1196,7 +1222,7 @@ var JobsAddOn = class extends BaseAddOn {
|
|
|
1196
1222
|
};
|
|
1197
1223
|
|
|
1198
1224
|
// src/registry/add-ons/mcp.ts
|
|
1199
|
-
import
|
|
1225
|
+
import path4 from "path";
|
|
1200
1226
|
var McpServerAddOn = class extends BaseAddOn {
|
|
1201
1227
|
constructor() {
|
|
1202
1228
|
super(...arguments);
|
|
@@ -1206,7 +1232,7 @@ var McpServerAddOn = class extends BaseAddOn {
|
|
|
1206
1232
|
this.hint = "For AI integration";
|
|
1207
1233
|
this.templates = [
|
|
1208
1234
|
{
|
|
1209
|
-
template:
|
|
1235
|
+
template: path4.resolve(
|
|
1210
1236
|
process.cwd(),
|
|
1211
1237
|
"templates/add-ons/mcp/mcp.ts.hbs"
|
|
1212
1238
|
),
|
|
@@ -1215,11 +1241,11 @@ var McpServerAddOn = class extends BaseAddOn {
|
|
|
1215
1241
|
{
|
|
1216
1242
|
template: (data) => {
|
|
1217
1243
|
const templates = {
|
|
1218
|
-
nextjs:
|
|
1244
|
+
nextjs: path4.resolve(
|
|
1219
1245
|
process.cwd(),
|
|
1220
1246
|
"templates/add-ons/mcp/nextjs/route-handler.hbs"
|
|
1221
1247
|
),
|
|
1222
|
-
"tanstack-start":
|
|
1248
|
+
"tanstack-start": path4.resolve(
|
|
1223
1249
|
process.cwd(),
|
|
1224
1250
|
"templates/add-ons/mcp/tanstack-start/route-handler.hbs"
|
|
1225
1251
|
)
|
|
@@ -1299,7 +1325,7 @@ var McpServerAddOn = class extends BaseAddOn {
|
|
|
1299
1325
|
};
|
|
1300
1326
|
|
|
1301
1327
|
// src/registry/add-ons/logging.ts
|
|
1302
|
-
import
|
|
1328
|
+
import path5 from "path";
|
|
1303
1329
|
var LoggingAddOn = class extends BaseAddOn {
|
|
1304
1330
|
constructor() {
|
|
1305
1331
|
super(...arguments);
|
|
@@ -1309,7 +1335,7 @@ var LoggingAddOn = class extends BaseAddOn {
|
|
|
1309
1335
|
this.hint = "For better observability";
|
|
1310
1336
|
this.templates = [
|
|
1311
1337
|
{
|
|
1312
|
-
template:
|
|
1338
|
+
template: path5.resolve(
|
|
1313
1339
|
process.cwd(),
|
|
1314
1340
|
"templates/add-ons/logging/logger.ts.hbs"
|
|
1315
1341
|
),
|
|
@@ -1335,7 +1361,7 @@ var LoggingAddOn = class extends BaseAddOn {
|
|
|
1335
1361
|
};
|
|
1336
1362
|
|
|
1337
1363
|
// src/registry/add-ons/telemetry.ts
|
|
1338
|
-
import
|
|
1364
|
+
import path6 from "path";
|
|
1339
1365
|
var TelemetryAddOn = class extends BaseAddOn {
|
|
1340
1366
|
constructor() {
|
|
1341
1367
|
super(...arguments);
|
|
@@ -1346,7 +1372,7 @@ var TelemetryAddOn = class extends BaseAddOn {
|
|
|
1346
1372
|
this.dockerServices = [];
|
|
1347
1373
|
this.templates = [
|
|
1348
1374
|
{
|
|
1349
|
-
template:
|
|
1375
|
+
template: path6.resolve(
|
|
1350
1376
|
process.cwd(),
|
|
1351
1377
|
"templates/add-ons/telemetry/telemetry.ts.hbs"
|
|
1352
1378
|
),
|
|
@@ -1386,7 +1412,7 @@ var TelemetryAddOn = class extends BaseAddOn {
|
|
|
1386
1412
|
};
|
|
1387
1413
|
|
|
1388
1414
|
// src/registry/add-ons/bots.ts
|
|
1389
|
-
import
|
|
1415
|
+
import path7 from "path";
|
|
1390
1416
|
var BotsAddOn = class extends BaseAddOn {
|
|
1391
1417
|
constructor() {
|
|
1392
1418
|
super(...arguments);
|
|
@@ -1396,7 +1422,7 @@ var BotsAddOn = class extends BaseAddOn {
|
|
|
1396
1422
|
this.hint = "For multi-platform chatbot support";
|
|
1397
1423
|
this.templates = [
|
|
1398
1424
|
{
|
|
1399
|
-
template:
|
|
1425
|
+
template: path7.resolve(
|
|
1400
1426
|
process.cwd(),
|
|
1401
1427
|
"templates/add-ons/bots/sample-bot.hbs"
|
|
1402
1428
|
),
|
|
@@ -1405,11 +1431,11 @@ var BotsAddOn = class extends BaseAddOn {
|
|
|
1405
1431
|
{
|
|
1406
1432
|
template: (data) => {
|
|
1407
1433
|
const templates = {
|
|
1408
|
-
nextjs:
|
|
1434
|
+
nextjs: path7.resolve(
|
|
1409
1435
|
process.cwd(),
|
|
1410
1436
|
"templates/add-ons/bots/nextjs/route-handler.hbs"
|
|
1411
1437
|
),
|
|
1412
|
-
"tanstack-start":
|
|
1438
|
+
"tanstack-start": path7.resolve(
|
|
1413
1439
|
process.cwd(),
|
|
1414
1440
|
"templates/add-ons/bots/tanstack-start/route-handler.hbs"
|
|
1415
1441
|
)
|
|
@@ -1453,7 +1479,7 @@ var BotsAddOn = class extends BaseAddOn {
|
|
|
1453
1479
|
};
|
|
1454
1480
|
|
|
1455
1481
|
// src/registry/add-ons/database.ts
|
|
1456
|
-
import
|
|
1482
|
+
import path8 from "path";
|
|
1457
1483
|
var DatabaseAddOn = class extends BaseAddOn {
|
|
1458
1484
|
constructor() {
|
|
1459
1485
|
super(...arguments);
|
|
@@ -1491,21 +1517,21 @@ var DatabaseAddOn = class extends BaseAddOn {
|
|
|
1491
1517
|
],
|
|
1492
1518
|
templates: [
|
|
1493
1519
|
{
|
|
1494
|
-
template:
|
|
1520
|
+
template: path8.resolve(
|
|
1495
1521
|
process.cwd(),
|
|
1496
1522
|
"templates/add-ons/database/prisma/lib.hbs"
|
|
1497
1523
|
),
|
|
1498
1524
|
outputPath: "src/lib/database.ts"
|
|
1499
1525
|
},
|
|
1500
1526
|
{
|
|
1501
|
-
template:
|
|
1527
|
+
template: path8.resolve(
|
|
1502
1528
|
process.cwd(),
|
|
1503
1529
|
"templates/add-ons/database/prisma/prisma.config.hbs"
|
|
1504
1530
|
),
|
|
1505
1531
|
outputPath: "prisma.config.ts"
|
|
1506
1532
|
},
|
|
1507
1533
|
{
|
|
1508
|
-
template:
|
|
1534
|
+
template: path8.resolve(
|
|
1509
1535
|
process.cwd(),
|
|
1510
1536
|
"templates/add-ons/database/prisma/schema.hbs"
|
|
1511
1537
|
),
|
|
@@ -1519,7 +1545,7 @@ var DatabaseAddOn = class extends BaseAddOn {
|
|
|
1519
1545
|
hint: "Lightweight, modern, SQL-like",
|
|
1520
1546
|
templates: [
|
|
1521
1547
|
{
|
|
1522
|
-
template:
|
|
1548
|
+
template: path8.resolve(
|
|
1523
1549
|
process.cwd(),
|
|
1524
1550
|
"templates/add-ons/database/drizzle/lib.hbs"
|
|
1525
1551
|
),
|
|
@@ -1838,9 +1864,9 @@ var addOnRegistry = AddOnRegistry.create().register(new RedisStoreAddOn()).regis
|
|
|
1838
1864
|
|
|
1839
1865
|
// src/core/file-system.ts
|
|
1840
1866
|
import * as fs2 from "fs/promises";
|
|
1841
|
-
async function isPathEmpty(
|
|
1867
|
+
async function isPathEmpty(path23) {
|
|
1842
1868
|
try {
|
|
1843
|
-
const files = await fs2.readdir(
|
|
1869
|
+
const files = await fs2.readdir(path23);
|
|
1844
1870
|
return files.length === 0;
|
|
1845
1871
|
} catch (error) {
|
|
1846
1872
|
if (error.code === "ENOENT") {
|
|
@@ -1851,13 +1877,13 @@ async function isPathEmpty(path25) {
|
|
|
1851
1877
|
}
|
|
1852
1878
|
|
|
1853
1879
|
// src/core/framework.ts
|
|
1854
|
-
import
|
|
1880
|
+
import path9 from "path";
|
|
1855
1881
|
import fs3 from "fs";
|
|
1856
1882
|
function detectFramework(projectDir) {
|
|
1857
|
-
if (fs3.existsSync(
|
|
1883
|
+
if (fs3.existsSync(path9.join(projectDir, "next.config.js")) || fs3.existsSync(path9.join(projectDir, "next.config.ts"))) {
|
|
1858
1884
|
return "nextjs";
|
|
1859
1885
|
}
|
|
1860
|
-
const packageJson = JSON.parse(fs3.readFileSync(
|
|
1886
|
+
const packageJson = JSON.parse(fs3.readFileSync(path9.join(projectDir, "package.json"), "utf8"));
|
|
1861
1887
|
if (packageJson.dependencies["@tanstack/react-start"]) {
|
|
1862
1888
|
return "tanstack-start";
|
|
1863
1889
|
} else {
|
|
@@ -1916,7 +1942,7 @@ async function runInitPrompts(options) {
|
|
|
1916
1942
|
},
|
|
1917
1943
|
projectName: async ({ results }) => {
|
|
1918
1944
|
if (options.projectName) return options.projectName;
|
|
1919
|
-
if (results.useCurrentDir) return
|
|
1945
|
+
if (results.useCurrentDir) return path10.basename(process.cwd());
|
|
1920
1946
|
const projectName = await p2.text({
|
|
1921
1947
|
message: "What will your project be called?",
|
|
1922
1948
|
validate: (value) => {
|
|
@@ -1931,7 +1957,7 @@ async function runInitPrompts(options) {
|
|
|
1931
1957
|
},
|
|
1932
1958
|
mode: async ({ results }) => {
|
|
1933
1959
|
const projectName = results.projectName;
|
|
1934
|
-
const targetDir =
|
|
1960
|
+
const targetDir = path10.resolve(projectName);
|
|
1935
1961
|
const isEmpty = await isPathEmpty(targetDir);
|
|
1936
1962
|
if (!isEmpty) {
|
|
1937
1963
|
return await p2.select({
|
|
@@ -1946,7 +1972,7 @@ async function runInitPrompts(options) {
|
|
|
1946
1972
|
},
|
|
1947
1973
|
starter: async ({ results }) => {
|
|
1948
1974
|
if (results.mode !== "new-project") {
|
|
1949
|
-
const targetDir =
|
|
1975
|
+
const targetDir = path10.resolve(results.projectName);
|
|
1950
1976
|
const framework = detectFramework(targetDir);
|
|
1951
1977
|
if (framework === "nextjs") {
|
|
1952
1978
|
return "nextjs";
|
|
@@ -2174,9 +2200,9 @@ var ProjectGenerator = class {
|
|
|
2174
2200
|
`Checking and stopping currently running containers...`
|
|
2175
2201
|
);
|
|
2176
2202
|
const fs9 = await import("fs/promises");
|
|
2177
|
-
const
|
|
2203
|
+
const path23 = await import("path");
|
|
2178
2204
|
const yaml2 = await import("js-yaml");
|
|
2179
|
-
const composeFilePath =
|
|
2205
|
+
const composeFilePath = path23.join(this.targetDir, "docker-compose.yml");
|
|
2180
2206
|
let ports = [];
|
|
2181
2207
|
try {
|
|
2182
2208
|
const composeContent = await fs9.readFile(composeFilePath, "utf8");
|
|
@@ -2260,7 +2286,7 @@ async function handleInitAction(projectName, options) {
|
|
|
2260
2286
|
git: options.git,
|
|
2261
2287
|
install: options.install
|
|
2262
2288
|
});
|
|
2263
|
-
const targetDir =
|
|
2289
|
+
const targetDir = path11.resolve(config.projectName);
|
|
2264
2290
|
const generator = new ProjectGenerator(config, targetDir);
|
|
2265
2291
|
await generator.generate();
|
|
2266
2292
|
p5.log.success("Project initialized successfully!");
|
|
@@ -2293,7 +2319,7 @@ import { Command as Command8 } from "commander";
|
|
|
2293
2319
|
import { Command as Command2 } from "commander";
|
|
2294
2320
|
|
|
2295
2321
|
// src/commands/generate/feature/action.ts
|
|
2296
|
-
import * as
|
|
2322
|
+
import * as path15 from "path";
|
|
2297
2323
|
import * as p7 from "@clack/prompts";
|
|
2298
2324
|
import { existsSync as existsSync4 } from "fs";
|
|
2299
2325
|
import { writeFile as writeFile5 } from "fs/promises";
|
|
@@ -2301,11 +2327,11 @@ import { writeFile as writeFile5 } from "fs/promises";
|
|
|
2301
2327
|
// src/core/template-engine.ts
|
|
2302
2328
|
import { mkdirSync, existsSync as existsSync3 } from "fs";
|
|
2303
2329
|
import { readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
2304
|
-
import * as
|
|
2330
|
+
import * as path12 from "path";
|
|
2305
2331
|
import handlebars4 from "handlebars";
|
|
2306
|
-
import { fileURLToPath } from "url";
|
|
2307
|
-
var
|
|
2308
|
-
var
|
|
2332
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2333
|
+
var __filename2 = fileURLToPath2(import.meta?.url);
|
|
2334
|
+
var __dirname2 = path12.dirname(__filename2);
|
|
2309
2335
|
var TemplateEngine = class {
|
|
2310
2336
|
constructor() {
|
|
2311
2337
|
}
|
|
@@ -2323,7 +2349,7 @@ var _DefaultTemplateEngine = class _DefaultTemplateEngine extends TemplateEngine
|
|
|
2323
2349
|
this.templateRoot = this.resolveTemplateRoot();
|
|
2324
2350
|
}
|
|
2325
2351
|
resolvePath(...segments) {
|
|
2326
|
-
return
|
|
2352
|
+
return path12.join(this.templateRoot, ...segments);
|
|
2327
2353
|
}
|
|
2328
2354
|
async render(templatePath, context) {
|
|
2329
2355
|
this.ensureHelpersRegistered();
|
|
@@ -2333,7 +2359,7 @@ var _DefaultTemplateEngine = class _DefaultTemplateEngine extends TemplateEngine
|
|
|
2333
2359
|
}
|
|
2334
2360
|
async renderToFile(templatePath, context, outputPath) {
|
|
2335
2361
|
const rendered = await this.render(templatePath, context);
|
|
2336
|
-
const outputDir =
|
|
2362
|
+
const outputDir = path12.dirname(outputPath);
|
|
2337
2363
|
if (!existsSync3(outputDir)) {
|
|
2338
2364
|
mkdirSync(outputDir, { recursive: true });
|
|
2339
2365
|
}
|
|
@@ -2363,24 +2389,24 @@ var _DefaultTemplateEngine = class _DefaultTemplateEngine extends TemplateEngine
|
|
|
2363
2389
|
}
|
|
2364
2390
|
};
|
|
2365
2391
|
_DefaultTemplateEngine.TEMPLATE_CANDIDATES = [
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2392
|
+
path12.resolve(__dirname2, "..", "..", "templates"),
|
|
2393
|
+
path12.resolve(__dirname2, "..", "..", "..", "templates"),
|
|
2394
|
+
path12.resolve(__dirname2, "..", "templates"),
|
|
2395
|
+
path12.resolve(__dirname2, "..", "..", "..", "templates"),
|
|
2396
|
+
path12.resolve(
|
|
2371
2397
|
process.cwd(),
|
|
2372
2398
|
"node_modules",
|
|
2373
2399
|
"@igniter-js",
|
|
2374
2400
|
"new-cli",
|
|
2375
2401
|
"templates"
|
|
2376
2402
|
),
|
|
2377
|
-
|
|
2403
|
+
path12.resolve(process.cwd(), "templates")
|
|
2378
2404
|
];
|
|
2379
2405
|
var DefaultTemplateEngine = _DefaultTemplateEngine;
|
|
2380
2406
|
|
|
2381
2407
|
// src/commands/generate/feature/feature.ts
|
|
2382
2408
|
import { mkdir as mkdir2, readdir as readdir3, stat as stat2, writeFile as writeFile4 } from "fs/promises";
|
|
2383
|
-
import * as
|
|
2409
|
+
import * as path13 from "path";
|
|
2384
2410
|
var FeatureWorkspace = class {
|
|
2385
2411
|
constructor() {
|
|
2386
2412
|
}
|
|
@@ -2388,30 +2414,30 @@ var FeatureWorkspace = class {
|
|
|
2388
2414
|
* Returns the absolute path to the feature root directory.
|
|
2389
2415
|
*/
|
|
2390
2416
|
static root() {
|
|
2391
|
-
return
|
|
2417
|
+
return path13.join(process.cwd(), "src", "features");
|
|
2392
2418
|
}
|
|
2393
2419
|
/**
|
|
2394
2420
|
* Returns the absolute path for a specific feature name.
|
|
2395
2421
|
*/
|
|
2396
2422
|
static featureDir(featureName) {
|
|
2397
|
-
return
|
|
2423
|
+
return path13.join(this.root(), featureName);
|
|
2398
2424
|
}
|
|
2399
2425
|
/**
|
|
2400
2426
|
* Ensures that the directory structure required for a feature exists.
|
|
2401
2427
|
*/
|
|
2402
2428
|
static async ensureStructure(featureDir) {
|
|
2403
2429
|
await mkdir2(featureDir, { recursive: true });
|
|
2404
|
-
await mkdir2(
|
|
2405
|
-
await mkdir2(
|
|
2406
|
-
await mkdir2(
|
|
2407
|
-
await mkdir2(
|
|
2408
|
-
await writeFile4(
|
|
2409
|
-
await mkdir2(
|
|
2410
|
-
await writeFile4(
|
|
2411
|
-
await mkdir2(
|
|
2412
|
-
await writeFile4(
|
|
2413
|
-
await mkdir2(
|
|
2414
|
-
await writeFile4(
|
|
2430
|
+
await mkdir2(path13.join(featureDir, "controllers"), { recursive: true });
|
|
2431
|
+
await mkdir2(path13.join(featureDir, "procedures"), { recursive: true });
|
|
2432
|
+
await mkdir2(path13.join(featureDir, "presentation"), { recursive: true });
|
|
2433
|
+
await mkdir2(path13.join(featureDir, "presentation", "components"), { recursive: true });
|
|
2434
|
+
await writeFile4(path13.join(featureDir, "presentation", "components", ".gitkeep"), "");
|
|
2435
|
+
await mkdir2(path13.join(featureDir, "presentation", "hooks"), { recursive: true });
|
|
2436
|
+
await writeFile4(path13.join(featureDir, "presentation", "hooks", ".gitkeep"), "");
|
|
2437
|
+
await mkdir2(path13.join(featureDir, "presentation", "contexts"), { recursive: true });
|
|
2438
|
+
await writeFile4(path13.join(featureDir, "presentation", "contexts", ".gitkeep"), "");
|
|
2439
|
+
await mkdir2(path13.join(featureDir, "presentation", "utils"), { recursive: true });
|
|
2440
|
+
await writeFile4(path13.join(featureDir, "presentation", "utils", ".gitkeep"), "");
|
|
2415
2441
|
}
|
|
2416
2442
|
/**
|
|
2417
2443
|
* Lists all available feature directories under `src/features`.
|
|
@@ -2570,7 +2596,7 @@ var SchemaProviderRegistryBuilder = class {
|
|
|
2570
2596
|
// src/registry/schema-provider/prisma.ts
|
|
2571
2597
|
import { getSchema } from "@mrleebo/prisma-ast";
|
|
2572
2598
|
import * as fs4 from "fs/promises";
|
|
2573
|
-
import * as
|
|
2599
|
+
import * as path14 from "path";
|
|
2574
2600
|
|
|
2575
2601
|
// src/core/registry/schema-provider/base-schema-provider.ts
|
|
2576
2602
|
var SchemaProvider = class {
|
|
@@ -2651,7 +2677,7 @@ var PrismaSchemaProvider = class extends SchemaProvider {
|
|
|
2651
2677
|
super(...arguments);
|
|
2652
2678
|
this.id = "prisma";
|
|
2653
2679
|
this.name = "Prisma";
|
|
2654
|
-
this.defaultSchemaPath =
|
|
2680
|
+
this.defaultSchemaPath = path14.join(process.cwd(), "prisma", "schema.prisma");
|
|
2655
2681
|
}
|
|
2656
2682
|
async validateSchemaPath(schemaPath) {
|
|
2657
2683
|
try {
|
|
@@ -2706,7 +2732,7 @@ var PrismaSchemaProvider = class extends SchemaProvider {
|
|
|
2706
2732
|
})),
|
|
2707
2733
|
createOmitFields: modelFields.filter((field) => field.isId || field.isAutoGenerated || field.hasDefault).map((field) => field.name)
|
|
2708
2734
|
},
|
|
2709
|
-
|
|
2735
|
+
path14.join(context.featureDir, `${context.featureName}.interfaces.ts`)
|
|
2710
2736
|
);
|
|
2711
2737
|
await context.templateEngine.renderToFile(
|
|
2712
2738
|
procedureTemplate,
|
|
@@ -2718,7 +2744,7 @@ var PrismaSchemaProvider = class extends SchemaProvider {
|
|
|
2718
2744
|
featureName: context.featureName,
|
|
2719
2745
|
idType: this.mapIdType(modelFields)
|
|
2720
2746
|
},
|
|
2721
|
-
|
|
2747
|
+
path14.join(context.featureDir, "procedures", `${context.featureName}.procedure.ts`)
|
|
2722
2748
|
);
|
|
2723
2749
|
await context.templateEngine.renderToFile(
|
|
2724
2750
|
controllerTemplate,
|
|
@@ -2732,7 +2758,7 @@ var PrismaSchemaProvider = class extends SchemaProvider {
|
|
|
2732
2758
|
featureName: context.featureName,
|
|
2733
2759
|
procedureExport: target.procedureExport
|
|
2734
2760
|
},
|
|
2735
|
-
|
|
2761
|
+
path14.join(context.featureDir, "controllers", `${context.featureName}.controller.ts`)
|
|
2736
2762
|
);
|
|
2737
2763
|
}
|
|
2738
2764
|
extractFields(model) {
|
|
@@ -2762,13 +2788,13 @@ var PrismaSchemaProvider = class extends SchemaProvider {
|
|
|
2762
2788
|
}
|
|
2763
2789
|
async ensurePathsAreFree(featureDir, featureSlug) {
|
|
2764
2790
|
const filesToCheck = [
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2791
|
+
path14.join(featureDir, "controllers", `${featureSlug}.controller.ts`),
|
|
2792
|
+
path14.join(featureDir, "procedures", `${featureSlug}.procedure.ts`),
|
|
2793
|
+
path14.join(featureDir, `${featureSlug}.interfaces.ts`)
|
|
2768
2794
|
];
|
|
2769
2795
|
for (const file of filesToCheck) {
|
|
2770
2796
|
if (await FeatureWorkspace.fileExists(file)) {
|
|
2771
|
-
throw new Error(`File '${
|
|
2797
|
+
throw new Error(`File '${path14.relative(process.cwd(), file)}' already exists.`);
|
|
2772
2798
|
}
|
|
2773
2799
|
}
|
|
2774
2800
|
}
|
|
@@ -2895,7 +2921,7 @@ async function handleGenerateFeatureAction(name, options) {
|
|
|
2895
2921
|
const featureDir = FeatureWorkspace.featureDir(featureSlug);
|
|
2896
2922
|
if (existsSync4(featureDir)) {
|
|
2897
2923
|
p7.log.error(
|
|
2898
|
-
`Feature '${featureSlug}' already exists at ${
|
|
2924
|
+
`Feature '${featureSlug}' already exists at ${path15.relative(process.cwd(), featureDir)}.`
|
|
2899
2925
|
);
|
|
2900
2926
|
p7.outro("Nothing to do.");
|
|
2901
2927
|
process.exit(1);
|
|
@@ -3003,14 +3029,14 @@ async function generateEmptyFeature(featureSlug, featureDir, templateEngine) {
|
|
|
3003
3029
|
controllerDisplayName,
|
|
3004
3030
|
controllerRoute: featureSlug
|
|
3005
3031
|
},
|
|
3006
|
-
|
|
3032
|
+
path15.join(featureDir, "controllers", `${featureSlug}.controller.ts`)
|
|
3007
3033
|
);
|
|
3008
3034
|
await templateEngine.renderToFile(
|
|
3009
3035
|
interfacesTemplate,
|
|
3010
3036
|
{ featureName: Casing.toPascalCase(featureSlug) },
|
|
3011
|
-
|
|
3037
|
+
path15.join(featureDir, `${featureSlug}.interfaces.ts`)
|
|
3012
3038
|
);
|
|
3013
|
-
await writeFile5(
|
|
3039
|
+
await writeFile5(path15.join(featureDir, "procedures", ".gitkeep"), "");
|
|
3014
3040
|
}
|
|
3015
3041
|
|
|
3016
3042
|
// src/commands/generate/feature/index.ts
|
|
@@ -3063,13 +3089,13 @@ var OpenAPIGenerator = class _OpenAPIGenerator {
|
|
|
3063
3089
|
for (const [controllerKey, controller] of Object.entries(router.controllers)) {
|
|
3064
3090
|
for (const [actionKey, action] of Object.entries(controller.actions)) {
|
|
3065
3091
|
const actionName = action.name || actionKey;
|
|
3066
|
-
let
|
|
3067
|
-
|
|
3068
|
-
if (
|
|
3069
|
-
|
|
3092
|
+
let path23 = `/${controller.path}/${action.path}`;
|
|
3093
|
+
path23 = path23.replace(/\/{2,}/g, "/");
|
|
3094
|
+
if (path23.length > 1 && path23.endsWith("/")) {
|
|
3095
|
+
path23 = path23.slice(0, -1);
|
|
3070
3096
|
}
|
|
3071
|
-
if (!paths[
|
|
3072
|
-
paths[
|
|
3097
|
+
if (!paths[path23]) {
|
|
3098
|
+
paths[path23] = {};
|
|
3073
3099
|
}
|
|
3074
3100
|
const operation = {
|
|
3075
3101
|
summary: action.description || actionName,
|
|
@@ -3131,7 +3157,7 @@ var OpenAPIGenerator = class _OpenAPIGenerator {
|
|
|
3131
3157
|
if (action.isStream) {
|
|
3132
3158
|
operation.description = (operation.description ? operation.description + "\n\n" : "") + "This endpoint supports Server-Sent Events (SSE) for real-time updates. It functions as a standard GET request initially, then maintains an open connection for streaming data.";
|
|
3133
3159
|
}
|
|
3134
|
-
paths[
|
|
3160
|
+
paths[path23][action.method.toLowerCase()] = operation;
|
|
3135
3161
|
}
|
|
3136
3162
|
}
|
|
3137
3163
|
return paths;
|
|
@@ -3139,7 +3165,7 @@ var OpenAPIGenerator = class _OpenAPIGenerator {
|
|
|
3139
3165
|
};
|
|
3140
3166
|
|
|
3141
3167
|
// src/core/router-instrospector.ts
|
|
3142
|
-
import * as
|
|
3168
|
+
import * as path16 from "path";
|
|
3143
3169
|
import { build } from "esbuild";
|
|
3144
3170
|
import zodToJsonSchema from "zod-to-json-schema";
|
|
3145
3171
|
import { createRequire } from "module";
|
|
@@ -3165,7 +3191,7 @@ var RouterInstrospector = class _RouterInstrospector {
|
|
|
3165
3191
|
* @throws RouterLoadError if loading or compiling fails.
|
|
3166
3192
|
*/
|
|
3167
3193
|
async loadRouter(routerPath) {
|
|
3168
|
-
const fullPath =
|
|
3194
|
+
const fullPath = path16.resolve(process.cwd(), routerPath);
|
|
3169
3195
|
try {
|
|
3170
3196
|
const result = await build({
|
|
3171
3197
|
entryPoints: [fullPath],
|
|
@@ -3204,7 +3230,7 @@ var RouterInstrospector = class _RouterInstrospector {
|
|
|
3204
3230
|
}
|
|
3205
3231
|
};
|
|
3206
3232
|
const factory = new Function("exports", "require", "module", "__filename", "__dirname", compiledCode);
|
|
3207
|
-
factory(routerModule.exports, requireFunc, routerModule, fullPath,
|
|
3233
|
+
factory(routerModule.exports, requireFunc, routerModule, fullPath, path16.dirname(fullPath));
|
|
3208
3234
|
const moduleExports = routerModule.exports;
|
|
3209
3235
|
const router = moduleExports.AppRouter || moduleExports.default || moduleExports;
|
|
3210
3236
|
if (router && typeof router.controllers === "object") {
|
|
@@ -3275,14 +3301,14 @@ ${errorMessages}`;
|
|
|
3275
3301
|
// src/commands/generate/docs/action.ts
|
|
3276
3302
|
import * as p9 from "@clack/prompts";
|
|
3277
3303
|
import * as fs5 from "fs";
|
|
3278
|
-
import * as
|
|
3304
|
+
import * as path17 from "path";
|
|
3279
3305
|
async function generateDocsWatchMode(routerPath, outputDir) {
|
|
3280
3306
|
const startTime = Date.now();
|
|
3281
|
-
const outputDirFull =
|
|
3307
|
+
const outputDirFull = path17.resolve(outputDir);
|
|
3282
3308
|
if (!fs5.existsSync(outputDirFull)) {
|
|
3283
3309
|
fs5.mkdirSync(outputDirFull, { recursive: true });
|
|
3284
3310
|
}
|
|
3285
|
-
const outputPath =
|
|
3311
|
+
const outputPath = path17.join(outputDirFull, "openapi.json");
|
|
3286
3312
|
if (!fs5.existsSync(outputPath)) {
|
|
3287
3313
|
fs5.writeFileSync(outputPath, "{}", "utf8");
|
|
3288
3314
|
}
|
|
@@ -3330,7 +3356,7 @@ import { Command as Command4 } from "commander";
|
|
|
3330
3356
|
|
|
3331
3357
|
// src/commands/generate/schema/action.ts
|
|
3332
3358
|
import * as fs6 from "fs";
|
|
3333
|
-
import * as
|
|
3359
|
+
import * as path18 from "path";
|
|
3334
3360
|
import * as p10 from "@clack/prompts";
|
|
3335
3361
|
async function generateSchemaWatchMode(routerPath, outputPath) {
|
|
3336
3362
|
const startTime = Date.now();
|
|
@@ -3343,7 +3369,7 @@ async function generateSchemaWatchMode(routerPath, outputPath) {
|
|
|
3343
3369
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3344
3370
|
schemaString: JSON.stringify(schema, null, 2)
|
|
3345
3371
|
});
|
|
3346
|
-
const outputFullPath =
|
|
3372
|
+
const outputFullPath = path18.resolve(process.cwd(), outputPath);
|
|
3347
3373
|
fs6.writeFileSync(outputFullPath, schemaContent, "utf8");
|
|
3348
3374
|
return {
|
|
3349
3375
|
durationMs: Date.now() - startTime,
|
|
@@ -3377,7 +3403,7 @@ var schemaCommand = new Command4().command("schema").description("Generate clien
|
|
|
3377
3403
|
import { Command as Command5 } from "commander";
|
|
3378
3404
|
|
|
3379
3405
|
// src/commands/generate/controller/action.ts
|
|
3380
|
-
import * as
|
|
3406
|
+
import * as path19 from "path";
|
|
3381
3407
|
import * as p11 from "@clack/prompts";
|
|
3382
3408
|
|
|
3383
3409
|
// src/utils/try-catch.ts
|
|
@@ -3415,14 +3441,14 @@ async function handleGenerateControllerAction(name, options) {
|
|
|
3415
3441
|
const featureSlug = Casing.toKebabCase(selectedFeature.data);
|
|
3416
3442
|
const featureDir = FeatureWorkspace.featureDir(featureSlug);
|
|
3417
3443
|
await FeatureWorkspace.ensureStructure(featureDir);
|
|
3418
|
-
const controllerPath =
|
|
3444
|
+
const controllerPath = path19.join(
|
|
3419
3445
|
featureDir,
|
|
3420
3446
|
"controllers",
|
|
3421
3447
|
`${controllerSlug}.controller.ts`
|
|
3422
3448
|
);
|
|
3423
3449
|
if (await FeatureWorkspace.fileExists(controllerPath)) {
|
|
3424
3450
|
p11.log.error(
|
|
3425
|
-
`Controller '${controllerSlug}' already exists at ${
|
|
3451
|
+
`Controller '${controllerSlug}' already exists at ${path19.relative(process.cwd(), controllerPath)}.`
|
|
3426
3452
|
);
|
|
3427
3453
|
process.exit(1);
|
|
3428
3454
|
}
|
|
@@ -3466,7 +3492,7 @@ var controllerCommand = new Command5().command("controller").description("Scaffo
|
|
|
3466
3492
|
import { Command as Command6 } from "commander";
|
|
3467
3493
|
|
|
3468
3494
|
// src/commands/generate/procedure/action.ts
|
|
3469
|
-
import * as
|
|
3495
|
+
import * as path20 from "path";
|
|
3470
3496
|
import * as p12 from "@clack/prompts";
|
|
3471
3497
|
import { rm as rm2 } from "fs/promises";
|
|
3472
3498
|
async function handleGenerateProcedureAction(name, options) {
|
|
@@ -3493,14 +3519,14 @@ async function handleGenerateProcedureAction(name, options) {
|
|
|
3493
3519
|
const featureSlug = Casing.toKebabCase(selectedFeature.data);
|
|
3494
3520
|
const featureDir = FeatureWorkspace.featureDir(featureSlug);
|
|
3495
3521
|
await FeatureWorkspace.ensureStructure(featureDir);
|
|
3496
|
-
const procedurePath =
|
|
3522
|
+
const procedurePath = path20.join(
|
|
3497
3523
|
featureDir,
|
|
3498
3524
|
"procedures",
|
|
3499
3525
|
`${procedureSlug}.procedure.ts`
|
|
3500
3526
|
);
|
|
3501
3527
|
if (await FeatureWorkspace.fileExists(procedurePath)) {
|
|
3502
3528
|
p12.log.error(
|
|
3503
|
-
`Procedure '${procedureSlug}' already exists at ${
|
|
3529
|
+
`Procedure '${procedureSlug}' already exists at ${path20.relative(process.cwd(), procedurePath)}.`
|
|
3504
3530
|
);
|
|
3505
3531
|
process.exit(1);
|
|
3506
3532
|
}
|
|
@@ -3514,8 +3540,8 @@ async function handleGenerateProcedureAction(name, options) {
|
|
|
3514
3540
|
spinner8.start(
|
|
3515
3541
|
`Creating procedure '${procedureSlug}' inside feature '${featureSlug}'...`
|
|
3516
3542
|
);
|
|
3517
|
-
if (await FeatureWorkspace.fileExists(
|
|
3518
|
-
await rm2(
|
|
3543
|
+
if (await FeatureWorkspace.fileExists(path20.join(featureDir, "procedures", ".gitkeep"))) {
|
|
3544
|
+
await rm2(path20.join(featureDir, "procedures", ".gitkeep"));
|
|
3519
3545
|
}
|
|
3520
3546
|
try {
|
|
3521
3547
|
await templateEngine.renderToFile(
|
|
@@ -3548,11 +3574,11 @@ import { Command as Command7 } from "commander";
|
|
|
3548
3574
|
|
|
3549
3575
|
// src/commands/generate/caller/action.ts
|
|
3550
3576
|
import { promises as fs7 } from "fs";
|
|
3551
|
-
import
|
|
3577
|
+
import path21 from "path";
|
|
3552
3578
|
import * as p13 from "@clack/prompts";
|
|
3553
3579
|
import yaml from "js-yaml";
|
|
3554
3580
|
import SwaggerParser from "@apidevtools/swagger-parser";
|
|
3555
|
-
var SUPPORTED_METHODS = ["get", "post", "put", "patch", "delete"];
|
|
3581
|
+
var SUPPORTED_METHODS = ["get", "post", "put", "patch", "delete", "head"];
|
|
3556
3582
|
async function handleGenerateCallerAction(options) {
|
|
3557
3583
|
p13.intro("Generate Igniter Caller");
|
|
3558
3584
|
try {
|
|
@@ -3562,32 +3588,34 @@ async function handleGenerateCallerAction(options) {
|
|
|
3562
3588
|
spinner8.start("Loading OpenAPI spec...");
|
|
3563
3589
|
const parsedDoc = await loadOpenApiDocument(source);
|
|
3564
3590
|
const host = deriveHostname(source, parsedDoc) || "api";
|
|
3565
|
-
const outputDir =
|
|
3591
|
+
const outputDir = path21.resolve(
|
|
3566
3592
|
process.cwd(),
|
|
3567
|
-
options.output ??
|
|
3593
|
+
options.output ?? path21.join("src", "callers", host)
|
|
3568
3594
|
);
|
|
3569
3595
|
const prefix = Casing.toPascalCase(callerName);
|
|
3570
3596
|
const converter = new SchemaConverter(prefix, parsedDoc.components);
|
|
3571
|
-
const pathsCode = buildSchemasObject(parsedDoc, converter);
|
|
3572
3597
|
const componentsCode = converter.renderComponentSchemas();
|
|
3573
|
-
const schemaConstName = `${
|
|
3574
|
-
const schemaTypeName = `${prefix}
|
|
3598
|
+
const schemaConstName = `${Casing.toCamelCase(callerName)}CallerSchemas`;
|
|
3599
|
+
const schemaTypeName = `${prefix}CallerSchemas`;
|
|
3600
|
+
const { builderCode, typeAliases } = buildSchemaBuilder(
|
|
3601
|
+
parsedDoc,
|
|
3602
|
+
converter,
|
|
3603
|
+
schemaConstName
|
|
3604
|
+
);
|
|
3575
3605
|
const schemaFileContents = [
|
|
3576
3606
|
"/* eslint-disable */",
|
|
3577
3607
|
"/* prettier-ignore */",
|
|
3578
|
-
"",
|
|
3579
3608
|
"/**",
|
|
3580
3609
|
" * @generated by @igniter-js/cli",
|
|
3581
3610
|
" * This file was automatically created from your OpenAPI spec.",
|
|
3582
3611
|
" * Do not edit manually; regenerate via `igniter generate caller`.",
|
|
3583
3612
|
" */",
|
|
3584
|
-
"",
|
|
3585
3613
|
'import { z } from "zod";',
|
|
3614
|
+
'import { IgniterCallerSchema } from "@igniter-js/caller";',
|
|
3586
3615
|
componentsCode,
|
|
3587
|
-
|
|
3588
|
-
"",
|
|
3589
|
-
`export const ${schemaConstName} = schemas;`,
|
|
3616
|
+
builderCode,
|
|
3590
3617
|
`export type ${schemaTypeName} = typeof ${schemaConstName};`,
|
|
3618
|
+
typeAliases,
|
|
3591
3619
|
""
|
|
3592
3620
|
].filter(Boolean).join("\n");
|
|
3593
3621
|
const baseUrl = inferBaseUrl(source, parsedDoc);
|
|
@@ -3607,15 +3635,13 @@ async function handleGenerateCallerAction(options) {
|
|
|
3607
3635
|
""
|
|
3608
3636
|
].filter(Boolean).join("\n");
|
|
3609
3637
|
await fs7.mkdir(outputDir, { recursive: true });
|
|
3610
|
-
await fs7.writeFile(
|
|
3611
|
-
await fs7.writeFile(
|
|
3638
|
+
await fs7.writeFile(path21.join(outputDir, "schema.ts"), schemaFileContents, "utf8");
|
|
3639
|
+
await fs7.writeFile(path21.join(outputDir, "index.ts"), callerFileContents, "utf8");
|
|
3612
3640
|
spinner8.stop("Caller generated successfully.");
|
|
3613
3641
|
p13.log.success(
|
|
3614
|
-
`Schemas and caller created at ${
|
|
3615
|
-
);
|
|
3616
|
-
p13.log.info(
|
|
3617
|
-
`Exported caller: ${callerVar} (schemas: ${schemaConstName})`
|
|
3642
|
+
`Schemas and caller created at ${path21.relative(process.cwd(), outputDir)}`
|
|
3618
3643
|
);
|
|
3644
|
+
p13.log.info(`Exported caller: ${callerVar} (schemas: ${schemaConstName})`);
|
|
3619
3645
|
} catch (error) {
|
|
3620
3646
|
const message = error instanceof Error ? error.message : String(error);
|
|
3621
3647
|
p13.log.error(message);
|
|
@@ -3684,13 +3710,12 @@ async function resolveSource(options) {
|
|
|
3684
3710
|
async function loadOpenApiDocument(source) {
|
|
3685
3711
|
const raw = await loadRawContent(source);
|
|
3686
3712
|
const parsed = parseOpenApi(raw);
|
|
3687
|
-
|
|
3713
|
+
const version = parsed.openapi ?? "";
|
|
3714
|
+
if (typeof version !== "string" || !version.startsWith("3.")) {
|
|
3688
3715
|
throw new Error("Only OpenAPI 3.x documents are supported.");
|
|
3689
3716
|
}
|
|
3690
|
-
const
|
|
3691
|
-
|
|
3692
|
-
);
|
|
3693
|
-
return dereferenced;
|
|
3717
|
+
const bundled = await SwaggerParser.bundle(parsed);
|
|
3718
|
+
return bundled;
|
|
3694
3719
|
}
|
|
3695
3720
|
async function loadRawContent(source) {
|
|
3696
3721
|
if (source.type === "url") {
|
|
@@ -3702,7 +3727,7 @@ async function loadRawContent(source) {
|
|
|
3702
3727
|
}
|
|
3703
3728
|
return await response.text();
|
|
3704
3729
|
}
|
|
3705
|
-
const filePath =
|
|
3730
|
+
const filePath = path21.resolve(process.cwd(), source.path);
|
|
3706
3731
|
return await fs7.readFile(filePath, "utf8");
|
|
3707
3732
|
}
|
|
3708
3733
|
function parseOpenApi(content) {
|
|
@@ -3756,15 +3781,34 @@ var SchemaConverter = class {
|
|
|
3756
3781
|
}
|
|
3757
3782
|
renderComponentSchemas() {
|
|
3758
3783
|
const entries = [];
|
|
3759
|
-
const names =
|
|
3784
|
+
const names = this.listComponents();
|
|
3760
3785
|
for (const name of names) {
|
|
3761
3786
|
const identifier = this.componentIdentifier(name);
|
|
3762
3787
|
const expression = this.convertWithCache(name);
|
|
3763
|
-
|
|
3788
|
+
const registryKey = this.registryKey(name);
|
|
3789
|
+
entries.push(
|
|
3790
|
+
[
|
|
3791
|
+
"/**",
|
|
3792
|
+
` * Schema: ${registryKey}`,
|
|
3793
|
+
` * Source: openapi#/components/schemas/${name}`,
|
|
3794
|
+
" */",
|
|
3795
|
+
`const ${identifier} = ${expression};`,
|
|
3796
|
+
""
|
|
3797
|
+
].join("\n")
|
|
3798
|
+
);
|
|
3764
3799
|
}
|
|
3765
3800
|
return entries.length ? `${entries.join("\n")}
|
|
3766
3801
|
` : "";
|
|
3767
3802
|
}
|
|
3803
|
+
listComponents() {
|
|
3804
|
+
return Object.keys(this.components?.schemas ?? {}).sort();
|
|
3805
|
+
}
|
|
3806
|
+
registryKey(name) {
|
|
3807
|
+
return Casing.toPascalCase(name);
|
|
3808
|
+
}
|
|
3809
|
+
componentName(name) {
|
|
3810
|
+
return this.componentIdentifier(name);
|
|
3811
|
+
}
|
|
3768
3812
|
convert(schema) {
|
|
3769
3813
|
if ("$ref" in schema) {
|
|
3770
3814
|
const refName = this.refName(schema.$ref);
|
|
@@ -3772,13 +3816,15 @@ var SchemaConverter = class {
|
|
|
3772
3816
|
this.convertWithCache(refName);
|
|
3773
3817
|
return this.wrapLazyIfNeeded(refName, identifier);
|
|
3774
3818
|
}
|
|
3819
|
+
const schemaType = Array.isArray(schema.type) ? schema.type[0] : schema.type;
|
|
3820
|
+
const nullable = isNullable(schema);
|
|
3775
3821
|
if (schema.oneOf?.length) {
|
|
3776
3822
|
const parts = schema.oneOf.map((item) => this.convert(item));
|
|
3777
|
-
return `z.union([${parts.join(", ")}])
|
|
3823
|
+
return wrapNullable(`z.union([${parts.join(", ")}])`, nullable);
|
|
3778
3824
|
}
|
|
3779
3825
|
if (schema.anyOf?.length) {
|
|
3780
3826
|
const parts = schema.anyOf.map((item) => this.convert(item));
|
|
3781
|
-
return `z.union([${parts.join(", ")}])
|
|
3827
|
+
return wrapNullable(`z.union([${parts.join(", ")}])`, nullable);
|
|
3782
3828
|
}
|
|
3783
3829
|
if (schema.allOf?.length) {
|
|
3784
3830
|
const [first, ...rest] = schema.allOf;
|
|
@@ -3786,31 +3832,29 @@ var SchemaConverter = class {
|
|
|
3786
3832
|
for (const part of rest) {
|
|
3787
3833
|
expr = `z.intersection(${expr}, ${this.convert(part)})`;
|
|
3788
3834
|
}
|
|
3789
|
-
return
|
|
3835
|
+
return wrapNullable(expr, nullable);
|
|
3790
3836
|
}
|
|
3791
|
-
switch (
|
|
3837
|
+
switch (schemaType) {
|
|
3792
3838
|
case "string":
|
|
3793
3839
|
if (schema.enum) {
|
|
3794
3840
|
const values = schema.enum.map((v) => JSON.stringify(String(v)));
|
|
3795
|
-
return `z.enum([${values.join(", ")}])
|
|
3841
|
+
return wrapNullable(`z.enum([${values.join(", ")}])`, nullable);
|
|
3796
3842
|
}
|
|
3797
|
-
return
|
|
3843
|
+
return wrapNullable("z.string()", nullable);
|
|
3798
3844
|
case "number":
|
|
3799
3845
|
case "integer": {
|
|
3800
3846
|
let expr = "z.number()";
|
|
3801
|
-
if (
|
|
3847
|
+
if (schemaType === "integer") {
|
|
3802
3848
|
expr = `${expr}.int()`;
|
|
3803
3849
|
}
|
|
3804
|
-
|
|
3805
|
-
expr = `${expr}.nullable()`;
|
|
3806
|
-
}
|
|
3807
|
-
return expr;
|
|
3850
|
+
return wrapNullable(expr, nullable);
|
|
3808
3851
|
}
|
|
3809
3852
|
case "boolean":
|
|
3810
|
-
return
|
|
3853
|
+
return wrapNullable("z.boolean()", nullable);
|
|
3811
3854
|
case "array": {
|
|
3812
|
-
const
|
|
3813
|
-
|
|
3855
|
+
const arraySchema = schema;
|
|
3856
|
+
const items = arraySchema.items ? this.convert(arraySchema.items) : "z.unknown()";
|
|
3857
|
+
return wrapNullable(`z.array(${items})`, nullable);
|
|
3814
3858
|
}
|
|
3815
3859
|
case "object": {
|
|
3816
3860
|
const properties = schema.properties ?? {};
|
|
@@ -3824,10 +3868,7 @@ var SchemaConverter = class {
|
|
|
3824
3868
|
const apValue = schema.additionalProperties === true ? "z.unknown()" : this.convert(schema.additionalProperties);
|
|
3825
3869
|
base = `${base}.catchall(${apValue})`;
|
|
3826
3870
|
}
|
|
3827
|
-
|
|
3828
|
-
base = `${base}.nullable()`;
|
|
3829
|
-
}
|
|
3830
|
-
return base;
|
|
3871
|
+
return wrapNullable(base, nullable);
|
|
3831
3872
|
}
|
|
3832
3873
|
default:
|
|
3833
3874
|
return "z.unknown()";
|
|
@@ -3848,9 +3889,8 @@ var SchemaConverter = class {
|
|
|
3848
3889
|
this.inProgress.add(name);
|
|
3849
3890
|
const expression = this.convert(schema);
|
|
3850
3891
|
this.inProgress.delete(name);
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
return finalized;
|
|
3892
|
+
this.generated.set(name, expression);
|
|
3893
|
+
return expression;
|
|
3854
3894
|
}
|
|
3855
3895
|
componentIdentifier(name) {
|
|
3856
3896
|
return `${this.prefix}${Casing.toPascalCase(name)}Schema`;
|
|
@@ -3869,71 +3909,271 @@ var SchemaConverter = class {
|
|
|
3869
3909
|
return identifier;
|
|
3870
3910
|
}
|
|
3871
3911
|
};
|
|
3872
|
-
function
|
|
3873
|
-
const
|
|
3912
|
+
function buildSchemaBuilder(doc, converter, schemaConstName) {
|
|
3913
|
+
const usedNames = /* @__PURE__ */ new Map();
|
|
3914
|
+
const operations = [];
|
|
3915
|
+
const pathBlocks = [];
|
|
3916
|
+
let needsVoid = false;
|
|
3874
3917
|
const sortedPaths = Object.keys(doc.paths || {}).sort();
|
|
3875
3918
|
for (const rawPath of sortedPaths) {
|
|
3876
3919
|
const pathItem = doc.paths?.[rawPath];
|
|
3877
3920
|
if (!pathItem) continue;
|
|
3878
|
-
const
|
|
3921
|
+
const methodBlocks = [];
|
|
3879
3922
|
for (const method of SUPPORTED_METHODS) {
|
|
3880
3923
|
const operation = pathItem[method];
|
|
3881
3924
|
if (!operation) continue;
|
|
3882
|
-
const
|
|
3883
|
-
const requestBody = buildRequestBody(
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
const
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3925
|
+
const normalizedPath2 = normalizePath(rawPath);
|
|
3926
|
+
const requestBody = buildRequestBody(
|
|
3927
|
+
operation.requestBody,
|
|
3928
|
+
converter,
|
|
3929
|
+
doc
|
|
3930
|
+
);
|
|
3931
|
+
const responses = buildResponses(operation.responses, converter, doc);
|
|
3932
|
+
const typeBaseName = ensureUniqueTypeName(
|
|
3933
|
+
buildOperationTypeName(rawPath, method, operation.operationId),
|
|
3934
|
+
usedNames
|
|
3935
|
+
);
|
|
3936
|
+
operations.push({
|
|
3937
|
+
path: normalizedPath2,
|
|
3938
|
+
method: method.toUpperCase(),
|
|
3939
|
+
request: Boolean(requestBody),
|
|
3940
|
+
responses: responses.entries,
|
|
3941
|
+
typeName: typeBaseName
|
|
3942
|
+
});
|
|
3943
|
+
const docBlock = buildMethodDocBlock({
|
|
3944
|
+
method: method.toUpperCase(),
|
|
3945
|
+
path: normalizedPath2,
|
|
3946
|
+
summary: operation.summary ?? operation.description,
|
|
3947
|
+
tags: operation.tags,
|
|
3948
|
+
operationId: operation.operationId,
|
|
3949
|
+
requestLabel: requestBody?.label,
|
|
3950
|
+
responses: responses.entries,
|
|
3951
|
+
source: `openapi#/paths/${encodeJsonPointerPath(rawPath)}/${method}`
|
|
3952
|
+
});
|
|
3953
|
+
const methodCall = buildMethodCall(method, {
|
|
3954
|
+
request: requestBody?.expression,
|
|
3955
|
+
responses: responses.code,
|
|
3956
|
+
doc: operation.summary ?? operation.description,
|
|
3957
|
+
tags: operation.tags,
|
|
3958
|
+
operationId: operation.operationId
|
|
3959
|
+
});
|
|
3960
|
+
methodBlocks.push(indent(`${docBlock}
|
|
3961
|
+
${methodCall}`, 3));
|
|
3962
|
+
needsVoid = needsVoid || responses.usesVoid;
|
|
3895
3963
|
}
|
|
3896
|
-
if (!
|
|
3964
|
+
if (!methodBlocks.length) continue;
|
|
3897
3965
|
const normalizedPath = normalizePath(rawPath);
|
|
3898
|
-
const
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
"
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
}
|
|
3966
|
+
const pathLines = [
|
|
3967
|
+
` .path(${JSON.stringify(normalizedPath)}, (path) =>`,
|
|
3968
|
+
" path",
|
|
3969
|
+
methodBlocks.join("\n"),
|
|
3970
|
+
" )"
|
|
3971
|
+
];
|
|
3972
|
+
pathBlocks.push(pathLines.join("\n"));
|
|
3973
|
+
}
|
|
3974
|
+
const builderLines = [];
|
|
3975
|
+
builderLines.push(`export const ${schemaConstName} = IgniterCallerSchema.create()`);
|
|
3976
|
+
const componentNames = converter.listComponents();
|
|
3977
|
+
for (const name of componentNames) {
|
|
3978
|
+
const registryKey = converter.registryKey(name);
|
|
3979
|
+
const identifier = converter.componentName(name);
|
|
3980
|
+
builderLines.push(` .schema(${JSON.stringify(registryKey)}, ${identifier})`);
|
|
3981
|
+
}
|
|
3982
|
+
if (needsVoid) {
|
|
3983
|
+
builderLines.push(` .schema("Void", z.void(), { internal: true })`);
|
|
3984
|
+
}
|
|
3985
|
+
if (pathBlocks.length) {
|
|
3986
|
+
builderLines.push(pathBlocks.join("\n"));
|
|
3987
|
+
}
|
|
3988
|
+
builderLines.push(" .build()");
|
|
3989
|
+
return {
|
|
3990
|
+
builderCode: `${builderLines.join("\n")}
|
|
3991
|
+
`,
|
|
3992
|
+
typeAliases: buildTypeAliases(operations, schemaConstName)
|
|
3993
|
+
};
|
|
3908
3994
|
}
|
|
3909
|
-
function
|
|
3910
|
-
|
|
3911
|
-
|
|
3995
|
+
function buildMethodDocBlock(params) {
|
|
3996
|
+
const lines = [];
|
|
3997
|
+
lines.push("/**");
|
|
3998
|
+
lines.push(` * ${params.method} ${params.path}`);
|
|
3999
|
+
if (params.summary) {
|
|
4000
|
+
lines.push(` * Summary: ${params.summary}`);
|
|
4001
|
+
}
|
|
4002
|
+
if (params.tags?.length) {
|
|
4003
|
+
lines.push(` * Tags: ${params.tags.join(", ")}`);
|
|
4004
|
+
}
|
|
4005
|
+
if (params.operationId) {
|
|
4006
|
+
lines.push(` * OperationId: ${params.operationId}`);
|
|
4007
|
+
}
|
|
4008
|
+
if (params.requestLabel) {
|
|
4009
|
+
lines.push(` * Request: ${params.requestLabel}`);
|
|
4010
|
+
}
|
|
4011
|
+
if (params.responses.length) {
|
|
4012
|
+
lines.push(" * Responses:");
|
|
4013
|
+
for (const response of params.responses) {
|
|
4014
|
+
lines.push(` * - ${response.status}: ${response.label}`);
|
|
4015
|
+
}
|
|
3912
4016
|
}
|
|
4017
|
+
lines.push(` * Source: ${params.source}`);
|
|
4018
|
+
lines.push(" */");
|
|
4019
|
+
return lines.join("\n");
|
|
4020
|
+
}
|
|
4021
|
+
function buildMethodCall(method, params) {
|
|
4022
|
+
const lines = [];
|
|
4023
|
+
lines.push(`.${method}({`);
|
|
4024
|
+
if (params.request) {
|
|
4025
|
+
lines.push(` request: ${params.request},`);
|
|
4026
|
+
}
|
|
4027
|
+
lines.push(" responses: {");
|
|
4028
|
+
lines.push(params.responses);
|
|
4029
|
+
lines.push(" },");
|
|
4030
|
+
if (params.doc) {
|
|
4031
|
+
lines.push(` doc: ${JSON.stringify(params.doc)},`);
|
|
4032
|
+
}
|
|
4033
|
+
if (params.tags?.length) {
|
|
4034
|
+
lines.push(` tags: ${JSON.stringify(params.tags)},`);
|
|
4035
|
+
}
|
|
4036
|
+
if (params.operationId) {
|
|
4037
|
+
lines.push(` operationId: ${JSON.stringify(params.operationId)},`);
|
|
4038
|
+
}
|
|
4039
|
+
lines.push("})");
|
|
4040
|
+
return lines.join("\n");
|
|
4041
|
+
}
|
|
4042
|
+
function buildResponses(responses, converter, doc) {
|
|
4043
|
+
const builder = new CodeBuilder();
|
|
3913
4044
|
const entries = [];
|
|
4045
|
+
let usesVoid = false;
|
|
4046
|
+
if (!responses || !Object.keys(responses).length) {
|
|
4047
|
+
const expression = `path.ref("Void").schema`;
|
|
4048
|
+
builder.line(indent(`200: ${expression},`, 2));
|
|
4049
|
+
entries.push({
|
|
4050
|
+
status: "200",
|
|
4051
|
+
statusLiteral: "200",
|
|
4052
|
+
label: "Void"
|
|
4053
|
+
});
|
|
4054
|
+
return { code: builder.toString(), entries, usesVoid: true };
|
|
4055
|
+
}
|
|
3914
4056
|
const sorted = Object.keys(responses).sort();
|
|
3915
4057
|
for (const status of sorted) {
|
|
3916
4058
|
const responseOrRef = responses[status];
|
|
3917
4059
|
if (!responseOrRef) continue;
|
|
3918
|
-
const
|
|
3919
|
-
const schema = resolveSchemaFromResponse(
|
|
3920
|
-
const
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
4060
|
+
const resolved = resolveResponse(responseOrRef, doc);
|
|
4061
|
+
const schema = resolveSchemaFromResponse(resolved);
|
|
4062
|
+
const resolvedSchema = resolveSchemaExpression(schema, converter);
|
|
4063
|
+
builder.line(indent(`${formatStatusKey(status)}: ${resolvedSchema.expression},`, 2));
|
|
4064
|
+
entries.push({
|
|
4065
|
+
status: String(status),
|
|
4066
|
+
statusLiteral: formatStatusType(status),
|
|
4067
|
+
label: resolvedSchema.label
|
|
4068
|
+
});
|
|
4069
|
+
usesVoid = usesVoid || resolvedSchema.usesVoid;
|
|
3925
4070
|
}
|
|
3926
|
-
return
|
|
3927
|
-
${indentLines(entries.join(",\n"), 2)}
|
|
3928
|
-
}`;
|
|
4071
|
+
return { code: builder.toString(), entries, usesVoid };
|
|
3929
4072
|
}
|
|
3930
|
-
function buildRequestBody(requestBody, converter) {
|
|
4073
|
+
function buildRequestBody(requestBody, converter, doc) {
|
|
3931
4074
|
if (!requestBody) return null;
|
|
3932
|
-
const resolved = "$ref" in requestBody ?
|
|
4075
|
+
const resolved = "$ref" in requestBody ? resolveRequestBody(requestBody, doc) : requestBody;
|
|
3933
4076
|
if (!resolved?.content) return null;
|
|
3934
4077
|
const schema = selectJsonSchema(resolved.content);
|
|
3935
4078
|
if (!schema) return null;
|
|
3936
|
-
return
|
|
4079
|
+
return resolveSchemaExpression(schema, converter);
|
|
4080
|
+
}
|
|
4081
|
+
function resolveSchemaExpression(schema, converter) {
|
|
4082
|
+
if (!schema) {
|
|
4083
|
+
return {
|
|
4084
|
+
expression: `path.ref("Void").schema`,
|
|
4085
|
+
label: "Void",
|
|
4086
|
+
usesVoid: true
|
|
4087
|
+
};
|
|
4088
|
+
}
|
|
4089
|
+
const refName = extractSchemaRef(schema);
|
|
4090
|
+
if (refName) {
|
|
4091
|
+
const registryKey = converter.registryKey(refName);
|
|
4092
|
+
const base = `path.ref(${JSON.stringify(registryKey)}).schema`;
|
|
4093
|
+
return {
|
|
4094
|
+
expression: wrapNullable(base, isNullable(schema)),
|
|
4095
|
+
label: registryKey,
|
|
4096
|
+
usesVoid: false
|
|
4097
|
+
};
|
|
4098
|
+
}
|
|
4099
|
+
const arrayRefName = extractArraySchemaRef(schema);
|
|
4100
|
+
if (arrayRefName) {
|
|
4101
|
+
const registryKey = converter.registryKey(arrayRefName);
|
|
4102
|
+
const base = `path.ref(${JSON.stringify(registryKey)}).array()`;
|
|
4103
|
+
return {
|
|
4104
|
+
expression: wrapNullable(base, isNullable(schema)),
|
|
4105
|
+
label: `${registryKey}[]`,
|
|
4106
|
+
usesVoid: false
|
|
4107
|
+
};
|
|
4108
|
+
}
|
|
4109
|
+
return {
|
|
4110
|
+
expression: converter.convert(schema),
|
|
4111
|
+
label: "InlineSchema",
|
|
4112
|
+
usesVoid: false
|
|
4113
|
+
};
|
|
4114
|
+
}
|
|
4115
|
+
function buildTypeAliases(operations, schemaConstName) {
|
|
4116
|
+
if (!operations.length) return "";
|
|
4117
|
+
const lines = [];
|
|
4118
|
+
lines.push("// Derived types");
|
|
4119
|
+
for (const operation of operations) {
|
|
4120
|
+
const pathLiteral = JSON.stringify(operation.path);
|
|
4121
|
+
const methodLiteral = JSON.stringify(operation.method);
|
|
4122
|
+
if (operation.request) {
|
|
4123
|
+
lines.push(
|
|
4124
|
+
`export type ${operation.typeName}Request = ReturnType<typeof ${schemaConstName}.$Infer.Request<${pathLiteral}, ${methodLiteral}>>;`
|
|
4125
|
+
);
|
|
4126
|
+
}
|
|
4127
|
+
lines.push(
|
|
4128
|
+
`export type ${operation.typeName}Responses = ReturnType<typeof ${schemaConstName}.$Infer.Responses<${pathLiteral}, ${methodLiteral}>>;`
|
|
4129
|
+
);
|
|
4130
|
+
for (const response of operation.responses) {
|
|
4131
|
+
const suffix = formatStatusSuffix(response.status);
|
|
4132
|
+
lines.push(
|
|
4133
|
+
`export type ${operation.typeName}Response${suffix} = ReturnType<typeof ${schemaConstName}.$Infer.Response<${pathLiteral}, ${methodLiteral}, ${response.statusLiteral}>>;`
|
|
4134
|
+
);
|
|
4135
|
+
}
|
|
4136
|
+
lines.push("");
|
|
4137
|
+
}
|
|
4138
|
+
return lines.join("\n");
|
|
4139
|
+
}
|
|
4140
|
+
function buildOperationTypeName(rawPath, method, operationId) {
|
|
4141
|
+
if (operationId) {
|
|
4142
|
+
return Casing.toPascalCase(operationId);
|
|
4143
|
+
}
|
|
4144
|
+
const normalizedPath = normalizePath(rawPath);
|
|
4145
|
+
const segments = normalizedPath.split("/").filter(Boolean).map((segment) => segment.startsWith(":") ? `by-${segment.slice(1)}` : segment);
|
|
4146
|
+
return Casing.toPascalCase([...segments, method].join("-"));
|
|
4147
|
+
}
|
|
4148
|
+
function ensureUniqueTypeName(baseName, used) {
|
|
4149
|
+
const count = used.get(baseName) ?? 0;
|
|
4150
|
+
if (count === 0) {
|
|
4151
|
+
used.set(baseName, 1);
|
|
4152
|
+
return baseName;
|
|
4153
|
+
}
|
|
4154
|
+
const next = `${baseName}${count + 1}`;
|
|
4155
|
+
used.set(baseName, count + 1);
|
|
4156
|
+
return next;
|
|
4157
|
+
}
|
|
4158
|
+
function encodeJsonPointerPath(pathname) {
|
|
4159
|
+
return pathname.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
4160
|
+
}
|
|
4161
|
+
function extractSchemaRef(schema) {
|
|
4162
|
+
if (!schema || typeof schema !== "object") return null;
|
|
4163
|
+
if (!("$ref" in schema)) return null;
|
|
4164
|
+
return extractComponentSchemaName(schema.$ref);
|
|
4165
|
+
}
|
|
4166
|
+
function extractArraySchemaRef(schema) {
|
|
4167
|
+
if (!schema || typeof schema !== "object") return null;
|
|
4168
|
+
if (schema.type !== "array") return null;
|
|
4169
|
+
const items = schema.items;
|
|
4170
|
+
if (!items || typeof items !== "object") return null;
|
|
4171
|
+
if (!("$ref" in items)) return null;
|
|
4172
|
+
return extractComponentSchemaName(items.$ref);
|
|
4173
|
+
}
|
|
4174
|
+
function extractComponentSchemaName(ref) {
|
|
4175
|
+
const match = ref.match(/^#\/components\/schemas\/(.+)$/);
|
|
4176
|
+
return match ? match[1] : null;
|
|
3937
4177
|
}
|
|
3938
4178
|
function selectJsonSchema(content) {
|
|
3939
4179
|
if (content["application/json"]?.schema) {
|
|
@@ -3951,10 +4191,61 @@ function resolveSchemaFromResponse(response) {
|
|
|
3951
4191
|
function normalizePath(pathname) {
|
|
3952
4192
|
return pathname.replace(/{(.*?)}/g, ":$1");
|
|
3953
4193
|
}
|
|
3954
|
-
function
|
|
4194
|
+
function indent(value, depth) {
|
|
3955
4195
|
const pad = " ".repeat(depth);
|
|
3956
4196
|
return value.split("\n").map((line) => line ? pad + line : line).join("\n");
|
|
3957
4197
|
}
|
|
4198
|
+
function isNullable(schema) {
|
|
4199
|
+
if (!schema || typeof schema !== "object") return false;
|
|
4200
|
+
return Boolean(schema.nullable);
|
|
4201
|
+
}
|
|
4202
|
+
function wrapNullable(expr, nullable) {
|
|
4203
|
+
return nullable ? `${expr}.nullable()` : expr;
|
|
4204
|
+
}
|
|
4205
|
+
function formatStatusKey(status) {
|
|
4206
|
+
const trimmed = String(status).trim();
|
|
4207
|
+
const numeric = Number(trimmed);
|
|
4208
|
+
if (!Number.isNaN(numeric) && `${numeric}` === trimmed) {
|
|
4209
|
+
return trimmed;
|
|
4210
|
+
}
|
|
4211
|
+
return JSON.stringify(trimmed);
|
|
4212
|
+
}
|
|
4213
|
+
function formatStatusType(status) {
|
|
4214
|
+
return formatStatusKey(status);
|
|
4215
|
+
}
|
|
4216
|
+
function formatStatusSuffix(status) {
|
|
4217
|
+
const safe = String(status).replace(/[^a-zA-Z0-9]+/g, "-");
|
|
4218
|
+
const pascal = Casing.toPascalCase(safe);
|
|
4219
|
+
return pascal || "Unknown";
|
|
4220
|
+
}
|
|
4221
|
+
function resolveResponse(response, doc) {
|
|
4222
|
+
if ("$ref" in response) {
|
|
4223
|
+
return getComponent(doc, response.$ref, "responses");
|
|
4224
|
+
}
|
|
4225
|
+
return response;
|
|
4226
|
+
}
|
|
4227
|
+
function resolveRequestBody(requestBody, doc) {
|
|
4228
|
+
return getComponent(doc, requestBody.$ref, "requestBodies");
|
|
4229
|
+
}
|
|
4230
|
+
function getComponent(doc, ref, type) {
|
|
4231
|
+
const match = ref.match(/^#\/components\/([^/]+)\/(.+)$/);
|
|
4232
|
+
if (!match) return void 0;
|
|
4233
|
+
const [, category, name] = match;
|
|
4234
|
+
if (category !== type) return void 0;
|
|
4235
|
+
const component = doc.components?.[type]?.[name];
|
|
4236
|
+
return component;
|
|
4237
|
+
}
|
|
4238
|
+
var CodeBuilder = class {
|
|
4239
|
+
constructor() {
|
|
4240
|
+
this.lines = [];
|
|
4241
|
+
}
|
|
4242
|
+
line(text4) {
|
|
4243
|
+
this.lines.push(text4);
|
|
4244
|
+
}
|
|
4245
|
+
toString() {
|
|
4246
|
+
return this.lines.join("\n");
|
|
4247
|
+
}
|
|
4248
|
+
};
|
|
3958
4249
|
|
|
3959
4250
|
// src/commands/generate/caller/index.ts
|
|
3960
4251
|
var callerCommand = new Command7().command("caller").description("Generate Igniter Caller schemas from an OpenAPI spec").option("--name <name>", "Name used to prefix generated schemas and caller export").option("--url <url>", "URL to the OpenAPI document").option("--path <path>", "Local path to the OpenAPI document").option(
|
|
@@ -3969,7 +4260,7 @@ var generateCommand = new Command8().command("generate").description("Scaffold n
|
|
|
3969
4260
|
import { Command as Command9 } from "commander";
|
|
3970
4261
|
|
|
3971
4262
|
// src/commands/dev/action.ts
|
|
3972
|
-
import * as
|
|
4263
|
+
import * as path22 from "path";
|
|
3973
4264
|
import * as fs8 from "fs";
|
|
3974
4265
|
import { spawn as spawn2 } from "child_process";
|
|
3975
4266
|
import chokidar from "chokidar";
|
|
@@ -4074,7 +4365,7 @@ async function regenerateSchemaAndDocs(routerPath, outputPath, docsOutputDir, ad
|
|
|
4074
4365
|
}
|
|
4075
4366
|
async function handleDevAction(options) {
|
|
4076
4367
|
const packageManager = detectPackageManager();
|
|
4077
|
-
const routerPath =
|
|
4368
|
+
const routerPath = path22.resolve(process.cwd(), options.router || "src/igniter.router.ts");
|
|
4078
4369
|
const outputPath = options.output || "src/igniter.schema.ts";
|
|
4079
4370
|
const docsOutputDir = options.docsOutput || "./src/docs";
|
|
4080
4371
|
const devCommand2 = options.cmd || getDefaultDevCommand(packageManager);
|
|
@@ -4125,7 +4416,7 @@ async function handleDevAction(options) {
|
|
|
4125
4416
|
});
|
|
4126
4417
|
process.exit(1);
|
|
4127
4418
|
}
|
|
4128
|
-
const featuresDir =
|
|
4419
|
+
const featuresDir = path22.join(process.cwd(), "src", "features");
|
|
4129
4420
|
const watchPaths = [
|
|
4130
4421
|
routerPath,
|
|
4131
4422
|
// Watch router file directly
|
|
@@ -4142,7 +4433,7 @@ async function handleDevAction(options) {
|
|
|
4142
4433
|
}
|
|
4143
4434
|
addIgniterLog({
|
|
4144
4435
|
type: "info",
|
|
4145
|
-
message: `Watching for changes in: ${watchPaths.map((p14) =>
|
|
4436
|
+
message: `Watching for changes in: ${watchPaths.map((p14) => path22.relative(process.cwd(), p14)).join(", ")}`,
|
|
4146
4437
|
timestamp: /* @__PURE__ */ new Date()
|
|
4147
4438
|
});
|
|
4148
4439
|
let regenerateTimeout = null;
|
|
@@ -4162,7 +4453,7 @@ async function handleDevAction(options) {
|
|
|
4162
4453
|
ignoreInitial: true
|
|
4163
4454
|
});
|
|
4164
4455
|
watcher.on("change", (filePath) => {
|
|
4165
|
-
const relativePath =
|
|
4456
|
+
const relativePath = path22.relative(process.cwd(), filePath);
|
|
4166
4457
|
if (regenerateTimeout) {
|
|
4167
4458
|
clearTimeout(regenerateTimeout);
|
|
4168
4459
|
}
|