Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: tj/commander.js
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v11.1.0
Choose a base ref
...
head repository: tj/commander.js
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v12.0.0
Choose a head ref

Commits on Aug 5, 2023

  1. Copy the full SHA
    681a7e4 View commit details
  2. Copy the full SHA
    af67d11 View commit details
  3. Copy the full SHA
    1453bdf View commit details
  4. Copy the full SHA
    c60ce9d View commit details
  5. Unclutter error message in broken passThrough checks

    Co-authored-by: John Gee <john@ruru.gen.nz>
    2 people authored and abetomo committed Aug 5, 2023
    Copy the full SHA
    ec1942d View commit details
  6. Copy the full SHA
    ac8db3a View commit details

Commits on Aug 22, 2023

  1. Copy the full SHA
    95d54c3 View commit details

Commits on Sep 3, 2023

  1. Copy the full SHA
    f570b08 View commit details

Commits on Sep 15, 2023

  1. Copy the full SHA
    c876dee View commit details

Commits on Sep 16, 2023

  1. Copy the full SHA
    37c9398 View commit details

Commits on Sep 23, 2023

  1. Copy the full SHA
    9afbabd View commit details

Commits on Oct 7, 2023

  1. Copy the full SHA
    a0ca1bd View commit details
  2. Copy the full SHA
    5aaca0d View commit details
  3. Copy the full SHA
    72e6f7a View commit details

Commits on Oct 13, 2023

  1. Copy the full SHA
    d90c59c View commit details

Commits on Oct 15, 2023

  1. Bump @types/node from 20.2.5 to 20.8.5 (#2034)

    Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.2.5 to 20.8.5.
    - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
    - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)
    
    ---
    updated-dependencies:
    - dependency-name: "@types/node"
      dependency-type: direct:development
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Oct 15, 2023
    Copy the full SHA
    1652a6c View commit details
  2. Bump eslint from 8.41.0 to 8.51.0 (#2033)

    Bumps [eslint](https://github.com/eslint/eslint) from 8.41.0 to 8.51.0.
    - [Release notes](https://github.com/eslint/eslint/releases)
    - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
    - [Commits](eslint/eslint@v8.41.0...v8.51.0)
    
    ---
    updated-dependencies:
    - dependency-name: eslint
      dependency-type: direct:development
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Oct 15, 2023
    Copy the full SHA
    270bb12 View commit details
  3. Bump @typescript-eslint/parser from 5.59.7 to 5.62.0 (#2030)

    Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 5.59.7 to 5.62.0.
    - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
    - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
    - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v5.62.0/packages/parser)
    
    ---
    updated-dependencies:
    - dependency-name: "@typescript-eslint/parser"
      dependency-type: direct:development
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Oct 15, 2023
    Copy the full SHA
    1a328d2 View commit details
  4. Bump eslint-config-standard from 17.0.0 to 17.1.0 (#2031)

    Bumps [eslint-config-standard](https://github.com/standard/eslint-config-standard) from 17.0.0 to 17.1.0.
    - [Commits](standard/eslint-config-standard@v17.0.0...v17.1.0)
    
    ---
    updated-dependencies:
    - dependency-name: eslint-config-standard
      dependency-type: direct:development
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Oct 15, 2023
    Copy the full SHA
    f8bd5be View commit details

Commits on Oct 16, 2023

  1. Bump @typescript-eslint/eslint-plugin from 5.59.7 to 6.7.5 (#2032)

    * Bump @typescript-eslint/eslint-plugin from 5.59.7 to 6.7.5
    
    Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 5.59.7 to 6.7.5.
    - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
    - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
    - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.7.5/packages/eslint-plugin)
    
    ---
    updated-dependencies:
    - dependency-name: "@typescript-eslint/eslint-plugin"
      dependency-type: direct:development
      update-type: version-update:semver-major
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    
    * Fix for `Could not resolve dependency`
    
    ---------
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    Co-authored-by: abetomo <abe@enzou.tokyo>
    dependabot[bot] and abetomo authored Oct 16, 2023
    Copy the full SHA
    7e6c663 View commit details
  2. Copy the full SHA
    e56e9d0 View commit details
  3. Bump tsd from 0.28.1 to 0.29.0

    Bumps [tsd](https://github.com/SamVerschueren/tsd) from 0.28.1 to 0.29.0.
    - [Release notes](https://github.com/SamVerschueren/tsd/releases)
    - [Commits](tsdjs/tsd@v0.28.1...v0.29.0)
    
    ---
    updated-dependencies:
    - dependency-name: tsd
      dependency-type: direct:development
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored and shadowspawn committed Oct 16, 2023
    Copy the full SHA
    695f419 View commit details
  4. Copy the full SHA
    d90e81e View commit details

Commits on Oct 26, 2023

  1. Bump @types/jest from 29.5.5 to 29.5.6 (#2047)

    Bumps [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 29.5.5 to 29.5.6.
    - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
    - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest)
    
    ---
    updated-dependencies:
    - dependency-name: "@types/jest"
      dependency-type: direct:development
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Oct 26, 2023
    Copy the full SHA
    f2e26c3 View commit details
  2. Bump eslint-plugin-n from 15.7.0 to 16.2.0 (#2044)

    Bumps [eslint-plugin-n](https://github.com/eslint-community/eslint-plugin-n) from 15.7.0 to 16.2.0.
    - [Release notes](https://github.com/eslint-community/eslint-plugin-n/releases)
    - [Commits](eslint-community/eslint-plugin-n@15.7.0...16.2.0)
    
    ---
    updated-dependencies:
    - dependency-name: eslint-plugin-n
      dependency-type: direct:development
      update-type: version-update:semver-major
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Oct 26, 2023
    Copy the full SHA
    27edf5d View commit details
  3. Bump @typescript-eslint/parser from 6.7.5 to 6.8.0 (#2043)

    Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 6.7.5 to 6.8.0.
    - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
    - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
    - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.8.0/packages/parser)
    
    ---
    updated-dependencies:
    - dependency-name: "@typescript-eslint/parser"
      dependency-type: direct:development
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Oct 26, 2023
    Copy the full SHA
    2bcf2ef View commit details
  4. Bump eslint-plugin-jest from 27.4.2 to 27.4.3 (#2045)

    Bumps [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) from 27.4.2 to 27.4.3.
    - [Release notes](https://github.com/jest-community/eslint-plugin-jest/releases)
    - [Changelog](https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md)
    - [Commits](jest-community/eslint-plugin-jest@v27.4.2...v27.4.3)
    
    ---
    updated-dependencies:
    - dependency-name: eslint-plugin-jest
      dependency-type: direct:development
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Oct 26, 2023
    Copy the full SHA
    9322aa1 View commit details

Commits on Oct 28, 2023

  1. Bump eslint from 8.51.0 to 8.52.0 (#2046)

    Bumps [eslint](https://github.com/eslint/eslint) from 8.51.0 to 8.52.0.
    - [Release notes](https://github.com/eslint/eslint/releases)
    - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
    - [Commits](eslint/eslint@v8.51.0...v8.52.0)
    
    ---
    updated-dependencies:
    - dependency-name: eslint
      dependency-type: direct:development
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Oct 28, 2023
    Copy the full SHA
    fac24a9 View commit details

Commits on Oct 31, 2023

  1. Bump eslint-plugin-jest from 27.4.3 to 27.6.0 (#2049)

    Bumps [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) from 27.4.3 to 27.6.0.
    - [Release notes](https://github.com/jest-community/eslint-plugin-jest/releases)
    - [Changelog](https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md)
    - [Commits](jest-community/eslint-plugin-jest@v27.4.3...v27.6.0)
    
    ---
    updated-dependencies:
    - dependency-name: eslint-plugin-jest
      dependency-type: direct:development
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Oct 31, 2023
    Copy the full SHA
    84b44f4 View commit details
  2. Bump @types/node from 20.8.6 to 20.8.9 (#2052)

    Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.8.6 to 20.8.9.
    - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
    - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)
    
    ---
    updated-dependencies:
    - dependency-name: "@types/node"
      dependency-type: direct:development
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Oct 31, 2023
    Copy the full SHA
    0e5f2e8 View commit details
  3. Bump actions/setup-node from 3 to 4 (#2054)

    Bumps [actions/setup-node](https://github.com/actions/setup-node) from 3 to 4.
    - [Release notes](https://github.com/actions/setup-node/releases)
    - [Commits](actions/setup-node@v3...v4)
    
    ---
    updated-dependencies:
    - dependency-name: actions/setup-node
      dependency-type: direct:production
      update-type: version-update:semver-major
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Oct 31, 2023
    Copy the full SHA
    63dd43a View commit details
  4. Bump @typescript-eslint/eslint-plugin from 6.7.5 to 6.9.0 (#2053)

    Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 6.7.5 to 6.9.0.
    - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
    - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
    - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.9.0/packages/eslint-plugin)
    
    ---
    updated-dependencies:
    - dependency-name: "@typescript-eslint/eslint-plugin"
      dependency-type: direct:development
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Oct 31, 2023
    Copy the full SHA
    4c842a8 View commit details
  5. Bump eslint-plugin-import from 2.28.1 to 2.29.0 (#2051)

    Bumps [eslint-plugin-import](https://github.com/import-js/eslint-plugin-import) from 2.28.1 to 2.29.0.
    - [Release notes](https://github.com/import-js/eslint-plugin-import/releases)
    - [Changelog](https://github.com/import-js/eslint-plugin-import/blob/main/CHANGELOG.md)
    - [Commits](import-js/eslint-plugin-import@v2.28.1...v2.29.0)
    
    ---
    updated-dependencies:
    - dependency-name: eslint-plugin-import
      dependency-type: direct:development
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Oct 31, 2023
    Copy the full SHA
    67c1e09 View commit details
  6. Bump @typescript-eslint/parser from 6.8.0 to 6.9.0 (#2050)

    Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 6.8.0 to 6.9.0.
    - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
    - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
    - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.9.0/packages/parser)
    
    ---
    updated-dependencies:
    - dependency-name: "@typescript-eslint/parser"
      dependency-type: direct:development
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Oct 31, 2023
    Copy the full SHA
    49f4766 View commit details

Commits on Nov 1, 2023

  1. Change npm package checks in dependabot to monthly (#2057)

    github-actions will remain weekly as it is updated infrequently.
    abetomo authored Nov 1, 2023
    Copy the full SHA
    7d08bc7 View commit details
  2. Copy the full SHA
    b96af40 View commit details

Commits on Nov 4, 2023

  1. Add check for overlapping command names or aliases (#2059)

    Co-authored-by: aweebit <aweebit64@gmail.com>
    shadowspawn and aweebit authored Nov 4, 2023
    Copy the full SHA
    1d3dd47 View commit details

Commits on Nov 7, 2023

  1. Copy the full SHA
    b521b7a View commit details
  2. Copy the full SHA
    ce4d5f7 View commit details

Commits on Nov 9, 2023

  1. Copy the full SHA
    0e0fedb View commit details

Commits on Nov 10, 2023

  1. Copy the full SHA
    c6820a5 View commit details

Commits on Nov 11, 2023

  1. Copy the full SHA
    4085ac7 View commit details
  2. Copy the full SHA
    db6b4d5 View commit details
  3. 12.0.0-0

    shadowspawn committed Nov 11, 2023
    Copy the full SHA
    18f921d View commit details
  4. Bump @types/jest from 29.5.6 to 29.5.7 (#2064)

    Bumps [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 29.5.6 to 29.5.7.
    - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
    - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest)
    
    ---
    updated-dependencies:
    - dependency-name: "@types/jest"
      dependency-type: direct:development
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Nov 11, 2023
    Copy the full SHA
    48f9fd9 View commit details
  5. Bump eslint from 8.52.0 to 8.53.0 (#2061)

    Bumps [eslint](https://github.com/eslint/eslint) from 8.52.0 to 8.53.0.
    - [Release notes](https://github.com/eslint/eslint/releases)
    - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
    - [Commits](eslint/eslint@v8.52.0...v8.53.0)
    
    ---
    updated-dependencies:
    - dependency-name: eslint
      dependency-type: direct:development
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Nov 11, 2023
    Copy the full SHA
    902124d View commit details
  6. Bump @types/node from 20.8.9 to 20.8.10 (#2063)

    Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.8.9 to 20.8.10.
    - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
    - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)
    
    ---
    updated-dependencies:
    - dependency-name: "@types/node"
      dependency-type: direct:development
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Nov 11, 2023
    Copy the full SHA
    c20a71d View commit details
  7. Bump @typescript-eslint/eslint-plugin from 6.9.0 to 6.9.1 (#2060)

    Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 6.9.0 to 6.9.1.
    - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
    - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
    - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.9.1/packages/eslint-plugin)
    
    ---
    updated-dependencies:
    - dependency-name: "@typescript-eslint/eslint-plugin"
      dependency-type: direct:development
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Nov 11, 2023
    Copy the full SHA
    6b74d26 View commit details
  8. Bump @typescript-eslint/parser from 6.9.0 to 6.9.1 (#2062)

    Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 6.9.0 to 6.9.1.
    - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
    - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
    - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.9.1/packages/parser)
    
    ---
    updated-dependencies:
    - dependency-name: "@typescript-eslint/parser"
      dependency-type: direct:development
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Nov 11, 2023
    Copy the full SHA
    2978456 View commit details

Commits on Nov 14, 2023

  1. Bump @types/jest from 29.5.7 to 29.5.8 (#2076)

    Bumps [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 29.5.7 to 29.5.8.
    - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
    - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest)
    
    ---
    updated-dependencies:
    - dependency-name: "@types/jest"
      dependency-type: direct:development
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Nov 14, 2023
    Copy the full SHA
    883d326 View commit details
2 changes: 1 addition & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ updates:
target-branch: "develop"
directory: "/"
schedule:
interval: "weekly"
interval: "monthly"
- package-ecosystem: "github-actions"
target-branch: "develop"
directory: "/"
6 changes: 3 additions & 3 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ jobs:

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -40,7 +40,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
uses: github/codeql-action/autobuild@v3

# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -54,4 +54,4 @@ jobs:
# make release

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v3
4 changes: 2 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -12,13 +12,13 @@ jobs:
strategy:
fail-fast: false
matrix:
node-version: [16.x, 18.x, 20.x]
node-version: [18.x, 20.x]
os: [ubuntu-latest, windows-latest, macos-latest]

steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
cache: 'npm'
node-version: ${{ matrix.node-version }}
70 changes: 70 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -8,6 +8,63 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
<!-- markdownlint-disable MD024 -->
<!-- markdownlint-disable MD004 -->

## [12.0.0] (2024-02-03)

### Added

- `.addHelpOption()` as another way of configuring built-in help option ([#2006])
- `.helpCommand()` for configuring built-in help command ([#2087])

### Fixed

- *Breaking:* use non-zero exit code when spawned executable subcommand terminates due to a signal ([#2023])
- *Breaking:* check `passThroughOptions` constraints when using `.addCommand` and throw if parent command does not have `.enablePositionalOptions()` enabled ([#1937])

### Changed

- *Breaking:* Commander 12 requires Node.js v18 or higher ([#2027])
- *Breaking:* throw an error if add an option with a flag which is already in use ([#2055])
- *Breaking:* throw an error if add a command with name or alias which is already in use ([#2059])
- *Breaking:* throw error when calling `.storeOptionsAsProperties()` after setting an option value ([#1928])
- replace non-standard JSDoc of `@api private` with documented `@private` ([#1949])
- `.addHelpCommand()` now takes a Command (passing string or boolean still works as before but deprecated) ([#2087])
- refactor internal implementation of built-in help option ([#2006])
- refactor internal implementation of built-in help command ([#2087])

### Deprecated

- `.addHelpCommand()` passing string or boolean (use `.helpCommand()` or pass a Command) ([#2087])

### Removed

- *Breaking:* removed default export of a global Command instance from CommonJS (use the named `program` export instead) ([#2017])

### Migration Tips

**global program**

If you are using the [deprecated](./docs/deprecated.md#default-import-of-global-command-object) default import of the global Command object, you need to switch to using a named import (or create a new `Command`).

```js
// const program = require('commander');
const { program } = require('commander');
```

**option and command clashes**

A couple of configuration problems now throw an error, which will pick up issues in existing programs:

- adding an option which uses the same flag as a previous option
- adding a command which uses the same name or alias as a previous command

## [12.0.0-1] (2024-01-20)

(Released in 12.0.0)

## [12.0.0-0] (2023-11-11)

(Released in 12.0.0)

## [11.1.0] (2023-10-13)

### Fixed
@@ -1188,13 +1245,23 @@ program
[#1874]: https://github.com/tj/commander.js/pull/1874
[#1886]: https://github.com/tj/commander.js/pull/1886
[#1896]: https://github.com/tj/commander.js/pull/1896
[#1928]: https://github.com/tj/commander.js/pull/1928
[#1930]: https://github.com/tj/commander.js/pull/1930
[#1937]: https://github.com/tj/commander.js/pull/1937
[#1949]: https://github.com/tj/commander.js/pull/1949
[#1965]: https://github.com/tj/commander.js/pull/1965
[#1969]: https://github.com/tj/commander.js/pull/1969
[#1982]: https://github.com/tj/commander.js/pull/1982
[#1983]: https://github.com/tj/commander.js/pull/1983
[#2006]: https://github.com/tj/commander.js/pull/2006
[#2010]: https://github.com/tj/commander.js/pull/2010
[#2017]: https://github.com/tj/commander.js/pull/2017
[#2019]: https://github.com/tj/commander.js/pull/2019
[#2023]: https://github.com/tj/commander.js/pull/2023
[#2027]: https://github.com/tj/commander.js/pull/2027
[#2055]: https://github.com/tj/commander.js/pull/2055
[#2059]: https://github.com/tj/commander.js/pull/2059
[#2087]: https://github.com/tj/commander.js/pull/2087

<!-- Referenced in 5.x -->
[#1]: https://github.com/tj/commander.js/issues/1
@@ -1274,6 +1341,9 @@ program
[#1028]: https://github.com/tj/commander.js/pull/1028

[Unreleased]: https://github.com/tj/commander.js/compare/master...develop
[12.0.0]: https://github.com/tj/commander.js/compare/v11.1.0...v12.0.0
[12.0.0-1]: https://github.com/tj/commander.js/compare/v12.0.0-0...v12.0.0-1
[12.0.0-0]: https://github.com/tj/commander.js/compare/v11.1.0...v12.0.0-0
[11.1.0]: https://github.com/tj/commander.js/compare/v11.0.0...v11.1.0
[11.0.0]: https://github.com/tj/commander.js/compare/v10.0.1...v11.0.0
[10.0.1]: https://github.com/tj/commander.js/compare/v10.0.0...v10.0.1
21 changes: 14 additions & 7 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -37,7 +37,7 @@ Read this in other languages: English | [简体中文](./Readme_zh-CN.md)
- [.usage](#usage)
- [.description and .summary](#description-and-summary)
- [.helpOption(flags, description)](#helpoptionflags-description)
- [.addHelpCommand()](#addhelpcommand)
- [.helpCommand()](#helpcommand)
- [More configuration](#more-configuration-2)
- [Custom event listeners](#custom-event-listeners)
- [Bits and pieces](#bits-and-pieces)
@@ -904,16 +904,20 @@ program
.helpOption('-e, --HELP', 'read more information');
```

### .addHelpCommand()
(Or use `.addHelpOption()` to add an option you construct yourself.)

A help command is added by default if your command has subcommands. You can explicitly turn on or off the implicit help command with `.addHelpCommand()` and `.addHelpCommand(false)`.
### .helpCommand()

A help command is added by default if your command has subcommands. You can explicitly turn on or off the implicit help command with `.helpCommand(true)` and `.helpCommand(false)`.

You can both turn on and customise the help command by supplying the name and description:

```js
program.addHelpCommand('assist [command]', 'show assistance');
program.helpCommand('assist [command]', 'show assistance');
```

(Or use `.addHelpCommand()` to add a command you construct yourself.)

### More configuration

The built-in help is formatted using the Help class.
@@ -967,6 +971,8 @@ program.parse(); // Implicit, and auto-detect electron
program.parse(['-f', 'filename'], { from: 'user' });
```

If you want to parse multiple times, create a new program each time. Calling parse does not clear out any previous state.

### Parsing Configuration

If the default parsing does not suit your needs, there are some behaviours to support other usage patterns.
@@ -1092,8 +1098,9 @@ program.error('Custom processing has failed', { exitCode: 2, code: 'my.custom.er
By default, Commander calls `process.exit` when it detects errors, or after displaying the help or version. You can override
this behaviour and optionally supply a callback. The default override throws a `CommanderError`.

The override callback is passed a `CommanderError` with properties `exitCode` number, `code` string, and `message`. The default override behaviour is to throw the error, except for async handling of executable subcommand completion which carries on. The normal display of error messages or version or help
is not affected by the override which is called after the display.
The override callback is passed a `CommanderError` with properties `exitCode` number, `code` string, and `message`.
Commander expects the callback to terminate the normal program flow, and will call `process.exit` if the callback returns.
The normal display of error messages or version or help is not affected by the override which is called after the display.

```js
program.exitOverride();
@@ -1136,7 +1143,7 @@ There is more information available about:

## Support

The current version of Commander is fully supported on Long Term Support versions of Node.js, and requires at least v16.
The current version of Commander is fully supported on Long Term Support versions of Node.js, and requires at least v18.
(For older versions of Node.js, use an older version of Commander.)

The main forum for free and community support is the project [Issues](https://github.com/tj/commander.js/issues) on GitHub.
2 changes: 1 addition & 1 deletion Readme_zh-CN.md
Original file line number Diff line number Diff line change
@@ -1059,7 +1059,7 @@ program
## 支持
当前版本的 Commander 在 LTS 版本的 Node.js 上完全支持。并且至少需要 v16
当前版本的 Commander 在 LTS 版本的 Node.js 上完全支持。并且至少需要 v18
(使用更低版本 Node.js 的用户建议安装更低版本的 Commander)
社区支持请访问项目的 [Issues](https://github.com/tj/commander.js/issues)。
4 changes: 2 additions & 2 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -6,8 +6,8 @@ Old versions receive security updates for six months.

| Version | Supported |
| ------- | ------------------------------------------ |
| 10.x | :white_check_mark: support ends 2024-01-16 |
| < 10 | :x: |
| 11.x | :white_check_mark: support ends 2024-07-03 |
| < 11 | :x: |

Pull Requests for security issues will be considered for older versions back to 2.x.

116 changes: 71 additions & 45 deletions docs/deprecated.md
Original file line number Diff line number Diff line change
@@ -4,20 +4,22 @@ These features are deprecated, which means they may go away in a future major ve
They are currently still available for backwards compatibility, but should not be used in new code.

- [Deprecated](#deprecated)
- [RegExp .option() parameter](#regexp-option-parameter)
- [noHelp](#nohelp)
- [Default import of global Command object](#default-import-of-global-command-object)
- [Callback to .help() and .outputHelp()](#callback-to-help-and-outputhelp)
- [.on('--help')](#on--help)
- [.on('command:\*')](#oncommand)
- [.command('\*')](#command)
- [cmd.description(cmdDescription, argDescriptions)](#cmddescriptioncmddescription-argdescriptions)
- [InvalidOptionArgumentError](#invalidoptionargumenterror)
- [Short option flag longer than a single character](#short-option-flag-longer-than-a-single-character)
- [Import from `commander/esm.mjs`](#import-from-commanderesmmjs)
- [cmd.\_args](#cmd_args)

## RegExp .option() parameter
- [RegExp .option() parameter](#regexp-option-parameter)
- [noHelp](#nohelp)
- [Callback to .help() and .outputHelp()](#callback-to-help-and-outputhelp)
- [.on('--help')](#on--help)
- [.on('command:\*')](#oncommand)
- [.command('\*')](#command)
- [cmd.description(cmdDescription, argDescriptions)](#cmddescriptioncmddescription-argdescriptions)
- [InvalidOptionArgumentError](#invalidoptionargumenterror)
- [Short option flag longer than a single character](#short-option-flag-longer-than-a-single-character)
- [Import from `commander/esm.mjs`](#import-from-commanderesmmjs)
- [cmd.\_args](#cmd_args)
- [.addHelpCommand(string|boolean|undefined)](#addhelpcommandstringbooleanundefined)
- [Removed](#removed)
- [Default import of global Command object](#default-import-of-global-command-object)

### RegExp .option() parameter

The `.option()` method allowed a RegExp as the third parameter to restrict what values were accepted.

@@ -29,7 +31,7 @@ Removed from README in Commander v3. Deprecated from Commander v7.

The newer functionality is the Option `.choices()` method, or using a custom option processing function.

## noHelp
### noHelp

This was an option passed to `.command()` to hide the command from the built-in help:

@@ -39,28 +41,7 @@ program.command('example', 'example command', { noHelp: true });

The option was renamed `hidden` in Commander v5.1. Deprecated from Commander v7.

## Default import of global Command object

The default import was a global Command object.

```js
const program = require('commander');
```

The global Command object is exported as `program` from Commander v5, or import the Command object.

```js
const { program } = require('commander');
// or
const { Command } = require('commander');
const program = new Command()
```

- Removed from README in Commander v5.
- Deprecated from Commander v7.
- Removed from TypeScript declarations in Commander v8.

## Callback to .help() and .outputHelp()
### Callback to .help() and .outputHelp()

These routines allowed a callback parameter to process the built-in help before display.

@@ -78,7 +59,7 @@ console.error(colors.red(program.helpInformation()));

Deprecated from Commander v7.

## .on('--help')
### .on('--help')

This was the way to add custom help after the built-in help. From Commander v3.0.0 this used the custom long help option flags, if changed.

@@ -103,7 +84,7 @@ Examples:

Deprecated from Commander v7.

## .on('command:*')
### .on('command:*')

This was emitted when the command argument did not match a known subcommand (as part of the implementation of `.command('*')`).

@@ -114,7 +95,7 @@ or for custom behaviour catch the `commander.unknownCommand` error.

Deprecated from Commander v8.3.

## .command('*')
### .command('*')

This was used to add a default command to the program.

@@ -134,7 +115,7 @@ program

Removed from README in Commander v5. Deprecated from Commander v8.3.

## cmd.description(cmdDescription, argDescriptions)
### cmd.description(cmdDescription, argDescriptions)

This was used to add command argument descriptions for the help.

@@ -157,7 +138,7 @@ program

Deprecated from Commander v8.

## InvalidOptionArgumentError
### InvalidOptionArgumentError

This was used for throwing an error from custom option processing, for a nice error message.

@@ -187,13 +168,13 @@ function myParseInt(value, dummyPrevious) {

Deprecated from Commander v8.

## Short option flag longer than a single character
### Short option flag longer than a single character

Short option flags like `-ws` were never supported, but the old README did not make this clear. The README now states that short options are a single character.

README updated in Commander v3. Deprecated from Commander v9.

## Import from `commander/esm.mjs`
### Import from `commander/esm.mjs`

The first support for named imports required an explicit entry file.

@@ -209,7 +190,7 @@ import { Command } from 'commander';

README updated in Commander v9. Deprecated from Commander v9.

## cmd._args
### cmd._args

This was always private, but was previously the only way to access the command `Argument` array.

@@ -224,3 +205,48 @@ const registeredArguments = program.registeredArguments;
```

Deprecated from Commander v11.

### .addHelpCommand(string|boolean|undefined)

This was originally used with a variety of parameters, but not by passing a Command object despite the "add" name.

```js
program.addHelpCommand('assist [command]');
program.addHelpCommand('assist', 'show assistance');
program.addHelpCommand(false);

```

In new code you configure the help command with `.helpCommand()`. Or use `.addHelpCommand()` which now takes a Command object, like `.addCommand()`.

```js
program.helpCommand('assist [command]');
program.helpCommand('assist', 'show assistance');
program.helpCommand(false);

program.addHelpCommand(new Command('assist').argument('[command]').description('show assistance'));

```
## Removed

### Default import of global Command object

The default import was a global Command object.

```js
const program = require('commander');
```

The global Command object is exported as `program` from Commander v5, or import the Command object.

```js
const { program } = require('commander');
// or
const { Command } = require('commander');
const program = new Command()
```

- Removed from README in Commander v5.
- Deprecated from Commander v7.
- Removed from TypeScript declarations in Commander v8.
- Removed from CommonJS in Commander v12. Deprecated and gone!
10 changes: 4 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
@@ -4,13 +4,11 @@ const { CommanderError, InvalidArgumentError } = require('./lib/error.js');
const { Help } = require('./lib/help.js');
const { Option } = require('./lib/option.js');

/**
* Expose the root command.
*/
exports.program = new Command();

exports = module.exports = new Command();
exports.program = exports; // More explicit access to global command.
// createArgument, createCommand, and createOption are implicitly available as they are methods on program.
exports.createCommand = (name) => new Command(name);
exports.createOption = (flags, description) => new Option(flags, description);
exports.createArgument = (name, description) => new Argument(name, description);

/**
* Expose classes
4 changes: 2 additions & 2 deletions lib/argument.js
Original file line number Diff line number Diff line change
@@ -50,7 +50,7 @@ class Argument {
}

/**
* @api private
* @package internal use only
*/

_concatValue(value, previous) {
@@ -130,7 +130,7 @@ class Argument {
*
* @param {Argument} arg
* @return {string}
* @api private
* @private
*/

function humanReadableArgName(arg) {
424 changes: 272 additions & 152 deletions lib/command.js

Large diffs are not rendered by default.

33 changes: 14 additions & 19 deletions lib/help.js
Original file line number Diff line number Diff line change
@@ -26,13 +26,8 @@ class Help {

visibleCommands(cmd) {
const visibleCommands = cmd.commands.filter(cmd => !cmd._hidden);
if (cmd._hasImplicitHelpCommand()) {
// Create a command matching the implicit help command.
const [, helpName, helpArgs] = cmd._helpCommandnameAndArgs.match(/([^ ]+) *(.*)/);
const helpCommand = cmd.createCommand(helpName)
.helpOption(false);
helpCommand.description(cmd._helpCommandDescription);
if (helpArgs) helpCommand.arguments(helpArgs);
const helpCommand = cmd._getHelpCommand();
if (helpCommand && !helpCommand._hidden) {
visibleCommands.push(helpCommand);
}
if (this.sortSubcommands) {
@@ -68,19 +63,19 @@ class Help {

visibleOptions(cmd) {
const visibleOptions = cmd.options.filter((option) => !option.hidden);
// Implicit help
const showShortHelpFlag = cmd._hasHelpOption && cmd._helpShortFlag && !cmd._findOption(cmd._helpShortFlag);
const showLongHelpFlag = cmd._hasHelpOption && !cmd._findOption(cmd._helpLongFlag);
if (showShortHelpFlag || showLongHelpFlag) {
let helpOption;
if (!showShortHelpFlag) {
helpOption = cmd.createOption(cmd._helpLongFlag, cmd._helpDescription);
} else if (!showLongHelpFlag) {
helpOption = cmd.createOption(cmd._helpShortFlag, cmd._helpDescription);
} else {
helpOption = cmd.createOption(cmd._helpFlags, cmd._helpDescription);
// Built-in help option.
const helpOption = cmd._getHelpOption();
if (helpOption && !helpOption.hidden) {
// Automatically hide conflicting flags. Bit dubious but a historical behaviour that is convenient for single-command programs.
const removeShort = helpOption.short && cmd._findOption(helpOption.short);
const removeLong = helpOption.long && cmd._findOption(helpOption.long);
if (!removeShort && !removeLong) {
visibleOptions.push(helpOption); // no changes needed
} else if (helpOption.long && !removeLong) {
visibleOptions.push(cmd.createOption(helpOption.long, helpOption.description));
} else if (helpOption.short && !removeShort) {
visibleOptions.push(cmd.createOption(helpOption.short, helpOption.description));
}
visibleOptions.push(helpOption);
}
if (this.sortOptions) {
visibleOptions.sort(this.compareOptions);
14 changes: 6 additions & 8 deletions lib/option.js
Original file line number Diff line number Diff line change
@@ -74,7 +74,7 @@ class Option {
* new Option('--rgb').conflicts('cmyk');
* new Option('--js').conflicts(['ts', 'jsx']);
*
* @param {string | string[]} names
* @param {(string | string[])} names
* @return {Option}
*/

@@ -158,7 +158,7 @@ class Option {
}

/**
* @api private
* @package internal use only
*/

_concatValue(value, previous) {
@@ -208,7 +208,6 @@ class Option {
* as a object attribute key.
*
* @return {string}
* @api private
*/

attributeName() {
@@ -220,7 +219,7 @@ class Option {
*
* @param {string} arg
* @return {boolean}
* @api private
* @package internal use only
*/

is(arg) {
@@ -233,7 +232,7 @@ class Option {
* Options are one of boolean, negated, required argument, or optional argument.
*
* @return {boolean}
* @api private
* @package internal use only
*/

isBoolean() {
@@ -293,7 +292,7 @@ class DualOptions {
*
* @param {string} str
* @return {string}
* @api private
* @private
*/

function camelcase(str) {
@@ -305,7 +304,7 @@ function camelcase(str) {
/**
* Split the short and long flag out of something like '-m,--mixed <value>'
*
* @api private
* @private
*/

function splitOptionFlags(flags) {
@@ -325,5 +324,4 @@ function splitOptionFlags(flags) {
}

exports.Option = Option;
exports.splitOptionFlags = splitOptionFlags;
exports.DualOptions = DualOptions;
7,588 changes: 1,725 additions & 5,863 deletions package-lock.json

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "commander",
"version": "11.1.0",
"version": "12.0.0",
"description": "the complete solution for node.js command-line programs",
"keywords": [
"commander",
@@ -16,7 +16,7 @@
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/tj/commander.js.git"
"url": "git+https://github.com/tj/commander.js.git"
},
"scripts": {
"lint": "npm run lint:javascript && npm run lint:typescript",
@@ -58,23 +58,23 @@
"devDependencies": {
"@types/jest": "^29.2.4",
"@types/node": "^20.2.5",
"@typescript-eslint/eslint-plugin": "^5.47.1",
"@typescript-eslint/parser": "^5.47.1",
"@typescript-eslint/eslint-plugin": "^6.7.5",
"@typescript-eslint/parser": "^6.7.5",
"eslint": "^8.30.0",
"eslint-config-standard": "^17.0.0",
"eslint-config-standard-with-typescript": "^33.0.0",
"eslint-config-standard-with-typescript": "^40.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jest": "^27.1.7",
"eslint-plugin-n": "^15.6.0",
"eslint-plugin-n": "^16.2.0",
"eslint-plugin-promise": "^6.1.1",
"jest": "^29.3.1",
"ts-jest": "^29.0.3",
"tsd": "^0.28.1",
"tsd": "^0.30.4",
"typescript": "^5.0.4"
},
"types": "typings/index.d.ts",
"engines": {
"node": ">=16"
"node": ">=18"
},
"support": true
}
54 changes: 54 additions & 0 deletions tests/command.addHelpOption.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
const { Command, Option } = require('../');

// More complete tests are in command.helpOption.test.js.

describe('addHelpOption', () => {
let writeSpy;
let writeErrorSpy;

beforeAll(() => {
// Optional. Suppress expected output to keep test output clean.
writeSpy = jest.spyOn(process.stdout, 'write').mockImplementation(() => { });
writeErrorSpy = jest.spyOn(process.stderr, 'write').mockImplementation(() => { });
});

afterEach(() => {
writeSpy.mockClear();
writeErrorSpy.mockClear();
});

afterAll(() => {
writeSpy.mockRestore();
writeErrorSpy.mockRestore();
});

test('when addHelpOption has custom flags then custom short flag invokes help', () => {
const program = new Command();
program
.exitOverride()
.addHelpOption(new Option('-c,--custom-help'));

expect(() => {
program.parse(['-c'], { from: 'user' });
}).toThrow('(outputHelp)');
});

test('when addHelpOption has custom flags then custom long flag invokes help', () => {
const program = new Command();
program
.exitOverride()
.addHelpOption(new Option('-c,--custom-help'));

expect(() => {
program.parse(['--custom-help'], { from: 'user' });
}).toThrow('(outputHelp)');
});

test('when addHelpOption with hidden help option then help does not include help option', () => {
const program = new Command();
program
.addHelpOption(new Option('-c,--custom-help', 'help help help').hideHelp());
const helpInfo = program.helpInformation();
expect(helpInfo).not.toMatch(/help/);
});
});
57 changes: 53 additions & 4 deletions tests/command.chain.test.js
Original file line number Diff line number Diff line change
@@ -34,12 +34,54 @@ describe('Command methods that should return this for chaining', () => {
expect(result).toBe(program);
});

test('when call .addHelpCommand() then returns this', () => {
test('when call .addHelpCommand(cmd) then returns this', () => {
const program = new Command();
const result = program.addHelpCommand(false);
const result = program.addHelpCommand(new Command('assist'));
expect(result).toBe(program);
});

test('when call deprecated .addHelpCommand() then returns this', () => {
const program = new Command();
const result = program.addHelpCommand();
expect(result).toBe(program);
});

test('when call deprecated .addHelpCommand(boolean) then returns this', () => {
const program = new Command();
const result1 = program.addHelpCommand(true);
expect(result1).toBe(program);
const result2 = program.addHelpCommand(false);
expect(result2).toBe(program);
});

test('when call deprecated .addHelpCommand(string[, string]) then returns this', () => {
const program = new Command();
const result1 = program.addHelpCommand('assist');
expect(result1).toBe(program);
const result2 = program.addHelpCommand('assist', 'assist description');
expect(result2).toBe(program);
});

test('when call .helpCommand(name) then returns this', () => {
const program = new Command();
const result = program.helpCommand();
expect(result).toBe(program);
});

test('when call .helpCommand(name, description) then returns this', () => {
const program = new Command();
const result1 = program.helpCommand('assist', 'assist description');
expect(result1).toBe(program);
});

test('when call .helpCommand(boolean) then returns this', () => {
const program = new Command();
const result1 = program.helpCommand(true);
expect(result1).toBe(program);
const result2 = program.helpCommand(false);
expect(result2).toBe(program);
});

test('when call .exitOverride() then returns this', () => {
const program = new Command();
const result = program.exitOverride(() => { });
@@ -130,9 +172,16 @@ describe('Command methods that should return this for chaining', () => {
expect(result).toBe(program);
});

test('when call .helpOption() then returns this', () => {
test('when call .helpOption(flags) then returns this', () => {
const program = new Command();
const flags = '-h, --help';
const result = program.helpOption(flags);
expect(result).toBe(program);
});

test('when call .addHelpOption() then returns this', () => {
const program = new Command();
const result = program.helpOption(false);
const result = program.addHelpOption(new Option('-h, --help'));
expect(result).toBe(program);
});

36 changes: 25 additions & 11 deletions tests/command.copySettings.test.js
Original file line number Diff line number Diff line change
@@ -31,11 +31,10 @@ describe('copyInheritedSettings property tests', () => {
test('when copyInheritedSettings then copies helpOption(false)', () => {
const source = new commander.Command();
const cmd = new commander.Command();
expect(cmd._hasHelpOption).toBeTruthy();

source.helpOption(false);
cmd.copyInheritedSettings(source);
expect(cmd._hasHelpOption).toBeFalsy();
expect(cmd._getHelpOption()).toBe(null);
});

test('when copyInheritedSettings then copies helpOption(flags, description)', () => {
@@ -44,21 +43,36 @@ describe('copyInheritedSettings property tests', () => {

source.helpOption('-Z, --zz', 'ddd');
cmd.copyInheritedSettings(source);
expect(cmd._helpFlags).toBe('-Z, --zz');
expect(cmd._helpDescription).toBe('ddd');
expect(cmd._helpShortFlag).toBe('-Z');
expect(cmd._helpLongFlag).toBe('--zz');
expect(cmd._getHelpOption()).toBe(source._getHelpOption());
// const helpOption = cmd._getHelpOption();
// expect(helpOption.flags).toBe('-Z, --zz');
// expect(helpOption.description).toBe('ddd');
// expect(helpOption.short).toBe('-Z');
// expect(helpOption.long).toBe('--zz');
});

test('when copyInheritedSettings then copies addHelpCommand(name, description)', () => {
test('when copyInheritedSettings then copies custom help command', () => {
const source = new commander.Command();
const cmd = new commander.Command();

source.addHelpCommand('HELP [cmd]', 'ddd');
source.helpCommand('HELP [cmd]', 'ddd');
cmd.copyInheritedSettings(source);
expect(cmd._helpCommandName).toBe('HELP');
expect(cmd._helpCommandnameAndArgs).toBe('HELP [cmd]');
expect(cmd._helpCommandDescription).toBe('ddd');
cmd.helpCommand(true); // force enable
const helpCommand = cmd._getHelpCommand();
expect(helpCommand).toBeTruthy();
expect(helpCommand.name()).toBe('HELP');
expect(helpCommand.description()).toBe('ddd');
});

test('when copyInheritedSettings then does not copy help enable override', () => {
const source = new commander.Command();
const cmd = new commander.Command();

// Existing behaviour, force enable/disable does not inherit,
// largely so (probably redundant) program.helpCommand(true) does not inherit to leaf subcommands.
source.helpCommand(true);
cmd.copyInheritedSettings(source);
expect(cmd._addHelpOption).toBeUndefined();
});

test('when copyInheritedSettings then copies configureHelp(config)', () => {
61 changes: 34 additions & 27 deletions tests/command.executableSubcommand.signals.test.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,46 @@
const childProcess = require('child_process');
const path = require('path');

// Test that a signal sent to the parent process is received by the executable subcommand process (which is listening).
const pmPath = path.join(__dirname, 'fixtures', 'pm');

// Disabling tests on Windows as:
// Disabling some tests on Windows as:
// "Windows does not support sending signals"
// https://nodejs.org/api/process.html#process_signal_events
const describeOrSkipOnWindows = (process.platform === 'win32') ? describe.skip : describe;

// Note: the previous (sinon) test had custom code for SIGUSR1, revisit if required:
// As described at https://nodejs.org/api/process.html#process_signal_events
// this signal will start a debugger and thus the process might output an
// additional error message:
// "Failed to open socket on port 5858, waiting 1000 ms before retrying".
describeOrSkipOnWindows('signals', () => {
test.each(['SIGINT', 'SIGHUP', 'SIGTERM', 'SIGUSR1', 'SIGUSR2'])('when program sent %s then executableSubcommand sent signal too', (signal, done) => {
// Spawn program. The listen subcommand waits for a signal and writes the name of the signal to stdout.
const proc = childProcess.spawn(pmPath, ['listen'], {});

describeOrSkipOnWindows.each([['SIGINT'], ['SIGHUP'], ['SIGTERM'], ['SIGUSR1'], ['SIGUSR2']])(
'test signal handling in executableSubcommand', (value) => {
// Slightly tricky test, stick with callback and disable lint warning.
// eslint-disable-next-line jest/no-done-callback
test(`when command killed with ${value} then executableSubcommand receives ${value}`, (done) => {
const pmPath = path.join(__dirname, './fixtures/pm');
let processOutput = '';
proc.stdout.on('data', (data) => {
if (processOutput.length === 0) {
// Send signal to program.
proc.kill(`${signal}`);
}
processOutput += data.toString();
});
proc.on('close', (code) => {
// Check the child subcommand received the signal too.
expect(processOutput).toBe(`Listening for signal...${signal}`);
done();
});
});

// The child process writes to stdout.
const proc = childProcess.spawn(pmPath, ['listen'], {});
test('when executable subcommand sent signal then program exit code is non-zero', () => {
const { status } = childProcess.spawnSync(pmPath, ['terminate'], {});
expect(status).toBeGreaterThan(0);
});

let processOutput = '';
proc.stdout.on('data', (data) => {
if (processOutput.length === 0) {
proc.kill(`${value}`);
}
processOutput += data.toString();
});
proc.on('close', (code) => {
expect(processOutput).toBe(`Listening for signal...${value}`);
done();
});
});
test('when command has exitOverride and executable subcommand sent signal then exit code is non-zero', () => {
const { status } = childProcess.spawnSync(pmPath, ['exit-override', 'terminate'], {});
expect(status).toBeGreaterThan(0);
});

// Not a signal test, but closely related code so adding here.
test('when command has exitOverride and executable subcommand fails then program exit code is subcommand exit code', () => {
const { status } = childProcess.spawnSync(pmPath, ['exit-override', 'fail'], {});
expect(status).toEqual(42);
});
});
24 changes: 18 additions & 6 deletions tests/command.positionalOptions.test.js
Original file line number Diff line number Diff line change
@@ -362,13 +362,25 @@ describe('program with action handler and positionalOptions and subcommand', ()

// ------------------------------------------------------------------------------

test('when program not positional and turn on passthrough in subcommand then error', () => {
const program = new commander.Command();
const sub = program.command('sub');
describe('broken passThrough', () => {
test('when program not positional and turn on passThroughOptions in subcommand then error', () => {
const program = new commander.Command();
const sub = program.command('sub');

expect(() => {
sub.passThroughOptions();
}).toThrow();
});

expect(() => {
sub.passThroughOptions();
}).toThrow();
test('when program not positional and add subcommand with passThroughOptions then error', () => {
const program = new commander.Command();
const sub = new commander.Command('sub')
.passThroughOptions();

expect(() => {
program.addCommand(sub);
}).toThrow();
});
});

// ------------------------------------------------------------------------------
49 changes: 49 additions & 0 deletions tests/command.registerClash.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const { Command } = require('../');

test('when command name conflicts with existing name then throw', () => {
expect(() => {
const program = new Command();
program.command('one');
program.command('one');
}).toThrow('cannot add command');
});

test('when command name conflicts with existing alias then throw', () => {
expect(() => {
const program = new Command();
program.command('one').alias('1');
program.command('1');
}).toThrow('cannot add command');
});

test('when command alias conflicts with existing name then throw', () => {
expect(() => {
const program = new Command();
program.command('one');
program.command('1').alias('one');
}).toThrow('cannot add alias');
});

test('when command alias conflicts with existing alias then throw', () => {
expect(() => {
const program = new Command();
program.command('one').alias('1');
program.command('unity').alias('1');
}).toThrow('cannot add alias');
});

test('when .addCommand name conflicts with existing name then throw', () => {
expect(() => {
const program = new Command();
program.command('one');
program.addCommand(new Command('one'));
}).toThrow('cannot add command');
});

test('when .addCommand alias conflicts with existing name then throw', () => {
expect(() => {
const program = new Command();
program.command('one');
program.addCommand(new Command('unity').alias('one'));
}).toThrow('cannot add command');
});
14 changes: 7 additions & 7 deletions tests/commander.configureCommand.test.js
Original file line number Diff line number Diff line change
@@ -85,10 +85,10 @@ test('when storeOptionsAsProperties() after adding option then throw', () => {
}).toThrow();
});

// test('when storeOptionsAsProperties() after setting option value then throw', () => {
// const program = new commander.Command();
// program.setOptionValue('foo', 'bar');
// expect(() => {
// program.storeOptionsAsProperties();
// }).toThrow();
// });
test('when storeOptionsAsProperties() after setting option value then throw', () => {
const program = new commander.Command();
program.setOptionValue('foo', 'bar');
expect(() => {
program.storeOptionsAsProperties();
}).toThrow();
});
2 changes: 1 addition & 1 deletion tests/fixtures-extensions/pm.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env node

const program = require('../../');
const { program } = require('../../');

program
.command('try-ts', 'test file extension lookup')
2 changes: 1 addition & 1 deletion tests/fixtures/inspect.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env node

const program = require('../../');
const { program } = require('../../');

process.env.FORCE_COLOR = 0; // work-around bug in Jest: https://github.com/jestjs/jest/issues/14391

15 changes: 13 additions & 2 deletions tests/fixtures/pm
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#!/usr/bin/env node

process.env.FORCE_COLOR = 0; // work-around bug in Jest: https://github.com/jestjs/jest/issues/14391
const path = require('node:path');
const { program } = require('../../');

var program = require('../../');
process.env.FORCE_COLOR = 0; // work-around bug in Jest: https://github.com/jestjs/jest/issues/14391

program
.version('0.0.1')
@@ -17,4 +18,14 @@ program
.command('specifyInstall', 'specify install subcommand', { executableFile: 'pm-install' })
.command('specifyPublish', 'specify publish subcommand', { executableFile: 'pm-publish' })
.command('silent', 'silently succeed')
.command('fail', 'exit with non-zero status code')
.command('terminate', 'terminate due to signal');

program
.command('exit-override')
.exitOverride((err) => { process.exit(err.exitCode); })
.command('fail', 'exit with non-zero status code', { executableFile: path.join(__dirname, 'pm-fail.js') })
.command('terminate', 'terminate due to signal', { executableFile: path.join(__dirname, 'pm-terminate.js') });

program
.parse(process.argv);
2 changes: 1 addition & 1 deletion tests/fixtures/pm-cache.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const program = require('../../');
const { program } = require('../../');

program
.command('clear', 'clear the cache')
1 change: 1 addition & 0 deletions tests/fixtures/pm-fail.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
process.exit(42);
1 change: 1 addition & 0 deletions tests/fixtures/pm-terminate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
process.kill(process.pid, 'SIGINT');
59 changes: 59 additions & 0 deletions tests/options.registerClash.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
const { Command, Option } = require('../');

describe('.option()', () => {
test('when short option flag conflicts then throws', () => {
expect(() => {
const program = new Command();
program
.option('-c, --cheese <type>', 'cheese type')
.option('-c, --conflict');
}).toThrow('Cannot add option');
});

test('when long option flag conflicts then throws', () => {
expect(() => {
const program = new Command();
program
.option('-c, --cheese <type>', 'cheese type')
.option('-H, --cheese');
}).toThrow('Cannot add option');
});

test('when use help options separately then does not throw', () => {
expect(() => {
const program = new Command();
program
.option('-h, --help', 'display help');
}).not.toThrow();
});

test('when reuse flags in subcommand then does not throw', () => {
expect(() => {
const program = new Command();
program
.option('e, --example');
program.command('sub')
.option('e, --example');
}).not.toThrow();
});
});

describe('.addOption()', () => {
test('when short option flags conflicts then throws', () => {
expect(() => {
const program = new Command();
program
.option('-c, --cheese <type>', 'cheese type')
.addOption(new Option('-c, --conflict'));
}).toThrow('Cannot add option');
});

test('when long option flags conflicts then throws', () => {
expect(() => {
const program = new Command();
program
.option('-c, --cheese <type>', 'cheese type')
.addOption(new Option('-H, --cheese'));
}).toThrow('Cannot add option');
});
});
71 changes: 59 additions & 12 deletions tests/program.test.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,67 @@
const commander = require('../');
const {
program,
Command,
Option,
Argument,
Help,
CommanderError,
InvalidArgumentError,
InvalidOptionArgumentError,
createCommand,
createOption,
createArgument
} = require('../index.js');

// Do some testing of the default export(s).
// Similar tests to ts-imports.test.ts and esm-imports-test.js.

test('when require commander then is a Command (default export of global)', () => {
// Deprecated global command
const program = commander;
expect(program.constructor.name).toBe('Command');
/* eslint jest/expect-expect: ["error", { "assertFunctionNames": ["expect", "checkClass"] }] */

function checkClass(obj, name) {
expect(typeof obj).toEqual('object');
expect(obj.constructor.name).toEqual(name);
}

test('program', () => {
checkClass(program, 'Command');
});

test('Command', () => {
checkClass(new Command('name'), 'Command');
});

test('Option', () => {
checkClass(new Option('-e, --example', 'description'), 'Option');
});

test('Argument', () => {
checkClass(new Argument('<foo>', 'description'), 'Argument');
});

test('Help', () => {
checkClass(new Help(), 'Help');
});

test('CommanderError', () => {
checkClass(new CommanderError(1, 'code', 'failed'), 'CommanderError');
});

test('InvalidArgumentError', () => {
checkClass(new InvalidArgumentError('failed'), 'InvalidArgumentError');
});

test('InvalidOptionArgumentError', () => { // Deprecated
checkClass(new InvalidOptionArgumentError('failed'), 'InvalidArgumentError');
});

test('createCommand', () => {
checkClass(createCommand('foo'), 'Command');
});

test('when require commander then has program (named export of global)', () => {
// program added in v5
const program = commander.program;
expect(program.constructor.name).toBe('Command');
test('createOption', () => {
checkClass(createOption('-e, --example', 'description'), 'Option');
});

test('when require commander then has newable Command', () => {
const cmd = new commander.Command();
expect(cmd.constructor.name).toBe('Command');
test('createArgument', () => {
checkClass(createArgument('<foo>', 'description'), 'Argument');
});
123 changes: 23 additions & 100 deletions tests/ts-imports.test.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,4 @@
import {
program,
Command,
Option,
Argument,
Help,
CommanderError,
InvalidArgumentError,
InvalidOptionArgumentError,
createCommand,
createOption,
createArgument
} from '../';

import * as commander from '../'; // This does interesting things when esModuleInterop is true!
import { program, Command, Option, CommanderError, InvalidArgumentError, InvalidOptionArgumentError, Help, createCommand } from '../';

// Do some simple checks that expected imports are available at runtime.
// Similar tests to esm-imports-test.js
@@ -23,97 +9,34 @@ function checkClass(obj: object, name: string): void {
expect(obj.constructor.name).toEqual(name);
}

describe('named imports', () => {
test('program', () => {
checkClass(program, 'Command');
});

test('Command', () => {
checkClass(new Command('name'), 'Command');
});

test('Option', () => {
checkClass(new Option('-e, --example', 'description'), 'Option');
});

test('Argument', () => {
checkClass(new Argument('<foo>', 'description'), 'Argument');
});

test('Help', () => {
checkClass(new Help(), 'Help');
});

test('CommanderError', () => {
checkClass(new CommanderError(1, 'code', 'failed'), 'CommanderError');
});

test('InvalidArgumentError', () => {
checkClass(new InvalidArgumentError('failed'), 'InvalidArgumentError');
});

test('InvalidOptionArgumentError', () => { // Deprecated
checkClass(new InvalidOptionArgumentError('failed'), 'InvalidArgumentError');
});

test('createCommand', () => {
checkClass(createCommand('foo'), 'Command');
});

test('createOption', () => {
checkClass(createOption('-e, --example', 'description'), 'Option');
});

test('createArgument', () => {
checkClass(createArgument('<foo>', 'description'), 'Argument');
});
test('program', () => {
checkClass(program, 'Command');
});

describe('import * as commander', () => {
test('program', () => {
checkClass(commander.program, 'Command');
});

test('Command', () => {
checkClass(new commander.Command('name'), 'Command');
});

test('Option', () => {
checkClass(new commander.Option('-e, --example', 'description'), 'Option');
});

test('Argument', () => {
checkClass(new commander.Argument('<foo>', 'description'), 'Argument');
});

test('Help', () => {
checkClass(new commander.Help(), 'Help');
});

test('CommanderError', () => {
checkClass(new commander.CommanderError(1, 'code', 'failed'), 'CommanderError');
});
test('createCommand', () => {
checkClass(createCommand(), 'Command');
});

test('InvalidArgumentError', () => {
checkClass(new commander.InvalidArgumentError('failed'), 'InvalidArgumentError');
});
test('Command', () => {
checkClass(new Command('name'), 'Command');
});

test('InvalidOptionArgumentError', () => { // Deprecated
checkClass(new commander.InvalidOptionArgumentError('failed'), 'InvalidArgumentError');
});
test('Option', () => {
checkClass(new Option('-e, --example', 'description'), 'Option');
});

// Factory functions are not found if esModuleInterop is true, so comment out tests for now.
// Can uncomment these again when we drop the default export of global program and add the factory functions explicitly.
test('CommanderError', () => {
checkClass(new CommanderError(1, 'code', 'failed'), 'CommanderError');
});

// test('createCommand', () => {
// checkClass(commander.createCommand('foo'), 'Command');
// });
test('InvalidArgumentError', () => {
checkClass(new InvalidArgumentError('failed'), 'InvalidArgumentError');
});

// test('createOption', () => {
// checkClass(commander.createOption('-e, --example', 'description'), 'Option');
// });
test('InvalidOptionArgumentError', () => { // Deprecated
checkClass(new InvalidOptionArgumentError('failed'), 'InvalidArgumentError');
});

// test('createArgument', () => {
// checkClass(commander.createArgument('<foo>', 'description'), 'Argument');
// });
test('Help', () => {
checkClass(new Help(), 'Help');
});
31 changes: 23 additions & 8 deletions typings/index.d.ts
Original file line number Diff line number Diff line change
@@ -419,18 +419,27 @@ export class Command {
arguments(names: string): this;

/**
* Override default decision whether to add implicit help command.
* Customise or override default help command. By default a help command is automatically added if your command has subcommands.
*
* @example
* ```ts
* program.helpCommand('help [cmd]');
* program.helpCommand('help [cmd]', 'show help');
* program.helpCommand(false); // suppress default help command
* program.helpCommand(true); // add help command even if no subcommands
* ```
* addHelpCommand() // force on
* addHelpCommand(false); // force off
* addHelpCommand('help [cmd]', 'display help for [cmd]'); // force on with custom details
* ```
*
* @returns `this` command for chaining
*/
addHelpCommand(enableOrNameAndArgs?: string | boolean, description?: string): this;
helpCommand(nameAndArgs: string, description?: string): this;
helpCommand(enable: boolean): this;

/**
* Add prepared custom help command.
*/
addHelpCommand(cmd: Command): this;
/** @deprecated since v12, instead use helpCommand */
addHelpCommand(nameAndArgs: string, description?: string): this;
/** @deprecated since v12, instead use helpCommand */
addHelpCommand(enable?: boolean): this;

/**
* Add hook for life cycle event.
@@ -838,6 +847,12 @@ export class Command {
*/
helpOption(flags?: string | boolean, description?: string): this;

/**
* Supply your own option to use for the built-in help option.
* This is an alternative to using helpOption() to customise the flags and description etc.
*/
addHelpOption(option: Option): this;

/**
* Output help information and exit.
*
15 changes: 13 additions & 2 deletions typings/index.test-d.ts
Original file line number Diff line number Diff line change
@@ -59,11 +59,19 @@ expectType<commander.Command>(program.argument('[value]', 'description', parseFl
expectType<commander.Command>(program.arguments('<cmd> [env]'));

// addHelpCommand
expectType<commander.Command>(program.addHelpCommand(new commander.Command('assist')));
// Deprecated uses
expectType<commander.Command>(program.addHelpCommand());
expectType<commander.Command>(program.addHelpCommand(false));
expectType<commander.Command>(program.addHelpCommand(true));
expectType<commander.Command>(program.addHelpCommand('compress <file>'));
expectType<commander.Command>(program.addHelpCommand('compress <file>', 'compress target file'));
expectType<commander.Command>(program.addHelpCommand('assist [cmd]'));
expectType<commander.Command>(program.addHelpCommand('assist [file]', 'display help'));

// helpCommand
expectType<commander.Command>(program.helpCommand(false));
expectType<commander.Command>(program.helpCommand(true));
expectType<commander.Command>(program.helpCommand('assist [cmd]'));
expectType<commander.Command>(program.helpCommand('assist [file]', 'display help'));

// exitOverride
expectType<commander.Command>(program.exitOverride());
@@ -302,6 +310,9 @@ expectType<commander.Command>(program.helpOption('-h,--help', 'custom descriptio
expectType<commander.Command>(program.helpOption(undefined, 'custom description'));
expectType<commander.Command>(program.helpOption(false));

// addHelpOption
expectType<commander.Command>(program.addHelpOption(new commander.Option('-h,--help')));

// addHelpText
expectType<commander.Command>(program.addHelpText('after', 'text'));
expectType<commander.Command>(program.addHelpText('afterAll', 'text'));