ProvenPin Install

html-entities encode and decode: working versions (tested 2026-10-15)

Encode and decode HTML entities offline with html-entities, covering specialChars and nonAscii encode modes, named and numeric entity decoding, and safely escaping untrusted user content.

passed7 passed · 0 failed2026-10-15 22:58 UTC
Status
passed
Last passed
2026-10-15 22:58 UTC
Tests
7 / 7
Language
TypeScript
Runtime
node v22.23.3
pinned versions3
html-entities@2.6.0@types/node@26.6.5tsx@4.23.15
run it
npm install --no-audit --no-fund --ignore-scripts=false
npm test
test environment
node v22.23.3
linux 6.17.0-1022-azure
x64
runner: github-actions 38820570375

The code

Exactly the files that passed. Your agent can pull them with get_recipe("html-entities-encode-decode") (install), or see them on GitHub.

package.json
{
  "name": "html-entities-encode-decode",
  "private": true,
  "type": "module",
  "scripts": {
    "test": "node --import tsx --test test/*.test.ts"
  },
  "dependencies": {"html-entities":"2.6.0"},
  "devDependencies": {"@types/node":"26.6.5","tsx":"4.23.15"}
}
src/html-entities.ts
import { encode, decode } from "html-entities";

export type EntityLevel = "xml" | "html4" | "html5" | "all";
export type EncodeModeName = "specialChars" | "nonAscii";

export function encodeHtml(
  input: string,
  mode: EncodeModeName = "specialChars",
  level: EntityLevel = "html5",
): string {
  return encode(input, { mode, level });
}

export function decodeHtml(input: string, level: EntityLevel = "html5"): string {
  return decode(input, { level });
}

export function escapeUserContent(input: string): string {
  return encodeHtml(input, "specialChars", "html5");
}

export function escapeAttribute(input: string): string {
  return encodeHtml(input, "specialChars", "xml");
}
test/html-entities.test.ts
import { test } from "node:test";
import assert from "node:assert/strict";
import {
  encodeHtml,
  decodeHtml,
  escapeUserContent,
  escapeAttribute,
} from "../src/html-entities.ts";

test("encodes HTML special characters with the specialChars mode", () => {
  assert.equal(
    encodeHtml("<script>a & b</script>"),
    "&lt;script&gt;a &amp; b&lt;/script&gt;",
  );
});

test("specialChars mode leaves non-ASCII characters untouched", () => {
  const input = "café";
  const encoded = encodeHtml(input, "specialChars");
  assert.equal(encoded.includes("é"), true);
  assert.equal(decodeHtml(encoded), input);
});

test("nonAscii mode escapes non-ASCII characters", () => {
  const input = "café";
  const encoded = encodeHtml(input, "nonAscii");
  assert.equal(encoded.includes("é"), false);
  assert.equal(decodeHtml(encoded), input);
});

test("decodes named entities", () => {
  assert.equal(decodeHtml("&copy; &amp; &lt;b&gt;"), "© & <b>");
});

test("decodes decimal and hexadecimal numeric entities", () => {
  assert.equal(decodeHtml("&#65;&#x42;&#67;"), "ABC");
});

test("escapes untrusted user content safely", () => {
  const payload = '<img src=x onerror="alert(1)">';
  const safe = escapeUserContent(payload);
  assert.equal(safe.includes("<"), false);
  assert.equal(safe.includes(">"), false);
  assert.equal(safe.includes('"'), false);
  assert.equal(decodeHtml(safe), payload);
});

test("escapes values for attribute contexts", () => {
  const value = `Tom & "Jerry"`;
  const safe = escapeAttribute(value);
  assert.equal(safe, "Tom &amp; &quot;Jerry&quot;");
  assert.equal(decodeHtml(safe), value);
});

Connect to ProvenPin

Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.

terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp

Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.