HTML to Plain Text CLI
A dependency-free Node CLI that converts a small HTML document to readable plain text, honoring block breaks and decoding common entities.
Project
node-html-to-text
Entry point: html-to-text.mjs
Install
node --versionRun
node html-to-text.mjs page.htmlTest
node --test html-to-text.test.mjsExpected output
Prints the visible text with block elements on separate lines and HTML entities decoded, and strips script and style contents.Dependencies
- node >=20
What it does
Removes script and style blocks, replaces block-level tags with newlines, strips remaining tags, and decodes a set of named and numeric entities. It is intentionally a small, predictable converter rather than a full parser.
const ENTITIES = { amp: '&', lt: '<', gt: '>', quot: '"', apos: "'", nbsp: ' ' };
const BLOCK = /<\/?(p|div|h[1-6]|li|tr|br|section|article)[^>]*>/gi;
export function htmlToText(html) {
return html
.replace(/<(script|style)[\s\S]*?<\/\1>/gi, ' ')
.replace(BLOCK, '\n')
.replace(/<[^>]+>/g, '')
.replace(/&#(\d+);/g, (_, d) => String.fromCodePoint(Number(d)))
.replace(/&(\w+);/g, (m, name) => ENTITIES[name] ?? m)
.split('\n').map((l) => l.trim()).filter(Boolean).join('\n');
}
import { readFileSync } from 'node:fs';
const file = process.argv[2];
const input = file ? readFileSync(file, 'utf8') : readFileSync(0, 'utf8');
console.log(htmlToText(input));
Run and verify
node html-to-text.mjs page.html
Run the test command to check the implementation: node --test html-to-text.test.mjs.
Expected Output
For a document containing <h1>Title</h1><p>A & B</p>, script and style are dropped and entities decoded:
Title
A & B
Limitations
Not a spec-compliant parser: malformed markup, entity edge cases, and nested tables may not convert as a browser would render them.