Urara-Blog/node_modules/.pnpm-store/v3/files/41/3ff18d4f872f91c6df6dfbd37d9d28ef772c8cf1b62551deadf24655e830b7e51591c9a633cfaf09c1db13ed8d544703ec1e4565fb3fddc77d232f0a4ababe
2022-08-14 01:14:53 +08:00

367 lines
8.5 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @typedef {import('micromark-util-types').Construct} Construct
* @typedef {import('micromark-util-types').Resolver} Resolver
* @typedef {import('micromark-util-types').Tokenizer} Tokenizer
* @typedef {import('micromark-util-types').Event} Event
* @typedef {import('micromark-util-types').Token} Token
* @typedef {import('micromark-util-types').State} State
* @typedef {import('micromark-util-types').Code} Code
*/
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'
/** @type {Construct} */
export const labelEnd = {
name: 'labelEnd',
tokenize: tokenizeLabelEnd,
resolveTo: resolveToLabelEnd,
resolveAll: resolveAllLabelEnd
}
/** @type {Construct} */
const resourceConstruct = {
tokenize: tokenizeResource
}
/** @type {Construct} */
const fullReferenceConstruct = {
tokenize: tokenizeFullReference
}
/** @type {Construct} */
const collapsedReferenceConstruct = {
tokenize: tokenizeCollapsedReference
}
/** @type {Resolver} */
function resolveAllLabelEnd(events) {
let index = -1
/** @type {Token} */
let token
while (++index < events.length) {
token = events[index][1]
if (
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
}
/** @type {Resolver} */
function resolveToLabelEnd(events, context) {
let index = events.length
let offset = 0
/** @type {Token} */
let token
/** @type {number|undefined} */
let open
/** @type {number|undefined} */
let close
/** @type {Event[]} */
let media // Find an opening.
while (index--) {
token = events[index][1]
if (open) {
// If we see another link, or inactive link label, weve been here before.
if (
token.type === 'link' ||
(token.type === 'labelLink' && token._inactive)
) {
break
} // Mark other link openings as inactive, as we cant 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
}
}
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]
] // Opening marker.
media = push(media, events.slice(open + 1, open + offset + 3)) // Text open.
media = push(media, [['enter', text, context]]) // Between.
media = push(
media,
resolveAll(
context.parser.constructs.insideSpan.null,
events.slice(open + offset + 4, close - 3),
context
)
) // Text close, marker close, label close.
media = push(media, [
['exit', text, context],
events[close - 2],
events[close - 1],
['exit', label, context]
]) // Reference, resource, or so.
media = push(media, events.slice(close + 1)) // Media close.
media = push(media, [['exit', group, context]])
splice(events, open, events.length, media)
return events
}
/** @type {Tokenizer} */
function tokenizeLabelEnd(effects, ok, nok) {
const self = this
let index = self.events.length
/** @type {Token} */
let labelStart
/** @type {boolean} */
let 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
/** @type {State} */
function start(code) {
if (!labelStart) {
return nok(code)
} // Its a balanced bracket, but contains a link.
if (labelStart._inactive) return balanced(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 afterLabelEnd
}
/** @type {State} */
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)
}
/** @type {State} */
function balanced(code) {
labelStart._balanced = true
return nok(code)
}
}
/** @type {Tokenizer} */
function tokenizeResource(effects, ok, nok) {
return start
/** @type {State} */
function start(code) {
effects.enter('resource')
effects.enter('resourceMarker')
effects.consume(code)
effects.exit('resourceMarker')
return factoryWhitespace(effects, open)
}
/** @type {State} */
function open(code) {
if (code === 41) {
return end(code)
}
return factoryDestination(
effects,
destinationAfter,
nok,
'resourceDestination',
'resourceDestinationLiteral',
'resourceDestinationLiteralMarker',
'resourceDestinationRaw',
'resourceDestinationString',
32
)(code)
}
/** @type {State} */
function destinationAfter(code) {
return markdownLineEndingOrSpace(code)
? factoryWhitespace(effects, between)(code)
: end(code)
}
/** @type {State} */
function between(code) {
if (code === 34 || code === 39 || code === 40) {
return factoryTitle(
effects,
factoryWhitespace(effects, end),
nok,
'resourceTitle',
'resourceTitleMarker',
'resourceTitleString'
)(code)
}
return end(code)
}
/** @type {State} */
function end(code) {
if (code === 41) {
effects.enter('resourceMarker')
effects.consume(code)
effects.exit('resourceMarker')
effects.exit('resource')
return ok
}
return nok(code)
}
}
/** @type {Tokenizer} */
function tokenizeFullReference(effects, ok, nok) {
const self = this
return start
/** @type {State} */
function start(code) {
return factoryLabel.call(
self,
effects,
afterLabel,
nok,
'reference',
'referenceMarker',
'referenceString'
)(code)
}
/** @type {State} */
function afterLabel(code) {
return self.parser.defined.includes(
normalizeIdentifier(
self.sliceSerialize(self.events[self.events.length - 1][1]).slice(1, -1)
)
)
? ok(code)
: nok(code)
}
}
/** @type {Tokenizer} */
function tokenizeCollapsedReference(effects, ok, nok) {
return start
/** @type {State} */
function start(code) {
effects.enter('reference')
effects.enter('referenceMarker')
effects.consume(code)
effects.exit('referenceMarker')
return open
}
/** @type {State} */
function open(code) {
if (code === 93) {
effects.enter('referenceMarker')
effects.consume(code)
effects.exit('referenceMarker')
effects.exit('reference')
return ok
}
return nok(code)
}
}