(value: string)
| 263 | * anything that looks like markup stays inert on the way back out. |
| 264 | */ |
| 265 | const decodeEntities = (value: string): string => |
| 266 | value.replace(/&(#x?[0-9a-f]+|[a-z]+);/gi, (match, body: string) => { |
| 267 | if (body.startsWith("#")) { |
| 268 | const code = |
| 269 | body.startsWith("#x") || body.startsWith("#X") |
| 270 | ? Number.parseInt(body.slice(2), 16) |
| 271 | : Number.parseInt(body.slice(1), 10); |
| 272 | return Number.isFinite(code) && code > 0 && code <= 0x10_ff_ff |
| 273 | ? String.fromCodePoint(code) |
| 274 | : match; |
| 275 | } |
| 276 | return NAMED_ENTITIES[body.toLowerCase()] ?? match; |
| 277 | }); |
| 278 | |
| 279 | const escapeText = (value: string): string => |
| 280 | decodeEntities(value).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); |
no test coverage detected