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(/
const value = 1;\n console\.log\(value\);<\/code><\/pre>/,html,'code container indentation + dedent');
has(/]*>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>/,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(/@Ala<\/code>/,html,'inline code excluded');
has(/]*>@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\nSzczegóły
\n## Procedura\n');
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: '&"', color: '#112233'}]);
html = renderMarkdown('Hello @a[1]\\x and @&" but not @a[1]\\xy');
assert.equal((html.match(/class="markdown-mention"/g)||[]).length, 2, 'escaped nicknames');
assert.doesNotMatch(html, //, 'no raw HTML from nickname');
console.log('PASS: special-character nicknames remain escaped');