xml-but-prettier

A lightweight JavaScript library that indents and formats XML strings into human-readable output.

Library
npm
v1.0.1
1stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
22/100Needs Attention
Development Activity0
Maintenance20
Community8
Maturity60
Momentum0

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
54/100Fair
Architecture60
Code Quality55
Innovation30
Learning Curve70

xml-but-prettier is a small, focused JavaScript library that beautifies XML documents by placing each tag and text node on its own line and indenting everything to the correct nesting depth. The entire implementation is a single module built around a regex-based lexer that classifies each token as an opening tag, closing tag, self-closing tag, or text node, then walks the token stream while tracking depth to build the indented output.

The library began as a fork of jonathanp/xml-beautifier and is commonly reached for when a project needs to make generated markup readable — for example, using React as a static page generator and wanting the emitted HTML to be diff-friendly and human-readable rather than a single unbroken line. Configuration is minimal: a custom indentor string can replace the default four-space indent, and a textNodesOnSameLine option collapses short text content back onto the same line as its surrounding tag for more compact output. The only runtime dependency is repeat-string.

What You Get

  • A single-function API with a minimal, predictable signature: pass in an XML string and get back an indented one
  • Configurable indentation via the indentor option, so consumers can swap the default four-space indent for tabs or any custom string
  • A textNodesOnSameLine option that collapses short text nodes back onto the same line as their surrounding tag
  • A regex-based lexer that correctly distinguishes opening tags, closing tags, self-closing tags, and text nodes
  • Correct handling of attribute values containing / (e.g. href="/") so they aren’t mistaken for closing tags

Common Use Cases

  • Pretty-printing HTML emitted from React used as a static site generator
  • Debugging templating or code-generation pipelines by visually inspecting the nesting and indentation of their output
  • Normalizing serialized XML/HTML output in snapshot tests so diffs stay stable and readable
  • Formatting generated XML configuration or data files so they’re readable when reviewed by humans

Under The Hood

Architecture The library is a single ~80-line module (src/index.js) with no internal layering: a lexer function splits the input string on a tag-matching regex and classifies each resulting token as a ClosingTag, OpeningTag, SelfClosingTag, or Text node via small predicate helpers (isTag, isClosingTag, isSelfClosingTag, isOpeningTag). The exported function then maps over the token array once, tracking a depth counter that increments after opening tags and decrements before closing tags, prefixing each line with repeat-string-generated indentation. The textNodesOnSameLine option is implemented as a lookbehind pass over the same array that detects an OpeningTag/Text/ClosingTag triplet and collapses it into one line, marking the now-redundant indices for removal before the final join. There is no plugin system or extensibility surface beyond the two options; the abstraction that would break if changed is the token-classification regexes themselves, since depth tracking and formatting both depend on them.

Tech Stack The package targets plain Node.js/JavaScript with no framework dependency. Source is written in ES2015+ syntax and transpiled with Babel (babel-cli, babel-preset-es2015) via a build script that outputs to dist/, which is what main in package.json points to. The only runtime dependency is repeat-string, used purely for generating indentation whitespace. Tests run under Jest (babel-jest, jest), and tape is listed as a devDependency though the current test suite uses Jest exclusively. Releases are cut with release-it, and CI is configured via a Travis CI badge/config (.travis.yml).

Code Quality A single test file (test/main.js) exercises the public API with Jest’s describe/it blocks, covering basic tag indentation, self-closing tags, text node placement, the / attribute-value edge case, the indentor option, the textNodesOnSameLine option, and two performance assertions that process a bundled 2MB huge.xml fixture within fixed time budgets. There are no TypeScript types, no linter configuration, and no explicit error handling — the library assumes well-formed XML/HTML input and does not validate or throw on malformed markup. Naming is short and consistent with the module’s small scope, and the code favors plain functions over classes throughout.

What Makes It Unique The library doesn’t attempt to be a general XML parser or DOM library — it deliberately stays a single-pass, regex-based line formatter, which keeps its footprint and dependency surface minimal compared to full XML toolkits. Its two configuration options (custom indent characters and same-line text collapsing) are narrowly scoped to the one real complaint the README calls out: making programmatically generated markup readable, particularly output from using a UI framework as a static renderer. It does not aim to compete with general-purpose XML/HTML formatters on features like attribute reordering, comment handling, or CDATA support.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search