diff --git a/lib/factory-label.js b/lib/factory-label.js index d6cfa44..458fa5c 100644 --- a/lib/factory-label.js +++ b/lib/factory-label.js @@ -1,12 +1,11 @@ module.exports = createLabel var markdownLineEnding = require('micromark/dist/character/markdown-line-ending') -var markdownSpace = require('micromark/dist/character/markdown-space') // This is a fork of: // -// to allow empty, support text instead of strings, and optionally w/o EOLs, -// labels. +// 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( @@ -16,11 +15,10 @@ function createLabel( type, markerType, stringType, - allowEmpty, disallowEol ) { var size = 0 - var data + var balance = 0 return start @@ -35,7 +33,7 @@ function createLabel( } function afterStart(code) { - if (code === 93 /* `]` */ && allowEmpty) { + if (code === 93 /* `]` */) { effects.enter(markerType) effects.consume(code) effects.exit(markerType) @@ -50,21 +48,14 @@ function createLabel( function atBreak(code) { if ( code === null /* EOF */ || - code === 91 /* `[` */ || - (code === 93 /* `]` */ && !data && !allowEmpty) || /* */ size > 999 ) { return nok(code) } - if (code === 93 /* `]` */) { - effects.exit(stringType) - effects.enter(markerType) - effects.consume(code) - effects.exit(markerType) - effects.exit(type) - return ok + if (code === 93 /* `]` */ && !balance--) { + return atClosingBrace(code) } if (markdownLineEnding(code)) { @@ -85,8 +76,6 @@ function createLabel( function label(code) { if ( code === null /* EOF */ || - code === 91 /* `[` */ || - code === 93 /* `]` */ || markdownLineEnding(code) || /* */ size > 999 @@ -95,11 +84,28 @@ function createLabel( return atBreak(code) } + if (code === 91 /* `[` */ && ++balance > 3) { + return nok(code) + } + + if (code === 93 /* `]` */ && !balance--) { + effects.exit('chunkText') + return atClosingBrace(code) + } + effects.consume(code) - data = data || !markdownSpace(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 /* `[` */ || diff --git a/lib/tokenize-directive-container.js b/lib/tokenize-directive-container.js index e288da7..0cea1d8 100644 --- a/lib/tokenize-directive-container.js +++ b/lib/tokenize-directive-container.js @@ -184,7 +184,6 @@ function tokenizeLabel(effects, ok, nok) { 'directiveContainerLabel', 'directiveContainerLabelMarker', 'directiveContainerLabelString', - true, true ) } diff --git a/lib/tokenize-directive-leaf.js b/lib/tokenize-directive-leaf.js index 07c3295..fcbac8d 100644 --- a/lib/tokenize-directive-leaf.js +++ b/lib/tokenize-directive-leaf.js @@ -69,7 +69,6 @@ function tokenizeLabel(effects, ok, nok) { 'directiveLeafLabel', 'directiveLeafLabelMarker', 'directiveLeafLabelString', - true, true ) } diff --git a/lib/tokenize-directive-text.js b/lib/tokenize-directive-text.js index 00aff94..ffffba8 100644 --- a/lib/tokenize-directive-text.js +++ b/lib/tokenize-directive-text.js @@ -65,8 +65,7 @@ function tokenizeLabel(effects, ok, nok) { nok, 'directiveTextLabel', 'directiveTextLabelMarker', - 'directiveTextLabelString', - true + 'directiveTextLabelString' ) } diff --git a/readme.md b/readme.md index be23acb..2239867 100644 --- a/readme.md +++ b/readme.md @@ -188,8 +188,6 @@ this implementation mimics CommonMark as closely as possible: label (~~`:a []`~~), name and attributes (~~`:a {}`~~), or label and attributes (~~`:a[] {}`~~) — because it’s not allowed in links either (~~`[] ()`~~) -* Only escaped brackets are allow in the label (~~`:a[b[c]d]`~~) — because - links in links are not allowed either * No trailing colons allowed on the opening fence of a container (~~`:::a:::`~~) — because it’s not allowed in fenced code either * The label and attributes in a leaf or container cannot include line endings diff --git a/test.js b/test.js index 111d2c2..4dbab6c 100644 --- a/test.js +++ b/test.js @@ -114,6 +114,12 @@ test('micromark-extension-directive (syntax)', function (t) { 'should support markdown in an label' ) + t.equal( + micromark('a :b[c :d[e] f] g', options()), + '

a g

', + 'should support a directive in an label' + ) + t.equal( micromark(':a[]asd', options()), '

asd

', @@ -1120,6 +1126,12 @@ test('micromark-extension-directive (compile)', function (t) { 'should support fall through directives (`*`)' ) + t.equal( + micromark(':a[:img{src="x" alt=y}]{href="z"}', options({'*': h})), + '

y

', + 'should support fall through directives (`*`)' + ) + t.end() }) @@ -1136,6 +1148,24 @@ test('content', function (t) { 'should support escaped brackets in a label' ) + t.equal( + micromark(':abbr[x[y]z]', options({abbr: abbr})), + '

x[y]z

', + 'should support balanced brackets in a label' + ) + + t.equal( + micromark(':abbr[a[b[c[d]e]f]g]h', options({abbr: abbr})), + '

a[b[c[d]e]f]gh

', + 'should support balanced brackets in a label, three levels deep' + ) + + t.equal( + micromark(':abbr[a[b[c[d[e]f]g]h]i]j', options({abbr: abbr})), + '

[a[b[c[d[e]f]g]h]i]j

', + 'should *not* support balanced brackets in a label, four levels deep' + ) + t.equal( micromark(':abbr[a\nb\rc]', options({abbr: abbr})), '

a\nb\rc

',