Skip to content

Commit

Permalink
feat(Instance)!: parser throw when default async is true and called w…
Browse files Browse the repository at this point in the history
…ith 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.
  • Loading branch information
Yimiprod committed Mar 9, 2024
1 parent 784a9a9 commit 3e7320a
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 13 deletions.
12 changes: 4 additions & 8 deletions src/Instance.ts
Expand Up @@ -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'));
Expand Down
4 changes: 2 additions & 2 deletions src/MarkedOptions.ts
Expand Up @@ -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;
}
16 changes: 14 additions & 2 deletions test/types/marked.ts
Expand Up @@ -261,13 +261,25 @@ marked.use(asyncExtension);
const md = '# foobar';
const asyncMarked: string = await marked(md, { async: true });
const promiseMarked: Promise<string> = 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<string> = 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
Expand Down
20 changes: 19 additions & 1 deletion test/unit/marked.test.js
Expand Up @@ -632,7 +632,25 @@ used extension2 walked</p>
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', () => {
Expand Down

0 comments on commit 3e7320a

Please sign in to comment.