This commit is contained in:
Mateusz Gruszczyński committed 2026-10-12 12:19:33 +02:00
1 parent acfe926066
commit df403c0aa7
26 files changed
+1502 -144

No files matched your search

+53
View File
@@ -0,0 +1,53 @@
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
globalThis.location = {origin:'https://example.org'};
let source = readFileSync('static/js/markdown.js','utf8')
.replace(/^import .*;$/gm, '');
source = `const EMOJI_SHORTCODES = {}; const t = (key,vars,alternative) => alternative; const parseImageAlias = () => null;\n` + source;
const {renderMarkdown, setMarkdownMentions} = await import('data:text/javascript;base64,'+Buffer.from(source).toString('base64'));
function has(re, text, message) { assert.match(text,re,message); }
let html = renderMarkdown('# Instrukcja testowa\n[Przejdź](#instrukcja-testowa)\n# Instrukcja testowa\n[TOC]\n## Etap drugi');
has(/<h1 id="instrukcja-testowa"/,html,'first anchor');
has(/<h1 id="instrukcja-testowa-2"/,html,'duplicate heading anchor');
has(/href="#instrukcja-testowa"/,html,'link to section');
has(/heading-permalink/,html,'visible link icon');
has(/href="#etap-drugi"/,html,'TOC anchor');
html = renderMarkdown(' ```js\n const value = 1;\n console.log(value);\n ```\nafter');
has(/<pre[^>]*style="margin-left:2ch"[^>]*><code class="language-javascript">const value = 1;\n console\.log\(value\);<\/code><\/pre>/,html,'code container indentation + dedent');
has(/<p[^>]*>after<\/p>/,html,'code closed');
html = renderMarkdown(' ```python=42\n print(42)\n ```');
has(/class="code-with-lines[^>]*style="margin-left:4ch"/,html,'numbered fenced code whole block shifted');
has(/data-line="42">print\(42\)/,html,'numbered content dedented');
html = renderMarkdown(' ```\n ~~~\n ```');
has(/<code>~~~<\/code>/,html,'other marker must remain inside code');
html = renderMarkdown('```\n## hidden in code\n```\n## Visible');
assert.doesNotMatch(html, /id="hidden-in-code"/);
has(/id="visible"/,html,'headings outside code');
setMarkdownMentions([{nickname:'Ala',color:'#aabbcc'},{nickname:'John+Dev',color:'red'}]);
html = renderMarkdown('Cześć @Ala i @John+Dev! @Other @Alana a@Ala `@Ala` [@Ala](https://site.test)');
assert.equal((html.match(/class="markdown-mention"/g)||[]).length,2,'valid mentions only');
has(/style="--owner:#aabbcc"/,html,'real author color');
has(/@Other @Alana a@Ala/,html,'nonmembers and suffixes not chips');
has(/<code>@Ala<\/code>/,html,'inline code excluded');
has(/<a href="https:\/\/site.test\/"[^>]*>@Ala<\/a>/,html,'links excluded');
assert.doesNotMatch(renderMarkdown('```\n@Ala\n```'), /markdown-mention/);
html = renderMarkdown('Sentence @Ala. Domain @Ala.example');
assert.equal((html.match(/class="markdown-mention"/g) || []).length, 1, 'punctuation after a mention is allowed, domains are not');
setMarkdownMentions([]);
assert.doesNotMatch(renderMarkdown('@Ala'), /markdown-mention/);
console.log('PASS: anchors, TOC, duplicate headings, indented fences, numbered blocks, mentions, exclusions');
html = renderMarkdown('[TOC]\n# Procedura\n<details>\n<summary>Szczegóły</summary>\n## Procedura\n</details>');
has(/id="procedura"/,html);
has(/id="procedura-2"/,html,'nested heading anchor unique');
has(/href="#procedura-2"/,html,'TOC link for heading inside details');
console.log('PASS: anchors in nested details match TOC');
setMarkdownMentions([{nickname: 'a[1]\\x', color: '#123456'}, {nickname: '<f>&"', color: '#112233'}]);
html = renderMarkdown('Hello @a[1]\\x and @<f>&" but not @a[1]\\xy');
assert.equal((html.match(/class="markdown-mention"/g)||[]).length, 2, 'escaped nicknames');
assert.doesNotMatch(html, /<f>/, 'no raw HTML from nickname');
console.log('PASS: special-character nicknames remain escaped');