Skip to content

Commit 13cb5ef

Browse files
authored
Allow extension handlers to fall through to default logic
1 parent 553a0e3 commit 13cb5ef

File tree

4 files changed

+75
-5
lines changed

4 files changed

+75
-5
lines changed

dev/lib/index.js

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1309,9 +1309,15 @@ function extension(combined, extension) {
13091309

13101310
case 'enter':
13111311
case 'exit': {
1312+
const left = combined[key]
13121313
const right = extension[key]
1313-
if (right) {
1314-
Object.assign(combined[key], right)
1314+
for (const tokenType in right) {
1315+
if (right[tokenType]) {
1316+
left[tokenType] = combineHandles(
1317+
left[tokenType],
1318+
right[tokenType]
1319+
)
1320+
}
13151321
}
13161322

13171323
break
@@ -1322,6 +1328,22 @@ function extension(combined, extension) {
13221328
}
13231329
}
13241330

1331+
/**
1332+
* Creates a new handle that calls `right` first, then falls through to `left`
1333+
* only if `right` explicitly returns `false`.
1334+
* @param {Handle?} left
1335+
* @param {Handle} right
1336+
* @returns {Handle}
1337+
*/
1338+
function combineHandles(left, right) {
1339+
if (!left) return right
1340+
1341+
return function (...params) {
1342+
const rightResult = right.apply(this, params)
1343+
return rightResult === false ? left.apply(this, params) : rightResult
1344+
}
1345+
}
1346+
13251347
/** @type {OnEnterError} */
13261348
function defaultOnError(left, right) {
13271349
if (left) {

dev/lib/types.d.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,9 +226,10 @@ export type Handles = Record<string, Handle>
226226
* @param token
227227
* Current token.
228228
* @returns
229-
* Nothing.
229+
* Nothing, if the token was fully handled by this extension and should be ignored by previous extensions / default logic.
230+
* Or `false`, if the token has not been handled by this extension and handling should fall back to preceding logic.
230231
*/
231-
export type Handle = (this: CompileContext, token: Token) => undefined | void
232+
export type Handle = (this: CompileContext, token: Token) => undefined | void | false
232233

233234
/**
234235
* Handle the case where the `right` token is open, but it is closed (by the

readme.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,9 @@ Handle a token (TypeScript type).
248248
249249
###### Returns
250250
251-
Nothing (`undefined`).
251+
Nothing, if the token was fully handled and should be ignored by previous
252+
extensions / default logic. Or `false`, if the token has not been handled here
253+
and the parser should fall back to preceding logic.
252254
253255
### `OnEnterError`
254256

test/index.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,51 @@ test('fromMarkdown', async function (t) {
146146
)
147147
})
148148

149+
await t.test(
150+
'should allow extension handlers to fall through',
151+
async function () {
152+
assert.deepEqual(
153+
fromMarkdown('a\nb', {
154+
mdastExtensions: [
155+
{
156+
enter: {
157+
paragraph() {
158+
return false
159+
}
160+
}
161+
}
162+
]
163+
}),
164+
{
165+
type: 'root',
166+
children: [
167+
{
168+
type: 'paragraph',
169+
children: [
170+
{
171+
type: 'text',
172+
value: 'a\nb',
173+
position: {
174+
start: {line: 1, column: 1, offset: 0},
175+
end: {line: 2, column: 2, offset: 3}
176+
}
177+
}
178+
],
179+
position: {
180+
start: {line: 1, column: 1, offset: 0},
181+
end: {line: 2, column: 2, offset: 3}
182+
}
183+
}
184+
],
185+
position: {
186+
start: {line: 1, column: 1, offset: 0},
187+
end: {line: 2, column: 2, offset: 3}
188+
}
189+
}
190+
)
191+
}
192+
)
193+
149194
await t.test('should support multiple extensions', async function () {
150195
assert.deepEqual(
151196
fromMarkdown('a\nb', {

0 commit comments

Comments
 (0)