diff --git a/src/routes/api/the-nook/_releases.ts b/src/routes/api/the-nook/_releases.ts index e72ea6d..5a946e9 100644 --- a/src/routes/api/the-nook/_releases.ts +++ b/src/routes/api/the-nook/_releases.ts @@ -35,7 +35,11 @@ const ENTITY_REPLACEMENTS: [RegExp, string][] = [ [/</g, "<"], [/>/g, ">"], [/"/g, '"'], + // Python's html.escape, which embed_release_notes.py writes the appcast + // with, prefers the hex form for apostrophes (NOOK-565). + [/'/g, "'"], [/'/g, "'"], + [/'/g, "'"], [/ /g, " "], // Last, so "&lt;" cannot decode twice. [/&/g, "&"] diff --git a/src/routes/api/the-nook/releases.test.ts b/src/routes/api/the-nook/releases.test.ts index c26587d..079d622 100644 --- a/src/routes/api/the-nook/releases.test.ts +++ b/src/routes/api/the-nook/releases.test.ts @@ -256,6 +256,21 @@ describe("sectionsFromHtml", () => { expect(sectionsFromHtml("")).toEqual([]); expect(sectionsFromHtml("

Added

")).toEqual([]); }); + + it("decodes the entities embed_release_notes.py's html.escape writes", () => { + // Python's html.escape prefers the hex form for apostrophes; this is what + // the live appcast actually carries (NOOK-565). + expect( + sectionsFromHtml( + "

Added

" + ) + ).toEqual([ + { + title: "Added", + bullets: ["Each app's meter & the icon", "don't expand"] + } + ]); + }); }); describe("isoDateOrNull", () => {