decode-named-character-reference

Decodes a single named HTML character reference, such as amp or notin, into its actual Unicode character.

Library
npm
v1.3.0
3stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
23/100Needs Attention
Development Activity4
Maintenance20
Community12
Maturity56
Momentum0

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
61/100Good
Architecture70
Code Quality75
Innovation55
Learning Curve45

decode-named-character-reference is a minimal, focused utility for turning one named HTML character reference — the identifier between the & and the ; in something like & — into the actual character it represents. Given a string such as amp it returns &; given an unrecognized name it returns false rather than throwing, so callers can treat it as a simple lookup instead of wrapping every call in a try/catch.

The package ships two interchangeable implementations selected automatically via Node’s package.json exports conditions: a table-driven version for Node.js, Deno, and edge runtimes that looks up the reference in the character-entities dataset, and a DOM-based version for browsers that lets the browser’s own HTML parser do the decoding by writing &value; into a detached element and reading back its textContent. This keeps browser bundles small by not shipping the full entity table twice. It’s a low-level building block used internally by higher-level HTML/markdown parsing packages such as parse-entities, rather than something most application code calls directly.

What You Get

  • Single exported function - decodeNamedCharacterReference(value) takes the bare reference name (no & or ;) and returns the decoded string or false.
  • Dual runtime implementations - a table-driven Node/Deno/edge version and a DOM-based browser version, picked automatically via package.json exports conditions.
  • Full TypeScript types - ships hand-authored .d.ts declarations built with tsc and enforced at 100% type coverage.
  • Zero-throw contract - unrecognized references resolve to false instead of throwing, simplifying caller error handling.
  • ESM-only, dependency-light package - a single runtime dependency (character-entities) and no build step for the JavaScript itself.

Common Use Cases

  • Building a custom HTML/XML parser - a developer writing a parser that needs to resolve named entities without pulling in a full HTML-decoding library uses this as the lookup primitive.
  • Implementing a Markdown-to-HTML pipeline - projects like parse-entities (used by micromark/remark) call this internally to resolve character references found in source text.
  • Sanitizing or normalizing user-submitted markup - a tool stripping or rewriting entities before further processing decodes each reference through this function.
  • Cross-runtime content processing - a library that must run identically in Node.js and the browser relies on the package’s exports-based implementation swap instead of writing its own runtime detection.

Under The Hood

Architecture This is a tiny, single-purpose module with no internal layering: index.js exports one function, decodeNamedCharacterReference, that looks up its input in the characterEntities object from the character-entities package using a safe own.call (hasOwnProperty) check, returning false on a miss. A parallel implementation, index.dom.js, takes a completely different approach for browsers — it writes &value; into a detached <i> element’s innerHTML and reads the resulting textContent back, with explicit handling for legacy entities that don’t require a trailing semicolon (e.g. &notin vs &notit;) by detecting a stray trailing ; in the output. The two implementations are wired together purely through package.json’s conditional exports map (browser vs default/deno/edge-light/etc.), so consumers and bundlers get the right one automatically with zero runtime branching in application code. The main coupling risk is keeping the two implementations’ edge-case behavior in sync, since they solve the same problem via unrelated mechanisms.

Tech Stack Plain ESM JavaScript ("type": "module") targeting Node.js 14.14+/16+, Deno, and modern browsers, with a single runtime dependency, character-entities (^2.0.0), supplying the name-to-character dataset. TypeScript types are not hand-written inline but generated via tsc --build and gated by type-coverage at 100% coverage, so the shipped .d.ts files are a build artifact rather than part of the authored source. Linting and formatting run through xo (an opinionated ESLint preset) configured to defer to prettier, and docs/markdown are linted via remark-cli with remark-preset-wooorm. Tests run with Node’s built-in node:test and node:assert/strict — no third-party test framework — and coverage is measured with c8 at a required 100%.

Code Quality The single test.js file exercises exactly the two paths the function has: a recognized reference (amp&) and an unrecognized one (asdasdasdfalse), run via the test-api script under Node’s development condition and required to hit 100% coverage via c8 --100. For a package this small that is a genuinely complete test surface rather than a token one. Error handling follows a deliberate return-false-not-throw contract, documented directly in the JSDoc above the function, so callers never need exception handling for a missed lookup. Naming is minimal and clear, and the enforced 100% type-coverage threshold substitutes for traditional unit-test-driven type safety.

API Design The public surface is a single named export with no configuration object, no classes, and no default export — about as low-friction as an API can be to learn, at the cost of doing exactly one thing. The main design sophistication is invisible to the API itself: choosing the browser vs. Node/Deno/edge implementation through package.json exports conditions instead of a typeof window runtime check, which keeps the browser bundle free of the (comparatively large) static entity table. This is a recognizable pattern from the author’s other packages in the unified/remark ecosystem rather than a novel technique, but it’s applied correctly and consistently here.

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