From a28743391a589fca188f19249ad25aae24f4b305 Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Fri, 8 Dec 2023 00:17:36 -0700 Subject: [PATCH] fix: allow Renderer class in marked.use (#3118) --- src/Instance.ts | 18 ++++++++++--- test/unit/instance.test.js | 54 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 67 insertions(+), 5 deletions(-) diff --git a/src/Instance.ts b/src/Instance.ts index 2ca489f297..bd0553ba16 100644 --- a/src/Instance.ts +++ b/src/Instance.ts @@ -142,9 +142,13 @@ export class Marked { if (pack.renderer) { const renderer = this.defaults.renderer || new _Renderer(this.defaults); for (const prop in pack.renderer) { - if (!(prop in renderer) || prop === 'options') { + if (!(prop in renderer)) { throw new Error(`renderer '${prop}' does not exist`); } + if (prop === 'options') { + // ignore options property + continue; + } const rendererProp = prop as Exclude; const rendererFunc = pack.renderer[rendererProp] as GenericRendererFunction; const prevRenderer = renderer[rendererProp] as GenericRendererFunction; @@ -162,9 +166,13 @@ export class Marked { if (pack.tokenizer) { const tokenizer = this.defaults.tokenizer || new _Tokenizer(this.defaults); for (const prop in pack.tokenizer) { - if (!(prop in tokenizer) || ['options', 'rules', 'lexer'].includes(prop)) { + if (!(prop in tokenizer)) { throw new Error(`tokenizer '${prop}' does not exist`); } + if (['options', 'rules', 'lexer'].includes(prop)) { + // ignore options, rules, and lexer properties + continue; + } const tokenizerProp = prop as Exclude; const tokenizerFunc = pack.tokenizer[tokenizerProp] as UnknownFunction; const prevTokenizer = tokenizer[tokenizerProp] as UnknownFunction; @@ -185,9 +193,13 @@ export class Marked { if (pack.hooks) { const hooks = this.defaults.hooks || new _Hooks(); for (const prop in pack.hooks) { - if (!(prop in hooks) || prop === 'options') { + if (!(prop in hooks)) { throw new Error(`hook '${prop}' does not exist`); } + if (prop === 'options') { + // ignore options property + continue; + } const hooksProp = prop as Exclude; const hooksFunc = pack.hooks[hooksProp] as UnknownFunction; const prevHook = hooks[hooksProp] as UnknownFunction; diff --git a/test/unit/instance.test.js b/test/unit/instance.test.js index c7e525616d..d00e533a01 100644 --- a/test/unit/instance.test.js +++ b/test/unit/instance.test.js @@ -1,5 +1,5 @@ -import { marked, Marked, Renderer } from '../../lib/marked.esm.js'; -import { describe, it } from 'node:test'; +import { marked, Marked, Renderer, Tokenizer, Hooks } from '../../lib/marked.esm.js'; +import { describe, it, beforeEach } from 'node:test'; import assert from 'node:assert'; describe('Marked', () => { @@ -89,4 +89,54 @@ describe('Marked', () => { assert.strictEqual(html, 'test'); }); + + describe('use class objects', () => { + beforeEach(() => { + marked.setOptions(marked.getDefaults()); + }); + + it('allow new Renderer()', () => { + const marked1 = new Marked(); + const newRenderer = new Renderer(); + newRenderer.heading = () => 'im marked renderer'; + + marked1.use({ renderer: newRenderer }); + marked.use({ renderer: newRenderer }); + + assert.strictEqual(marked1.parse('# header'), 'im marked renderer'); + assert.strictEqual(marked.parse('# header'), 'im marked renderer'); + }); + + it('allow new Tokenizer()', () => { + const marked1 = new Marked(); + const newTokenizer = new Tokenizer(); + newTokenizer.heading = function(src) { + return { + type: 'heading', + raw: src, + depth: 1, + text: 'im marked tokenizer', + tokens: this.lexer.inlineTokens('im marked tokenizer') + }; + }; + + marked1.use({ tokenizer: newTokenizer }); + marked.use({ tokenizer: newTokenizer }); + + assert.strictEqual(marked1.parse('# header'), '

im marked tokenizer

\n'); + assert.strictEqual(marked.parse('# header'), '

im marked tokenizer

\n'); + }); + + it('allow new Hooks()', () => { + const marked1 = new Marked(); + const newHooks = new Hooks(); + newHooks.preprocess = () => 'im marked hooks'; + + marked1.use({ hooks: newHooks }); + marked.use({ hooks: newHooks }); + + assert.strictEqual(marked1.parse('# header'), '

im marked hooks

\n'); + assert.strictEqual(marked.parse('# header'), '

im marked hooks

\n'); + }); + }); });