Skip to content

feat(cli): add --json output flag to list and env commands - #195

Open
aosmcleod wants to merge 3 commits into
heroui-inc:mainfrom
aosmcleod:feat/json-output
Open

feat(cli): add --json output flag to list and env commands#195
aosmcleod wants to merge 3 commits into
heroui-inc:mainfrom
aosmcleod:feat/json-output

Conversation

@aosmcleod

Copy link
Copy Markdown
Contributor

Closes #192

📝 Description

Adds a --json flag to the list and env commands that outputs structured JSON instead of the human-readable box-drawing tables.

heroui list --json

{
  "packages": [
    {
      "package": "@heroui/react",
      "version": "3.0.0 -> 3.0.4",
      "status": "stable",
      "docs": "https://heroui.com"
    },
    {
      "package": "@heroui/styles",
      "version": "3.0.0 -> 3.0.4",
      "status": "stable",
      "docs": "https://heroui.com"
    }
  ]
}

heroui env --json

{
  "packages": [...],
  "environment": {
    "os": "darwin",
    "arch": "arm64",
    "nodeVersion": "v22.0.0"
  }
}

Why

  • CI/CD pipelines need to parse CLI output programmatically
  • Scripts wrapping the CLI can't reliably parse colored table output with ANSI codes
  • Other tools (MCP servers, IDE extensions) could consume structured output
  • Standard pattern in modern CLIs (npm, yarn, pnpm all support --json)

Implementation

The data was already structured internally as PackageComponent[] objects. This PR adds an alternative output path:

  1. Added --json option to list and env command registration
  2. In each action, checks for the flag and JSON.stringifys the data instead of calling outputComponents()
  3. When --json is set, outputs clean JSON to stdout (no banners, no colors)
  4. Errors are also output as JSON when the flag is set

💣 Is this a breaking change (Yes/No):

No — the flag is opt-in. Default behavior is unchanged.

✅ Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Refactoring (improve a current implementation without adding a new feature or fixing a bug)
  • Improvement (non-breaking change which improves an existing feature)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update

@aosmcleod
aosmcleod requested a review from jrgarciadev as a code owner May 24, 2026 21:21

@wingkwong wingkwong left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

pls fix lint

@wingkwong wingkwong changed the title feat(cli): add --json output flag to list and env commands (fix #192) feat(cli): add --json output flag to list and env commands May 25, 2026
Apply eslint --fix for sort-keys / sort-destructure-keys / prettier
errors in list-action and env-action, and replace direct console.log
calls with Logger.log so they no longer trip the no-console rule
(--max-warnings=0).
@aosmcleod

Copy link
Copy Markdown
Contributor Author

@wingkwong fixed the lint. The failing job was ESLint (under the `lint` workflow) with sort-keys / sort-destructure-keys / prettier errors plus four no-console warnings — and --max-warnings=0 failed the whole job on the warnings too.

  • Ran `eslint --fix` to auto-fix the sort-keys / prettier rules on the two action files.
  • Replaced the four `console.log` calls (used for the new JSON output) with `Logger.log` so the `no-console` rule isn't tripped — `Logger.log` already wraps `console.log` and has `/* eslint-disable no-console */` at the top of the file.

Local `pnpm lint` now exits clean. Ready for re-review.

@aosmcleod
aosmcleod requested a review from wingkwong May 28, 2026 15:34
@wingkwong wingkwong assigned wingkwong and unassigned aosmcleod May 28, 2026

@wingkwong wingkwong left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

image

If it is for CI, I think we shouldn't use -> like table one. I'd suggest something like

{
  "package": "@heroui/react",
  "version": "3.0.0",
  "latestVersion": "3.0.4",
  "upgradeAvailable": true,
  "versionMode": "^",
  "status": "stable",
  "docs": "https://heroui.com"
}

Comment on lines +21 to +27
if (json) {
Logger.log(JSON.stringify({packages: []}, null, 2));
} else {
Logger.warn(
'No HeroUI packages found. Run `heroui install` to install @heroui/react and @heroui/styles.'
);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The key message "No HeroUI packages found. Run heroui install to install @heroui/react and @heroui/styles." should be shown even in --json mode.

{
  "packages": []
}

Comment thread src/actions/env-action.ts Outdated

export async function envAction(options: EnvOptions) {
const {packagePath = resolver('package.json')} = options;
const {json, packagePath = resolver('package.json')} = options as EnvOptions & {json?: boolean};

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

avoid as ... & { json?: boolean }. just add it in EnvOptions

Comment thread src/actions/list-action.ts Outdated

export async function listAction(options: CommandOptions) {
const {packagePath = resolver('package.json')} = options;
const {json, packagePath = resolver('package.json')} = options as CommandOptions & {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

avoid as ... & { json?: boolean }. just add it in CommandOptions

Comment thread src/actions/list-action.ts Outdated
} catch (error) {
Logger.prefix('error', `An error occurred while listing packages: ${error}`);
if (json) {
Logger.log(JSON.stringify({error: String(error)}, null, 2));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

if it is an error, it shouldn't use Logger.log

@wingkwong wingkwong assigned aosmcleod and unassigned wingkwong May 30, 2026
- Add `json?: boolean` to CommandOptions and EnvOptions, drop the
  `as ... & { json?: boolean }` casts in both action files.
- Restructure JSON package objects to match the requested CI-friendly
  shape: split the previous `"current -> latest"` string into discrete
  `version`, `latestVersion`, `upgradeAvailable`, `versionMode` fields.
  Helper lives in @helpers/package as mapPackageComponentForJson.
- list --json with no installed packages now ALSO emits the human
  hint (via Logger.warn → stderr) so the message isn't silently
  dropped, while the `{ "packages": [] }` JSON still goes to stdout.
- list --json error path uses Logger.error (stderr) instead of
  Logger.log so errors don't masquerade as regular output.
- Suppress the gradient "HeroUI CLI v<version>" branding banner when
  `--json` is on the command line so the JSON payload on stdout
  remains clean for `... --json | jq` pipelines.
@aosmcleod

Copy link
Copy Markdown
Contributor Author

@wingkwong addressed all four inline comments plus the JSON shape suggestion:

Type definitions — added json?: boolean to CommandOptions and EnvOptions in src/helpers/type.ts. Removed the as CommandOptions & { json?: boolean } casts from both list-action.ts and env-action.ts.

JSON output shape — restructured to match your suggestion. The previous string-with-arrow "3.0.0 -> 3.0.4" is now split into discrete fields. Helper extracted to @helpers/package as mapPackageComponentForJson so list and env share it. Example:

```json
{
"docs": "https://heroui.com",
"latestVersion": "3.1.0",
"package": "@heroui/react",
"status": "stable",
"upgradeAvailable": true,
"version": "3.0.0",
"versionMode": "^"
}
```

(Keys are alphabetized to satisfy sort-keys — same set of fields you suggested.)

list --json no-packages case — still emits the No HeroUI packages found... hint, via Logger.warn to stderr so the JSON payload on stdout stays clean for ... --json | jq pipelines. The JSON path emits { "packages": [] } to stdout. Both are present.

list --json error path — switched from Logger.log to Logger.error so error responses don't masquerade as regular output.

Bonus — found a separate stdout-pollution issue while testing: the gradient "HeroUI CLI v<version>" banner was emitting to stdout on every command, contaminating --json output. Added a guard in getCommandDescAndLog so the banner is suppressed when --json is on the command line. Verified end-to-end: node dist/index.js list --json and ... env --json now emit only the JSON payload to stdout.

Ready for re-review.

@aosmcleod
aosmcleod requested a review from wingkwong May 31, 2026 18:35
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.

[FEAT] - Add --json output flag to list and env commands for CI/scripting

2 participants