Analyzer::Javascript::Cli
Inherits CliEndpointSupport < Analyzer::Javascript::JavascriptEngine < Analyzer < FileHelper < Reference < Object
Surfaces the command-line attack surface of JavaScript/TypeScript programs
(Node, Deno, Bun) as cli:// endpoints: one endpoint per (sub)command
with named options (param_type "flag"), positional arguments ("argument")
and consumed environment variables ("env"). Covers the util.parseArgs
builtin plus commander, yargs, cac, sade, meow, minimist, arg,
command-line-args, getopts and citty. A single analyzer scans every JS/TS
extension so a .ts CLI isn't double-counted.
Constants
arg: arg({ '--name': String, '-n': '--name' }). Keys whose value is a
quoted string are aliases pointing at the canonical flag and are
skipped so an alias doesn't surface as a second, meaningless flag.
citty also allows each subcommand to be declared as its own top-level
const NAME = defineCommand({...}) and merely referenced by identifier
inside subCommands: { key: NAME }, instead of nesting the
defineCommand call inline. resolve_citty_var_subcommands resolves
those same-file references so args: inside NAME's block attributes to
<root>/<key> rather than falling back to root.
citty: serve: defineCommand({ args: { port: { type: 'string' } } }).
Subcommands nest their own defineCommand object inside subCommands,
so args are attributed via a brace-depth stack (never a sticky cursor).
command-line-args: commandLineArgs(optionDefinitions) referencing a
separately-declared const optionDefinitions = [...] array (the
library's own documented convention), or an inline
commandLineArgs([...]) array. Matching is bounded to the resolved
array's own brackets (never a whole-file scan) so an unrelated
same-shaped object literal elsewhere in the file (e.g. a content-field
schema) is never picked up as a bogus flag, and each {...} entry is
scanned as its own brace-bounded block so Prettier-style
multi-line-per-key formatting isn't silently dropped.
Two more OR-ed pairs of whole-file scans, collapsed the same way: the evidence gate every JS/TS file passes through, and the web-framework veto that decides whether env reads are emitted.
Precompiled once — a single PCRE2-JIT scan replaces up to eleven naive String#includes? substring scans over the whole file content. Regex.union auto-escapes each literal (including the dots in "Deno.args"/"Bun.argv"), so it is provably equivalent to the OR-of-includes? it replaces.
commander / cac / sade / yargs subcommand. The command string may carry
an arg spec (serve <port>), so the first whitespace token is the name.
builtin / runtime argv markers (root surface).
env reads (gated). NODE_ENV is config plumbing, not an input.
getopts: getopts(process.argv.slice(2), { alias: {...}, default: {...}, boolean: [...], string: [...] }). Bounded to the call's own parens so
unrelated alias/default object literals elsewhere aren't picked up.
require('arg') / from 'arg', and likewise for getopts/citty/
command-line-args — these are short/generic tokens too easy to trip as
a bare substring (e.g. bash's own getopts builtin, a stray comment,
or an ordinary identifier fragment), so they require an actual import
statement rather than content.includes?.
A fresh statement that chains command/option/argument off an identifier
(program.option(...), cli.command(...)) starts at the root program,
not the previously-seen subcommand — used to reset the cursor so a
global option declared after a subcommand isn't mis-attributed to it.
commander/cac/sade: .option('-p, --port <n>'); yargs: .option('port').
object-literal schema headers (keys become root flags).
Class methods
Instance methods
Instance-side view of the same declaration. The per-file rescues live on
this base class, which has no way to name the analyzer that is running
inside them, so a skipped file could not be attributed to a tech.
Deriving it from analyzer_for keeps the name written exactly once.