mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
perf(cli): prepare positional token schemas only for the selected command
This commit is contained in:
1 parent
cc18e9ad0d
commit
315b23403f
2 files changed
+49
-10
No files matched your search
@@ -62,20 +62,25 @@ export const rejectSurplusCliArguments = (
|
||||
if (final !== undefined && tokenType(final) instanceof z.ZodArray) return;
|
||||
let tail = "__rea_unbound_positionals";
|
||||
while (Object.hasOwn(fields, tail)) tail += "_";
|
||||
const args = z.object({
|
||||
...Object.fromEntries(
|
||||
entries.map(([name]) => [name, z.unknown().optional()]),
|
||||
),
|
||||
[tail]: z.array(z.string()).optional(),
|
||||
});
|
||||
const options =
|
||||
command.options instanceof z.ZodObject
|
||||
? optionTokenShape(command.options)
|
||||
: undefined;
|
||||
const optionsSchema =
|
||||
command.options instanceof z.ZodObject ? command.options : undefined;
|
||||
command.middleware = [
|
||||
async (context, next) => {
|
||||
const tokens = invocation.getStore();
|
||||
if (tokens !== undefined) {
|
||||
// Only the resolved command needs an inert token-binding schema.
|
||||
// Keep the original schema references, but do not prepare every
|
||||
// registered command for each one-shot invocation.
|
||||
const args = z.object({
|
||||
...Object.fromEntries(
|
||||
entries.map(([name]) => [name, z.unknown().optional()]),
|
||||
),
|
||||
[tail]: z.array(z.string()).optional(),
|
||||
});
|
||||
const options =
|
||||
optionsSchema === undefined
|
||||
? undefined
|
||||
: optionTokenShape(optionsSchema);
|
||||
// Incur supplies the invoked path, including aliases, after resolving
|
||||
// groups. No second router decides which command receives the tokens.
|
||||
const parsed = Parser.parse(
|
||||
|
||||
@@ -175,3 +175,37 @@ it("uses resolved group and alias paths and preserves declared variadic inputs",
|
||||
values: ["one", "two", "three"],
|
||||
});
|
||||
});
|
||||
|
||||
it("preserves counted aliases and negated booleans while checking the positional tail", async () => {
|
||||
let runs = 0;
|
||||
const cli = Cli.create("strict-counted-flags", { sync: false });
|
||||
cli.command("capture", {
|
||||
args: z.object({ path: z.string() }),
|
||||
options: z.object({
|
||||
enabled: z.boolean().default(true),
|
||||
verbosity: z.number().default(0).meta({ count: true }),
|
||||
}),
|
||||
alias: { verbosity: "v" },
|
||||
run: ({ args, options }) => {
|
||||
runs++;
|
||||
return { args, options };
|
||||
},
|
||||
});
|
||||
installAdmission(cli);
|
||||
const valid = await serve(cli, ["capture", "one", "--no-enabled", "-vvv"]);
|
||||
expect(valid.exitCode).toBe(0);
|
||||
expect(JSON.parse(valid.stdout)).toMatchObject({
|
||||
args: { path: "one" },
|
||||
options: { enabled: false, verbosity: 3 },
|
||||
});
|
||||
const surplus = await serve(cli, [
|
||||
"capture",
|
||||
"one",
|
||||
"--no-enabled",
|
||||
"-vvv",
|
||||
"extra",
|
||||
]);
|
||||
expect(surplus.exitCode).toBe(1);
|
||||
expect(surplus.stdout).toContain("Unexpected positional arguments");
|
||||
expect(runs).toBe(1);
|
||||
});
|
||||
Reference in new issue
Block a user