micromark-extension-directive/lib/factory-label.js
Titus Wormer 38836e5c61
Add support for balanced brackets in labels
Previously, brackets were only allowed in labels when escaped,
making it impossible to use media with resources (links, images),
or nested directives.

This adds support for up to three levels of nesting in a label.

This also removes a hidden flag that was not used anymore.

Closes GH-7.
2021-02-22 14:41:52 +01:00

122 lines
2.6 KiB
JavaScript

module.exports = createLabel
var markdownLineEnding = require('micromark/dist/character/markdown-line-ending')
// This is a fork of:
// <https://github.com/micromark/micromark/blob/bf53bf9/lib/tokenize/factory-label.js>
// to allow empty labels, balanced brackets (such as for nested directives),
// text instead of strings, and optionally disallows EOLs.
// eslint-disable-next-line max-params
function createLabel(
effects,
ok,
nok,
type,
markerType,
stringType,
disallowEol
) {
var size = 0
var balance = 0
return start
function start(code) {
/* istanbul ignore if - always `[` */
if (code !== 91 /* `[` */) throw new Error('expected `[`')
effects.enter(type)
effects.enter(markerType)
effects.consume(code)
effects.exit(markerType)
return afterStart
}
function afterStart(code) {
if (code === 93 /* `]` */) {
effects.enter(markerType)
effects.consume(code)
effects.exit(markerType)
effects.exit(type)
return ok
}
effects.enter(stringType)
return atBreak(code)
}
function atBreak(code) {
if (
code === null /* EOF */ ||
/* <https://github.com/micromark/micromark/blob/bf53bf9/lib/constant/constants.js#L34> */
size > 999
) {
return nok(code)
}
if (code === 93 /* `]` */ && !balance--) {
return atClosingBrace(code)
}
if (markdownLineEnding(code)) {
if (disallowEol) {
return nok(code)
}
effects.enter('lineEnding')
effects.consume(code)
effects.exit('lineEnding')
return atBreak
}
effects.enter('chunkText', {contentType: 'text'})
return label(code)
}
function label(code) {
if (
code === null /* EOF */ ||
markdownLineEnding(code) ||
/* <https://github.com/micromark/micromark/blob/bf53bf9/lib/constant/constants.js#L34> */
size > 999
) {
effects.exit('chunkText')
return atBreak(code)
}
if (code === 91 /* `[` */ && ++balance > 3) {
return nok(code)
}
if (code === 93 /* `]` */ && !balance--) {
effects.exit('chunkText')
return atClosingBrace(code)
}
effects.consume(code)
return code === 92 /* `\` */ ? labelEscape : label
}
function atClosingBrace(code) {
effects.exit(stringType)
effects.enter(markerType)
effects.consume(code)
effects.exit(markerType)
effects.exit(type)
return ok
}
function labelEscape(code) {
if (
code === 91 /* `[` */ ||
code === 92 /* `\` */ ||
code === 93 /* `]` */
) {
effects.consume(code)
size++
return label
}
return label(code)
}
}