entities 6.0.1 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/dist/decode-codepoint.d.ts +8 -0
  2. package/dist/decode-codepoint.d.ts.map +1 -0
  3. package/dist/decode-codepoint.js +46 -0
  4. package/dist/decode-codepoint.js.map +1 -0
  5. package/dist/{esm/decode.d.ts → decode.d.ts} +11 -26
  6. package/dist/decode.d.ts.map +1 -0
  7. package/dist/{esm/decode.js → decode.js} +130 -83
  8. package/dist/decode.js.map +1 -0
  9. package/dist/{commonjs/encode.d.ts → encode.d.ts} +2 -0
  10. package/dist/encode.d.ts.map +1 -0
  11. package/dist/encode.js +90 -0
  12. package/dist/encode.js.map +1 -0
  13. package/dist/{esm/escape.d.ts → escape.d.ts} +13 -8
  14. package/dist/escape.d.ts.map +1 -0
  15. package/dist/{esm/escape.js → escape.js} +49 -34
  16. package/dist/escape.js.map +1 -0
  17. package/dist/generated/decode-data-html.d.ts +3 -0
  18. package/dist/generated/decode-data-html.d.ts.map +1 -0
  19. package/dist/generated/decode-data-html.js +5 -0
  20. package/dist/generated/decode-data-html.js.map +1 -0
  21. package/dist/generated/decode-data-xml.d.ts +3 -0
  22. package/dist/generated/decode-data-xml.d.ts.map +1 -0
  23. package/dist/generated/decode-data-xml.js +5 -0
  24. package/dist/generated/decode-data-xml.js.map +1 -0
  25. package/dist/generated/encode-html.d.ts +5 -0
  26. package/dist/generated/encode-html.d.ts.map +1 -0
  27. package/dist/generated/encode-html.js +12 -0
  28. package/dist/generated/encode-html.js.map +1 -0
  29. package/dist/{commonjs/index.d.ts → index.d.ts} +10 -17
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/{esm/index.js → index.js} +9 -25
  32. package/dist/index.js.map +1 -0
  33. package/dist/internal/bin-trie-flags.d.ts +17 -0
  34. package/dist/internal/bin-trie-flags.d.ts.map +1 -0
  35. package/dist/internal/bin-trie-flags.js +18 -0
  36. package/dist/internal/bin-trie-flags.js.map +1 -0
  37. package/dist/internal/decode-shared.d.ts +7 -0
  38. package/dist/internal/decode-shared.d.ts.map +1 -0
  39. package/dist/internal/decode-shared.js +17 -0
  40. package/dist/internal/decode-shared.js.map +1 -0
  41. package/dist/internal/encode-shared.d.ts +33 -0
  42. package/dist/internal/encode-shared.d.ts.map +1 -0
  43. package/dist/internal/encode-shared.js +93 -0
  44. package/dist/internal/encode-shared.js.map +1 -0
  45. package/package.json +38 -73
  46. package/readme.md +36 -27
  47. package/src/decode-codepoint.ts +1 -32
  48. package/src/decode.ts +127 -76
  49. package/src/encode.ts +49 -31
  50. package/src/escape.ts +50 -38
  51. package/src/generated/decode-data-html.ts +4 -5
  52. package/src/generated/decode-data-xml.ts +4 -5
  53. package/src/generated/encode-html.ts +15 -14
  54. package/src/index.ts +23 -49
  55. package/src/internal/bin-trie-flags.ts +16 -0
  56. package/src/internal/decode-shared.ts +18 -0
  57. package/src/internal/encode-shared.ts +123 -0
  58. package/decode.d.ts +0 -1
  59. package/decode.js +0 -3
  60. package/dist/commonjs/decode-codepoint.d.ts +0 -19
  61. package/dist/commonjs/decode-codepoint.d.ts.map +0 -1
  62. package/dist/commonjs/decode-codepoint.js +0 -77
  63. package/dist/commonjs/decode-codepoint.js.map +0 -1
  64. package/dist/commonjs/decode.d.ts +0 -209
  65. package/dist/commonjs/decode.d.ts.map +0 -1
  66. package/dist/commonjs/decode.js +0 -511
  67. package/dist/commonjs/decode.js.map +0 -1
  68. package/dist/commonjs/encode.d.ts.map +0 -1
  69. package/dist/commonjs/encode.js +0 -73
  70. package/dist/commonjs/encode.js.map +0 -1
  71. package/dist/commonjs/escape.d.ts +0 -43
  72. package/dist/commonjs/escape.d.ts.map +0 -1
  73. package/dist/commonjs/escape.js +0 -121
  74. package/dist/commonjs/escape.js.map +0 -1
  75. package/dist/commonjs/generated/decode-data-html.d.ts +0 -2
  76. package/dist/commonjs/generated/decode-data-html.d.ts.map +0 -1
  77. package/dist/commonjs/generated/decode-data-html.js +0 -10
  78. package/dist/commonjs/generated/decode-data-html.js.map +0 -1
  79. package/dist/commonjs/generated/decode-data-xml.d.ts +0 -2
  80. package/dist/commonjs/generated/decode-data-xml.d.ts.map +0 -1
  81. package/dist/commonjs/generated/decode-data-xml.js +0 -10
  82. package/dist/commonjs/generated/decode-data-xml.js.map +0 -1
  83. package/dist/commonjs/generated/encode-html.d.ts +0 -8
  84. package/dist/commonjs/generated/encode-html.d.ts.map +0 -1
  85. package/dist/commonjs/generated/encode-html.js +0 -13
  86. package/dist/commonjs/generated/encode-html.js.map +0 -1
  87. package/dist/commonjs/index.d.ts.map +0 -1
  88. package/dist/commonjs/index.js +0 -131
  89. package/dist/commonjs/index.js.map +0 -1
  90. package/dist/commonjs/package.json +0 -3
  91. package/dist/esm/decode-codepoint.d.ts +0 -19
  92. package/dist/esm/decode-codepoint.d.ts.map +0 -1
  93. package/dist/esm/decode-codepoint.js +0 -72
  94. package/dist/esm/decode-codepoint.js.map +0 -1
  95. package/dist/esm/decode.d.ts.map +0 -1
  96. package/dist/esm/decode.js.map +0 -1
  97. package/dist/esm/encode.d.ts +0 -22
  98. package/dist/esm/encode.d.ts.map +0 -1
  99. package/dist/esm/encode.js +0 -69
  100. package/dist/esm/encode.js.map +0 -1
  101. package/dist/esm/escape.d.ts.map +0 -1
  102. package/dist/esm/escape.js.map +0 -1
  103. package/dist/esm/generated/decode-data-html.d.ts +0 -2
  104. package/dist/esm/generated/decode-data-html.d.ts.map +0 -1
  105. package/dist/esm/generated/decode-data-html.js +0 -7
  106. package/dist/esm/generated/decode-data-html.js.map +0 -1
  107. package/dist/esm/generated/decode-data-xml.d.ts +0 -2
  108. package/dist/esm/generated/decode-data-xml.d.ts.map +0 -1
  109. package/dist/esm/generated/decode-data-xml.js +0 -7
  110. package/dist/esm/generated/decode-data-xml.js.map +0 -1
  111. package/dist/esm/generated/encode-html.d.ts +0 -8
  112. package/dist/esm/generated/encode-html.d.ts.map +0 -1
  113. package/dist/esm/generated/encode-html.js +0 -10
  114. package/dist/esm/generated/encode-html.js.map +0 -1
  115. package/dist/esm/index.d.ts +0 -96
  116. package/dist/esm/index.d.ts.map +0 -1
  117. package/dist/esm/index.js.map +0 -1
  118. package/dist/esm/package.json +0 -3
  119. package/escape.d.ts +0 -1
  120. package/escape.js +0 -3
  121. package/src/decode.spec.ts +0 -320
  122. package/src/encode.spec.ts +0 -78
  123. package/src/escape.spec.ts +0 -14
  124. package/src/generated/.eslintrc.json +0 -10
  125. package/src/index.spec.ts +0 -125
@@ -0,0 +1,33 @@
1
+ /**
2
+ * A node inside the encoding trie used by `encode.ts`.
3
+ *
4
+ * There are two physical shapes to minimize allocations and lookup cost:
5
+ *
6
+ * 1. Leaf node (string)
7
+ * - A plain string (already in the form `"&name;"`).
8
+ * - Represents a terminal match with no children.
9
+ *
10
+ * 2. Branch / value node (object)
11
+ */
12
+ export type EncodeTrieNode = string | {
13
+ /**
14
+ * Entity value for the current code point sequence (wrapped: `&...;`).
15
+ * Present when the path to this node itself is a valid named entity.
16
+ */
17
+ value: string | undefined;
18
+ /** If a number, the next code unit of the only next character. */
19
+ next: number | Map<number, EncodeTrieNode>;
20
+ /** If next is a number, `nextValue` contains the entity value. */
21
+ nextValue?: string;
22
+ };
23
+ /**
24
+ * Parse a compact encode trie string into a Map structure used for encoding.
25
+ *
26
+ * Format per entry (ascending code points using delta encoding):
27
+ * <diffBase36>[&name;][{<children>}] -- diff omitted when 0
28
+ * Where diff = currentKey - previousKey - 1 (first entry stores absolute key).
29
+ * `&name;` is the entity value (already wrapped); a following `{` denotes children.
30
+ * @param serialized Serialized text fragment to encode.
31
+ */
32
+ export declare function parseEncodeTrie(serialized: string): Map<number, EncodeTrieNode>;
33
+ //# sourceMappingURL=encode-shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encode-shared.d.ts","sourceRoot":"","sources":["../../src/internal/encode-shared.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,MAAM,cAAc,GACpB,MAAM,GACN;IACI;;;OAGG;IACH,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,kEAAkE;IAClE,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC3C,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAER;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC3B,UAAU,EAAE,MAAM,GACnB,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAsF7B"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Parse a compact encode trie string into a Map structure used for encoding.
3
+ *
4
+ * Format per entry (ascending code points using delta encoding):
5
+ * <diffBase36>[&name;][{<children>}] -- diff omitted when 0
6
+ * Where diff = currentKey - previousKey - 1 (first entry stores absolute key).
7
+ * `&name;` is the entity value (already wrapped); a following `{` denotes children.
8
+ * @param serialized Serialized text fragment to encode.
9
+ */
10
+ export function parseEncodeTrie(serialized) {
11
+ const top = new Map();
12
+ const totalLength = serialized.length;
13
+ let cursor = 0;
14
+ let lastTopKey = -1;
15
+ function readDiff() {
16
+ const start = cursor;
17
+ while (cursor < totalLength) {
18
+ const char = serialized.charAt(cursor);
19
+ if ((char < "0" || char > "9") && (char < "a" || char > "z")) {
20
+ break;
21
+ }
22
+ cursor++;
23
+ }
24
+ if (cursor === start)
25
+ return 0;
26
+ return Number.parseInt(serialized.slice(start, cursor), 36);
27
+ }
28
+ function readEntity() {
29
+ if (serialized[cursor] !== "&") {
30
+ throw new Error(`Child entry missing value near index ${cursor}`);
31
+ }
32
+ // Cursor currently points at '&'
33
+ const start = cursor;
34
+ const end = serialized.indexOf(";", cursor + 1);
35
+ if (end === -1) {
36
+ throw new Error(`Unterminated entity starting at index ${start}`);
37
+ }
38
+ cursor = end + 1; // Move past ';'
39
+ return serialized.slice(start, cursor); // Includes & ... ;
40
+ }
41
+ while (cursor < totalLength) {
42
+ const keyDiff = readDiff();
43
+ const key = lastTopKey === -1 ? keyDiff : lastTopKey + keyDiff + 1;
44
+ let value;
45
+ if (serialized[cursor] === "&")
46
+ value = readEntity();
47
+ if (serialized[cursor] === "{") {
48
+ cursor++; // Skip '{'
49
+ // Parse first child
50
+ let diff = readDiff();
51
+ let childKey = diff; // First key (lastChildKey = -1)
52
+ const firstValue = readEntity();
53
+ if (serialized[cursor] === "{") {
54
+ throw new Error("Unexpected nested '{' beyond depth 2");
55
+ }
56
+ // If end of block -> single child optimization
57
+ if (serialized[cursor] === "}") {
58
+ top.set(key, { value, next: childKey, nextValue: firstValue });
59
+ cursor++; // Skip '}'
60
+ }
61
+ else {
62
+ const childMap = new Map([
63
+ [childKey, firstValue],
64
+ ]);
65
+ let lastChildKey = childKey;
66
+ while (cursor < totalLength && serialized[cursor] !== "}") {
67
+ diff = readDiff();
68
+ childKey = lastChildKey + diff + 1;
69
+ const childValue = readEntity();
70
+ if (serialized[cursor] === "{") {
71
+ throw new Error("Unexpected nested '{' beyond depth 2");
72
+ }
73
+ childMap.set(childKey, childValue);
74
+ lastChildKey = childKey;
75
+ }
76
+ if (serialized[cursor] !== "}") {
77
+ throw new Error("Unterminated child block");
78
+ }
79
+ cursor++; // Skip '}'
80
+ top.set(key, { value, next: childMap });
81
+ }
82
+ }
83
+ else if (value === undefined) {
84
+ throw new Error(`Malformed encode trie: missing value at index ${cursor}`);
85
+ }
86
+ else {
87
+ top.set(key, value);
88
+ }
89
+ lastTopKey = key;
90
+ }
91
+ return top;
92
+ }
93
+ //# sourceMappingURL=encode-shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encode-shared.js","sourceRoot":"","sources":["../../src/internal/encode-shared.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "entities",
3
- "version": "6.0.1",
3
+ "version": "8.0.0",
4
4
  "description": "Encode & decode XML and HTML entities with ease & speed",
5
5
  "keywords": [
6
6
  "html entities",
@@ -13,7 +13,7 @@
13
13
  ],
14
14
  "repository": {
15
15
  "type": "git",
16
- "url": "git://github.com/fb55/entities.git"
16
+ "url": "https://github.com/fb55/entities.git"
17
17
  },
18
18
  "funding": "https://github.com/fb55/entities?sponsor=1",
19
19
  "license": "BSD-2-Clause",
@@ -22,97 +22,62 @@
22
22
  "type": "module",
23
23
  "exports": {
24
24
  ".": {
25
- "import": {
26
- "types": "./dist/esm/index.d.ts",
27
- "default": "./dist/esm/index.js"
28
- },
29
- "require": {
30
- "types": "./dist/commonjs/index.d.ts",
31
- "default": "./dist/commonjs/index.js"
32
- }
25
+ "types": "./dist/index.d.ts",
26
+ "default": "./dist/index.js"
33
27
  },
34
28
  "./decode": {
35
- "import": {
36
- "types": "./dist/esm/decode.d.ts",
37
- "default": "./dist/esm/decode.js"
38
- },
39
- "require": {
40
- "types": "./dist/commonjs/decode.d.ts",
41
- "default": "./dist/commonjs/decode.js"
42
- }
29
+ "types": "./dist/decode.d.ts",
30
+ "default": "./dist/decode.js"
43
31
  },
44
32
  "./escape": {
45
- "import": {
46
- "types": "./dist/esm/escape.d.ts",
47
- "default": "./dist/esm/escape.js"
48
- },
49
- "require": {
50
- "types": "./dist/commonjs/escape.d.ts",
51
- "default": "./dist/commonjs/escape.js"
52
- }
33
+ "types": "./dist/escape.d.ts",
34
+ "default": "./dist/escape.js"
53
35
  }
54
36
  },
55
- "main": "./dist/commonjs/index.js",
56
- "module": "./dist/esm/index.js",
57
- "types": "./dist/commonjs/index.d.ts",
37
+ "main": "./dist/index.js",
38
+ "types": "./dist/index.d.ts",
58
39
  "files": [
59
- "decode.js",
60
- "decode.d.ts",
61
- "escape.js",
62
- "escape.d.ts",
63
40
  "dist",
64
- "src"
41
+ "src",
42
+ "!**/*.spec.ts"
65
43
  ],
66
44
  "scripts": {
45
+ "benchmark": "node --import=tsx scripts/benchmark.ts",
46
+ "build": "tsc",
67
47
  "build:docs": "typedoc --hideGenerator src/index.ts",
68
48
  "build:encode-trie": "node --import=tsx scripts/write-encode-map.ts",
69
49
  "build:trie": "node --import=tsx scripts/write-decode-map.ts",
70
- "format": "npm run format:es && npm run format:prettier",
50
+ "format": "npm run format:es && npm run format:biome",
51
+ "format:biome": "biome check --fix .",
71
52
  "format:es": "npm run lint:es -- --fix",
72
- "format:prettier": "npm run prettier -- --write",
73
- "lint": "npm run lint:es && npm run lint:ts && npm run lint:prettier",
74
- "lint:es": "eslint . --ignore-path .gitignore",
75
- "lint:prettier": "npm run prettier -- --check",
53
+ "lint": "npm run lint:es && npm run lint:ts && npm run lint:biome",
54
+ "lint:biome": "biome check .",
55
+ "lint:es": "eslint .",
76
56
  "lint:ts": "tsc --noEmit",
77
- "prepublishOnly": "tshy",
78
- "prettier": "prettier '**/*.{ts,md,json,yml}'",
57
+ "prepublishOnly": "npm run build",
79
58
  "test": "npm run test:vi && npm run lint",
80
59
  "test:vi": "vitest run"
81
60
  },
82
- "prettier": {
83
- "proseWrap": "always",
84
- "tabWidth": 4
85
- },
86
61
  "devDependencies": {
87
- "@types/node": "^22.15.30",
88
- "@typescript-eslint/eslint-plugin": "^8.33.1",
89
- "@typescript-eslint/parser": "^8.33.1",
90
- "@vitest/coverage-v8": "^2.1.8",
91
- "eslint": "^8.57.1",
92
- "eslint-config-prettier": "^10.1.5",
93
- "eslint-plugin-n": "^17.19.0",
94
- "eslint-plugin-unicorn": "^56.0.1",
95
- "prettier": "^3.5.3",
96
- "tshy": "^3.0.2",
97
- "tsx": "^4.19.4",
98
- "typedoc": "^0.28.5",
99
- "typescript": "^5.8.3",
100
- "vitest": "^2.0.2"
62
+ "@biomejs/biome": "^2.4.7",
63
+ "@eslint/compat": "^2.0.3",
64
+ "@feedic/eslint-config": "^0.3.1",
65
+ "@types/he": "^1.2.3",
66
+ "@types/node": "^25.5.0",
67
+ "eslint": "^10.0.3",
68
+ "eslint-config-biome": "^2.1.3",
69
+ "globals": "^17.4.0",
70
+ "he": "^1.2.0",
71
+ "html-entities": "^2.6.0",
72
+ "parse-entities": "^4.0.2",
73
+ "tinybench": "^6.0.0",
74
+ "tsx": "^4.21.0",
75
+ "typedoc": "^0.28.17",
76
+ "typescript": "^5.9.3",
77
+ "typescript-eslint": "^8.57.1",
78
+ "vitest": "^4.0.17"
101
79
  },
102
80
  "engines": {
103
- "node": ">=0.12"
104
- },
105
- "tshy": {
106
- "exclude": [
107
- "**/*.spec.ts",
108
- "**/__fixtures__/*",
109
- "**/__tests__/*",
110
- "**/__snapshots__/*"
111
- ],
112
- "exports": {
113
- ".": "./src/index.ts",
114
- "./decode": "./src/decode.ts",
115
- "./escape": "./src/escape.ts"
116
- }
81
+ "node": ">=20.19.0"
117
82
  }
118
83
  }
package/readme.md CHANGED
@@ -10,7 +10,7 @@ Encode & decode HTML & XML entities with ease & speed.
10
10
  [`commonmark`](https://github.com/commonmark/commonmark.js) use it to process
11
11
  HTML entities.
12
12
  - ⚡️ Fast: `entities` is the fastest library for decoding HTML entities (as of
13
- April 2022); see [performance](#performance).
13
+ September 2025); see [performance](#performance).
14
14
  - 🎛 Configurable: Get an output tailored for your needs. You are fine with
15
15
  UTF8? That'll save you some bytes. Prefer to only have ASCII characters? We
16
16
  can do that as well!
@@ -24,7 +24,7 @@ Encode & decode HTML & XML entities with ease & speed.
24
24
  ### …use `entities`
25
25
 
26
26
  ```javascript
27
- const entities = require("entities");
27
+ import * as entities from "entities";
28
28
 
29
29
  // Encoding
30
30
  entities.escapeUTF8("&#38; ü"); // "&amp;#38; ü"
@@ -38,15 +38,36 @@ entities.decodeHTML("asdf &amp; &yuml; &uuml; &apos;"); // "asdf & ÿ ü '"
38
38
 
39
39
  ## Performance
40
40
 
41
- This is how `entities` compares to other libraries on a very basic benchmark
42
- (see `scripts/benchmark.ts`, for 10,000,000 iterations; **lower is better**):
41
+ Benchmarked in September 2025 with Node v24.6.0 on Apple M2 using `tinybench`.
42
+ Higher ops/s is better; `avg (μs)` is the mean time per operation.
43
+ See `scripts/benchmark.ts` to reproduce.
43
44
 
44
- | Library | Version | `decode` perf | `encode` perf | `escape` perf |
45
- | -------------- | ------- | ------------- | ------------- | ------------- |
46
- | entities | `3.0.1` | 1.418s | 6.786s | 2.196s |
47
- | html-entities | `2.3.2` | 2.530s | 6.829s | 2.415s |
48
- | he | `1.2.0` | 5.800s | 24.237s | 3.624s |
49
- | parse-entities | `3.0.0` | 9.660s | N/A | N/A |
45
+ ### Decoding
46
+
47
+ | Library | Version | ops/s | avg (μs) | ±% | slower |
48
+ | -------------- | ------- | --------- | -------- | ---- | ------ |
49
+ | entities | 7.0.0 | 5,838,416 | 175.57 | 0.06 | — |
50
+ | html-entities | 2.6.0 | 2,919,637 | 347.77 | 0.33 | 50.0% |
51
+ | he | 1.2.0 | 2,318,438 | 446.48 | 0.70 | 60.3% |
52
+ | parse-entities | 4.0.2 | 852,855 | 1,199.51 | 0.36 | 85.4% |
53
+
54
+ ### Encoding
55
+
56
+ | Library | Version | ops/s | avg (μs) | ±% | slower |
57
+ | -------------- | ------- | --------- | -------- | ---- | ------ |
58
+ | entities | 7.0.0 | 2,770,115 | 368.09 | 0.11 | — |
59
+ | html-entities | 2.6.0 | 1,491,963 | 679.96 | 0.58 | 46.2% |
60
+ | he | 1.2.0 | 481,278 | 2,118.25 | 0.61 | 82.6% |
61
+
62
+ ### Escaping
63
+
64
+ | Library | Version | ops/s | avg (μs) | ±% | slower |
65
+ | -------------- | ------- | --------- | -------- | ---- | ------ |
66
+ | entities | 7.0.0 | 4,616,468 | 223.84 | 0.17 | — |
67
+ | he | 1.2.0 | 3,659,301 | 280.76 | 0.58 | 20.7% |
68
+ | html-entities | 2.6.0 | 3,555,301 | 296.63 | 0.84 | 23.0% |
69
+
70
+ Note: Micro-benchmarks may vary across machines and Node versions.
50
71
 
51
72
  ---
52
73
 
@@ -68,8 +89,8 @@ This is helpful for decoding entities in legacy environments.
68
89
 
69
90
  > Why should I use `entities` instead of alternative modules?
70
91
 
71
- As of April 2022, `entities` is a bit faster than other modules. Still, this is
72
- not a very differentiated space and other modules can catch up.
92
+ As of September 2025, `entities` is faster than other modules. Still, this is
93
+ not a differentiated space and other modules can catch up.
73
94
 
74
95
  **More importantly**, you might already have `entities` in your dependency graph
75
96
  (as a dependency of eg. `cheerio`, or `htmlparser2`), and including it directly
@@ -78,10 +99,9 @@ libraries, so have a look through your `node_modules` directory!
78
99
 
79
100
  > Does `entities` support tree shaking?
80
101
 
81
- Yes! `entities` ships as both a CommonJS and a ES module. Note that for best
82
- results, you should not use the `encode` and `decode` functions, as they wrap
83
- around a number of other functions, all of which will remain in the bundle.
84
- Instead, use the functions that you need directly.
102
+ Yes! Note that for best results, you should not use the `encode` and `decode`
103
+ functions, as they wrap around a number of other functions, all of which will
104
+ remain in the bundle. Instead, use the functions that you need directly.
85
105
 
86
106
  ---
87
107
 
@@ -109,14 +129,3 @@ License: BSD-2-Clause
109
129
  To report a security vulnerability, please use the
110
130
  [Tidelift security contact](https://tidelift.com/security). Tidelift will
111
131
  coordinate the fix and disclosure.
112
-
113
- ## `entities` for enterprise
114
-
115
- Available as part of the Tidelift Subscription
116
-
117
- The maintainers of `entities` and thousands of other packages are working with
118
- Tidelift to deliver commercial support and maintenance for the open source
119
- dependencies you use to build your applications. Save time, reduce risk, and
120
- improve code health, while paying the maintainers of the exact dependencies you
121
- use.
122
- [Learn more.](https://tidelift.com/subscription/pkg/npm-entities?utm_source=npm-entities&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
@@ -32,31 +32,11 @@ const decodeMap = new Map([
32
32
  [159, 376],
33
33
  ]);
34
34
 
35
- /**
36
- * Polyfill for `String.fromCodePoint`. It is used to create a string from a Unicode code point.
37
- */
38
- export const fromCodePoint: (...codePoints: number[]) => string =
39
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, n/no-unsupported-features/es-builtins
40
- String.fromCodePoint ??
41
- function (codePoint: number): string {
42
- let output = "";
43
-
44
- if (codePoint > 0xff_ff) {
45
- codePoint -= 0x1_00_00;
46
- output += String.fromCharCode(
47
- ((codePoint >>> 10) & 0x3_ff) | 0xd8_00,
48
- );
49
- codePoint = 0xdc_00 | (codePoint & 0x3_ff);
50
- }
51
-
52
- output += String.fromCharCode(codePoint);
53
- return output;
54
- };
55
-
56
35
  /**
57
36
  * Replace the given code point with a replacement character if it is a
58
37
  * surrogate or is outside the valid range. Otherwise return the code
59
38
  * point unchanged.
39
+ * @param codePoint Unicode code point to convert.
60
40
  */
61
41
  export function replaceCodePoint(codePoint: number): number {
62
42
  if (
@@ -68,14 +48,3 @@ export function replaceCodePoint(codePoint: number): number {
68
48
 
69
49
  return decodeMap.get(codePoint) ?? codePoint;
70
50
  }
71
-
72
- /**
73
- * Replace the code point if relevant, then convert it to a string.
74
- *
75
- * @deprecated Use `fromCodePoint(replaceCodePoint(codePoint))` instead.
76
- * @param codePoint The code point to decode.
77
- * @returns The decoded code point.
78
- */
79
- export function decodeCodePoint(codePoint: number): string {
80
- return fromCodePoint(replaceCodePoint(codePoint));
81
- }