fix(whatsnew): decode HTML entities and trim em-dash detail in fallback bullets
The Features-fallback showed raw changelog text, so a commit subject like 'branded URL shortener — /s/<slug> with OG injection' surfaced two problems in the admin banner: - release-please escapes <slug> to <slug>; React renders the literal entity, so the banner read '/s/<slug>'. Decode the entities (< > & " '), & last to avoid double-decoding. - the technical tail leaked into a user-facing highlight. Drop a trailing '— detail' clause (em dash only, so 'mark-paid' is untouched) so the bullet reads as the headline 'branded URL shortener'. Only affects the deterministic fallback; curated <!-- whatsnew --> blocks are unchanged.
This commit is contained in:
@@ -33,6 +33,21 @@ describe('parseWhatsNew', () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('decodes HTML entities release-please escapes into changelog text', () => {
|
||||||
|
const body = '### Features\n* **gallery:** supports A & B <tags> "quoted" ([#1](http://x))';
|
||||||
|
expect(parseWhatsNew(body)).toEqual(['supports A & B <tags> "quoted"']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('trims a trailing "— implementation detail" clause to the headline', () => {
|
||||||
|
const body = '### Features\n* **gallery:** branded URL shortener — /s/<slug> with OG injection ([#699](http://x))';
|
||||||
|
expect(parseWhatsNew(body)).toEqual(['branded URL shortener']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('leaves hyphenated words and dash-free bullets intact', () => {
|
||||||
|
const body = '### Features\n* **invoices:** mark-paid now supports bank transfer ([#2](http://x))';
|
||||||
|
expect(parseWhatsNew(body)).toEqual(['mark-paid now supports bank transfer']);
|
||||||
|
});
|
||||||
|
|
||||||
it('excludes Bug Fixes from the fallback', () => {
|
it('excludes Bug Fixes from the fallback', () => {
|
||||||
const body = '### Features\n* **a:** feature one\n### Bug Fixes\n* **b:** fix one';
|
const body = '### Features\n* **a:** feature one\n### Bug Fixes\n* **b:** fix one';
|
||||||
expect(parseWhatsNew(body)).toEqual(['feature one']);
|
expect(parseWhatsNew(body)).toEqual(['feature one']);
|
||||||
|
|||||||
@@ -14,14 +14,35 @@
|
|||||||
|
|
||||||
const MAX_BULLETS = 8;
|
const MAX_BULLETS = 8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode the handful of HTML entities release-please escapes into changelog
|
||||||
|
* text (a raw "/s/<slug>" in a commit subject lands as "/s/<slug>").
|
||||||
|
* Without this the banner shows the literal entity, since React renders text
|
||||||
|
* nodes verbatim. `&` is decoded last so "&lt;" stays "<".
|
||||||
|
*/
|
||||||
|
function decodeEntities(s) {
|
||||||
|
return s
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.replace(/�*39;|�*27;|'/gi, "'")
|
||||||
|
.replace(/&/g, '&');
|
||||||
|
}
|
||||||
|
|
||||||
/** Strip list markers, conventional-commit scope, and trailing PR/sha links. */
|
/** Strip list markers, conventional-commit scope, and trailing PR/sha links. */
|
||||||
function cleanBullet(line) {
|
function cleanBullet(line) {
|
||||||
return line
|
return decodeEntities(line
|
||||||
.replace(/^\s*[-*]\s+/, '') // "- " / "* " marker
|
.replace(/^\s*[-*]\s+/, '') // "- " / "* " marker
|
||||||
.replace(/^\*\*([^:*]+):\*\*\s*/, '') // "**scope:** " prefix
|
.replace(/^\*\*([^:*]+):\*\*\s*/, '') // "**scope:** " prefix
|
||||||
.replace(/\s*\(\[[^\]]*\]\([^)]*\)\)/g, '') // " ([#41](url))" / " ([sha](url))"
|
.replace(/\s*\(\[[^\]]*\]\([^)]*\)\)/g, '') // " ([#41](url))" / " ([sha](url))"
|
||||||
.replace(/\s*\(#\d+\)/g, '') // bare " (#41)"
|
.replace(/\s*\(#\d+\)/g, '') // bare " (#41)"
|
||||||
.replace(/`/g, '')
|
.replace(/`/g, ''))
|
||||||
|
// Drop a trailing "— implementation detail" clause so a release highlight
|
||||||
|
// reads as the headline ("branded URL shortener"), not the commit subject
|
||||||
|
// ("branded URL shortener — /s/<slug> with OG injection"). Em dash only, so
|
||||||
|
// hyphenated words ("mark-paid") are untouched. Skipped if it would empty
|
||||||
|
// the bullet (i.e. nothing before the dash).
|
||||||
|
.replace(/^(.+?\S)\s+—\s+.*$/, '$1')
|
||||||
.replace(/\s+/g, ' ')
|
.replace(/\s+/g, ' ')
|
||||||
.trim();
|
.trim();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user