npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

formatpp

v0.1.0

Published

A professional code formatter for 26 languages, from JS to Zig to Vue to Python to Ruby

Readme

fmtpp — Format++

A professional-grade, multi-language code formatter written in C++. One static binary, twenty-six languages, zero runtime dependencies.

Full guides with the same content live on the docs site: docs/ (run npm run docs:dev inside docs/).

Supported languages

The formatter is picked from the file extension. Unknown extensions fall back to JavaScript.

| Language | Extensions | Formatter | Reference style | |------------|-----------------------------|--------------------|--------------------| | JavaScript | .js .mjs .cjs .jsx | JSFormatter | Prettier | | TypeScript | .ts .tsx .mts .cts | TSFormatter | Prettier | | Java | .java | JavaFormatter | google-java-format | | C | .c .h | CFormatter | clang-format | | C++ | .cpp .cc .cxx .hpp .hh .hxx .ino .cu .cuh | CppFormatter | clang-format | | C# | .cs | CSharpFormatter | dotnet format | | Go | .go | GoFormatter | gofmt | | Rust | .rs | RustFormatter | rustfmt | | Kotlin | .kt .kts | KotlinFormatter | ktfmt | | Swift | .swift | SwiftFormatter | swift-format | | Dart | .dart | DartFormatter | dart format | | PHP | .php .phtml | PhpFormatter | php-cs-fixer | | Scala | .scala .sc | ScalaFormatter | scalafmt | | Objective-C| .m .mm | ObjectiveCFormatter | clang-format | | Zig | .zig .zon | ZigFormatter | zig fmt | | D | .d .di | DFormatter | dfmt | | Groovy | .groovy .gvy | GroovyFormatter | Spotless | | Solidity | .sol | SolidityFormatter| prettier-plugin-solidity | | V | .v .vsh .vv | VFormatter | v fmt | | GLSL | .glsl .vert .frag .geom .comp .tesc .tese .vs .fs | GlslFormatter | clang-format | | HTML/XML | .html .htm .xhtml .svg .xml | HtmlFormatter | Prettier | | CSS | .css .scss .less | CssFormatter | Prettier | | JSON | .json | JSFormatter | Prettier | | Vue SFC | .vue | VueFormatter | Prettier/Volar | | Python | .py .pyw .pyi | PythonFormatter | black | | Ruby | .rb | RubyFormatter | rubocop |

Install

Option A — npm (prebuilt binary, no compilation)

npm install fmtpp
npx fmtpp --version

Prebuilt static binaries ship for linux-x64, linux-arm64, macos-x64, macos-arm64 and win-x64 under npm/. The fmtpp launcher (index.js) picks the right one for your OS and CPU.

Two escape hatches:

# Use an exact binary (e.g. your own build)
FMTPP_BINARY=/path/to/fmtpp npx fmtpp format main.js

# No matching prebuilt binary? The launcher compiles from source
# automatically using zig cc — no action needed.

Option B — build from source

You need CMake ≥ 3.16, Ninja (or Make) and a C++11-capable compiler (GCC 5+, Clang 6+, MSVC 2019+). CLI11 and toml++ are vendored under lib/, nothing else to install. Details in Building from source.

cmake -S . -B build
cmake --build build --config Release
./build/fmtpp --version        # Linux / macOS
.\build\fmtpp.exe --version    # Windows

Formatting files

Format one file (prints to stdout)

fmtpp format main.js
fmtpp main.js                  # shorthand, same thing

The formatted code goes to stdout, the original file is never touched. To rewrite a file in place, redirect:

# POSIX
fmtpp format main.js > main.js.tmp && mv main.js.tmp main.js

# PowerShell
fmtpp format main.js | Set-Content main.js.tmp; Move-Item main.js.tmp main.js -Force

Format several files at once

fmtpp format a.js b.go c.rs
Formatting 3 files with 16 threads...
  Formatted: a.js
  Formatted: b.go
  Formatted: c.rs
Done: 3 succeeded, 0 failed

This path is parallel (one file per thread) and prints a status report, not the formatted code. Single-file mode prints code; multi-file mode prints progress. Files that cannot be read or parsed are listed as Failed: and the command exits with code 1.

Which config is used?

format looks for .fmtpp.toml starting in the formatted file's own directory, then each parent directory (same rule as Prettier). The first config found wins; if none exists (or it is broken), built-in defaults apply. See Configuration.

Benchmark a file

fmtpp bench app.js                     # 10 iterations + warmup
fmtpp bench app.js --runs 100          # custom iteration count
fmtpp bench app.js --runs 20 --compare oxfmt   # also time Oxfmt/Prettier

Prints total/average/min/max/median/P95 time, throughput and a verdict against the 12 ms budget.

Configuration

fmtpp reads .fmtpp.toml (TOML). Three ways to get one:

fmtpp learn example.js                 # detect style, write ./.fmtpp.toml
fmtpp learn example.js --output custom.toml
fmtpp config                           # interactive TUI editor (needs a terminal)

learn runs StyleDetector over the file (indent, brace placement, semicolons, trailing commas, print width, spacing, final newline) and writes the result as TOML:

printWidth = 80
useTabs = false
tabWidth = 2
semi = true
singleQuote = false
trailingComma = "es5"     # "none", "es5" or "all"
bracketSpacing = true
arrowParens = "always"
endOfLine = "lf"          # "lf", "crlf", "cr" or "auto"
braceStyle = "same-line"  # "same-line" (K&R) or "next-line" (Allman)
spaceBeforeBrace = true
spaceAfterKeyword = true  # space after if/for/while
spaceAroundOperators = true

Defaults mirror Prettier. Unknown keys are ignored; a missing or unparseable file silently falls back to defaults.

CLI reference

fmtpp [OPTIONS] [FILE]
fmtpp <command> [options]

  fmtpp format <file...>   format files (code to stdout for 1 file, report for N)
  fmtpp <file>             shorthand for formatting a single file
  fmtpp bench <file> [--runs N] [--compare <oxfmt|prettier>]
  fmtpp learn <file> [--output .fmtpp.toml]
  fmtpp config             interactive TUI configurator
  fmtpp --version, -v
  fmtpp --help, -h

Hidden flags (just for fun): --easter-egg, --cowbell, --kittens, --unicorn. Running fmtpp with no arguments prints usage.

Exit codes: 0 on success, 1 when a file cannot be read/parsed or any file in a multi-file run fails.

Running the tests

C++ suites (the real coverage)

33 suites under ctest: one formatter suite per language plus infra (pool, buffers, parser, thread pool, config, benchmark).

# From the repo root:
cmake -S . -B build
cmake --build build --config Release
ctest --test-dir build --output-on-failure

Useful variants (run from build/):

ctest -R javaformatter --output-on-failure   # one suite only
ctest -R "formatter"                         # all 23 formatter suites
./test_goformatter.exe                       # run a suite binary directly

Each language suite is tests/test_<lang>formatter.cpp, with a matching real-world sample in tests/fixtures/sample.<ext>:

| Suite | Fixture | What it checks | |---|---|---| | test_jsformatter | sample.js | let/const, functions, imports, classes, arrows, arrays, objects, exports | | test_tsformatter | sample.ts | return types, interfaces, enums, type aliases, extends | | test_javaformatter | sample.java | public methods, extends/implements, imports, switch+break, try/catch | | test_cformatter | sample.c | decls, pointers, #include/#define, if/for/while, comments | | test_cppformatter | sample.cpp | Ret name(), : public Base, namespace, forward decls | | test_csharpformatter | sample.cs | public class : Base, IFace, methods, namespace, interfaces | | test_goformatter | sample.go | func, :=, no semicolons, structs, iota, panic, nil | | test_rustformatter | sample.rs | fn ->, let [mut], use, match, panic!, vec!, closures, traits | | test_kotlinformatter | sample.kt | fun, classes, when, package/import without semicolons | | test_swiftformatter | sample.swift | func ->, structs, for-in/switch without parens | | test_dartformatter | sample.dart | C-style functions, classes, quoted imports | | test_phpformatter | sample.php | $ sigils, use/namespace, <?php | | test_scalaformatter | sample.scala | def, classes/objects, match, package/import | | test_objectivecformatter | sample.m | @interface/@protocol/@end, raw methods | | test_zigformatter | sample.zig | fn, struct containers, @import, captures | | test_dformatter | sample.d | : bases, dotted imports, module | | test_groovyformatter | sample.groovy | def, package/import without semicolons | | test_solidityformatter | sample.sol | contract is, modifiers/returns, pragmas | | test_vformatter | sample.v | mut, real enums, module, unquoted imports | | test_glslformatter | sample.glsl | struct;, uniforms, #version | | test_htmlformatter | sample.html | inline/block elements, voids, comments | | test_cssformatter | sample.css | rules, prop: value;, at-rules | | test_vueformatter | sample.vue | template/script/style delegation |

Suites share one pattern: build ASTs with ASTNodeFactory on a local MemoryPool, format into an OutputBuffer, assert on the output, print N passed, M failed, return nonzero on failure. To add coverage, copy the closest suite and register its name in FMTPP_TESTS in CMakeLists.txt — no other wiring needed.

npm packaging tests

npm test   # runs tests/test_npm_packaging.js

Checks package.json fields, platform detection, binary-path resolution, binary slots for all five targets, the FMTPP_BINARY override and the compile-from-source fallback.

Building from source

cmake -S . -B build
cmake --build build --config Release

Tested compilers: GCC 5+, Clang 6+, MSVC 2019+. The project targets C++11; the three toml++-including files compile as C++17 via per-file flags (-std=c++17 / /std:c++17).

Three portability details, all automatic:

  • Linking. Fully-static -static applies on Linux only (the macOS linker forbids it; it breaks lld-link on Windows). Windows/MinGW gets -static-libstdc++ -static-libgcc; ws2_32 links on Windows.
  • SIMD. toml++ uses SSE2 intrinsics on x86-64. A configure-time compile+link probe (FMTPP_HAVE_WORKING_SSE2) detects toolchains that cannot link them and defines TOML_ENABLE_SIMD=0 (scalar fallback) for those builds only. Healthy toolchains keep SIMD with no flags.
  • UB sanitizer. cmake -S . -B build-sanitize -DFMTPP_SANITIZE_UB=ON builds with -fsanitize=undefined for QA runs.

Cross-compiling the npm binaries

bash scripts/build-all.sh            # needs zig cc; fills npm/<platform-arch>/

Single target:

cmake -S . -B build-cross -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake -DTARGET=linux-arm64
cmake --build build-cross --config Release

Targets: linux-x64, linux-arm64, macos-x64, macos-arm64, windows-x64 (see toolchain.cmake).

Docs site

cd docs
npm install
npm run docs:dev       # local preview
npm run docs:build     # static build

Project layout

include/fmtpp/   public headers (formatters, AST, infra)
src/             implementation (C++11, Java-style OOP)
tests/           CTest suites + tests/fixtures/ language samples
docs/            VitePress documentation site
lib/             vendored CLI11 + toml++ mirrors
npm/             prebuilt binary slots per platform-arch
scripts/         cross-compilation (zig cc) helpers

How it works

SourceBuffer → Parser → AST → FormatterVisitor → OutputBuffer → stdout
                             (one per language)     ↑
ThreadPool fans multi-file runs out; each job owns its buffer and parser.
  • Parser — a real language-aware parser: comment/string/regex aware scanning, brace matching, per-language profiles. Declarations, control flow, imports and comments become structured AST nodes; leaf expressions stay verbatim and anything unrecognized passes through as RawTextNode. Formatting restructures only what it understands, so output is never invented and code cannot be corrupted.
  • MemoryPool — one 10 MB bump-allocated chunk per thread; every AST node comes from ASTNodeFactory via placement new. No per-node new/delete, freed in one shot.
  • CstyleFormatterBase — the shared master for all C-like languages (indent, braces, semicolons, spacing, wrapping, comments). Subclasses override only what differs (visitFunctionDecl, visitClassDecl, …). Go and Rust extend FormatterVisitor directly.
  • Resources — every acquisition (fopen, malloc, mmap) lives in a RAII wrapper (FileHandle, MallocBuffer, MmapRegion) or a goto-cleanup function with a single exit label.
  • Config precedence: .fmtpp.toml found from the file upward > built-in defaults. StyleDetector (learn) and TuiConfigurator (config) both read and write that file.

Troubleshooting

  • Fresh configure fails oddly / stale errors after editing CMakeLists.txt. Delete the build dir and reconfigure: cmake -S . -B build re-runs automatically under Ninja, but a clean Remove-Item -Recurse build; cmake -S . -B build never hurts.
  • ctest says "No tests were found". You ran it from the repo root without --test-dir build, or from inside build/ with cmake --build build (that path only exists at the repo root). From the root: ctest --test-dir build. From inside build/: plain ctest.
  • test_threadpool segfaults once, passes on re-run. Known flake: workers share the global MemoryPool while Parser::parse calls g_pool->reset() — a data race. Re-run; the proper fix is per-thread pools (pending ThreadPool/Parser rework).
  • Link errors about _mm_* / SSE intrinsics. Your toolchain cannot link them (seen with mismatched Clang/MSVC installs). The build detects this at configure time (fmtpp: toolchain cannot link SSE2 intrinsics…) and falls back to the scalar TOML path automatically — no action needed.
  • Formatted output looks odd for an exotic construct. By design the parser passes through what it cannot model (method signatures in class bodies, complex attributes, switch arms) verbatim instead of restructuring it. Structure (braces, indentation, semicolons) still applies around it. If output ever drops or rewrites code, that is a bug — file an issue with the input.
  • .fmtpp.toml seems ignored. It is resolved from the formatted file's directory upward, not from your shell's cwd. Put it next to (or above) the file you format; check learn output parses with no typos in key names.

Current status and limitations

Implemented and tested: a real parser for all 26 languages, all formatters, config load/merge, learn, TUI config, bench (+--compare), thread-pool multi-file runs, npm packaging with five prebuilt targets.

Known fidelity limits (valid output, lighter formatting): JS/TS class method signatures, complex decorators/attributes and switch-arm bodies pass through verbatim; leaf expressions (conditions, arguments, initializers) print as written. The full phase plan lives in the engineering blueprint (fmtpp.txt, gitignored) and docs/guide/architecture.md.

License

MIT — see package.json (fmtpp on npm).