import { Marked } from '../../lib/marked.esm.js'; import { timeout } from './utils.js'; import { describe, it, beforeEach } from 'node:test'; import assert from 'node:assert'; function createHeadingToken(text) { return { type: 'heading', raw: `# ${text}`, depth: 1, text, tokens: [ { type: 'text', raw: text, text }, ], }; } describe('Hooks', () => { let marked; beforeEach(() => { marked = new Marked(); }); it('should preprocess markdown', () => { marked.use({ hooks: { preprocess(markdown) { return `# preprocess\n\n${markdown}`; }, }, }); const html = marked.parse('*text*'); assert.strictEqual(html.trim(), '

preprocess

\n

text

'); }); it('should preprocess async', async() => { marked.use({ async: true, hooks: { async preprocess(markdown) { await timeout(); return `# preprocess async\n\n${markdown}`; }, }, }); const promise = marked.parse('*text*'); assert.ok(promise instanceof Promise); const html = await promise; assert.strictEqual(html.trim(), '

preprocess async

\n

text

'); }); it('should preprocess options', () => { marked.use({ hooks: { preprocess(markdown) { this.options.breaks = true; return markdown; }, }, }); const html = marked.parse('line1\nline2'); assert.strictEqual(html.trim(), '

line1
line2

'); }); it('should preprocess options async', async() => { marked.use({ async: true, hooks: { async preprocess(markdown) { await timeout(); this.options.breaks = true; return markdown; }, }, }); const html = await marked.parse('line1\nline2'); assert.strictEqual(html.trim(), '

line1
line2

'); }); it('should postprocess html', () => { marked.use({ hooks: { postprocess(html) { return html + '

postprocess

'; }, }, }); const html = marked.parse('*text*'); assert.strictEqual(html.trim(), '

text

\n

postprocess

'); }); it('should postprocess async', async() => { marked.use({ async: true, hooks: { async postprocess(html) { await timeout(); return html + '

postprocess async

\n'; }, }, }); const promise = marked.parse('*text*'); assert.ok(promise instanceof Promise); const html = await promise; assert.strictEqual(html.trim(), '

text

\n

postprocess async

'); }); it('should process tokens before walkTokens', () => { marked.use({ hooks: { processAllTokens(tokens) { tokens.push(createHeadingToken('processAllTokens')); return tokens; }, }, walkTokens(token) { if (token.type === 'heading') { token.tokens[0].text += ' walked'; } return token; }, }); const html = marked.parse('*text*'); assert.strictEqual(html.trim(), '

text

\n

processAllTokens walked

'); }); it('should process tokens async before walkTokens', async() => { marked.use({ async: true, hooks: { async processAllTokens(tokens) { await timeout(); tokens.push(createHeadingToken('processAllTokens async')); return tokens; }, }, walkTokens(token) { if (token.type === 'heading') { token.tokens[0].text += ' walked'; } return token; }, }); const promise = marked.parse('*text*'); assert.ok(promise instanceof Promise); const html = await promise; assert.strictEqual(html.trim(), '

text

\n

processAllTokens async walked

'); }); it('should process all hooks in reverse', async() => { marked.use({ hooks: { preprocess(markdown) { return `# preprocess1\n\n${markdown}`; }, postprocess(html) { return html + '

postprocess1

\n'; }, processAllTokens(tokens) { tokens.push(createHeadingToken('processAllTokens1')); return tokens; }, }, }); marked.use({ async: true, hooks: { preprocess(markdown) { return `# preprocess2\n\n${markdown}`; }, async postprocess(html) { await timeout(); return html + '

postprocess2 async

\n'; }, processAllTokens(tokens) { tokens.push(createHeadingToken('processAllTokens2')); return tokens; }, }, }); const promise = marked.parse('*text*'); assert.ok(promise instanceof Promise); const html = await promise; assert.strictEqual(html.trim(), `\

preprocess1

preprocess2

text

processAllTokens2

processAllTokens1

postprocess2 async

postprocess1

`); }); it('should provide lexer', () => { marked.use({ hooks: { provideLexer() { return (src) => [createHeadingToken(src)]; }, }, }); const html = marked.parse('text'); assert.strictEqual(html.trim(), '

text

'); }); it('should provide lexer async', async() => { marked.use({ async: true, hooks: { provideLexer() { return async(src) => { await timeout(); return [createHeadingToken(src)]; }; }, }, }); const html = await marked.parse('text'); assert.strictEqual(html.trim(), '

text

'); }); it('should provide parser return object', () => { marked.use({ hooks: { provideParser() { return (tokens) => ({ text: 'test parser' }); }, }, }); const html = marked.parse('text'); assert.strictEqual(html.text, 'test parser'); }); it('should provide parser', () => { marked.use({ hooks: { provideParser() { return (tokens) => 'test parser'; }, }, }); const html = marked.parse('text'); assert.strictEqual(html.trim(), 'test parser'); }); it('should provide parser async', async() => { marked.use({ async: true, hooks: { provideParser() { return async(tokens) => { await timeout(); return 'test parser'; }; }, }, }); const html = await marked.parse('text'); assert.strictEqual(html.trim(), 'test parser'); }); });