Skip to content

Make piped xmd syntax output complete #715

Description

@taras

Story

As a tool consuming the component catalog, I want piped xmd syntax output to
finish completely before the command exits, so I can rely on receiving valid,
complete Markdown or JSON.

Example

These two forms must produce the same bytes:

xmd syntax --json > direct.json
xmd syntax --json | cat > piped.json

cmp direct.json piped.json
jq empty piped.json

The same guarantee applies when the pipe's reader consumes output slowly.

Current gap

xmd syntax --json produces a complete catalog when stdout is a regular file,
but a catalog larger than the pipe buffer can end mid-token when stdout is a
pipe. A consumer such as jq receives truncated JSON even though xmd exits
without reporting a failure.

The current command hands the rendered catalog to process.stdout.write() and
can finish without waiting for an asynchronous pipe write to drain. Registering
additional components made the catalog exceed roughly 64 KiB and exposed the
existing lifetime defect; those components did not cause it.

Issue #632 established xmd syntax --json as the complete structured catalog.
Issue #678 consumes that catalog for generated reference documentation, but
does not own the CLI output lifetime.

Contract

  • xmd syntax does not complete successfully until stdout has accepted the
    complete rendered catalog.
  • A regular-file redirect and a pipe receive byte-identical output for the same
    invocation, in both Markdown and JSON forms.
  • Backpressure changes how long the command takes, not which bytes arrive.
  • A sink that closes or refuses the write makes the command fail rather than
    silently succeeding with partial output.
  • TTY presentation and catalog generation remain unchanged; this story owns
    delivery of the already-rendered xmd syntax result, not another catalog
    format or a general rewrite of CLI output.

Acceptance

  • A real subprocess emits a catalog larger than the platform pipe buffer through
    a slow or backpressured pipe, and the received bytes equal direct redirection.
  • The piped JSON parses successfully and contains the complete version-1
    catalog, including an entry placed beyond the former truncation boundary.
  • The default Markdown form is likewise complete through the same boundary.
  • Closing the consumer before completion produces a non-zero command outcome
    instead of a successful truncated result or a late unhandled write failure.
  • The regression fails when the command returns immediately after a
    fire-and-forget process.stdout.write().

Evidence

Extend the real CLI coverage in
packages/cli/tests/syntax-cli.test.ts and run:

deno task test packages/cli/tests/syntax-cli.test.ts

Use an actual subprocess and pipe boundary. A small catalog or a mocked
process.stdout.write() alone cannot discriminate the failure.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions