fix: shorten update notes and contain entry content in cards

This commit is contained in:
2026-09-07 14:15:39 +09:00
parent 98ef813cb5
commit 8f97683271
4 changed files with 48 additions and 13 deletions
+22
View File
@@ -0,0 +1,22 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import { renderReleaseMarkdown } from '../release-notes/markdown.ts';
test('업데이트의 모든 문단과 목록을 하나의 카드에 묶는다', () => {
const html = renderReleaseMarkdown('## 날짜\n\n### 기능\n\n첫 문단\n\n추가 문단\n\n- 목록\n\n### 다음 기능\n\n설명');
const cards = [...html.matchAll(/<section class="update-entry">([\s\S]*?)<\/section>/g)];
assert.equal(cards.length, 2);
assert.match(cards[0][1], /첫 문단[\s\S]*추가 문단[\s\S]*<ul>/);
assert.doesNotMatch(cards[0][1], /다음 기능/);
assert.match(cards[1][1], /다음 기능[\s\S]*설명/);
assert.ok(html.indexOf('<h2>') < html.indexOf('<section'));
});
test('구분선과 날짜는 카드 밖에 두고 원시 HTML은 계속 이스케이프한다', () => {
const html = renderReleaseMarkdown('### 기능\n\n<script>alert(1)</script>\n\n---\n\n## 다음 날짜\n\n### 새 기능\n\n[문서](https://example.com)');
assert.match(html, /<\/section>\s*<hr>/);
assert.match(html, /<hr>\s*<h2>다음 날짜<\/h2>\s*<section/);
assert.doesNotMatch(html, /<script>/);
assert.match(html, /&lt;script&gt;/);
assert.match(html, /href="https:\/\/example.com\/"/);
});
+18 -2
View File
@@ -39,10 +39,26 @@ renderer.image = ({ href, title, text }) => {
};
export function renderReleaseMarkdown(markdown: string): string {
return marked.parse(markdown, {
const options = {
async: false,
breaks: true,
gfm: true,
renderer
}) as string;
} as const;
const tokens = marked.lexer(markdown, options);
let html = '';
let entryOpen = false;
for (const token of tokens) {
const boundary = token.type === 'hr' || (token.type === 'heading' && token.depth <= 3);
if (boundary && entryOpen) {
html += '</section>\n';
entryOpen = false;
}
if (token.type === 'heading' && token.depth === 3) {
html += '<section class="update-entry">\n';
entryOpen = true;
}
html += marked.parser([token], options);
}
return html + (entryOpen ? '</section>\n' : '');
}