rtgl 1.4.0 → 2.0.1
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/cli.js +412 -31
- package/package.json +4 -4
package/cli.js
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { build, check, scaffold, watch, examples } from "@rettangoli/fe/cli";
|
|
4
|
-
import { check as checkContracts } from "@rettangoli/check/cli";
|
|
5
|
-
import { build as buildBe, check as checkBe, start as startBe, watch as watchBe } from "@rettangoli/be/cli";
|
|
6
|
-
import { generate, screenshot, report, accept } from "@rettangoli/vt/cli";
|
|
7
|
-
import { buildSite, watchSite, initSite } from "@rettangoli/sites/cli";
|
|
8
|
-
import { buildSvg } from "@rettangoli/ui/cli";
|
|
9
3
|
import { Command, InvalidArgumentError } from "commander";
|
|
10
4
|
import { readFileSync, existsSync } from "fs";
|
|
11
5
|
import { resolve } from "path";
|
|
@@ -15,6 +9,91 @@ const packageJson = JSON.parse(
|
|
|
15
9
|
readFileSync(new URL("./package.json", import.meta.url)),
|
|
16
10
|
);
|
|
17
11
|
|
|
12
|
+
const requestedCommand = process.argv[2];
|
|
13
|
+
|
|
14
|
+
let build;
|
|
15
|
+
let check;
|
|
16
|
+
let scaffold;
|
|
17
|
+
let watch;
|
|
18
|
+
let examples;
|
|
19
|
+
let checkContracts;
|
|
20
|
+
let generate;
|
|
21
|
+
let screenshot;
|
|
22
|
+
let report;
|
|
23
|
+
let accept;
|
|
24
|
+
let buildSite;
|
|
25
|
+
let watchSite;
|
|
26
|
+
let initSite;
|
|
27
|
+
let buildSvg;
|
|
28
|
+
let appBe;
|
|
29
|
+
let buildBe;
|
|
30
|
+
let checkBe;
|
|
31
|
+
let compatBe;
|
|
32
|
+
let dbBe;
|
|
33
|
+
let initBe;
|
|
34
|
+
let manifestBe;
|
|
35
|
+
let resumeBe;
|
|
36
|
+
let scaffoldBe;
|
|
37
|
+
let startBe;
|
|
38
|
+
let testBe;
|
|
39
|
+
let verifyBe;
|
|
40
|
+
let watchBe;
|
|
41
|
+
let loadBeRuntimeConfig;
|
|
42
|
+
|
|
43
|
+
if (requestedCommand === "fe") {
|
|
44
|
+
({ build, check, scaffold, watch, examples } = await import(
|
|
45
|
+
"@rettangoli/fe/cli",
|
|
46
|
+
));
|
|
47
|
+
} else if (requestedCommand === "check") {
|
|
48
|
+
({ check: checkContracts } = await import("@rettangoli/check/cli"));
|
|
49
|
+
} else if (requestedCommand === "vt") {
|
|
50
|
+
({ generate, screenshot, report, accept } = await import("@rettangoli/vt/cli"));
|
|
51
|
+
} else if (requestedCommand === "sites") {
|
|
52
|
+
({ buildSite, watchSite, initSite } = await import("@rettangoli/sites/cli"));
|
|
53
|
+
} else if (requestedCommand === "ui") {
|
|
54
|
+
({ buildSvg } = await import("@rettangoli/ui/cli"));
|
|
55
|
+
} else if (requestedCommand === "be") {
|
|
56
|
+
const localBeCliUrl = new URL("../rettangoli-be/src/cli/index.js", import.meta.url);
|
|
57
|
+
const beCli = existsSync(localBeCliUrl)
|
|
58
|
+
? await import(localBeCliUrl)
|
|
59
|
+
: await import("@rettangoli/be/cli");
|
|
60
|
+
|
|
61
|
+
({
|
|
62
|
+
app: appBe,
|
|
63
|
+
build: buildBe,
|
|
64
|
+
check: checkBe,
|
|
65
|
+
compat: compatBe,
|
|
66
|
+
db: dbBe,
|
|
67
|
+
init: initBe,
|
|
68
|
+
manifest: manifestBe,
|
|
69
|
+
resume: resumeBe,
|
|
70
|
+
scaffold: scaffoldBe,
|
|
71
|
+
start: startBe,
|
|
72
|
+
test: testBe,
|
|
73
|
+
verify: verifyBe,
|
|
74
|
+
watch: watchBe,
|
|
75
|
+
} = beCli);
|
|
76
|
+
|
|
77
|
+
const localBeRuntimeConfigUrl = new URL(
|
|
78
|
+
"../rettangoli-be/src/runtime/loadBeProjectConfig.js",
|
|
79
|
+
import.meta.url,
|
|
80
|
+
);
|
|
81
|
+
const beRuntimeConfig = existsSync(localBeRuntimeConfigUrl)
|
|
82
|
+
? await import(localBeRuntimeConfigUrl)
|
|
83
|
+
: await import("@rettangoli/be/runtime/loadBeProjectConfig");
|
|
84
|
+
({ loadBeProjectConfig: loadBeRuntimeConfig } = beRuntimeConfig);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function requireBeCommand(handler, name) {
|
|
88
|
+
if (typeof handler !== "function") {
|
|
89
|
+
throw new Error(
|
|
90
|
+
`@rettangoli/be/cli does not export '${name}'. Reinstall @rettangoli/be at the version required by rettangoli-cli.`,
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return handler;
|
|
95
|
+
}
|
|
96
|
+
|
|
18
97
|
// Function to read config file
|
|
19
98
|
function readConfig() {
|
|
20
99
|
const configPath = resolve(process.cwd(), "rettangoli.config.yaml");
|
|
@@ -66,16 +145,105 @@ function parseIsolationOption(value) {
|
|
|
66
145
|
function resolveBeRuntimePaths(config) {
|
|
67
146
|
const be = config?.be || {};
|
|
68
147
|
const dirs = Array.isArray(be.dirs) && be.dirs.length > 0 ? be.dirs : ["./src/modules"];
|
|
148
|
+
const runtimeConfig = loadBeRuntimeConfig({ cwd: process.cwd() });
|
|
69
149
|
|
|
70
150
|
return {
|
|
71
151
|
dirs,
|
|
72
152
|
middlewareDir: be.middlewareDir || "./src/middleware",
|
|
73
153
|
setup: be.setup || "./src/setup.js",
|
|
74
154
|
outdir: be.outdir || "./.rtgl-be/generated",
|
|
155
|
+
migrationsDir: be.migrationsDir || "./migrations",
|
|
75
156
|
domainErrors: be.domainErrors || {},
|
|
157
|
+
globalMiddleware: runtimeConfig.globalMiddleware,
|
|
76
158
|
};
|
|
77
159
|
}
|
|
78
160
|
|
|
161
|
+
function wantsJsonOutput(options) {
|
|
162
|
+
return options?.json === true || options?.format === "json";
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function writeBeCliError({ command, options, ruleId = "RTGL-BE-CLI-001", message }) {
|
|
166
|
+
if (!wantsJsonOutput(options)) {
|
|
167
|
+
throw new Error(message);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
console.log(JSON.stringify({
|
|
171
|
+
schemaVersion: "rettangoli.cliResult/v1",
|
|
172
|
+
command,
|
|
173
|
+
artifactSchemaVersion: "rettangoli.cliError/v1",
|
|
174
|
+
ok: false,
|
|
175
|
+
diagnostics: [
|
|
176
|
+
{
|
|
177
|
+
schemaVersion: "rettangoli.diagnostic/v1",
|
|
178
|
+
ruleId,
|
|
179
|
+
code: ruleId,
|
|
180
|
+
severity: "error",
|
|
181
|
+
phase: "cli",
|
|
182
|
+
message,
|
|
183
|
+
},
|
|
184
|
+
],
|
|
185
|
+
}, null, 2));
|
|
186
|
+
process.exitCode = 1;
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function requireBeConfig(command, options) {
|
|
191
|
+
let config;
|
|
192
|
+
try {
|
|
193
|
+
config = readConfig();
|
|
194
|
+
} catch (error) {
|
|
195
|
+
return writeBeCliError({
|
|
196
|
+
command,
|
|
197
|
+
options,
|
|
198
|
+
ruleId: "RTGL-BE-CLI-003",
|
|
199
|
+
message: error.message,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (config) {
|
|
204
|
+
return config;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return writeBeCliError({
|
|
208
|
+
command,
|
|
209
|
+
options,
|
|
210
|
+
message: "rettangoli.config.yaml not found",
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function readOptionalBeConfig(command, options) {
|
|
215
|
+
try {
|
|
216
|
+
return {
|
|
217
|
+
ok: true,
|
|
218
|
+
config: readConfig(),
|
|
219
|
+
};
|
|
220
|
+
} catch (error) {
|
|
221
|
+
writeBeCliError({
|
|
222
|
+
command,
|
|
223
|
+
options,
|
|
224
|
+
ruleId: "RTGL-BE-CLI-003",
|
|
225
|
+
message: error.message,
|
|
226
|
+
});
|
|
227
|
+
return {
|
|
228
|
+
ok: false,
|
|
229
|
+
config: null,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function resolveBeRuntimePathsOrReport(command, options, config) {
|
|
235
|
+
try {
|
|
236
|
+
return resolveBeRuntimePaths(config);
|
|
237
|
+
} catch (error) {
|
|
238
|
+
return writeBeCliError({
|
|
239
|
+
command,
|
|
240
|
+
options,
|
|
241
|
+
ruleId: "RTGL-BE-CLI-003",
|
|
242
|
+
message: error.message,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
79
247
|
const program = new Command();
|
|
80
248
|
|
|
81
249
|
program
|
|
@@ -150,7 +318,7 @@ Examples:
|
|
|
150
318
|
$ rettangoli fe build --setup-path src/setup.web.js
|
|
151
319
|
`,
|
|
152
320
|
)
|
|
153
|
-
.action((options) => {
|
|
321
|
+
.action(async (options) => {
|
|
154
322
|
const config = readConfig();
|
|
155
323
|
|
|
156
324
|
if (!config) {
|
|
@@ -180,7 +348,7 @@ Examples:
|
|
|
180
348
|
options.outfile = config.fe.outfile;
|
|
181
349
|
}
|
|
182
350
|
|
|
183
|
-
build(options);
|
|
351
|
+
await build(options);
|
|
184
352
|
});
|
|
185
353
|
|
|
186
354
|
feCommand
|
|
@@ -261,7 +429,7 @@ Examples:
|
|
|
261
429
|
$ rettangoli fe watch --setup-path src/setup.web.js
|
|
262
430
|
`,
|
|
263
431
|
)
|
|
264
|
-
.action((options) => {
|
|
432
|
+
.action(async (options) => {
|
|
265
433
|
const config = readConfig();
|
|
266
434
|
|
|
267
435
|
if (!config) {
|
|
@@ -291,7 +459,7 @@ Examples:
|
|
|
291
459
|
options.outfile = config.fe.outfile;
|
|
292
460
|
}
|
|
293
461
|
|
|
294
|
-
watch(options);
|
|
462
|
+
await watch(options);
|
|
295
463
|
});
|
|
296
464
|
|
|
297
465
|
feCommand
|
|
@@ -306,33 +474,57 @@ feCommand
|
|
|
306
474
|
|
|
307
475
|
const beCommand = program.command("be").description("Backend framework");
|
|
308
476
|
|
|
477
|
+
beCommand
|
|
478
|
+
.command("init")
|
|
479
|
+
.description("Initialize a minimal backend app")
|
|
480
|
+
.option("--method <method>", "Initial method id", "health.ping")
|
|
481
|
+
.option("--dir <path>", "Backend method directory to create under")
|
|
482
|
+
.option("--dry-run", "Print the init plan without writing files")
|
|
483
|
+
.option("--check", "Alias for --dry-run")
|
|
484
|
+
.option("--json", "Output JSON")
|
|
485
|
+
.action((options) => {
|
|
486
|
+
options.dirs = options.dir || "./src/modules";
|
|
487
|
+
if (options.json) options.format = "json";
|
|
488
|
+
requireBeCommand(initBe, "init")(options);
|
|
489
|
+
});
|
|
490
|
+
|
|
309
491
|
beCommand
|
|
310
492
|
.command("build")
|
|
311
493
|
.description("Build backend method registry and app entry")
|
|
494
|
+
.option("--dir <path>", "Backend method directory to scan (repeatable)", collectValues, [])
|
|
312
495
|
.option("-s, --setup-path <path>", "Custom setup file path")
|
|
313
496
|
.option("-m, --middleware-dir <path>", "Custom middleware directory path")
|
|
314
497
|
.option("-o, --outdir <path>", "Generated output directory")
|
|
498
|
+
.option("--dry-run", "Print the deterministic build plan without writing files")
|
|
499
|
+
.option("--check", "Check whether generated files are fresh")
|
|
500
|
+
.option("--json", "Output JSON")
|
|
315
501
|
.action((options) => {
|
|
316
|
-
const config =
|
|
317
|
-
|
|
318
|
-
if (!config) {
|
|
319
|
-
throw new Error("rettangoli.config.yaml not found");
|
|
320
|
-
}
|
|
502
|
+
const config = requireBeConfig("be build", options);
|
|
503
|
+
if (!config) return;
|
|
321
504
|
|
|
322
|
-
const bePaths =
|
|
505
|
+
const bePaths = resolveBeRuntimePathsOrReport("be build", options, config);
|
|
506
|
+
if (!bePaths) return;
|
|
323
507
|
|
|
324
|
-
const
|
|
508
|
+
const selectedDirs = options.dir.length > 0 ? options.dir : bePaths.dirs;
|
|
509
|
+
const missingDirs = selectedDirs.filter(
|
|
325
510
|
(dir) => !existsSync(resolve(process.cwd(), dir)),
|
|
326
511
|
);
|
|
327
512
|
if (missingDirs.length > 0) {
|
|
328
|
-
|
|
513
|
+
writeBeCliError({
|
|
514
|
+
command: "be build",
|
|
515
|
+
options,
|
|
516
|
+
ruleId: "RTGL-BE-CLI-004",
|
|
517
|
+
message: `Directories do not exist: ${missingDirs.join(", ")}`,
|
|
518
|
+
});
|
|
519
|
+
return;
|
|
329
520
|
}
|
|
330
521
|
|
|
331
|
-
options.dirs =
|
|
522
|
+
options.dirs = selectedDirs;
|
|
332
523
|
options.middlewareDir = options.middlewareDir || bePaths.middlewareDir;
|
|
333
524
|
options.setup = options.setupPath || bePaths.setup;
|
|
334
525
|
options.outdir = options.outdir || bePaths.outdir;
|
|
335
526
|
options.domainErrors = bePaths.domainErrors;
|
|
527
|
+
if (options.json) options.format = "json";
|
|
336
528
|
|
|
337
529
|
buildBe(options);
|
|
338
530
|
});
|
|
@@ -341,27 +533,216 @@ beCommand
|
|
|
341
533
|
.command("check")
|
|
342
534
|
.description("Validate backend RPC contracts")
|
|
343
535
|
.option("--format <format>", "Output format: text or json", "text")
|
|
536
|
+
.option("--json", "Output JSON")
|
|
537
|
+
.option("--dir <path>", "Backend method directory to scan (repeatable)", collectValues, [])
|
|
538
|
+
.option("--method <method>", "Validate one backend method id")
|
|
344
539
|
.option("-m, --middleware-dir <path>", "Custom middleware directory path")
|
|
345
540
|
.action((options) => {
|
|
346
|
-
const config =
|
|
541
|
+
const config = requireBeConfig("be check", options);
|
|
542
|
+
if (!config) return;
|
|
347
543
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
}
|
|
544
|
+
const bePaths = resolveBeRuntimePathsOrReport("be check", options, config);
|
|
545
|
+
if (!bePaths) return;
|
|
351
546
|
|
|
352
|
-
|
|
547
|
+
options.dirs = options.dir.length > 0 ? options.dir : bePaths.dirs;
|
|
548
|
+
options.middlewareDir = options.middlewareDir || bePaths.middlewareDir;
|
|
549
|
+
if (options.json) options.format = "json";
|
|
353
550
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
551
|
+
checkBe(options);
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
beCommand
|
|
555
|
+
.command("manifest")
|
|
556
|
+
.description("Print deterministic backend API manifest")
|
|
557
|
+
.option("--json", "Output JSON")
|
|
558
|
+
.option("--dir <path>", "Backend method directory to scan (repeatable)", collectValues, [])
|
|
559
|
+
.option("--method <method>", "Print manifest for one backend method id")
|
|
560
|
+
.option("-m, --middleware-dir <path>", "Custom middleware directory path")
|
|
561
|
+
.option("--outdir <path>", "Generated output directory used for target facts")
|
|
562
|
+
.option("--migrations-dir <path>", "SQLite migrations directory")
|
|
563
|
+
.option("-o, --output <path>", "Write manifest JSON to a file")
|
|
564
|
+
.action((options) => {
|
|
565
|
+
const config = requireBeConfig("be manifest", options);
|
|
566
|
+
if (!config) return;
|
|
567
|
+
|
|
568
|
+
const bePaths = resolveBeRuntimePathsOrReport("be manifest", options, config);
|
|
569
|
+
if (!bePaths) return;
|
|
570
|
+
|
|
571
|
+
options.dirs = options.dir.length > 0 ? options.dir : bePaths.dirs;
|
|
572
|
+
options.middlewareDir = options.middlewareDir || bePaths.middlewareDir;
|
|
573
|
+
options.outdir = options.outdir || bePaths.outdir;
|
|
574
|
+
options.migrationsDir = options.migrationsDir || bePaths.migrationsDir;
|
|
575
|
+
|
|
576
|
+
requireBeCommand(manifestBe, "manifest")(options);
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
beCommand
|
|
580
|
+
.command("compat")
|
|
581
|
+
.description("Compare two backend manifests for API compatibility")
|
|
582
|
+
.option("--from <path>", "Previous manifest JSON")
|
|
583
|
+
.option("--to <path>", "Current manifest JSON")
|
|
584
|
+
.option("--json", "Output JSON")
|
|
585
|
+
.action((options) => {
|
|
586
|
+
if (options.json) options.format = "json";
|
|
587
|
+
if (!options.from || !options.to) {
|
|
588
|
+
writeBeCliError({
|
|
589
|
+
command: "be compat",
|
|
590
|
+
options,
|
|
591
|
+
ruleId: "RTGL-BE-CLI-002",
|
|
592
|
+
message: "be compat requires --from and --to manifest JSON files.",
|
|
593
|
+
});
|
|
594
|
+
return;
|
|
359
595
|
}
|
|
596
|
+
requireBeCommand(compatBe, "compat")(options);
|
|
597
|
+
});
|
|
360
598
|
|
|
361
|
-
|
|
599
|
+
beCommand
|
|
600
|
+
.command("test")
|
|
601
|
+
.description("Run backend executable examples")
|
|
602
|
+
.option("--format <format>", "Output format: text or json", "text")
|
|
603
|
+
.option("--json", "Output JSON")
|
|
604
|
+
.option("--dir <path>", "Backend method directory to scan (repeatable)", collectValues, [])
|
|
605
|
+
.option("--method <method>", "Run examples for one backend method id")
|
|
606
|
+
.option("-s, --setup-path <path>", "Custom setup file path")
|
|
607
|
+
.option("-m, --middleware-dir <path>", "Custom middleware directory path")
|
|
608
|
+
.option("--config <path>", "Vitest config path", "./vitest.config.js")
|
|
609
|
+
.option("--test-config <path>", "Alias for --config")
|
|
610
|
+
.option("--package-manager <name>", "Package manager for running Vitest: npm, pnpm, yarn, bun")
|
|
611
|
+
.option("--runner <command>", "Executable used to run Vitest")
|
|
612
|
+
.action((options) => {
|
|
613
|
+
const config = requireBeConfig("be test", options);
|
|
614
|
+
if (!config) return;
|
|
615
|
+
|
|
616
|
+
const bePaths = resolveBeRuntimePathsOrReport("be test", options, config);
|
|
617
|
+
if (!bePaths) return;
|
|
618
|
+
|
|
619
|
+
options.dirs = options.dir.length > 0 ? options.dir : bePaths.dirs;
|
|
362
620
|
options.middlewareDir = options.middlewareDir || bePaths.middlewareDir;
|
|
621
|
+
options.setup = options.setupPath || bePaths.setup;
|
|
622
|
+
options.globalMiddlewareBefore = bePaths.globalMiddleware.before;
|
|
623
|
+
options.globalMiddlewareAfter = bePaths.globalMiddleware.after;
|
|
624
|
+
options.config = options.testConfig || options.config;
|
|
625
|
+
options.executable = options.runner;
|
|
626
|
+
if (options.json) options.format = "json";
|
|
363
627
|
|
|
364
|
-
|
|
628
|
+
requireBeCommand(testBe, "test")(options);
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
beCommand
|
|
632
|
+
.command("verify")
|
|
633
|
+
.description("Run backend check, build, manifest, and examples")
|
|
634
|
+
.option("--format <format>", "Output format: text or json", "text")
|
|
635
|
+
.option("--json", "Output JSON")
|
|
636
|
+
.option("--dir <path>", "Backend method directory to scan (repeatable)", collectValues, [])
|
|
637
|
+
.option("--method <method>", "Verify one backend method id")
|
|
638
|
+
.option("-s, --setup-path <path>", "Custom setup file path")
|
|
639
|
+
.option("-m, --middleware-dir <path>", "Custom middleware directory path")
|
|
640
|
+
.option("-o, --outdir <path>", "Generated output directory")
|
|
641
|
+
.option("--migrations-dir <path>", "SQLite migrations directory")
|
|
642
|
+
.option("--fail-on-warnings", "Return non-zero when warnings are present")
|
|
643
|
+
.option("--evidence <taskId>", "Write verification evidence under .rtgl-be/evidence")
|
|
644
|
+
.option("--task-id <taskId>", "Task id for verification evidence")
|
|
645
|
+
.option("--config <path>", "Alias for --test-config")
|
|
646
|
+
.option("--test-config <path>", "Vitest config path", "./vitest.config.js")
|
|
647
|
+
.option("--package-manager <name>", "Package manager for running Vitest: npm, pnpm, yarn, bun")
|
|
648
|
+
.option("--runner <command>", "Executable used to run Vitest")
|
|
649
|
+
.action(async (options) => {
|
|
650
|
+
const config = requireBeConfig("be verify", options);
|
|
651
|
+
if (!config) return;
|
|
652
|
+
|
|
653
|
+
const bePaths = resolveBeRuntimePathsOrReport("be verify", options, config);
|
|
654
|
+
if (!bePaths) return;
|
|
655
|
+
|
|
656
|
+
options.dirs = options.dir.length > 0 ? options.dir : bePaths.dirs;
|
|
657
|
+
options.middlewareDir = options.middlewareDir || bePaths.middlewareDir;
|
|
658
|
+
options.setup = options.setupPath || bePaths.setup;
|
|
659
|
+
options.outdir = options.outdir || bePaths.outdir;
|
|
660
|
+
options.migrationsDir = options.migrationsDir || bePaths.migrationsDir;
|
|
661
|
+
options.failOnWarnings = !!options.failOnWarnings;
|
|
662
|
+
options.globalMiddlewareBefore = bePaths.globalMiddleware.before;
|
|
663
|
+
options.globalMiddlewareAfter = bePaths.globalMiddleware.after;
|
|
664
|
+
options.testConfig = options.config || options.testConfig;
|
|
665
|
+
options.executable = options.runner;
|
|
666
|
+
if (options.json) options.format = "json";
|
|
667
|
+
|
|
668
|
+
await requireBeCommand(verifyBe, "verify")(options);
|
|
669
|
+
});
|
|
670
|
+
|
|
671
|
+
const beAppCommand = beCommand.command("app").description("Backend app runtime checks");
|
|
672
|
+
|
|
673
|
+
beAppCommand
|
|
674
|
+
.command("check")
|
|
675
|
+
.description("Import setup, handlers, middleware, and instantiate the backend app")
|
|
676
|
+
.option("--json", "Output JSON")
|
|
677
|
+
.option("--dir <path>", "Backend method directory to scan (repeatable)", collectValues, [])
|
|
678
|
+
.option("--method <method>", "Check one backend method id")
|
|
679
|
+
.option("-s, --setup-path <path>", "Custom setup file path")
|
|
680
|
+
.option("-m, --middleware-dir <path>", "Custom middleware directory path")
|
|
681
|
+
.action(async (options) => {
|
|
682
|
+
const config = requireBeConfig("be app check", options);
|
|
683
|
+
if (!config) return;
|
|
684
|
+
const bePaths = resolveBeRuntimePathsOrReport("be app check", options, config);
|
|
685
|
+
if (!bePaths) return;
|
|
686
|
+
|
|
687
|
+
options.dirs = options.dir.length > 0 ? options.dir : bePaths.dirs;
|
|
688
|
+
options.middlewareDir = options.middlewareDir || bePaths.middlewareDir;
|
|
689
|
+
options.setup = options.setupPath || bePaths.setup;
|
|
690
|
+
options.globalMiddlewareBefore = bePaths.globalMiddleware.before;
|
|
691
|
+
options.globalMiddlewareAfter = bePaths.globalMiddleware.after;
|
|
692
|
+
if (options.json) options.format = "json";
|
|
693
|
+
|
|
694
|
+
await requireBeCommand(appBe, "app")(options);
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
beCommand
|
|
698
|
+
.command("scaffold [methodId]")
|
|
699
|
+
.description("Scaffold a backend method package")
|
|
700
|
+
.option("--method <method>", "Backend method id, e.g. user.getProfile")
|
|
701
|
+
.option("--dir <path>", "Backend method directory to create under")
|
|
702
|
+
.option("--dry-run", "Print the scaffold plan without writing files")
|
|
703
|
+
.option("--check", "Alias for --dry-run")
|
|
704
|
+
.option("--json", "Output JSON")
|
|
705
|
+
.action((methodId, options) => {
|
|
706
|
+
const configResult = readOptionalBeConfig("be scaffold", options);
|
|
707
|
+
if (!configResult.ok) return;
|
|
708
|
+
const bePaths = resolveBeRuntimePathsOrReport("be scaffold", options, configResult.config);
|
|
709
|
+
if (!bePaths) return;
|
|
710
|
+
|
|
711
|
+
options.methodId = options.method || methodId;
|
|
712
|
+
options.dirs = options.dir || bePaths.dirs[0] || "./src/modules";
|
|
713
|
+
if (options.json) options.format = "json";
|
|
714
|
+
requireBeCommand(scaffoldBe, "scaffold")(options);
|
|
715
|
+
});
|
|
716
|
+
|
|
717
|
+
const beDbCommand = beCommand.command("db").description("SQLite backend database checks");
|
|
718
|
+
|
|
719
|
+
beDbCommand
|
|
720
|
+
.command("check")
|
|
721
|
+
.description("Validate and replay SQLite migrations")
|
|
722
|
+
.option("--json", "Output JSON")
|
|
723
|
+
.option("--migrations-dir <path>", "SQLite migrations directory")
|
|
724
|
+
.option("--fail-on-warnings", "Return non-zero when warnings are present")
|
|
725
|
+
.action((options) => {
|
|
726
|
+
const configResult = readOptionalBeConfig("be db check", options);
|
|
727
|
+
if (!configResult.ok) return;
|
|
728
|
+
const bePaths = resolveBeRuntimePathsOrReport("be db check", options, configResult.config);
|
|
729
|
+
if (!bePaths) return;
|
|
730
|
+
|
|
731
|
+
options.migrationsDir = options.migrationsDir || bePaths.migrationsDir;
|
|
732
|
+
options.failOnWarnings = !!options.failOnWarnings;
|
|
733
|
+
if (options.json) options.format = "json";
|
|
734
|
+
|
|
735
|
+
requireBeCommand(dbBe, "db")(options);
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
beCommand
|
|
739
|
+
.command("resume <taskId>")
|
|
740
|
+
.description("Resume a backend verification task anchor")
|
|
741
|
+
.option("--json", "Output JSON")
|
|
742
|
+
.action((taskId, options) => {
|
|
743
|
+
options.taskId = taskId;
|
|
744
|
+
if (options.json) options.format = "json";
|
|
745
|
+
requireBeCommand(resumeBe, "resume")(options);
|
|
365
746
|
});
|
|
366
747
|
|
|
367
748
|
beCommand
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rtgl",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "CLI tool for Rettangoli - A frontend framework and development toolkit",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"homepage": "https://rettangoli.dev/",
|
|
40
40
|
"engines": {
|
|
41
|
-
"node": "
|
|
41
|
+
"node": "^20.19.0 || >=22.12.0"
|
|
42
42
|
},
|
|
43
43
|
"publishConfig": {
|
|
44
44
|
"access": "public",
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
"commander": "^14.0.0",
|
|
49
49
|
"js-yaml": "^4.1.0",
|
|
50
50
|
"@rettangoli/check": "0.1.2",
|
|
51
|
-
"@rettangoli/be": "
|
|
52
|
-
"@rettangoli/fe": "1.2.
|
|
51
|
+
"@rettangoli/be": "2.0.0",
|
|
52
|
+
"@rettangoli/fe": "1.2.1",
|
|
53
53
|
"@rettangoli/sites": "1.2.0",
|
|
54
54
|
"@rettangoli/vt": "1.0.5",
|
|
55
55
|
"@rettangoli/ui": "1.4.2"
|