Skip to main content

select_leaf

Function select_leaf 

Source
pub fn select_leaf<'a>(
    schema: &'a ToolSchema,
    args: &[Arg],
) -> Result<&'a ToolSchema>
Expand description

Extract parameter types from a tool schema.

Returns a map from param name → param type (e.g., “verbose” → “bool”, “output” → “string”). Build a map from flag name → (canonical param name, param type).

Includes both primary names and aliases (with dashes stripped). For short flags like -n aliased to lines, maps "n"("lines", "int", 1). The third tuple slot is consumes: how many positionals the flag pulls per occurrence (1 for standard --flag value, 2 for jq’s --arg NAME VAL).

Positional params (positional: true) are excluded — they’re not flags, and including them would mis-route cat --paths foo.txt from positional to named, regressing builtins that read from args.positional. Walk leading positionals to select the active subcommand leaf of a schema.

A flat tool (schema.subcommands empty) returns the root immediately — today’s single-leaf behavior. For a subcommand-aware tool each leading positional, in order, must name a child (by name or a command-level alias) to descend; the first positional that names no child is the leaf’s own argument, and selection stops there. Multi-level trees fall out by construction (block edit insert → two descents).

Routing is literal-only: a subcommand selector must be a bareword or quoted string (both parse to Expr::Literal(Value::String)). A computed positional ($(…), $VAR, a glob) sitting where a subcommand is required is an error, not a silent guess — kaish can’t see its value at parse time, so picking a leaf from it would misroute the flags that bind against the leaf’s params. The fix is to spell the subcommand out, or use the --flag=value form (which binds without any schema lookup).

Returned leaf borrows from schema, so its params/subcommands outlive any schema_param_lookup taken from it.

Global value flags. A space-form value flag declared on the root (e.g. kj’s global --confirm <nonce>) can legitimately precede the subcommand path. Its value is a positional in the AST, so routing must not mistake it for a subcommand selector — select_leaf skips the value of any root-declared non-bool flag it sees. Leaf-specific value flags can’t precede their own subcommand by construction, so only the root’s flags need this.