parseCliArgs(args: string[]): CliOptions
Parses command line arguments into the three positionals and the flags.
Positionals fill the package, coder and command slots in order, skipping any
slot a flag already filled — so -p png -c pngFile decode and
png pngFile decode mean the same thing. decode and encode are reserved
in the coder slot: a second word that names a command is the command, and
the coder is left to be inferred (ADR 0005).
Every slot is text: positionals are read as strings, so 007 stays 007
rather than becoming the number 7 on its way to the specifier resolver.
A blank word fills its slot, and is then refused on its own terms. It
used to be dropped as if it had never been typed, which is not a smaller
version of the same thing: binstruct "" decode slid decode into the
package slot and answered confidently about jsr:@binstruct/decode, and
-p "" did it too. That is the shift an unknown flag causes, arriving by
another route, and it takes the same answer — the slots it landed in are
named in CliOptions.blankSlots and nothing runs.
There is no fourth slot, and a word that reaches for one is refused.
Extra positionals used to be dropped where they stood, so
binstruct arp arpData decode input.bin — the < forgotten — waited on a
terminal for input that was sitting in the file it had just discarded. They
are collected in CliOptions.extraArgs instead.
A word starting with - is a flag, and -- is how you say it is not.
Everything after the separator fills a slot whatever it starts with, so
binstruct -- -dash/mod.ts decode names a module the shell tab-completed
from a directory called -dash. Without it, -dash/ was read as the flag
cluster -d -a -s -h, whose h set --help — and the CLI answered a decode
with the whole help screen on stdout, at exit 0, which is precisely the
redirect corruption ADR 0001 exists to prevent.
A flag that is not recognised is refused, never ignored. Only the five
declared here exist; anything else consumes a word and shifts every
positional behind it, so binstruct --format json png would have answered
confidently about json. They are collected rather than thrown, since
reporting them is planCli's job.
Positionals and flags are interchangeable
Positionals and flags are interchangeable
import { assertEquals } from "@std/assert"; import { parseCliArgs } from "./cli.ts"; assertEquals(parseCliArgs(["png", "pngFile", "decode"]), { package: "png", coder: "pngFile", command: "decode", help: false, version: false, docs: false, unknownFlags: [], blankSlots: [], extraArgs: [], }); const flagged = parseCliArgs(["-p", "png", "-c", "pngFile", "decode"]); assertEquals(flagged.package, "png"); assertEquals(flagged.coder, "pngFile"); assertEquals(flagged.command, "decode");
A command word in the coder slot leaves the coder to be inferred
A command word in the coder slot leaves the coder to be inferred
import { assertEquals } from "@std/assert"; import { parseCliArgs } from "./cli.ts"; const options = parseCliArgs(["arp", "decode"]); assertEquals(options.package, "arp"); assertEquals(options.coder, undefined); assertEquals(options.command, "decode");
-- makes a leading dash ordinary, and a stray flag is reported
-- makes a leading dash ordinary, and a stray flag is reported
import { assertEquals } from "@std/assert"; import { parseCliArgs } from "./cli.ts"; const separated = parseCliArgs(["--", "-dash/mod.ts", "decode"]); assertEquals(separated.package, "-dash/mod.ts"); assertEquals(separated.command, "decode"); assertEquals(separated.help, false); assertEquals(parseCliArgs(["--format", "json", "png"]).unknownFlags, [ "--format", ]);
A blank word keeps its slot, and a fourth word is kept as well
A blank word keeps its slot, and a fourth word is kept as well
import { assertEquals } from "@std/assert"; import { parseCliArgs } from "./cli.ts"; const blank = parseCliArgs(["", "decode"]); assertEquals(blank.package, ""); assertEquals(blank.command, "decode"); assertEquals(blank.blankSlots, ["<package>"]); const extra = parseCliArgs(["arp", "arpData", "decode", "input.bin"]); assertEquals(extra.command, "decode"); assertEquals(extra.extraArgs, ["input.bin"]);
The parsed slots and flags, with absent and blank values left undefined