All checks were successful
Publish To Prod / deploy_and_publish (push) Successful in 35s
331 lines
7.5 KiB
JavaScript
331 lines
7.5 KiB
JavaScript
'use strict'
|
||
|
||
var markdownLineEndingOrSpace = require('../character/markdown-line-ending-or-space.js')
|
||
var chunkedPush = require('../util/chunked-push.js')
|
||
var chunkedSplice = require('../util/chunked-splice.js')
|
||
var normalizeIdentifier = require('../util/normalize-identifier.js')
|
||
var resolveAll = require('../util/resolve-all.js')
|
||
var shallow = require('../util/shallow.js')
|
||
var factoryDestination = require('./factory-destination.js')
|
||
var factoryLabel = require('./factory-label.js')
|
||
var factoryTitle = require('./factory-title.js')
|
||
var factoryWhitespace = require('./factory-whitespace.js')
|
||
|
||
var labelEnd = {
|
||
name: 'labelEnd',
|
||
tokenize: tokenizeLabelEnd,
|
||
resolveTo: resolveToLabelEnd,
|
||
resolveAll: resolveAllLabelEnd
|
||
}
|
||
var resourceConstruct = {
|
||
tokenize: tokenizeResource
|
||
}
|
||
var fullReferenceConstruct = {
|
||
tokenize: tokenizeFullReference
|
||
}
|
||
var collapsedReferenceConstruct = {
|
||
tokenize: tokenizeCollapsedReference
|
||
}
|
||
|
||
function resolveAllLabelEnd(events) {
|
||
var index = -1
|
||
var token
|
||
|
||
while (++index < events.length) {
|
||
token = events[index][1]
|
||
|
||
if (
|
||
!token._used &&
|
||
(token.type === 'labelImage' ||
|
||
token.type === 'labelLink' ||
|
||
token.type === 'labelEnd')
|
||
) {
|
||
// Remove the marker.
|
||
events.splice(index + 1, token.type === 'labelImage' ? 4 : 2)
|
||
token.type = 'data'
|
||
index++
|
||
}
|
||
}
|
||
|
||
return events
|
||
}
|
||
|
||
function resolveToLabelEnd(events, context) {
|
||
var index = events.length
|
||
var offset = 0
|
||
var group
|
||
var label
|
||
var text
|
||
var token
|
||
var open
|
||
var close
|
||
var media // Find an opening.
|
||
|
||
while (index--) {
|
||
token = events[index][1]
|
||
|
||
if (open) {
|
||
// If we see another link, or inactive link label, we’ve been here before.
|
||
if (
|
||
token.type === 'link' ||
|
||
(token.type === 'labelLink' && token._inactive)
|
||
) {
|
||
break
|
||
} // Mark other link openings as inactive, as we can’t have links in
|
||
// links.
|
||
|
||
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
|
||
}
|
||
}
|
||
|
||
group = {
|
||
type: events[open][1].type === 'labelLink' ? 'link' : 'image',
|
||
start: shallow(events[open][1].start),
|
||
end: shallow(events[events.length - 1][1].end)
|
||
}
|
||
label = {
|
||
type: 'label',
|
||
start: shallow(events[open][1].start),
|
||
end: shallow(events[close][1].end)
|
||
}
|
||
text = {
|
||
type: 'labelText',
|
||
start: shallow(events[open + offset + 2][1].end),
|
||
end: shallow(events[close - 2][1].start)
|
||
}
|
||
media = [
|
||
['enter', group, context],
|
||
['enter', label, context]
|
||
] // Opening marker.
|
||
|
||
media = chunkedPush(media, events.slice(open + 1, open + offset + 3)) // Text open.
|
||
|
||
media = chunkedPush(media, [['enter', text, context]]) // Between.
|
||
|
||
media = chunkedPush(
|
||
media,
|
||
resolveAll(
|
||
context.parser.constructs.insideSpan.null,
|
||
events.slice(open + offset + 4, close - 3),
|
||
context
|
||
)
|
||
) // Text close, marker close, label close.
|
||
|
||
media = chunkedPush(media, [
|
||
['exit', text, context],
|
||
events[close - 2],
|
||
events[close - 1],
|
||
['exit', label, context]
|
||
]) // Reference, resource, or so.
|
||
|
||
media = chunkedPush(media, events.slice(close + 1)) // Media close.
|
||
|
||
media = chunkedPush(media, [['exit', group, context]])
|
||
chunkedSplice(events, open, events.length, media)
|
||
return events
|
||
}
|
||
|
||
function tokenizeLabelEnd(effects, ok, nok) {
|
||
var self = this
|
||
var index = self.events.length
|
||
var labelStart
|
||
var defined // Find an opening.
|
||
|
||
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)
|
||
} // It’s a balanced bracket, but contains a link.
|
||
|
||
if (labelStart._inactive) return balanced(code)
|
||
defined =
|
||
self.parser.defined.indexOf(
|
||
normalizeIdentifier(
|
||
self.sliceSerialize({
|
||
start: labelStart.end,
|
||
end: self.now()
|
||
})
|
||
)
|
||
) > -1
|
||
effects.enter('labelEnd')
|
||
effects.enter('labelMarker')
|
||
effects.consume(code)
|
||
effects.exit('labelMarker')
|
||
effects.exit('labelEnd')
|
||
return afterLabelEnd
|
||
}
|
||
|
||
function afterLabelEnd(code) {
|
||
// Resource: `[asd](fgh)`.
|
||
if (code === 40) {
|
||
return effects.attempt(
|
||
resourceConstruct,
|
||
ok,
|
||
defined ? ok : balanced
|
||
)(code)
|
||
} // Collapsed (`[asd][]`) or full (`[asd][fgh]`) reference?
|
||
|
||
if (code === 91) {
|
||
return effects.attempt(
|
||
fullReferenceConstruct,
|
||
ok,
|
||
defined
|
||
? effects.attempt(collapsedReferenceConstruct, ok, balanced)
|
||
: balanced
|
||
)(code)
|
||
} // Shortcut reference: `[asd]`?
|
||
|
||
return defined ? ok(code) : balanced(code)
|
||
}
|
||
|
||
function balanced(code) {
|
||
labelStart._balanced = true
|
||
return nok(code)
|
||
}
|
||
}
|
||
|
||
function tokenizeResource(effects, ok, nok) {
|
||
return start
|
||
|
||
function start(code) {
|
||
effects.enter('resource')
|
||
effects.enter('resourceMarker')
|
||
effects.consume(code)
|
||
effects.exit('resourceMarker')
|
||
return factoryWhitespace(effects, open)
|
||
}
|
||
|
||
function open(code) {
|
||
if (code === 41) {
|
||
return end(code)
|
||
}
|
||
|
||
return factoryDestination(
|
||
effects,
|
||
destinationAfter,
|
||
nok,
|
||
'resourceDestination',
|
||
'resourceDestinationLiteral',
|
||
'resourceDestinationLiteralMarker',
|
||
'resourceDestinationRaw',
|
||
'resourceDestinationString',
|
||
3
|
||
)(code)
|
||
}
|
||
|
||
function destinationAfter(code) {
|
||
return markdownLineEndingOrSpace(code)
|
||
? factoryWhitespace(effects, between)(code)
|
||
: end(code)
|
||
}
|
||
|
||
function between(code) {
|
||
if (code === 34 || code === 39 || code === 40) {
|
||
return factoryTitle(
|
||
effects,
|
||
factoryWhitespace(effects, end),
|
||
nok,
|
||
'resourceTitle',
|
||
'resourceTitleMarker',
|
||
'resourceTitleString'
|
||
)(code)
|
||
}
|
||
|
||
return end(code)
|
||
}
|
||
|
||
function end(code) {
|
||
if (code === 41) {
|
||
effects.enter('resourceMarker')
|
||
effects.consume(code)
|
||
effects.exit('resourceMarker')
|
||
effects.exit('resource')
|
||
return ok
|
||
}
|
||
|
||
return nok(code)
|
||
}
|
||
}
|
||
|
||
function tokenizeFullReference(effects, ok, nok) {
|
||
var self = this
|
||
return start
|
||
|
||
function start(code) {
|
||
return factoryLabel.call(
|
||
self,
|
||
effects,
|
||
afterLabel,
|
||
nok,
|
||
'reference',
|
||
'referenceMarker',
|
||
'referenceString'
|
||
)(code)
|
||
}
|
||
|
||
function afterLabel(code) {
|
||
return self.parser.defined.indexOf(
|
||
normalizeIdentifier(
|
||
self.sliceSerialize(self.events[self.events.length - 1][1]).slice(1, -1)
|
||
)
|
||
) < 0
|
||
? nok(code)
|
||
: ok(code)
|
||
}
|
||
}
|
||
|
||
function tokenizeCollapsedReference(effects, ok, nok) {
|
||
return start
|
||
|
||
function start(code) {
|
||
effects.enter('reference')
|
||
effects.enter('referenceMarker')
|
||
effects.consume(code)
|
||
effects.exit('referenceMarker')
|
||
return open
|
||
}
|
||
|
||
function open(code) {
|
||
if (code === 93) {
|
||
effects.enter('referenceMarker')
|
||
effects.consume(code)
|
||
effects.exit('referenceMarker')
|
||
effects.exit('reference')
|
||
return ok
|
||
}
|
||
|
||
return nok(code)
|
||
}
|
||
}
|
||
|
||
module.exports = labelEnd
|