|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import {factoryDestination} from 'micromark-factory-destination' |
|
import {factoryLabel} from 'micromark-factory-label' |
|
import {factoryTitle} from 'micromark-factory-title' |
|
import {factoryWhitespace} from 'micromark-factory-whitespace' |
|
import {markdownLineEndingOrSpace} from 'micromark-util-character' |
|
import {push, splice} from 'micromark-util-chunked' |
|
import {normalizeIdentifier} from 'micromark-util-normalize-identifier' |
|
import {resolveAll} from 'micromark-util-resolve-all' |
|
|
|
export const labelEnd = { |
|
name: 'labelEnd', |
|
tokenize: tokenizeLabelEnd, |
|
resolveTo: resolveToLabelEnd, |
|
resolveAll: resolveAllLabelEnd |
|
} |
|
|
|
|
|
const resourceConstruct = { |
|
tokenize: tokenizeResource |
|
} |
|
|
|
const referenceFullConstruct = { |
|
tokenize: tokenizeReferenceFull |
|
} |
|
|
|
const referenceCollapsedConstruct = { |
|
tokenize: tokenizeReferenceCollapsed |
|
} |
|
|
|
|
|
function resolveAllLabelEnd(events) { |
|
let index = -1 |
|
while (++index < events.length) { |
|
const token = events[index][1] |
|
if ( |
|
token.type === 'labelImage' || |
|
token.type === 'labelLink' || |
|
token.type === 'labelEnd' |
|
) { |
|
|
|
events.splice(index + 1, token.type === 'labelImage' ? 4 : 2) |
|
token.type = 'data' |
|
index++ |
|
} |
|
} |
|
return events |
|
} |
|
|
|
|
|
function resolveToLabelEnd(events, context) { |
|
let index = events.length |
|
let offset = 0 |
|
|
|
let token |
|
|
|
let open |
|
|
|
let close |
|
|
|
let media |
|
|
|
|
|
while (index--) { |
|
token = events[index][1] |
|
if (open) { |
|
|
|
if ( |
|
token.type === 'link' || |
|
(token.type === 'labelLink' && token._inactive) |
|
) { |
|
break |
|
} |
|
|
|
|
|
|
|
if (events[index][0] === 'enter' && token.type === 'labelLink') { |
|
token._inactive = true |
|
} |
|
} else if (close) { |
|
if ( |
|
events[index][0] === 'enter' && |
|
(token.type === 'labelImage' || token.type === 'labelLink') && |
|
!token._balanced |
|
) { |
|
open = index |
|
if (token.type !== 'labelLink') { |
|
offset = 2 |
|
break |
|
} |
|
} |
|
} else if (token.type === 'labelEnd') { |
|
close = index |
|
} |
|
} |
|
const group = { |
|
type: events[open][1].type === 'labelLink' ? 'link' : 'image', |
|
start: Object.assign({}, events[open][1].start), |
|
end: Object.assign({}, events[events.length - 1][1].end) |
|
} |
|
const label = { |
|
type: 'label', |
|
start: Object.assign({}, events[open][1].start), |
|
end: Object.assign({}, events[close][1].end) |
|
} |
|
const text = { |
|
type: 'labelText', |
|
start: Object.assign({}, events[open + offset + 2][1].end), |
|
end: Object.assign({}, events[close - 2][1].start) |
|
} |
|
media = [ |
|
['enter', group, context], |
|
['enter', label, context] |
|
] |
|
|
|
|
|
media = push(media, events.slice(open + 1, open + offset + 3)) |
|
|
|
|
|
media = push(media, [['enter', text, context]]) |
|
|
|
|
|
|
|
|
|
media = push( |
|
media, |
|
resolveAll( |
|
context.parser.constructs.insideSpan.null, |
|
events.slice(open + offset + 4, close - 3), |
|
context |
|
) |
|
) |
|
|
|
|
|
media = push(media, [ |
|
['exit', text, context], |
|
events[close - 2], |
|
events[close - 1], |
|
['exit', label, context] |
|
]) |
|
|
|
|
|
media = push(media, events.slice(close + 1)) |
|
|
|
|
|
media = push(media, [['exit', group, context]]) |
|
splice(events, open, events.length, media) |
|
return events |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function tokenizeLabelEnd(effects, ok, nok) { |
|
const self = this |
|
let index = self.events.length |
|
|
|
let labelStart |
|
|
|
let defined |
|
|
|
|
|
while (index--) { |
|
if ( |
|
(self.events[index][1].type === 'labelImage' || |
|
self.events[index][1].type === 'labelLink') && |
|
!self.events[index][1]._balanced |
|
) { |
|
labelStart = self.events[index][1] |
|
break |
|
} |
|
} |
|
return start |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function start(code) { |
|
|
|
if (!labelStart) { |
|
return nok(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (labelStart._inactive) { |
|
return labelEndNok(code) |
|
} |
|
defined = self.parser.defined.includes( |
|
normalizeIdentifier( |
|
self.sliceSerialize({ |
|
start: labelStart.end, |
|
end: self.now() |
|
}) |
|
) |
|
) |
|
effects.enter('labelEnd') |
|
effects.enter('labelMarker') |
|
effects.consume(code) |
|
effects.exit('labelMarker') |
|
effects.exit('labelEnd') |
|
return after |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function after(code) { |
|
|
|
|
|
|
|
|
|
if (code === 40) { |
|
return effects.attempt( |
|
resourceConstruct, |
|
labelEndOk, |
|
defined ? labelEndOk : labelEndNok |
|
)(code) |
|
} |
|
|
|
|
|
if (code === 91) { |
|
return effects.attempt( |
|
referenceFullConstruct, |
|
labelEndOk, |
|
defined ? referenceNotFull : labelEndNok |
|
)(code) |
|
} |
|
|
|
|
|
return defined ? labelEndOk(code) : labelEndNok(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function referenceNotFull(code) { |
|
return effects.attempt( |
|
referenceCollapsedConstruct, |
|
labelEndOk, |
|
labelEndNok |
|
)(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function labelEndOk(code) { |
|
|
|
return ok(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function labelEndNok(code) { |
|
labelStart._balanced = true |
|
return nok(code) |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function tokenizeResource(effects, ok, nok) { |
|
return resourceStart |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function resourceStart(code) { |
|
effects.enter('resource') |
|
effects.enter('resourceMarker') |
|
effects.consume(code) |
|
effects.exit('resourceMarker') |
|
return resourceBefore |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function resourceBefore(code) { |
|
return markdownLineEndingOrSpace(code) |
|
? factoryWhitespace(effects, resourceOpen)(code) |
|
: resourceOpen(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function resourceOpen(code) { |
|
if (code === 41) { |
|
return resourceEnd(code) |
|
} |
|
return factoryDestination( |
|
effects, |
|
resourceDestinationAfter, |
|
resourceDestinationMissing, |
|
'resourceDestination', |
|
'resourceDestinationLiteral', |
|
'resourceDestinationLiteralMarker', |
|
'resourceDestinationRaw', |
|
'resourceDestinationString', |
|
32 |
|
)(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function resourceDestinationAfter(code) { |
|
return markdownLineEndingOrSpace(code) |
|
? factoryWhitespace(effects, resourceBetween)(code) |
|
: resourceEnd(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function resourceDestinationMissing(code) { |
|
return nok(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function resourceBetween(code) { |
|
if (code === 34 || code === 39 || code === 40) { |
|
return factoryTitle( |
|
effects, |
|
resourceTitleAfter, |
|
nok, |
|
'resourceTitle', |
|
'resourceTitleMarker', |
|
'resourceTitleString' |
|
)(code) |
|
} |
|
return resourceEnd(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function resourceTitleAfter(code) { |
|
return markdownLineEndingOrSpace(code) |
|
? factoryWhitespace(effects, resourceEnd)(code) |
|
: resourceEnd(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function resourceEnd(code) { |
|
if (code === 41) { |
|
effects.enter('resourceMarker') |
|
effects.consume(code) |
|
effects.exit('resourceMarker') |
|
effects.exit('resource') |
|
return ok |
|
} |
|
return nok(code) |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function tokenizeReferenceFull(effects, ok, nok) { |
|
const self = this |
|
return referenceFull |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function referenceFull(code) { |
|
return factoryLabel.call( |
|
self, |
|
effects, |
|
referenceFullAfter, |
|
referenceFullMissing, |
|
'reference', |
|
'referenceMarker', |
|
'referenceString' |
|
)(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function referenceFullAfter(code) { |
|
return self.parser.defined.includes( |
|
normalizeIdentifier( |
|
self.sliceSerialize(self.events[self.events.length - 1][1]).slice(1, -1) |
|
) |
|
) |
|
? ok(code) |
|
: nok(code) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function referenceFullMissing(code) { |
|
return nok(code) |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function tokenizeReferenceCollapsed(effects, ok, nok) { |
|
return referenceCollapsedStart |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function referenceCollapsedStart(code) { |
|
|
|
|
|
effects.enter('reference') |
|
effects.enter('referenceMarker') |
|
effects.consume(code) |
|
effects.exit('referenceMarker') |
|
return referenceCollapsedOpen |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function referenceCollapsedOpen(code) { |
|
if (code === 93) { |
|
effects.enter('referenceMarker') |
|
effects.consume(code) |
|
effects.exit('referenceMarker') |
|
effects.exit('reference') |
|
return ok |
|
} |
|
return nok(code) |
|
} |
|
} |
|
|