Skip to content

feat: add --format markdown output format#270

Open
TimNooren wants to merge 2 commits intomainfrom
feat/markdown-format
Open

feat: add --format markdown output format#270
TimNooren wants to merge 2 commits intomainfrom
feat/markdown-format

Conversation

@TimNooren
Copy link
Contributor

@TimNooren TimNooren commented Mar 8, 2026

Summary

Adds GitHub-flavoured Markdown as an output format via --format markdown. Zero external dependencies.

What

  • formatMarkdown(data) — pure Node.js, no deps
    • Arrays → GFM table with | col | col | syntax + | --- | separator, up to 10 columns / 100 rows
    • Single objects → - **key**: value list
    • Error path → **Error:** message
  • formatOutput() gains a markdown branch alongside csv/table/pretty
  • --format markdown advertised in research subcommand help
  • README updated

Usage

nansen research smart-money token-flows --chain ethereum --format markdown

Sample output:

## Results (2 items)

| symbol | price_usd | volume_usd |
| --- | --- | --- |
| ETH | 2.10K | 1500.00M |
| BTC | 48.00K | 3200.00M |

Zero regression risk

Opt-in flag. All existing formats unchanged. 876/876 tests pass.

🤖 Generated with Claude Code

Zero-dependency GFM rendering for agent pipelines.
Arrays → GFM tables; single objects → bold key-value lists.
LLMs parse markdown natively — no external package needed.

Alternative to --format toon (PR #268); resolves the same
token-efficiency problem without adding a dependency.
@nansen-pr-reviewer
Copy link

nansen-pr-reviewer bot commented Mar 8, 2026

pr-reviewer Summary

📝 3 findings

Review completed. Please address the findings below.

Findings by Severity

Severity Count
🟡 Medium 1
🔵 Low 2

Review effort: 2/5 (Simple)

Summary

A clean, well-scoped addition of a --format markdown output mode. The implementation follows existing patterns, tests cover all the key paths (unwrapping shapes, escaping, empty results, error path), and there are zero external dependencies. Three minor issues worth addressing:

Findings

src/cli.jsformatOutput markdown branch

[medium] Nullish coalescing vs. logical OR inconsistency

The markdown branch uses ?? while the csv branch uses ||:

// markdown (line 374)
const mdData = data.data ?? data;

// csv (line 380)
const csvData = data.data || data;

These diverge when data.data is 0, false, or ''. For data.data = false, ?? passes false to formatMarkdown, which isn't an array or object with the known shapes — records stays [] and the function returns '*(no results)*' instead of the full response object. In practice API responses never produce a falsy data.data, but the inconsistency is a latent surprise. Align with the existing || pattern for consistency.


src/cli.jsformatMarkdown column header

[low] Column names are not pipe-escaped in the GFM table header

Cell values correctly escape | with \\|, but the header row joins raw column names:

const header = `| ${columns.join(' | ')} |`;

If a field name ever contained |, the header row would produce malformed GFM. Real Nansen API field names are snake_case so this won't trigger in practice, but it's an inconsistency with the value-escaping logic directly below.

Fix: apply the same .replace(/\|/g, '\\|') to column names when building the header.


src/cli.js--format markdown + --stream interaction

[low] --format markdown is silently ignored when --stream is also passed

The stream branch at line 1650 returns NDJSON regardless of the markdown flag, with no warning. A user who writes nansen research … --stream --format markdown will get NDJSON. Documenting the mutual exclusion in the help text (or emitting a one-line warning via log()) would prevent confusion.


Token usage: 16 input, 8,829 output, 210,240 cache read, 29,959 cache write

- Fix help text: split --table/-t and --format <fmt> (table is a flag,
  not a --format value)
- Escape newlines in markdown cell values to prevent broken GFM rows
- Add 10 unit tests for formatMarkdown covering all extraction shapes,
  edge cases, and formatOutput integration
@TimNooren
Copy link
Contributor Author

All three addressed in 4c233c8:

  • Help text (High): Split into two separate lines — --table / -t for the flag, --format <fmt> listing only json, csv, markdown. No more false --format table.
  • Newline escaping (Low): Added .replace(/[\n\r]/g, ' ') alongside the pipe escape in the row builder.
  • Test coverage (Medium): Added 10 unit tests for formatMarkdown covering: empty array, array → GFM table, all four extraction shapes (data, data.data, data.results, data.data.results), single object → key-value, pipe escaping, newline escaping, and both formatOutput paths (success + error). 886/886 passing.

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.

1 participant