From 3e7320a6401a2dd9069b760a132179f0b4c7aa7e Mon Sep 17 00:00:00 2001 From: Yimiprod Date: Mon, 12 Feb 2024 16:11:01 +0100 Subject: [PATCH] feat(Instance)!: parser throw when default async is true and called with async at false BREAKING CHANGE: parser now throw an error when `defaultConfig` is modified by an extension to make the returned value a Promise and the we call parser with `async` option at false. It can be skipped with `silent` to true, making it still working for library that use it to modify the config globally but still calling each instance with the option `async` at false. --- src/Instance.ts | 12 ++++-------- src/MarkedOptions.ts | 4 ++-- test/types/marked.ts | 16 ++++++++++++++-- test/unit/marked.test.js | 20 +++++++++++++++++++- 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/src/Instance.ts b/src/Instance.ts index 9b99cd5687..a708945644 100644 --- a/src/Instance.ts +++ b/src/Instance.ts @@ -273,17 +273,13 @@ export class Marked { const origOpt: MarkedOptions = { ...options }; const opt: MarkedOptions = { ...this.defaults, ...origOpt }; - // Show warning if an extension set async to true but the parse was called with async: false - if (isAsyncOptions(this.defaults) && isSyncOptions(origOpt)) { - if (!opt.silent) { - console.warn('marked(): The async option was set to true by an extension. The async: false option sent to parse will be ignored.'); - } + const throwError = this.#onError(!!opt.silent, !!opt.async); - opt.async = true; + if (isAsyncOptions(this.defaults) && isSyncOptions(origOpt)) { + // Throw an error if an extension set async to true but the parse was called with async: false + return throwError(new Error('marked(): The async option was set to true by an extension. The async: false option sent to parse will be ignored.')); } - const throwError = this.#onError(!!opt.silent, !!opt.async); - // throw error in case of non string input if (typeof src === 'undefined' || src === null) { return throwError(new Error('marked(): input parameter is undefined or null')); diff --git a/src/MarkedOptions.ts b/src/MarkedOptions.ts index d1b73c779b..8ad955d71e 100644 --- a/src/MarkedOptions.ts +++ b/src/MarkedOptions.ts @@ -162,9 +162,9 @@ export interface MarkedAsyncOptions extends _MarkedOptions { export type MarkedOptions = MarkedSyncOptions | MarkedAsyncOptions; export function isAsyncOptions(options: MarkedOptions): options is MarkedAsyncOptions { - return 'async' in options && options.async === true; + return options.async === true; } export function isSyncOptions(options: MarkedOptions): options is MarkedSyncOptions { - return !isAsyncOptions(options); + return options.async === false; } diff --git a/test/types/marked.ts b/test/types/marked.ts index de2bd4bdd2..414b82d4d7 100644 --- a/test/types/marked.ts +++ b/test/types/marked.ts @@ -261,13 +261,25 @@ marked.use(asyncExtension); const md = '# foobar'; const asyncMarked: string = await marked(md, { async: true }); const promiseMarked: Promise = marked(md, { async: true }); -const notAsyncMarked: string = marked(md, { async: false }); +const notAsyncMarked: string = marked(md, { async: false, silent: true }); const defaultMarked: string = marked(md); const asyncMarkedParse: string = await marked.parse(md, { async: true }); const promiseMarkedParse: Promise = marked.parse(md, { async: true }); -const notAsyncMarkedParse: string = marked.parse(md, { async: false }); +const notAsyncMarkedParse: string = marked.parse(md, { async: false, silent: true }); const defaultMarkedParse: string = marked.parse(md); + +try { + const notAsyncMarkedThrow: string = marked(md, { async: false, silent: false }); +} catch { + console.log('expected throw'); +} + +try { + const notAsyncMarkedParseThrow: string = marked.parse(md, { async: false, silent: false }); +} catch { + console.log('expected throw'); +} })(); // Tests for List and ListItem diff --git a/test/unit/marked.test.js b/test/unit/marked.test.js index c9c0925a12..9bc1faaccd 100644 --- a/test/unit/marked.test.js +++ b/test/unit/marked.test.js @@ -632,7 +632,25 @@ used extension2 walked

it('should return Promise if async is set by extension', () => { marked.use({ async: true }); - assert.ok(marked.parse('test', { async: false }) instanceof Promise); + assert.ok(marked.parse('test') instanceof Promise); + }); + + it('should throw an if async is set by extension and a different async parameter is set', () => { + marked.use({ async: true }); + + assert.throws(() => marked.parse('test', { async: false }), /The async option was set to true by an extension/); + }); + + it('should not throw an if async is set by extension and a different async parameter is set and the silent parameter is set', () => { + marked.use({ async: true }); + + assert.doesNotThrow(() => marked.parse('test', { async: false, silent: true }), /The async option was set to true by an extension/); + }); + + it('should return a Promise if async is set by extension and a different async parameter is set and the silent parameter is set', () => { + marked.use({ async: true }); + + assert.ok(marked.parse('test', { async: false, silent: true }) instanceof Promise); }); it('should allow deleting/editing tokens', () => {