Skip to content

feat: add runtime global options support#155

Draft
toiroakr wants to merge 8 commits intomainfrom
fix/issue-154-global-options
Draft

feat: add runtime global options support#155
toiroakr wants to merge 8 commits intomainfrom
fix/issue-154-global-options

Conversation

@toiroakr
Copy link
Owner

@toiroakr toiroakr commented Mar 3, 2026

Summary

  • add runtime globalArgs support to runMain / runCommand
  • parse global options before and after subcommands, including --no-* boolean negation
  • merge global args with command args (command args take precedence on collisions)
  • add createDefineCommand and global-args type plumbing (GlobalArgs, GlobalArgsContext, MergedArgs)
  • show [global options] in usage and Global Options: in help output
  • address review feedback around global option collisions and help behavior:
    • keep global long flags working when only short aliases collide
    • respect global overrideBuiltinAlias for -h / -H in subcommand detection and help output
    • avoid treating option values as unknown subcommands on help paths
    • simplify createDefineCommand internals while preserving typing
  • follow-up review fixes:
    • derive unknown-flag handling mode from both command and global schemas
    • remove unnecessary as any in run-main global options tests
    • correct API docs for the createDefineCommand return type
  • update docs/golden generation to add Shared options: [Global Options](...) links from subcommand docs
  • update documentation for global option collision and help-alias override behavior

Closes #154

Code Metrics Report

main (fcea1f0) #155 (0dd44e8) +/-
Coverage 88.6% 89.0% +0.4%
Test Execution Time 1m21s 41s -40s
Details
  |                     | main (fcea1f0) | #155 (0dd44e8) |  +/-  |
  |---------------------|----------------|----------------|-------|
+ | Coverage            |          88.6% |          89.0% | +0.4% |
  |   Files             |             41 |             41 |     0 |
  |   Lines             |           3164 |           3478 |  +314 |
+ |   Covered           |           2804 |           3097 |  +293 |
+ | Test Execution Time |          1m21s |            41s |  -40s |

Code coverage of files in pull request scope (85.4% → 86.8%)

Files Coverage +/- Status
src/core/command.ts 100.0% 0.0% modified
src/core/runner.ts 92.1% +9.6% modified
src/core/schema-extractor.ts 87.0% +0.4% modified
src/docs/default-renderers.ts 85.3% -0.1% modified
src/docs/golden-test.ts 91.6% +0.0% modified
src/docs/types.ts 100.0% 0.0% modified
src/index.ts 0.0% 0.0% modified
src/output/help-generator.ts 73.2% +2.8% modified
src/parser/arg-parser.ts 89.1% -10.9% modified
src/types.ts 0.0% 0.0% modified
src/validator/error-formatter.ts 88.0% +8.0% affected

Reported by octocov

Copilot AI review requested due to automatic review settings March 3, 2026 05:39
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds runtime “global options” support so a single schema can define flags available across all subcommands, including parsing them before/after subcommands, merging them into command args, and exposing them in help/usage output.

Changes:

  • Add global-args typing and runtime plumbing (GlobalArgs, GlobalArgsContext, createDefineCommand, and globalArgs options for runMain/runCommand).
  • Update the arg parser to scan for subcommands while skipping known global flags (including --no-*) and to split global vs command raw args for leaf commands.
  • Add help output support for [global options] in usage and a dedicated “Global Options” section; add schema extraction caching (extractFieldsCached).

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/types.ts Introduces global-args types and adds globalArgs to runtime options types.
src/parser/arg-parser.ts Implements global args scanning/splitting and uses cached schema extraction.
src/parser/arg-parser.test.ts Adds tests covering global args parsing, --no-*, scanner stop conditions, and leaf splitting.
src/output/help-generator.ts Adds global options rendering in usage and help sections.
src/output/help-generator.test.ts Adds tests for [global options] usage and “Global Options” help section.
src/index.ts Exports createDefineCommand, extractFieldsCached, and global-args types.
src/core/schema-extractor.ts Adds WeakMap-based caching via extractFieldsCached; getExtractedFields uses it.
src/core/schema-extractor.test.ts Tests cache behavior for extractFieldsCached.
src/core/runner.ts Threads global args context through parsing/help and merges validated global args into command args.
src/core/run-main.test.ts Adds integration tests for global arg merging, precedence, validation errors, and env fallback.
src/core/command.ts Extends command typing to include global args and adds createDefineCommand.
src/core/command.test.ts Adds type-level tests for global args via factory, explicit type parameter, and declaration merging.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings March 3, 2026 14:30
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- resolve unknownKeysMode from both command/global extracted schemas

- remove unnecessary as any casts in run-main tests

- update createDefineCommand API reference signature text
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings March 4, 2026 13:05
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 22 out of 22 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

const withoutDashes = token.slice(2);

if (withoutDashes.startsWith("no-")) {
continue;
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In findPotentialSubcommandOnHelp(), any --no-* token is currently treated as a flag and skipped unconditionally. This can mis-detect the next token as a subcommand when the user passes --no-<non-boolean> (or an unknown --no-*) with a value (e.g. --no-config app.toml --help), reintroducing the “option value treated as subcommand” issue on help paths. Treat --no-* as boolean negation only when <name> is a known boolean long flag; otherwise handle it like a normal long option (including consuming the next value when appropriate).

Suggested change
continue;
const negatedName = withoutDashes.slice(3);
const negatedInfo = longFlags.get(negatedName);
if (negatedInfo && negatedInfo.boolean) {
// Known boolean long flag negation (e.g. --no-verbose); no value to consume.
continue;
}

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

global option support

2 participants