formatarc
v0.4.0
Published
Convert JSON, YAML, CSV, Markdown, HTML, and PDF from the terminal, and check Qiita / Zenn article compatibility. Browser-based version at formatarc.com.
Downloads
245
Maintainers
Readme
formatarc
Convert JSON, YAML, CSV, Markdown, HTML, and PDF from the terminal, and check whether a Qiita or Zenn article survives the move to the other platform — your data never leaves your machine. No config, no telemetry, no upload.
Web version → formatarc.com — the same conversions, 100% in your browser, no signup.
Why formatarc?
Most "online JSON / YAML / CSV converters" send the data you paste to a server. In November 2025, security firm watchTowr disclosed that two popular formatter sites (jsonformatter.org and codebeautify.org) had publicly exposed over 80,000 saved submissions (5 GB+) through a predictable "Recent Links" URL — including Active Directory credentials, cloud access keys, private keys, CI/CD secrets, JWTs, and full AWS Secrets Manager exports from government, banking, healthcare, and aerospace organizations. (watchTowr report)
formatarc is built so that can't happen. The CLI runs entirely on your machine, and the web version runs entirely in your browser — no upload, no logging, no telemetry, no account.
It is not only paste-to-a-server sites, either: in early 2026, a widely used JSON formatter browser extension was reported (on Hacker News and dev.to) to add third-party tracking and checkout-page injection after moving to a closed-source model — a reminder that an installed extension can change behaviour through an automatic update. Background on both risks: are online converters safe? and picking a JSON formatter Chrome extension by privacy and permissions.
| | formatarc CLI | formatarc web | Typical online converter | jq / yq / pandoc | |---|:---:|:---:|:---:|:---:| | Data stays local | ✅ | ✅ | ❌ | ✅ | | No signup / no upload | ✅ | ✅ | ⚠️ | ✅ | | JSON + YAML + CSV + Markdown + HTML in one tool | ✅ | ✅ | ⚠️ | ❌ | | Works offline | ✅ | after first load | ❌ | ✅ | | Single install | ✅ | n/a | n/a | ❌ |
JSON formatter comparison: privacy and breach history
A field-by-field comparison of the most common ways to format JSON in 2026. Sources for the breach column are linked below — paste-to-a-server sites have a verifiable incident history that local CLIs and browser-side tools structurally cannot.
| Tool | Type | Data stays local | Open source | Multi-format | Public breach (2024–2026) | |---|---|:---:|:---:|---|---| | formatarc (CLI) | CLI / npm | ✅ | ✅ MIT | JSON, YAML, CSV, Markdown, HTML | n/a — no server, no storage | | formatarc.com | Web (browser-side) | ✅ | ✅ MIT | JSON, YAML, CSV, Markdown, HTML | n/a — no server, no storage | | jsonformatter.org | Web (paste-to-server) | ❌ pasted JSON sent to server | ❌ | JSON-focused | ⚠️ Nov 2025 — 80,000+ saved submissions (5 GB+) exposed via predictable "Recent Links" URL (watchTowr) | | codebeautify.org | Web (paste-to-server) | ❌ pasted data sent to server | ❌ | multi-format | ⚠️ Nov 2025 — same watchTowr disclosure | | jsonlint.com | Web (paste-to-server) | ❌ pasted JSON sent to server | ❌ | JSON only | no public incident known to date | | jq | CLI | ✅ runs locally | ✅ MIT | JSON only | n/a | | prettier | CLI / npm | ✅ runs locally | ✅ MIT | code formatter (JSON, JS, TS, etc.) | n/a |
The takeaway is mechanical: if a tool sends your data to a third-party server, the breach surface is non-zero regardless of intent. CLIs and browser-side tools have no such surface to leak.
Install
npm install -g formatarcOr run directly with npx:
npx formatarc json-format '{"a":1}'Usage
formatarc <tool> [input or file]
cat file | formatarc <tool>Tools
| Command | Description |
|---------|-------------|
| json-format | Pretty-print JSON |
| yaml-to-json | Convert YAML to JSON |
| json-to-yaml | Convert JSON to YAML |
| csv-to-json | Convert CSV (with header row) to JSON |
| json-to-csv | Convert JSON objects to CSV (nested keys are flattened) |
| csv-to-markdown | Convert CSV to a Markdown (GFM) table |
| markdown-to-csv | Convert Markdown (GFM) tables to CSV |
| markdown-to-html | Convert Markdown to HTML |
| html-to-markdown | Convert HTML to Markdown |
| pdf-to-markdown | Extract the text of a PDF as Markdown |
| qiita-to-zenn | Check a Qiita article for Zenn compatibility |
| zenn-to-qiita | Check a Zenn article for Qiita compatibility |
About pdf-to-markdown
PDF is the one tool here that reads a file rather than text, and the one with real limits. They are worth knowing before you pipe it into anything:
- Works on PDFs that contain text. A scanned PDF stores each page as an image with no text layer, so it cannot be converted. The command says so and exits non-zero instead of guessing.
- Tables can come out misaligned. Most PDFs do not store a table as a table — the structure has to be inferred from lines and text positions. When a PDF contains tables, the command prints a note on stderr. Check the result against the original.
- Formulas are not supported.
- When the text layer cannot be read reliably (some CJK CFF fonts, where the extractor mistakes Adobe-Japan1 CIDs for Unicode codepoints), it falls back to plain text extraction and tells you on stderr. Headings and tables are not generated in that case.
Notes go to stderr, so formatarc pdf-to-markdown in.pdf > out.md still gives
you clean Markdown.
About qiita-to-zenn / zenn-to-qiita
These two do not convert an article and hand it back as done. They report every syntax difference and convert only the ones that convert without losing meaning, because most of them do not: of the 74 differences in the rule table, 37 convert deterministically, 14 need a decision only the author can make, and 23 have no counterpart at all. The table was compiled by surveying both platforms on 2026-08-04 and is shared with the web version, which lists the same counts: formatarc.com/en/qiita-zenn-compat.
The trap worth naming: Zenn renders Markdown with html: false, so raw HTML
that Qiita accepts — <details>, <img width>, <dl> — reaches the reader as
escaped tags. Nothing throws. The article just looks broken after it is
published. 21 rules are that shape, which is why the report exists at all.
The converted Markdown goes to stdout and the report to stderr, so
formatarc qiita-to-zenn article.md > converted.md gives you a clean article
and leaves the report on screen.
Examples
Format JSON:
formatarc json-format '{"name":"FormatArc","tools":["json","yaml","csv"]}'{
"name": "FormatArc",
"tools": [
"json",
"yaml",
"csv"
]
}Convert a YAML file to JSON:
formatarc yaml-to-json config.yamlPipe from curl:
curl -s https://api.example.com/data | formatarc json-formatConvert CSV from stdin:
cat users.csv | formatarc csv-to-jsonConvert JSON to CSV (nested objects become dotted column names):
cat users.json | formatarc json-to-csvConvert CSV to a Markdown table:
cat users.csv | formatarc csv-to-markdownPull the tables out of a Markdown document as CSV:
cat report.md | formatarc markdown-to-csvRender Markdown as HTML:
cat README.md | formatarc markdown-to-html > README.htmlStrip HTML to Markdown (handy for piping web pages into LLMs):
curl -s https://example.com | formatarc html-to-markdownExtract the text of a PDF as Markdown:
formatarc pdf-to-markdown report.pdf
formatarc pdf-to-markdown report.pdf > report.md
cat report.pdf | formatarc pdf-to-markdownCheck a Qiita article before moving it to Zenn:
formatarc qiita-to-zenn article.md > zenn-draft.mdValidate data in CI and git hooks
Every command exits 0 on success and 1 on failure, writing the result to stdout and any error to stderr. Errors are line-numbered, so a broken file points you straight at the problem instead of a cryptic parser dump:
$ echo '{"a":1,}' | formatarc json-format
Invalid JSON: remove the trailing comma on line 1.
$ echo $?
1That makes it a drop-in validator for pipelines and pre-commit hooks — and, like everything else here, the data never leaves the runner.
Fail a GitHub Actions build on malformed JSON or YAML:
- name: Validate config files
run: |
npx formatarc json-format config.json > /dev/null
npx formatarc yaml-to-json .github/settings.yaml > /dev/nullGate a cross-posting pipeline on article compatibility. qiita-to-zenn and
zenn-to-qiita exit 1 when the article carries anything that breaks
silently, needs a decision, or has no counterpart on the other platform, and
0 when every difference converted losslessly:
- name: Check the article survives the move to Zenn
run: npx formatarc qiita-to-zenn public/my-article.md > /dev/nullBlock a commit that stages invalid JSON (.git/hooks/pre-commit):
#!/bin/sh
for f in $(git diff --cached --name-only --diff-filter=ACM | grep '\.json$'); do
npx formatarc json-format "$f" > /dev/null || { echo "Invalid JSON in $f"; exit 1; }
doneProgrammatic API
import { convert } from "formatarc";
const result = convert("json-format", '{"a":1}');
console.log(result.output);
// {
// "a": 1
// }convert(tool, input)
Returns { output: string, error: string }.
output— the converted result (empty string on error)error— error message (empty string on success)
convertPdf(bytes)
PDF input is binary, so it does not go through convert(). Returns a promise.
It ships from formatarc/pdf rather than the package root: the implementation
imports node:fs and friends, and re-exporting it from the root broke bundlers
targeting the browser (the Chrome extension builds from this same package).
import { convertPdf, type PdfResult, type PdfRoute } from "formatarc/pdf";
import { readFileSync } from "node:fs";
const result = await convertPdf(new Uint8Array(readFileSync("report.pdf")));
if (result.error) throw new Error(result.error);
if (result.route === "refused") {
// scanned PDF — no text layer, OCR would be required
}
console.log(result.markdown);route—"inspector"(normal),"fallback"(text-only, the text layer was unreliable), or"refused"(scanned PDF, nothing was converted)hasTables— the PDF contains tables, so the result needs checkingpageCount,ocrPages,pdfType,error
analyzeQiitaZenn(input, direction, locale)
Ships from formatarc/qiita-zenn — it carries the rule table, which the string
conversions have no reason to load.
import { analyzeQiitaZenn } from "formatarc/qiita-zenn";
const result = analyzeQiitaZenn(markdown, "qiita-to-zenn", "en");
console.log(result.output); // the converted article
console.log(result.findings); // every difference, with line numbers
console.log(result.counts); // { total, breaksSilently, deterministic, lossy, unsupported }direction—"qiita-to-zenn"or"zenn-to-qiita"locale—"en"or"ja"; picks the language of the findings- a fourth argument takes the author's decisions (
{ [ruleId]: optionValue }). Without it, differences that need a decision are reported but left unconverted
Web Version
For a browser-based experience with no signup and no data upload:
- JSON Formatter, YAML ↔ JSON, CSV ↔ JSON
- CSV ↔ Markdown, Markdown ↔ HTML, PDF → Markdown
- Qiita / Zenn compatibility check
- Runs entirely in the browser
- Multilingual (English, Japanese, Spanish, Portuguese, Korean, Chinese)
There is also a Chrome extension for popup and right-click conversion — same browser-side processing, no upload.
Related projects by the same author
The CLI shares conversion logic and design goals with two sister projects, all under the same "data never leaves your machine" promise:
- Web app — formatarc.com — the same conversions, runs entirely in the browser, no signup
- Chrome extension — JSON / YAML formatter extension for Chrome — popup and right-click conversion, same browser-side processing
- npm package — formatarc on npm — this CLI's distribution channel
Companion reads on the privacy axis:
- Are online JSON / YAML / CSV converters safe? — what the November 2025 disclosure means for any "paste here, get formatted output" site
- Choosing a JSON formatter Chrome extension by privacy and permissions — what to check before installing a browser extension that touches every page
License
MIT
