import { render, type SlimdownExtension } from './index.js';
import test from 'ava';
const removeWhitespaces = (txt: string) => txt.replace(/\s+/g, '');
test('header', (t) => {
const expected = '
Hello world
';
const html = render('# Hello world');
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('single underscore', (t) => {
const expected = 'Hello_world
';
const html = render('Hello_world');
const html2 = render('Hello\\_world');
t.is(removeWhitespaces(html), removeWhitespaces(expected));
t.is(removeWhitespaces(html2), removeWhitespaces(expected));
});
test('double underscores', (t) => {
const expected = 'here_a_test
';
const html = render('here\\_a\\_test');
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('italics', (t) => {
const expected = 'This is italics.
';
const html = render('This is _italics_.');
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('superscript', (t) => {
const expected =
'This is the 1st test, and this is the 2nd version. But also consider a2 + b2 = c2.
';
const html = render(
'This is the 1^st^ test, and this is the 2^nd^ version. But also consider a^2^ + b^2^ = c^2^.',
);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('subscript', (t) => {
const expected =
'This is italics and this is a1 or C2.
';
const html = render('This is _italics_ and this is a~1~ or C~2~.');
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('footnote', (t) => {
const expected = `
Here is a simple footnote[1]. With some additional text after it.
`;
const html = render(
`Here is a simple footnote[^1]. With some additional text after it.
[^1]: My reference.`,
);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('code', (t) => {
const expected =
'This is italics and this is _italics_ too.
';
const html = render('This is `italics` and this is `_italics_` too.');
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('multiline codeblock', (t) => {
const expected = `## Table example
| Tables | Are | Cool |
|---------------|:-------------:|------:|
| col 3 is | right-aligned | $1600 |
| col 2 is | centered | $12 |
| zebra stripes | are neat | $1 |
`;
const html = render(`
\`\`\`md
## Table example
| Tables | Are | Cool |
|---------------|:-------------:|------:|
| col 3 is | right-aligned | $1600 |
| col 2 is | centered | $12 |
| zebra stripes | are neat | $1 |
\`\`\`
`);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('ul', (t) => {
const expected = '';
const html = render(`- Item 1\n- Item 2\n- Item 3`);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('ul using +', (t) => {
const expected = '';
const html = render(`+ Item 1\n+ Item 2\n+ Item 3`);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('ul using *', (t) => {
const expected = '';
const html = render(`* Item 1\n* Item 2\n* Item 3`);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('nested ul + ul', (t) => {
const expected =
'';
const html = render(
`- Item 1\n - Item 1.1\n - Item 1.2\n - Item 1.3\n- Item 2\n- Item 3`,
);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('nested ul + ol', (t) => {
const expected =
'- Item 1
- Item 1.1
- Item 1.2
- Item 1.3
- Item 2
- Item 3
';
const html = render(
`- Item 1\n 1. Item 1.1\n 2. Item 1.2\n 3. Item 1.3\n- Item 2\n- Item 3`,
);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('ol', (t) => {
const expected = '- Item 1
- Item 2
- Item 3
';
const html = render(`1. Item 1\n2. Item 2\n3. Item 3`);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('nested ol + ol', (t) => {
const expected =
'- Item 1
- Item 1.1
- Item 1.2
- Item 1.3
- Item 2
- Item 3
';
const html = render(
`1. Item 1\n 1. Item 1.1\n 2. Item 1.2\n 3. Item 1.3\n2. Item 2\n3. Item 3`,
);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('nested ol + ul', (t) => {
const expected =
'- Item 1
- Item 2
- Item 3
';
const html = render(
`1. Item 1\n - Item 1.1\n - Item 1.2\n - Item 1.3\n2. Item 2\n3. Item 3`,
);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('table 1', (t) => {
const table = `
| Threat \\ Context | rainy | sunny |
|------------------|------------|------------|
| terrorist | scenario 1 | scenario 2 |
| criminal | scenario 3 | scenario 4 |
`;
const expected = `
| Threat \\ Context | rainy | sunny |
| terrorist | scenario 1 | scenario 2 |
| criminal | scenario 3 | scenario 4 |
`;
const html = render(table);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('table 2', (t) => {
const table = `
| Threat \\ Context | rainy | sunny |
| ---------------- | ---------- | ---------- |
| terrorist | scenario 1 | scenario 2 |
| criminal | scenario 3 | scenario 4 |
`;
const expected = `
| Threat \\ Context | rainy | sunny |
| terrorist | scenario 1 | scenario 2 |
| criminal | scenario 3 | scenario 4 |
`;
const html = render(table);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('parsing strong in own paragraph', (t) => {
const md = `An **indie electronica music** bundle.
**Featuring** songs by ...
Pay what you want for Music`;
const generated = render(md);
const expected = `
An indie electronica music bundle.
Featuring songs by ...
Pay what you want for Music
`;
t.is(generated, expected);
});
test('parsing longer text', (t) => {
const md = `# Title
To use **Slimdown**, grap it from [npm](https://www.npmjs.com/package/slimdown-js) or *fork* the project on [GitHub](https://github.com/erikvullings/slimdown-js).
* One
* Two
* Three
## Underscores
my\\_var\\_is
## Subhead
One **two** three **four** five.
One __two__ three _four_ five __six__ seven _eight_.
1. One
2. Two
3. Three
More text with \`inline($code);\` sample.
> A block quote
> across two lines.
More text...`;
const expected = `Title
To use Slimdown, grap it from npm or fork the project on GitHub.
Underscores
my_var_is
Subhead
One two three four five.
One two three four five six seven eight.
- One
- Two
- Three
More text with inline($code); sample.
A block quote
across two lines.
More text...
`;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('headings have no id attribute by default', (t) => {
const md = `# Hello world\n\n## Setup`;
const html = render(md);
t.false(html.includes('id='));
});
test('headings have no id attribute when headingIds is false', (t) => {
const md = `# Hello world`;
const html = render(md, { headingIds: false });
t.false(html.includes('id='));
});
test('headingIds adds a slugified id to each heading', (t) => {
const md = `# Hello World\n\n## Second Level Heading`;
const html = render(md, { headingIds: true });
t.true(html.includes('Hello World
'));
t.true(html.includes('Second Level Heading
'));
});
test('headingIds slugifies rendered inline content, not raw markdown', (t) => {
const md = `## **Setup**`;
const html = render(md, { headingIds: true });
t.true(html.includes('Setup
'));
});
test('headingIds falls back to "section" for symbol-only headings', (t) => {
const md = `# !!!`;
const html = render(md, { headingIds: true });
t.true(html.includes(''));
});
test('headingIds strips accents to base Latin letters', (t) => {
const md = `# Café Déjà Vu`;
const html = render(md, { headingIds: true });
t.true(html.includes('Café Déjà Vu
'));
});
test('headingIds appends -2, -3 suffixes for duplicate slugs', (t) => {
const md = `# Overview\n\n## Overview\n\n### Overview`;
const html = render(md, { headingIds: true });
t.true(html.includes('Overview
'));
t.true(html.includes('Overview
'));
t.true(html.includes('Overview
'));
});
test('headingIds keeps slug counts scoped to a single render call', (t) => {
const first = render(`# Overview\n\n## Overview`, { headingIds: true });
const second = render(`# Overview`, { headingIds: true });
t.true(first.includes('Overview
'));
t.true(first.includes('Overview
'));
t.true(second.includes('Overview
'));
t.false(second.includes('id="overview-2"'));
});
test('parsing links with underscores', (t) => {
const md = `# Links fail with underscores
[Test Link](http://www.google.com/?some_param=another_value)`;
const expected = `Links fail with underscores
Test Link
`;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('parsing images', (t) => {
const md = `NS logo image: `;
const expected = `NS logo image: 
`;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('parsing base64 images with empty alt text', (t) => {
const md = ``;
const expected = `
`;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('parsing base64 images with empty alt text inside a table', (t) => {
const md = `| Image |
|-------|
|  |`;
const expected = `
| Image |
 |
`;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('parsing code blocks', (t) => {
const md = `# Code example
\`\`\`
Tab indented
codeblock
\`\`\`
`;
const expected = `Code example
Tab indented codeblock
`;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('parsing inline code', (t) => {
const md = `This is \`inline A & B\` code.`;
const expected = `This is inline A & B code.`;
const html = render(md, true);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('parsing inline HTML code', (t) => {
const md = `This is \`An HTML paragrahp
\` code.`;
const expected = `This is <p>An HTML paragrahp</p> code.`;
const html = render(md, true);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('bypassing HTML code', (t) => {
const md = `An HTML paragrahp`;
const expected = `An HTML paragrahp`;
const html = render(md, true);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('parsing tables', (t) => {
const md = `# Table example
| Tables | Are | Cool |
|---------------|:-------------:|------:|
| col 3 is | right-aligned | $1600 |
| col 2 is | centered | $12 |
| zebra stripes | are neat | $1 |
`;
const expected = `Table example
| Tables |
Are |
Cool |
| col 3 is |
right-aligned |
$1600 |
| col 2 is |
centered |
$12 |
| zebra stripes |
are neat |
$1 |
`;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('removing paragraphs', (t) => {
const expected = 'Hello world';
const html = render('Hello world', true);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('do not remove paragraphs for longer text', (t) => {
const expected = `Hello world
How are you?
`;
const html = render(
`# Hello world
How are you?`,
true,
);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('creating links', (t) => {
const md = 'This is a [link](https://www.google.com).';
const expected = 'This is a link.';
const html = render(md, true);
t.is(html.trim(), expected);
});
test('creating external links', (t) => {
const md = 'This is a [link](https://www.google.com).';
const expected =
'This is a link.';
const html = render(md, true, true);
t.is(html.trim(), expected);
});
test('creating links with underscores', (t) => {
const md = 'This is a [link](https://my_test_page.com).';
const expected = 'This is a link.';
const html = render(md, true);
t.is(html.trim(), expected);
});
test('creating emphasized text', (t) => {
const md = 'This is _emphasized_ text.';
const expected = 'This is emphasized text.';
const html = render(md, true);
t.is(html.trim(), expected);
});
test('creating emphasized text 2', (t) => {
const md = 'This is *emphasized* text.';
const expected = 'This is emphasized text.';
const html = render(md, true);
t.is(html.trim(), expected);
});
test('creating strong text', (t) => {
const md = 'This is **strong** text.';
const expected = 'This is strong text.';
const html = render(md, true);
t.is(html.trim(), expected);
});
test('creating strong text 2', (t) => {
const md = 'This is __strong__ text.';
const expected = 'This is strong text.';
const html = render(md, true);
t.is(html.trim(), expected);
});
test('creating strong and empasized text', (t) => {
const md = 'This is ***strong and emphasized*** text.';
const expected =
'This is strong and emphasized text.';
const html = render(md, true);
t.is(html.trim(), expected);
});
test('creating strong and empasized text 2', (t) => {
const md = 'This is ___strong and emphasized___ text.';
const expected =
'This is strong and emphasized text.';
const html = render(md, true);
t.is(html.trim(), expected);
});
test('creating deleted text', (t) => {
const md = 'This is ~~deleted~~ text.';
const expected = 'This is deleted text.';
const html = render(md, true);
t.is(html.trim(), expected);
});
test('creating quotes', (t) => {
const md = 'This is a quote: :"quoted": text.';
const expected = 'This is a quote: quoted
text.';
const html = render(md, true);
t.is(html.trim(), expected);
});
test('creating block quotes', (t) => {
const md = '> This is a blockquoted text.';
const expected = 'This is a blockquoted text.
';
const html = render(md, true);
t.is(html.trim(), expected);
});
test('complex nested ol with ul - continuous numbered list', (t) => {
const md = `1. First item
- Nested bullet 1
- Nested bullet 2
2. Second item
- Another nested bullet
3. Third item`;
const expected = `
- First item
- Nested bullet 1
- Nested bullet 2
- Second item
- Third item
`;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('complex nested ul with ol - continuous bullet list', (t) => {
const md = `- First item
1. Nested number 1
2. Nested number 2
- Second item
1. Another nested number
- Third item`;
const expected = `
- First item
- Nested number 1
- Nested number 2
- Second item
- Another nested number
- Third item
`;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('triple nested lists', (t) => {
const md = `1. Level 1 item 1
- Level 2 item 1
1. Level 3 item 1
2. Level 3 item 2
- Level 2 item 2
2. Level 1 item 2`;
const expected = `
- Level 1 item 1
- Level 2 item 1
- Level 3 item 1
- Level 3 item 2
- Level 2 item 2
- Level 1 item 2
`;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('real world complex nested list', (t) => {
const md = `1. **First Section:**
- **Subsection A:** Description A
- **Subsection B:** Description B
2. **Second Section:**
- **Subsection C:** Description C
- **Subsection D:** Description D`;
const expected = `
- First Section:
- Subsection A: Description A
- Subsection B: Description B
- Second Section:
- Subsection C: Description C
- Subsection D: Description D
`;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
// Phase 1 feature tests
test('inline math support', (t) => {
const md = 'The equation $E = mc^2$ is famous.';
const expected =
'The equation E = mc^2 is famous.
';
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('block math support', (t) => {
const md = `Here's a block equation:
$$
\\int_{-\\infty}^{\\infty} e^{-x^2} dx = \\sqrt{\\pi}
$$
That's Gaussian integral.`;
const expected = `Here's a block equation:
\\int_{-\\infty}^{\\infty} e^{-x^2} dx = \\sqrt{\\pi}
That's Gaussian integral.
`;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('task list with checked items', (t) => {
const md = `- [x] Completed task
- [ ] Incomplete task
- [X] Another completed task`;
const expected = ``;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('nested task lists', (t) => {
const md = `- [x] Main task
- [ ] Subtask 1
- [x] Subtask 2
- [ ] Another main task`;
const expected = ``;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('definition lists', (t) => {
const md = `Technology : Computer science field
Science : Study of natural world`;
const expected = `
- Technology
- Computer science field
- Science
- Study of natural world
`;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('no definition lists for regular colons', (t) => {
const md = `Technology: Computer science field
Science: Study of natural world`;
const expected = `
Technology: Computer science field
Science:Study of natural world
`;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('no definition lists for math', (t) => {
const md = `$15 : 3 = 5$`;
const expected = `15 : 3 = 5
`;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('table with empty cells not merged', (t) => {
const md = `| Header 1 | Header 2 | Header 3 |
|----------|----------|----------|
| Value | | End |
| | Middle | |`;
const expected = `
| Header 1 |
Header 2 |
Header 3 |
| Value |
|
End |
|
Middle |
|
`;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('table with column spanning', (t) => {
const md = `| Header 1 | Header 2|| | Header 3 |
|----------|----------|----------|
| Cell 1 | Spanning|| | Cell |
| Normal | Cell | Cell |`;
const expected = `
| Header 1 |
Header 2 |
Header 3 |
| Cell 1 |
Spanning |
Cell |
| Normal |
Cell |
Cell |
`;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('table with caption', (t) => {
const md = `[Table Caption]
| Name | Age |
|------|-----|
| John | 25 |
| Jane | 30 |`;
const expected = `Table Caption
| Name | Age |
| John | 25 |
| Jane | 30 |
`;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('math expressions with special characters', (t) => {
const md = `Complex math: $\\sum_{i=1}^{n} x_i < \\infty$ and block math:
$$
f(x) = \\begin{cases}
x^2 & \\text{if } x \\geq 0 \\\\
-x^2 & \\text{if } x < 0
\\end{cases}
$$`;
const expected = `Complex math: \\sum_{i=1}^{n} x_i < \\infty and block math:
f(x) = \\begin{cases}
x^2 & \\text{if } x \\geq 0 \\\\
-x^2 & \\text{if } x < 0
\\end{cases}
`;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('mixed content with all Phase 1 features', (t) => {
const md = `# Math and Tasks
Here's some inline math $a^2 + b^2 = c^2$ and a task list:
- [x] Learn math
- [ ] Practice LaTeX: $\\int_0^1 x dx = \\frac{1}{2}$
Technology : Computer science field
Science : Study of natural world
[Data Table]
| Name | Score|| | Total |
|------|------|------|
| Test | 85 | 95 |`;
const expected = `Math and Tasks
Here's some inline math a^2 + b^2 = c^2 and a task list:
- Technology
- Computer science field
- Science
- Study of natural world
Data Table
| Name | Score | Total |
| Test | 85 | 95 |
`;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('decimal numbers should not be converted to ordered lists', (t) => {
const md = '100.000-1.000.000';
const expected = '100.000-1.000.000
';
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('mix of decimal numbers and actual ordered list', (t) => {
const md = `100.000-1.000.000
1. This is a real list item
2. This is another real list item
Price range: 50.99-99.99`;
const expected = `100.000-1.000.000
- This is a real list item
- This is another real list item
Price range: 50.99-99.99
`;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('horizontal rule with three dashes', (t) => {
const expected = 'before
\n
\nafter
';
const html = render('before\n\n---\n\nafter');
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('horizontal rule variations', (t) => {
const expected1 = 'text
\n
\nmore
';
const html1 = render('text\n\n---\n\nmore');
t.is(removeWhitespaces(html1), removeWhitespaces(expected1));
const expected2 = 'text
\n
\nmore
';
const html2 = render('text\n\n----\n\nmore');
t.is(removeWhitespaces(html2), removeWhitespaces(expected2));
const expected3 = 'text
\n
\nmore
';
const html3 = render('text\n\n-----\n\nmore');
t.is(removeWhitespaces(html3), removeWhitespaces(expected3));
});
test('mixed ordered and unordered lists with text after', (t) => {
const md = `1. First item
2. Second item
3. Third item
- Unordered item
- Another item
- Last item
More text`;
const expected = `
- First item
- Second item
- Third item
- Unordered item
- Another item
- Last item
More text
`;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('mixed unordered and ordered lists', (t) => {
const md = `- First bullet
- Second bullet
1. First number
2. Second number
- Back to bullets
- Another bullet`;
const expected = `
- First bullet
- Second bullet
- First number
- Second number
- Back to bullets
- Another bullet
`;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('codeblock extension', (t) => {
const extension: SlimdownExtension = {
renderCodeBlock: ({ lang, code, escapeHtml }) =>
lang === 'mermaid'
? `${escapeHtml(code)}
`
: undefined,
};
const html = render(
`\`\`\`mermaid
graph TD
A --> B
\`\`\``,
{ extensions: [extension] },
);
t.is(
removeWhitespaces(html),
removeWhitespaces(
'graph TD\n A --> B
',
),
);
});
test('codeblock extension fallback', (t) => {
const extension: SlimdownExtension = {
renderCodeBlock: () => undefined,
};
const html = render(
`\`\`\`ts
const value = '';
\`\`\``,
{ extensions: [extension] },
);
t.is(
removeWhitespaces(html),
removeWhitespaces(
'const value = '<safe>';
',
),
);
});
test('math extensions', (t) => {
const extension: SlimdownExtension = {
renderInlineMath: ({ math, escapeHtml }) =>
`${escapeHtml(math)}`,
renderMathBlock: ({ math, escapeHtml }) =>
`${escapeHtml(math)}
`,
};
const html = render(
`Inline $E = mc^2$.
$$
\\sum_i x_i
$$`,
{ extensions: [extension] },
);
t.is(
removeWhitespaces(html),
removeWhitespaces(
'Inline E = mc^2.
\\sum_i x_i
',
),
);
});
test('ordered list preserves non-one start number', (t) => {
const md = `3. Third item
4. Fourth item`;
const expected = `
- Third item
- Fourth item
`;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('ordered list continuation after intervening paragraph keeps numbering', (t) => {
const md = `1. First item
Some text between.
2. Second item`;
const expected = `
- First item
Some text between.
- Second item
`;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('ordered lists support closing parenthesis markers', (t) => {
const md = `1) First item
2) Second item`;
const expected = `
- First item
- Second item
`;
const html = render(md);
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('alpha lists are ignored by default', (t) => {
const md = `a. First item
b. Second item`;
const html = render(md);
t.false(html.includes(' {
const md = `a. First item
b. Second item`;
const expected = `
- First item
- Second item
`;
const html = render(md, { alphaLists: true });
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('single alpha markers are ignored even when alpha lists are enabled', (t) => {
const md = `A. Smith wrote this paragraph.`;
const html = render(md, { alphaLists: true });
t.false(html.includes(' {
const md = `a. First item
c. Third item`;
const html = render(md, { alphaLists: true });
t.false(html.includes(' {
const md = `A. first item
1. first sub item
2. second sub item
B. second item`;
const expected = `
- first item
- first sub item
- second sub item
- second item
`;
const html = render(md, { alphaLists: true });
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('uppercase alpha lists preserve style and start', (t) => {
const md = `C) Third item
D) Fourth item`;
const expected = `
- Third item
- Fourth item
`;
const html = render(md, { alphaLists: true });
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('parenthesized alpha list markers are supported', (t) => {
const md = `(b) Second item
(c) Third item`;
const expected = `
- Second item
- Third item
`;
const html = render(md, { alphaLists: true });
t.is(removeWhitespaces(html), removeWhitespaces(expected));
});
test('code block with language class', (t) => {
const md = "```js\nconsole.log('hi');\n```\n";
const html = render(md);
t.true(html.includes(''));
t.true(html.includes('console.log('hi');'));
});
test('code block without language has no class', (t) => {
const md = "```\nplain code\n```\n";
const html = render(md);
t.true(html.includes('plain code'));
});
test('hard line breaks', (t) => {
const md = 'first line \nsecond line';
const html = render(md, true);
t.true(html.includes('
'));
t.true(html.includes('second line'));
});
test('autolinks', (t) => {
const html = render('', true);
t.is(removeWhitespaces(html), removeWhitespaces('https://example.com'));
});
test('render with RenderOptions object', (t) => {
const md = 'Hello [link](https://example.com)';
const html = render(md, { removeParagraphs: true, externalLinks: true });
t.true(html.includes('target="_blank"'));
t.false(html.includes(''));
});