Skip to content

feat: add configurable output stream - #13

Merged
PondWader merged 1 commit into
tinylibs:mainfrom
nightnei:addStderrStreamSupport
Apr 29, 2026
Merged

PondWader merged 1 commit into
tinylibs:mainfrom
nightnei:addStderrStreamSupport

Conversation

@nightnei

@nightnei nightnei commented Apr 29, 2026 •

Copy link
Copy Markdown
Contributor

picospinner currently writes all spinner frames to process.stdout. That is fine for simple interactive CLIs, but it breaks commands that reserve stdout for machine-readable output, such as JSON intended for jq, shell scripts, or CI tooling.

This PR adds an optional stream field to DisplayOptions, so callers can route spinner UI to stderr:

  const spinner = new Spinner({
    text: 'Loading...',
    stream: process.stderr,
  });

This gives CLI authors a way to follow the common convention (https://clig.dev/#the-basics) that stdout is for program output and stderr is for status/progress UI, without monkeypatching picospinner internals (as I temporary did here).
The default behavior is unchanged: spinners still write to process.stdout unless a stream is provided.

Testing instructions

  1. Let's assert that no regressions:
node --input-type=module -e "
  import { Spinner } from './dist/index.js';

  const spinner = new Spinner(
    { text: 'Loading...' },
    { colors: false }
  );

  spinner.start(80);

  setTimeout(() => {
    spinner.succeed('Done');
    console.log(JSON.stringify({ ok: true }));
  }, 250);
  "
  1. Assert that you see:
    Screenshot 2026-04-29 at 14 36 19
  2. Try the same with stderr:
node --input-type=module -e "
  import { Spinner } from './dist/index.js';

  const spinner = new Spinner(
    { text: 'Loading...', stream: process.stderr },
    { colors: false }
  );

  spinner.start(80);

  setTimeout(() => {
    spinner.succeed('Done');
    console.log(JSON.stringify({ ok: true }));
  }, 250);
  "
  1. Assert that you see the same:
    Screenshot 2026-04-29 at 14 36 19
  2. Try using jq to assert that it's indeed printed to stderr:
node --input-type=module -e "
  import { Spinner } from './dist/index.js';

  const spinner = new Spinner(
    { text: 'Loading...', stream: process.stderr },
    { colors: false }
  );

  spinner.start(80);

  setTimeout(() => {
    spinner.succeed('Done');
    console.log(JSON.stringify({ ok: true }));
  }, 250);
  " | jq
  1. Assert that you see no errors and json is parsed well (previously you would get error jq: parse error: Invalid numeric literal at line 1, column 3):
    Screenshot 2026-04-29 at 14 34 23

@43081j @PondWader

@PondWader
PondWader merged commit 4795283 into tinylibs:main Apr 29, 2026
4 checks passed
@PondWader

Copy link
Copy Markdown
Collaborator

Thanks, in hindsight defaulting to stdout was a mistake. Next major we should switch the default.

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.

2 participants