62 lines
4.1 KiB
JavaScript
62 lines
4.1 KiB
JavaScript
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');
|
|
|
|
html = renderMarkdown('- [ ] Open\n- [x] Done\n- [~] Cancelled\n - [~] Nested cancelled');
|
|
has(/task-list-item--cancelled/, html, 'cancelled task has its own class');
|
|
assert.equal((html.match(/task-list-item--cancelled/g) || []).length, 2, 'both cancelled tasks recognized');
|
|
has(/data-source-line="3" disabled aria-label="Cancelled task"/, html, 'cancelled checkbox cannot be clicked');
|
|
has(/data-source-prefix="- \[~\] "/, html, 'cancelled markdown marker preserved');
|
|
has(/data-source-line="1"(?! disabled)/, html, 'open task remains interactive');
|
|
console.log('PASS: cancelled tasks are disabled and retain their source markers');
|