Urara-Blog/node_modules/.pnpm-store/v3/files/c9/d0c58f7cc8b6c709778976e8327ab9e616d3029f115db2159e43905f28b9d699e24c1cffbf3cea9f62dfeaeb1bdb9e41143d5eda07f069266592963a15772d
2022-08-14 01:14:53 +08:00

1168 lines
33 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').Encoding} Encoding
* @typedef {import('micromark-util-types').Event} Event
* @typedef {import('micromark-util-types').ParseOptions} ParseOptions
* @typedef {import('micromark-util-types').Token} Token
* @typedef {import('micromark-util-types').TokenizeContext} TokenizeContext
* @typedef {import('micromark-util-types').Value} Value
* @typedef {import('unist').Parent} UnistParent
* @typedef {import('unist').Point} Point
* @typedef {import('mdast').PhrasingContent} PhrasingContent
* @typedef {import('mdast').Content} Content
* @typedef {Root|Content} Node
* @typedef {Extract<Node, UnistParent>} Parent
* @typedef {import('mdast').Break} Break
* @typedef {import('mdast').Blockquote} Blockquote
* @typedef {import('mdast').Code} Code
* @typedef {import('mdast').Definition} Definition
* @typedef {import('mdast').Emphasis} Emphasis
* @typedef {import('mdast').Heading} Heading
* @typedef {import('mdast').HTML} HTML
* @typedef {import('mdast').Image} Image
* @typedef {import('mdast').ImageReference} ImageReference
* @typedef {import('mdast').InlineCode} InlineCode
* @typedef {import('mdast').Link} Link
* @typedef {import('mdast').LinkReference} LinkReference
* @typedef {import('mdast').List} List
* @typedef {import('mdast').ListItem} ListItem
* @typedef {import('mdast').Paragraph} Paragraph
* @typedef {import('mdast').Root} Root
* @typedef {import('mdast').Strong} Strong
* @typedef {import('mdast').Text} Text
* @typedef {import('mdast').ThematicBreak} ThematicBreak
*
* @typedef {UnistParent & {type: 'fragment', children: Array<PhrasingContent>}} Fragment
*/
/**
* @typedef _CompileDataFields
* @property {boolean|undefined} expectingFirstListItemValue
* @property {boolean|undefined} flowCodeInside
* @property {boolean|undefined} setextHeadingSlurpLineEnding
* @property {boolean|undefined} atHardBreak
* @property {'collapsed'|'full'} referenceType
* @property {boolean|undefined} inReference
* @property {'characterReferenceMarkerHexadecimal'|'characterReferenceMarkerNumeric'} characterReferenceType
*
* @typedef {Record<string, unknown> & Partial<_CompileDataFields>} CompileData
*
* @typedef {(tree: Root) => Root|void} Transform
* @typedef {(this: CompileContext, token: Token) => void} Handle
* @typedef {Record<string, Handle>} Handles
* Token types mapping to handles
* @typedef {Record<string, Record<string, unknown>|Array<unknown>> & {canContainEols: Array<string>, transforms: Array<Transform>, enter: Handles, exit: Handles}} NormalizedExtension
* @typedef {Partial<NormalizedExtension>} Extension
* An mdast extension changes how markdown tokens are turned into mdast.
*
* @typedef {(this: Omit<CompileContext, 'sliceSerialize'>, left: Token|undefined, right: Token) => void} OnEnterError
* @typedef {(this: Omit<CompileContext, 'sliceSerialize'>, left: Token, right: Token) => void} OnExitError
*
* @typedef CompileContext
* mdast compiler context
* @property {Array<Node | Fragment>} stack
* @property {Array<[Token, OnEnterError|undefined]>} tokenStack
* @property {(key: string, value?: unknown) => void} setData
* Set data into the key-value store.
* @property {<K extends string>(key: K) => CompileData[K]} getData
* Get data from the key-value store.
* @property {(this: CompileContext) => void} buffer
* Capture some of the output data.
* @property {(this: CompileContext) => string} resume
* Stop capturing and access the output data.
* @property {<N extends Node>(this: CompileContext, node: N, token: Token, onError?: OnEnterError) => N} enter
* Enter a token.
* @property {(this: CompileContext, token: Token, onError?: OnExitError) => Node} exit
* Exit a token.
* @property {TokenizeContext['sliceSerialize']} sliceSerialize
* Get the string value of a token.
* @property {NormalizedExtension} config
* Configuration.
*
* @typedef {{mdastExtensions?: Array<Extension|Array<Extension>>}} FromMarkdownOptions
* @typedef {ParseOptions & FromMarkdownOptions} Options
*/
import {ok as assert} from 'uvu/assert'
import {toString} from 'mdast-util-to-string'
import {parse} from 'micromark/lib/parse.js'
import {preprocess} from 'micromark/lib/preprocess.js'
import {postprocess} from 'micromark/lib/postprocess.js'
import {decodeNumericCharacterReference} from 'micromark-util-decode-numeric-character-reference'
import {decodeString} from 'micromark-util-decode-string'
import {normalizeIdentifier} from 'micromark-util-normalize-identifier'
import {codes} from 'micromark-util-symbol/codes.js'
import {constants} from 'micromark-util-symbol/constants.js'
import {types} from 'micromark-util-symbol/types.js'
import {decodeNamedCharacterReference} from 'decode-named-character-reference'
import {stringifyPosition} from 'unist-util-stringify-position'
const own = {}.hasOwnProperty
/**
* @param value Markdown to parse (`string` or `Buffer`).
* @param [encoding] Character encoding to understand `value` as when its a `Buffer` (`string`, default: `'utf8'`).
* @param [options] Configuration
*/
export const fromMarkdown =
/**
* @type {(
* ((value: Value, encoding: Encoding, options?: Options) => Root) &
* ((value: Value, options?: Options) => Root)
* )}
*/
(
/**
* @param {Value} value
* @param {Encoding} [encoding]
* @param {Options} [options]
* @returns {Root}
*/
function (value, encoding, options) {
if (typeof encoding !== 'string') {
options = encoding
encoding = undefined
}
return compiler(options)(
postprocess(
parse(options).document().write(preprocess()(value, encoding, true))
)
)
}
)
/**
* Note this compiler only understand complete buffering, not streaming.
*
* @param {Options} [options]
*/
function compiler(options = {}) {
/** @type {NormalizedExtension} */
// @ts-expect-error: our base has all required fields, so the result will too.
const config = configure(
{
transforms: [],
canContainEols: [
'emphasis',
'fragment',
'heading',
'paragraph',
'strong'
],
enter: {
autolink: opener(link),
autolinkProtocol: onenterdata,
autolinkEmail: onenterdata,
atxHeading: opener(heading),
blockQuote: opener(blockQuote),
characterEscape: onenterdata,
characterReference: onenterdata,
codeFenced: opener(codeFlow),
codeFencedFenceInfo: buffer,
codeFencedFenceMeta: buffer,
codeIndented: opener(codeFlow, buffer),
codeText: opener(codeText, buffer),
codeTextData: onenterdata,
data: onenterdata,
codeFlowValue: onenterdata,
definition: opener(definition),
definitionDestinationString: buffer,
definitionLabelString: buffer,
definitionTitleString: buffer,
emphasis: opener(emphasis),
hardBreakEscape: opener(hardBreak),
hardBreakTrailing: opener(hardBreak),
htmlFlow: opener(html, buffer),
htmlFlowData: onenterdata,
htmlText: opener(html, buffer),
htmlTextData: onenterdata,
image: opener(image),
label: buffer,
link: opener(link),
listItem: opener(listItem),
listItemValue: onenterlistitemvalue,
listOrdered: opener(list, onenterlistordered),
listUnordered: opener(list),
paragraph: opener(paragraph),
reference: onenterreference,
referenceString: buffer,
resourceDestinationString: buffer,
resourceTitleString: buffer,
setextHeading: opener(heading),
strong: opener(strong),
thematicBreak: opener(thematicBreak)
},
exit: {
atxHeading: closer(),
atxHeadingSequence: onexitatxheadingsequence,
autolink: closer(),
autolinkEmail: onexitautolinkemail,
autolinkProtocol: onexitautolinkprotocol,
blockQuote: closer(),
characterEscapeValue: onexitdata,
characterReferenceMarkerHexadecimal: onexitcharacterreferencemarker,
characterReferenceMarkerNumeric: onexitcharacterreferencemarker,
characterReferenceValue: onexitcharacterreferencevalue,
codeFenced: closer(onexitcodefenced),
codeFencedFence: onexitcodefencedfence,
codeFencedFenceInfo: onexitcodefencedfenceinfo,
codeFencedFenceMeta: onexitcodefencedfencemeta,
codeFlowValue: onexitdata,
codeIndented: closer(onexitcodeindented),
codeText: closer(onexitcodetext),
codeTextData: onexitdata,
data: onexitdata,
definition: closer(),
definitionDestinationString: onexitdefinitiondestinationstring,
definitionLabelString: onexitdefinitionlabelstring,
definitionTitleString: onexitdefinitiontitlestring,
emphasis: closer(),
hardBreakEscape: closer(onexithardbreak),
hardBreakTrailing: closer(onexithardbreak),
htmlFlow: closer(onexithtmlflow),
htmlFlowData: onexitdata,
htmlText: closer(onexithtmltext),
htmlTextData: onexitdata,
image: closer(onexitimage),
label: onexitlabel,
labelText: onexitlabeltext,
lineEnding: onexitlineending,
link: closer(onexitlink),
listItem: closer(),
listOrdered: closer(),
listUnordered: closer(),
paragraph: closer(),
referenceString: onexitreferencestring,
resourceDestinationString: onexitresourcedestinationstring,
resourceTitleString: onexitresourcetitlestring,
resource: onexitresource,
setextHeading: closer(onexitsetextheading),
setextHeadingLineSequence: onexitsetextheadinglinesequence,
setextHeadingText: onexitsetextheadingtext,
strong: closer(),
thematicBreak: closer()
}
},
options.mdastExtensions || []
)
/** @type {CompileData} */
const data = {}
return compile
/**
* @param {Array<Event>} events
* @returns {Root}
*/
function compile(events) {
/** @type {Root} */
let tree = {type: 'root', children: []}
/** @type {CompileContext['stack']} */
const stack = [tree]
/** @type {CompileContext['tokenStack']} */
const tokenStack = []
/** @type {Array<number>} */
const listStack = []
/** @type {Omit<CompileContext, 'sliceSerialize'>} */
const context = {
stack,
tokenStack,
config,
enter,
exit,
buffer,
resume,
setData,
getData
}
let index = -1
while (++index < events.length) {
// We preprocess lists to add `listItem` tokens, and to infer whether
// items the list itself are spread out.
if (
events[index][1].type === types.listOrdered ||
events[index][1].type === types.listUnordered
) {
if (events[index][0] === 'enter') {
listStack.push(index)
} else {
const tail = listStack.pop()
assert(typeof tail === 'number', 'expected list ot be open')
index = prepareList(events, tail, index)
}
}
}
index = -1
while (++index < events.length) {
const handler = config[events[index][0]]
if (own.call(handler, events[index][1].type)) {
handler[events[index][1].type].call(
Object.assign(
{sliceSerialize: events[index][2].sliceSerialize},
context
),
events[index][1]
)
}
}
if (tokenStack.length > 0) {
const tail = tokenStack[tokenStack.length - 1]
const handler = tail[1] || defaultOnError
handler.call(context, undefined, tail[0])
}
// Figure out `root` position.
tree.position = {
start: point(
events.length > 0 ? events[0][1].start : {line: 1, column: 1, offset: 0}
),
end: point(
events.length > 0
? events[events.length - 2][1].end
: {line: 1, column: 1, offset: 0}
)
}
index = -1
while (++index < config.transforms.length) {
tree = config.transforms[index](tree) || tree
}
return tree
}
/**
* @param {Array<Event>} events
* @param {number} start
* @param {number} length
* @returns {number}
*/
function prepareList(events, start, length) {
let index = start - 1
let containerBalance = -1
let listSpread = false
/** @type {Token|undefined} */
let listItem
/** @type {number|undefined} */
let lineIndex
/** @type {number|undefined} */
let firstBlankLineIndex
/** @type {boolean|undefined} */
let atMarker
while (++index <= length) {
const event = events[index]
if (
event[1].type === types.listUnordered ||
event[1].type === types.listOrdered ||
event[1].type === types.blockQuote
) {
if (event[0] === 'enter') {
containerBalance++
} else {
containerBalance--
}
atMarker = undefined
} else if (event[1].type === types.lineEndingBlank) {
if (event[0] === 'enter') {
if (
listItem &&
!atMarker &&
!containerBalance &&
!firstBlankLineIndex
) {
firstBlankLineIndex = index
}
atMarker = undefined
}
} else if (
event[1].type === types.linePrefix ||
event[1].type === types.listItemValue ||
event[1].type === types.listItemMarker ||
event[1].type === types.listItemPrefix ||
event[1].type === types.listItemPrefixWhitespace
) {
// Empty.
} else {
atMarker = undefined
}
if (
(!containerBalance &&
event[0] === 'enter' &&
event[1].type === types.listItemPrefix) ||
(containerBalance === -1 &&
event[0] === 'exit' &&
(event[1].type === types.listUnordered ||
event[1].type === types.listOrdered))
) {
if (listItem) {
let tailIndex = index
lineIndex = undefined
while (tailIndex--) {
const tailEvent = events[tailIndex]
if (
tailEvent[1].type === types.lineEnding ||
tailEvent[1].type === types.lineEndingBlank
) {
if (tailEvent[0] === 'exit') continue
if (lineIndex) {
events[lineIndex][1].type = types.lineEndingBlank
listSpread = true
}
tailEvent[1].type = types.lineEnding
lineIndex = tailIndex
} else if (
tailEvent[1].type === types.linePrefix ||
tailEvent[1].type === types.blockQuotePrefix ||
tailEvent[1].type === types.blockQuotePrefixWhitespace ||
tailEvent[1].type === types.blockQuoteMarker ||
tailEvent[1].type === types.listItemIndent
) {
// Empty
} else {
break
}
}
if (
firstBlankLineIndex &&
(!lineIndex || firstBlankLineIndex < lineIndex)
) {
// @ts-expect-error Patched.
listItem._spread = true
}
// Fix position.
listItem.end = Object.assign(
{},
lineIndex ? events[lineIndex][1].start : event[1].end
)
events.splice(lineIndex || index, 0, ['exit', listItem, event[2]])
index++
length++
}
// Create a new list item.
if (event[1].type === types.listItemPrefix) {
listItem = {
type: 'listItem',
// @ts-expect-error Patched
_spread: false,
start: Object.assign({}, event[1].start)
}
// @ts-expect-error: `listItem` is most definitely defined, TS...
events.splice(index, 0, ['enter', listItem, event[2]])
index++
length++
firstBlankLineIndex = undefined
atMarker = true
}
}
}
// @ts-expect-error Patched.
events[start][1]._spread = listSpread
return length
}
/**
* @type {CompileContext['setData']}
* @param [value]
*/
function setData(key, value) {
data[key] = value
}
/**
* @type {CompileContext['getData']}
* @template {string} K
* @param {K} key
* @returns {CompileData[K]}
*/
function getData(key) {
return data[key]
}
/**
* @param {Point} d
* @returns {Point}
*/
function point(d) {
return {line: d.line, column: d.column, offset: d.offset}
}
/**
* @param {(token: Token) => Node} create
* @param {Handle} [and]
* @returns {Handle}
*/
function opener(create, and) {
return open
/**
* @this {CompileContext}
* @param {Token} token
* @returns {void}
*/
function open(token) {
enter.call(this, create(token), token)
if (and) and.call(this, token)
}
}
/** @type {CompileContext['buffer']} */
function buffer() {
this.stack.push({type: 'fragment', children: []})
}
/**
* @type {CompileContext['enter']}
* @template {Node} N
* @this {CompileContext}
* @param {N} node
* @param {Token} token
* @param {OnEnterError} [errorHandler]
* @returns {N}
*/
function enter(node, token, errorHandler) {
const parent = this.stack[this.stack.length - 1]
assert(parent, 'expected `parent`')
assert('children' in parent, 'expected `parent`')
// @ts-expect-error: Assume `Node` can exist as a child of `parent`.
parent.children.push(node)
this.stack.push(node)
this.tokenStack.push([token, errorHandler])
// @ts-expect-error: `end` will be patched later.
node.position = {start: point(token.start)}
return node
}
/**
* @param {Handle} [and]
* @returns {Handle}
*/
function closer(and) {
return close
/**
* @this {CompileContext}
* @param {Token} token
* @returns {void}
*/
function close(token) {
if (and) and.call(this, token)
exit.call(this, token)
}
}
/**
* @type {CompileContext['exit']}
* @this {CompileContext}
* @param {Token} token
* @param {OnExitError} [onExitError]
* @returns {Node}
*/
function exit(token, onExitError) {
const node = this.stack.pop()
assert(node, 'expected `node`')
const open = this.tokenStack.pop()
if (!open) {
throw new Error(
'Cannot close `' +
token.type +
'` (' +
stringifyPosition({start: token.start, end: token.end}) +
'): its not open'
)
} else if (open[0].type !== token.type) {
if (onExitError) {
onExitError.call(this, token, open[0])
} else {
const handler = open[1] || defaultOnError
handler.call(this, token, open[0])
}
}
assert(node.type !== 'fragment', 'unexpected fragment `exit`ed')
assert(node.position, 'expected `position` to be defined')
node.position.end = point(token.end)
return node
}
/**
* @this {CompileContext}
* @returns {string}
*/
function resume() {
return toString(this.stack.pop())
}
//
// Handlers.
//
/** @type {Handle} */
function onenterlistordered() {
setData('expectingFirstListItemValue', true)
}
/** @type {Handle} */
function onenterlistitemvalue(token) {
if (getData('expectingFirstListItemValue')) {
const ancestor = /** @type {List} */ (this.stack[this.stack.length - 2])
ancestor.start = Number.parseInt(
this.sliceSerialize(token),
constants.numericBaseDecimal
)
setData('expectingFirstListItemValue')
}
}
/** @type {Handle} */
function onexitcodefencedfenceinfo() {
const data = this.resume()
const node = /** @type {Code} */ (this.stack[this.stack.length - 1])
node.lang = data
}
/** @type {Handle} */
function onexitcodefencedfencemeta() {
const data = this.resume()
const node = /** @type {Code} */ (this.stack[this.stack.length - 1])
node.meta = data
}
/** @type {Handle} */
function onexitcodefencedfence() {
// Exit if this is the closing fence.
if (getData('flowCodeInside')) return
this.buffer()
setData('flowCodeInside', true)
}
/** @type {Handle} */
function onexitcodefenced() {
const data = this.resume()
const node = /** @type {Code} */ (this.stack[this.stack.length - 1])
node.value = data.replace(/^(\r?\n|\r)|(\r?\n|\r)$/g, '')
setData('flowCodeInside')
}
/** @type {Handle} */
function onexitcodeindented() {
const data = this.resume()
const node = /** @type {Code} */ (this.stack[this.stack.length - 1])
node.value = data.replace(/(\r?\n|\r)$/g, '')
}
/** @type {Handle} */
function onexitdefinitionlabelstring(token) {
// Discard label, use the source content instead.
const label = this.resume()
const node = /** @type {Definition} */ (this.stack[this.stack.length - 1])
node.label = label
node.identifier = normalizeIdentifier(
this.sliceSerialize(token)
).toLowerCase()
}
/** @type {Handle} */
function onexitdefinitiontitlestring() {
const data = this.resume()
const node = /** @type {Definition} */ (this.stack[this.stack.length - 1])
node.title = data
}
/** @type {Handle} */
function onexitdefinitiondestinationstring() {
const data = this.resume()
const node = /** @type {Definition} */ (this.stack[this.stack.length - 1])
node.url = data
}
/** @type {Handle} */
function onexitatxheadingsequence(token) {
const node = /** @type {Heading} */ (this.stack[this.stack.length - 1])
if (!node.depth) {
const depth = this.sliceSerialize(token).length
assert(
depth === 1 ||
depth === 2 ||
depth === 3 ||
depth === 4 ||
depth === 5 ||
depth === 6,
'expected `depth` between `1` and `6`'
)
node.depth = depth
}
}
/** @type {Handle} */
function onexitsetextheadingtext() {
setData('setextHeadingSlurpLineEnding', true)
}
/** @type {Handle} */
function onexitsetextheadinglinesequence(token) {
const node = /** @type {Heading} */ (this.stack[this.stack.length - 1])
node.depth =
this.sliceSerialize(token).charCodeAt(0) === codes.equalsTo ? 1 : 2
}
/** @type {Handle} */
function onexitsetextheading() {
setData('setextHeadingSlurpLineEnding')
}
/** @type {Handle} */
function onenterdata(token) {
const parent = /** @type {Parent} */ (this.stack[this.stack.length - 1])
/** @type {Node} */
let tail = parent.children[parent.children.length - 1]
if (!tail || tail.type !== 'text') {
// Add a new text node.
tail = text()
// @ts-expect-error: well add `end` later.
tail.position = {start: point(token.start)}
// @ts-expect-error: Assume `parent` accepts `text`.
parent.children.push(tail)
}
this.stack.push(tail)
}
/** @type {Handle} */
function onexitdata(token) {
const tail = this.stack.pop()
assert(tail, 'expected a `node` to be on the stack')
assert('value' in tail, 'expected a `literal` to be on the stack')
assert(tail.position, 'expected `node` to have an open position')
tail.value += this.sliceSerialize(token)
tail.position.end = point(token.end)
}
/** @type {Handle} */
function onexitlineending(token) {
const context = this.stack[this.stack.length - 1]
assert(context, 'expected `node`')
// If were at a hard break, include the line ending in there.
if (getData('atHardBreak')) {
assert('children' in context, 'expected `parent`')
const tail = context.children[context.children.length - 1]
assert(tail.position, 'expected tail to have a starting position')
tail.position.end = point(token.end)
setData('atHardBreak')
return
}
if (
!getData('setextHeadingSlurpLineEnding') &&
config.canContainEols.includes(context.type)
) {
onenterdata.call(this, token)
onexitdata.call(this, token)
}
}
/** @type {Handle} */
function onexithardbreak() {
setData('atHardBreak', true)
}
/** @type {Handle} */
function onexithtmlflow() {
const data = this.resume()
const node = /** @type {HTML} */ (this.stack[this.stack.length - 1])
node.value = data
}
/** @type {Handle} */
function onexithtmltext() {
const data = this.resume()
const node = /** @type {HTML} */ (this.stack[this.stack.length - 1])
node.value = data
}
/** @type {Handle} */
function onexitcodetext() {
const data = this.resume()
const node = /** @type {InlineCode} */ (this.stack[this.stack.length - 1])
node.value = data
}
/** @type {Handle} */
function onexitlink() {
const context = /** @type {Link & {identifier: string, label: string}} */ (
this.stack[this.stack.length - 1]
)
// To do: clean.
if (getData('inReference')) {
context.type += 'Reference'
// @ts-expect-error: mutate.
context.referenceType = getData('referenceType') || 'shortcut'
// @ts-expect-error: mutate.
delete context.url
delete context.title
} else {
// @ts-expect-error: mutate.
delete context.identifier
// @ts-expect-error: mutate.
delete context.label
}
setData('referenceType')
}
/** @type {Handle} */
function onexitimage() {
const context = /** @type {Image & {identifier: string, label: string}} */ (
this.stack[this.stack.length - 1]
)
// To do: clean.
if (getData('inReference')) {
context.type += 'Reference'
// @ts-expect-error: mutate.
context.referenceType = getData('referenceType') || 'shortcut'
// @ts-expect-error: mutate.
delete context.url
delete context.title
} else {
// @ts-expect-error: mutate.
delete context.identifier
// @ts-expect-error: mutate.
delete context.label
}
setData('referenceType')
}
/** @type {Handle} */
function onexitlabeltext(token) {
const ancestor =
/** @type {(Link|Image) & {identifier: string, label: string}} */ (
this.stack[this.stack.length - 2]
)
const string = this.sliceSerialize(token)
ancestor.label = decodeString(string)
ancestor.identifier = normalizeIdentifier(string).toLowerCase()
}
/** @type {Handle} */
function onexitlabel() {
const fragment = /** @type {Fragment} */ (this.stack[this.stack.length - 1])
const value = this.resume()
const node =
/** @type {(Link|Image) & {identifier: string, label: string}} */ (
this.stack[this.stack.length - 1]
)
// Assume a reference.
setData('inReference', true)
if (node.type === 'link') {
// @ts-expect-error: Assume static phrasing content.
node.children = fragment.children
} else {
node.alt = value
}
}
/** @type {Handle} */
function onexitresourcedestinationstring() {
const data = this.resume()
const node = /** @type {Link|Image} */ (this.stack[this.stack.length - 1])
node.url = data
}
/** @type {Handle} */
function onexitresourcetitlestring() {
const data = this.resume()
const node = /** @type {Link|Image} */ (this.stack[this.stack.length - 1])
node.title = data
}
/** @type {Handle} */
function onexitresource() {
setData('inReference')
}
/** @type {Handle} */
function onenterreference() {
setData('referenceType', 'collapsed')
}
/** @type {Handle} */
function onexitreferencestring(token) {
const label = this.resume()
const node = /** @type {LinkReference|ImageReference} */ (
this.stack[this.stack.length - 1]
)
node.label = label
node.identifier = normalizeIdentifier(
this.sliceSerialize(token)
).toLowerCase()
setData('referenceType', 'full')
}
/** @type {Handle} */
function onexitcharacterreferencemarker(token) {
setData('characterReferenceType', token.type)
}
/** @type {Handle} */
function onexitcharacterreferencevalue(token) {
const data = this.sliceSerialize(token)
const type = getData('characterReferenceType')
/** @type {string} */
let value
if (type) {
value = decodeNumericCharacterReference(
data,
type === types.characterReferenceMarkerNumeric
? constants.numericBaseDecimal
: constants.numericBaseHexadecimal
)
setData('characterReferenceType')
} else {
// @ts-expect-error `decodeNamedCharacterReference` can return false for
// invalid named character references, but everything weve tokenized is
// valid.
value = decodeNamedCharacterReference(data)
}
const tail = this.stack.pop()
assert(tail, 'expected `node`')
assert(tail.position, 'expected `node.position`')
assert('value' in tail, 'expected `node.value`')
tail.value += value
tail.position.end = point(token.end)
}
/** @type {Handle} */
function onexitautolinkprotocol(token) {
onexitdata.call(this, token)
const node = /** @type {Link} */ (this.stack[this.stack.length - 1])
node.url = this.sliceSerialize(token)
}
/** @type {Handle} */
function onexitautolinkemail(token) {
onexitdata.call(this, token)
const node = /** @type {Link} */ (this.stack[this.stack.length - 1])
node.url = 'mailto:' + this.sliceSerialize(token)
}
//
// Creaters.
//
/** @returns {Blockquote} */
function blockQuote() {
return {type: 'blockquote', children: []}
}
/** @returns {Code} */
function codeFlow() {
return {type: 'code', lang: null, meta: null, value: ''}
}
/** @returns {InlineCode} */
function codeText() {
return {type: 'inlineCode', value: ''}
}
/** @returns {Definition} */
function definition() {
return {
type: 'definition',
identifier: '',
label: null,
title: null,
url: ''
}
}
/** @returns {Emphasis} */
function emphasis() {
return {type: 'emphasis', children: []}
}
/** @returns {Heading} */
function heading() {
// @ts-expect-error `depth` will be set later.
return {type: 'heading', depth: undefined, children: []}
}
/** @returns {Break} */
function hardBreak() {
return {type: 'break'}
}
/** @returns {HTML} */
function html() {
return {type: 'html', value: ''}
}
/** @returns {Image} */
function image() {
return {type: 'image', title: null, url: '', alt: null}
}
/** @returns {Link} */
function link() {
return {type: 'link', title: null, url: '', children: []}
}
/**
* @param {Token} token
* @returns {List}
*/
function list(token) {
return {
type: 'list',
ordered: token.type === 'listOrdered',
start: null,
// @ts-expect-error Patched.
spread: token._spread,
children: []
}
}
/**
* @param {Token} token
* @returns {ListItem}
*/
function listItem(token) {
return {
type: 'listItem',
// @ts-expect-error Patched.
spread: token._spread,
checked: null,
children: []
}
}
/** @returns {Paragraph} */
function paragraph() {
return {type: 'paragraph', children: []}
}
/** @returns {Strong} */
function strong() {
return {type: 'strong', children: []}
}
/** @returns {Text} */
function text() {
return {type: 'text', value: ''}
}
/** @returns {ThematicBreak} */
function thematicBreak() {
return {type: 'thematicBreak'}
}
}
/**
* @param {Extension} combined
* @param {Array<Extension|Array<Extension>>} extensions
* @returns {Extension}
*/
function configure(combined, extensions) {
let index = -1
while (++index < extensions.length) {
const value = extensions[index]
if (Array.isArray(value)) {
configure(combined, value)
} else {
extension(combined, value)
}
}
return combined
}
/**
* @param {Extension} combined
* @param {Extension} extension
* @returns {void}
*/
function extension(combined, extension) {
/** @type {string} */
let key
for (key in extension) {
if (own.call(extension, key)) {
const list = key === 'canContainEols' || key === 'transforms'
const maybe = own.call(combined, key) ? combined[key] : undefined
/* c8 ignore next */
const left = maybe || (combined[key] = list ? [] : {})
const right = extension[key]
if (right) {
if (list) {
// @ts-expect-error: `left` is an array.
combined[key] = [...left, ...right]
} else {
Object.assign(left, right)
}
}
}
}
}
/** @type {OnEnterError} */
function defaultOnError(left, right) {
if (left) {
throw new Error(
'Cannot close `' +
left.type +
'` (' +
stringifyPosition({start: left.start, end: left.end}) +
'): a different token (`' +
right.type +
'`, ' +
stringifyPosition({start: right.start, end: right.end}) +
') is open'
)
} else {
throw new Error(
'Cannot close document, a token (`' +
right.type +
'`, ' +
stringifyPosition({start: right.start, end: right.end}) +
') is still open'
)
}
}