Skip to content

Commit

Permalink
Add support for improved exit error handling
Browse files Browse the repository at this point in the history
Related-to: 752dc22.
  • Loading branch information
wooorm committed Nov 21, 2021
1 parent 77208c8 commit d617634
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 11 deletions.
6 changes: 5 additions & 1 deletion dev/index.js
Expand Up @@ -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'
31 changes: 21 additions & 10 deletions dev/lib/index.js
Expand Up @@ -54,12 +54,13 @@
* @typedef {Partial<NormalizedExtension>} Extension
* An mdast extension changes how markdown tokens are turned into mdast.
*
* @typedef {(this: Omit<CompileContext, 'sliceSerialize'>, left: Token|undefined, right: Token) => void} OnError
* @typedef {(this: Omit<CompileContext, 'sliceSerialize'>, left: Token|undefined, right: Token) => void} OnEnterError
* @typedef {(this: Omit<CompileContext, 'sliceSerialize'>, left: Token, right: Token) => void} OnExitError
*
* @typedef CompileContext
* mdast compiler context
* @property {Array<Node | Fragment>} 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 {<K extends string>(key: K) => CompileData[K]} getData
Expand All @@ -68,9 +69,9 @@
* Capture some of the output data.
* @property {(this: CompileContext) => string} resume
* Stop capturing and access the output data.
* @property {<N extends Node>(this: CompileContext, node: N, token: Token, onError?: OnError) => N} enter
* @property {<N extends Node>(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.
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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()
Expand All @@ -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')
Expand Down Expand Up @@ -1130,7 +1141,7 @@ function extension(combined, extension) {
}
}

/** @type {OnError} */
/** @type {OnEnterError} */
function defaultOnError(left, right) {
if (left) {
throw new Error(
Expand Down
25 changes: 25 additions & 0 deletions test/index.js
Expand Up @@ -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('<tel:123>').children[0],
{
Expand Down

0 comments on commit d617634

Please sign in to comment.