Skip to content

feat: add ids-only output support - #121

Merged
gnapse merged 2 commits into
mainfrom
ernesto/add-ids-only-output
Aug 27, 2026
Merged

feat: add ids-only output support#121
gnapse merged 2 commits into
mainfrom
ernesto/add-ids-only-output

Conversation

@gnapse

@gnapse gnapse commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

Doist CLIs need a consistent way to return stable entity IDs for scripts and agents without requiring each consumer to reimplement output-mode validation, empty-state behavior, and machine-output detection.

Summary

  • add ListViewOptions and a canonical resolveOutputMode helper
  • add formatIds and outputIds for string and numeric IDs
  • parse --ids-only as a global machine-output signal and disable spinners for it
  • keep empty IDs-only results silent and support the mode in shared empty-output tests
  • reject combinations of --json, --ndjson, and --ids-only

Example

const mode = resolveOutputMode(options)
if (mode === "ids-only") {
    outputIds(items, (item) => item.id, paginationNotice)
    return
}

After release, Todoist CLI can replace its local helpers with these exports, and other CLIs can add the flag only to list commands with stable, unambiguous IDs.

@doistbot doistbot 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.

This PR adds a shared ids-only output mode to cli-core: a canonical resolveOutputMode helper, formatIds/outputIds emitters for string and numeric IDs, global --ids-only parsing with spinner gating, silent empty-state handling, and rejection of conflicting --json/--ndjson/--ids-only combinations — all well-tested and README-documented. Few things worth tightening:

  • printEmpty re-implements the flag→mode mapping inline instead of routing through resolveOutputMode, leaving two sources of truth; funneling through the resolver also makes it throw on conflicting flags rather than silently preferring --json, matching the contract this PR introduces.
  • Minor type nit: idsOnly is declared optional on the parsed GlobalArgs type even though the parser always initializes it to false.

I also included a few optional follow-up notes in the details below.

Optional follow-up notes (3)
  • P3 src/global-args.ts:20: idsOnly is declared via Pick<ListViewOptions, 'idsOnly'> (optional), but parseGlobalArgs always returns idsOnly: false. This is inconsistent with json/ndjson, which are Required because they too are always populated. Consumers reading args.idsOnly end up with boolean | undefined and need to handle undefined even though it never occurs. Fold idsOnly into the Required<Pick<...>> for consistency: Required<Pick<ListViewOptions, 'json' | 'ndjson' | 'idsOnly'>>.
  • P3 src/commands/errors.ts:7: CONFLICTING_OPTIONS is now listed under CommandErrorCode, whose doc comment says these are "codes thrown by @doist/cli-core/commands" — but the only throw site is resolveOutputMode in the root src/options.ts, not the commands subpath. Either amend the comment to note this code originates from the root options module, or move it to a root-level error-code union so the comment stays accurate.
  • P3 src/options.test.ts:49: The conflicts are asserted via toThrow(message), matching the human-readable string. resolveOutputMode throws a CliError with the stable 'CONFLICTING_OPTIONS' code, so the tests should assert on that code instead, e.g. expect(() => resolveOutputMode(options)).toThrowError(expect.objectContaining({ code: 'CONFLICTING_OPTIONS' })). Coupling the test to the message makes any future wording change break it for the wrong reason.

Share FeedbackReview Logs

Comment thread src/empty.ts Outdated
@gnapse

gnapse commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed the review feedback in fa464d9:

  • route empty-state handling through the canonical resolver
  • make parsed idsOnly a required boolean
  • clarify the shared error-code ownership
  • assert the stable conflict code in resolver tests

The updated core build also passes the full Todoist CLI suite through a local package link.

@gnapse
gnapse force-pushed the ernesto/add-ids-only-output branch from fa464d9 to f956eb4 Compare August 27, 2026 15:20
@gnapse
gnapse merged commit 43eaf80 into main Aug 27, 2026
5 checks passed
@gnapse
gnapse deleted the ernesto/add-ids-only-output branch August 27, 2026 15:27
doist-release-bot Bot added a commit that referenced this pull request Aug 27, 2026
## [1.4.0](v1.3.0...v1.4.0) (2026-08-27)

### Features

* add ids-only output support ([#121](#121)) ([43eaf80](43eaf80))
@doist-release-bot

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.4.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants