From d617634a3bace02e05aa0721f1cca0425ce4f750 Mon Sep 17 00:00:00 2001 From: Titus Wormer Date: Sun, 21 Nov 2021 11:14:33 +0100 Subject: [PATCH] Add support for improved exit error handling Related-to: 752dc22. --- dev/index.js | 6 +++++- dev/lib/index.js | 31 +++++++++++++++++++++---------- test/index.js | 25 +++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 11 deletions(-) diff --git a/dev/index.js b/dev/index.js index 67a8e96..70f9b52 100644 --- a/dev/index.js +++ b/dev/index.js @@ -7,7 +7,11 @@ * @typedef {import('./lib/index.js').Transform} Transform * @typedef {import('./lib/index.js').Token} Token * @typedef {import('./lib/index.js').CompileContext} CompileContext - * @typedef {import('./lib/index.js').OnError} OnError + * @typedef {import('./lib/index.js').OnEnterError} OnEnterError + * @typedef {import('./lib/index.js').OnExitError} OnExitError + * + * @typedef {import('./lib/index.js').OnEnterError} OnError + * To do: deprecate next major. */ export {fromMarkdown} from './lib/index.js' diff --git a/dev/lib/index.js b/dev/lib/index.js index 978eb0d..0242bae 100644 --- a/dev/lib/index.js +++ b/dev/lib/index.js @@ -54,12 +54,13 @@ * @typedef {Partial} Extension * An mdast extension changes how markdown tokens are turned into mdast. * - * @typedef {(this: Omit, left: Token|undefined, right: Token) => void} OnError + * @typedef {(this: Omit, left: Token|undefined, right: Token) => void} OnEnterError + * @typedef {(this: Omit, left: Token, right: Token) => void} OnExitError * * @typedef CompileContext * mdast compiler context * @property {Array} stack - * @property {Array<[Token, OnError|undefined]>} tokenStack + * @property {Array<[Token, OnEnterError|undefined]>} tokenStack * @property {(key: string, value?: unknown) => void} setData * Set data into the key-value store. * @property {(key: K) => CompileData[K]} getData @@ -68,9 +69,9 @@ * Capture some of the output data. * @property {(this: CompileContext) => string} resume * Stop capturing and access the output data. - * @property {(this: CompileContext, node: N, token: Token, onError?: OnError) => N} enter + * @property {(this: CompileContext, node: N, token: Token, onError?: OnEnterError) => N} enter * Enter a token. - * @property {(this: CompileContext, token: Token) => Node} exit + * @property {(this: CompileContext, token: Token, onError?: OnExitError) => Node} exit * Exit a token. * @property {TokenizeContext['sliceSerialize']} sliceSerialize * Get the string value of a token. @@ -535,7 +536,7 @@ function compiler(options = {}) { * @this {CompileContext} * @param {N} node * @param {Token} token - * @param {OnError} [errorHandler] + * @param {OnEnterError} [errorHandler] * @returns {N} */ function enter(node, token, errorHandler) { @@ -569,8 +570,14 @@ function compiler(options = {}) { } } - /** @type {CompileContext['exit']} */ - function exit(token) { + /** + * @type {CompileContext['exit']} + * @this {CompileContext} + * @param {Token} token + * @param {OnExitError} [onExitError] + * @returns {Node} + */ + function exit(token, onExitError) { const node = this.stack.pop() assert(node, 'expected `node`') const open = this.tokenStack.pop() @@ -584,8 +591,12 @@ function compiler(options = {}) { '): it’s not open' ) } else if (open[0].type !== token.type) { - const handler = open[1] || defaultOnError - handler.call(this, token, open[0]) + if (onExitError) { + onExitError.call(this, token, open[0]) + } else { + const handler = open[1] || defaultOnError + handler.call(this, token, open[0]) + } } assert(node.type !== 'fragment', 'unexpected fragment `exit`ed') @@ -1130,7 +1141,7 @@ function extension(combined, extension) { } } -/** @type {OnError} */ +/** @type {OnEnterError} */ function defaultOnError(left, right) { if (left) { throw new Error( diff --git a/test/index.js b/test/index.js index 237b523..df0ad4c 100644 --- a/test/index.js +++ b/test/index.js @@ -288,6 +288,31 @@ test('mdast-util-from-markdown', (t) => { 'should crash when closing a token when a different one is open' ) + t.throws( + () => { + fromMarkdown('a', { + mdastExtensions: [ + { + exit: { + paragraph(token) { + this.exit( + Object.assign({}, token, {type: 'lol'}), + function (a, b) { + t.equal(a.type, 'lol') + t.equal(b.type, 'paragraph') + throw new Error('problem') + } + ) + } + } + } + ] + }) + }, + /problem/, + 'should crash when closing a token when a different one is open with a custom handler' + ) + t.deepEqual( fromMarkdown('').children[0], {