lix-website/themes/lix/assets/bootstrap/node_modules/mdast-util-from-markdown/lib/index.js
2024-04-26 22:49:34 -06:00

820 lines
21 KiB
JavaScript
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.

'use strict'
module.exports = fromMarkdown
// These three are compiled away in the `dist/`
var codes = require('micromark/dist/character/codes')
var constants = require('micromark/dist/constant/constants')
var types = require('micromark/dist/constant/types')
var toString = require('mdast-util-to-string')
var assign = require('micromark/dist/constant/assign')
var own = require('micromark/dist/constant/has-own-property')
var normalizeIdentifier = require('micromark/dist/util/normalize-identifier')
var safeFromInt = require('micromark/dist/util/safe-from-int')
var parser = require('micromark/dist/parse')
var preprocessor = require('micromark/dist/preprocess')
var postprocess = require('micromark/dist/postprocess')
var decode = require('parse-entities/decode-entity')
var stringifyPosition = require('unist-util-stringify-position')
function fromMarkdown(value, encoding, options) {
if (typeof encoding !== 'string') {
options = encoding
encoding = undefined
}
return compiler(options)(
postprocess(
parser(options).document().write(preprocessor()(value, encoding, true))
)
)
}
// Note this compiler only understand complete buffering, not streaming.
function compiler(options) {
var settings = options || {}
var 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()
}
},
settings.mdastExtensions || []
)
var data = {}
return compile
function compile(events) {
var tree = {type: 'root', children: []}
var stack = [tree]
var tokenStack = []
var listStack = []
var index = -1
var handler
var listStart
var context = {
stack: stack,
tokenStack: tokenStack,
config: config,
enter: enter,
exit: exit,
buffer: buffer,
resume: resume,
setData: setData,
getData: getData
}
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 {
listStart = listStack.pop(index)
index = prepareList(events, listStart, index)
}
}
}
index = -1
while (++index < events.length) {
handler = config[events[index][0]]
if (own.call(handler, events[index][1].type)) {
handler[events[index][1].type].call(
assign({sliceSerialize: events[index][2].sliceSerialize}, context),
events[index][1]
)
}
}
if (tokenStack.length) {
throw new Error(
'Cannot close document, a token (`' +
tokenStack[tokenStack.length - 1].type +
'`, ' +
stringifyPosition({
start: tokenStack[tokenStack.length - 1].start,
end: tokenStack[tokenStack.length - 1].end
}) +
') is still open'
)
}
// Figure out `root` position.
tree.position = {
start: point(
events.length ? events[0][1].start : {line: 1, column: 1, offset: 0}
),
end: point(
events.length
? 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
}
function prepareList(events, start, length) {
var index = start - 1
var containerBalance = -1
var listSpread = false
var listItem
var tailIndex
var lineIndex
var tailEvent
var event
var firstBlankLineIndex
var atMarker
while (++index <= length) {
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) {
tailIndex = index
lineIndex = undefined
while (tailIndex--) {
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)
) {
listItem._spread = true
}
// Fix position.
listItem.end = point(
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',
_spread: false,
start: point(event[1].start)
}
events.splice(index, 0, ['enter', listItem, event[2]])
index++
length++
firstBlankLineIndex = undefined
atMarker = true
}
}
}
events[start][1]._spread = listSpread
return length
}
function setData(key, value) {
data[key] = value
}
function getData(key) {
return data[key]
}
function point(d) {
return {line: d.line, column: d.column, offset: d.offset}
}
function opener(create, and) {
return open
function open(token) {
enter.call(this, create(token), token)
if (and) and.call(this, token)
}
}
function buffer() {
this.stack.push({type: 'fragment', children: []})
}
function enter(node, token) {
this.stack[this.stack.length - 1].children.push(node)
this.stack.push(node)
this.tokenStack.push(token)
node.position = {start: point(token.start)}
return node
}
function closer(and) {
return close
function close(token) {
if (and) and.call(this, token)
exit.call(this, token)
}
}
function exit(token) {
var node = this.stack.pop()
var 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.type !== token.type) {
throw new Error(
'Cannot close `' +
token.type +
'` (' +
stringifyPosition({start: token.start, end: token.end}) +
'): a different token (`' +
open.type +
'`, ' +
stringifyPosition({start: open.start, end: open.end}) +
') is open'
)
}
node.position.end = point(token.end)
return node
}
function resume() {
return toString(this.stack.pop())
}
//
// Handlers.
//
function onenterlistordered() {
setData('expectingFirstListItemValue', true)
}
function onenterlistitemvalue(token) {
if (getData('expectingFirstListItemValue')) {
this.stack[this.stack.length - 2].start = parseInt(
this.sliceSerialize(token),
constants.numericBaseDecimal
)
setData('expectingFirstListItemValue')
}
}
function onexitcodefencedfenceinfo() {
var data = this.resume()
this.stack[this.stack.length - 1].lang = data
}
function onexitcodefencedfencemeta() {
var data = this.resume()
this.stack[this.stack.length - 1].meta = data
}
function onexitcodefencedfence() {
// Exit if this is the closing fence.
if (getData('flowCodeInside')) return
this.buffer()
setData('flowCodeInside', true)
}
function onexitcodefenced() {
var data = this.resume()
this.stack[this.stack.length - 1].value = data.replace(
/^(\r?\n|\r)|(\r?\n|\r)$/g,
''
)
setData('flowCodeInside')
}
function onexitcodeindented() {
var data = this.resume()
this.stack[this.stack.length - 1].value = data
}
function onexitdefinitionlabelstring(token) {
// Discard label, use the source content instead.
var label = this.resume()
this.stack[this.stack.length - 1].label = label
this.stack[this.stack.length - 1].identifier = normalizeIdentifier(
this.sliceSerialize(token)
).toLowerCase()
}
function onexitdefinitiontitlestring() {
var data = this.resume()
this.stack[this.stack.length - 1].title = data
}
function onexitdefinitiondestinationstring() {
var data = this.resume()
this.stack[this.stack.length - 1].url = data
}
function onexitatxheadingsequence(token) {
if (!this.stack[this.stack.length - 1].depth) {
this.stack[this.stack.length - 1].depth = this.sliceSerialize(
token
).length
}
}
function onexitsetextheadingtext() {
setData('setextHeadingSlurpLineEnding', true)
}
function onexitsetextheadinglinesequence(token) {
this.stack[this.stack.length - 1].depth =
this.sliceSerialize(token).charCodeAt(0) === codes.equalsTo ? 1 : 2
}
function onexitsetextheading() {
setData('setextHeadingSlurpLineEnding')
}
function onenterdata(token) {
var siblings = this.stack[this.stack.length - 1].children
var tail = siblings[siblings.length - 1]
if (!tail || tail.type !== 'text') {
// Add a new text node.
tail = text()
tail.position = {start: point(token.start)}
this.stack[this.stack.length - 1].children.push(tail)
}
this.stack.push(tail)
}
function onexitdata(token) {
var tail = this.stack.pop()
tail.value += this.sliceSerialize(token)
tail.position.end = point(token.end)
}
function onexitlineending(token) {
var context = this.stack[this.stack.length - 1]
// If were at a hard break, include the line ending in there.
if (getData('atHardBreak')) {
context.children[context.children.length - 1].position.end = point(
token.end
)
setData('atHardBreak')
return
}
if (
!getData('setextHeadingSlurpLineEnding') &&
config.canContainEols.indexOf(context.type) > -1
) {
onenterdata.call(this, token)
onexitdata.call(this, token)
}
}
function onexithardbreak() {
setData('atHardBreak', true)
}
function onexithtmlflow() {
var data = this.resume()
this.stack[this.stack.length - 1].value = data
}
function onexithtmltext() {
var data = this.resume()
this.stack[this.stack.length - 1].value = data
}
function onexitcodetext() {
var data = this.resume()
this.stack[this.stack.length - 1].value = data
}
function onexitlink() {
var context = this.stack[this.stack.length - 1]
// To do: clean.
if (getData('inReference')) {
context.type += 'Reference'
context.referenceType = getData('referenceType') || 'shortcut'
delete context.url
delete context.title
} else {
delete context.identifier
delete context.label
delete context.referenceType
}
setData('referenceType')
}
function onexitimage() {
var context = this.stack[this.stack.length - 1]
// To do: clean.
if (getData('inReference')) {
context.type += 'Reference'
context.referenceType = getData('referenceType') || 'shortcut'
delete context.url
delete context.title
} else {
delete context.identifier
delete context.label
delete context.referenceType
}
setData('referenceType')
}
function onexitlabeltext(token) {
this.stack[this.stack.length - 2].identifier = normalizeIdentifier(
this.sliceSerialize(token)
).toLowerCase()
}
function onexitlabel() {
var fragment = this.stack[this.stack.length - 1]
var value = this.resume()
this.stack[this.stack.length - 1].label = value
// Assume a reference.
setData('inReference', true)
if (this.stack[this.stack.length - 1].type === 'link') {
this.stack[this.stack.length - 1].children = fragment.children
} else {
this.stack[this.stack.length - 1].alt = value
}
}
function onexitresourcedestinationstring() {
var data = this.resume()
this.stack[this.stack.length - 1].url = data
}
function onexitresourcetitlestring() {
var data = this.resume()
this.stack[this.stack.length - 1].title = data
}
function onexitresource() {
setData('inReference')
}
function onenterreference() {
setData('referenceType', 'collapsed')
}
function onexitreferencestring(token) {
var label = this.resume()
this.stack[this.stack.length - 1].label = label
this.stack[this.stack.length - 1].identifier = normalizeIdentifier(
this.sliceSerialize(token)
).toLowerCase()
setData('referenceType', 'full')
}
function onexitcharacterreferencemarker(token) {
setData('characterReferenceType', token.type)
}
function onexitcharacterreferencevalue(token) {
var data = this.sliceSerialize(token)
var type = getData('characterReferenceType')
var value
var tail
if (type) {
value = safeFromInt(
data,
type === types.characterReferenceMarkerNumeric
? constants.numericBaseDecimal
: constants.numericBaseHexadecimal
)
setData('characterReferenceType')
} else {
value = decode(data)
}
tail = this.stack.pop()
tail.value += value
tail.position.end = point(token.end)
}
function onexitautolinkprotocol(token) {
onexitdata.call(this, token)
this.stack[this.stack.length - 1].url = this.sliceSerialize(token)
}
function onexitautolinkemail(token) {
onexitdata.call(this, token)
this.stack[this.stack.length - 1].url =
'mailto:' + this.sliceSerialize(token)
}
//
// Creaters.
//
function blockQuote() {
return {type: 'blockquote', children: []}
}
function codeFlow() {
return {type: 'code', lang: null, meta: null, value: ''}
}
function codeText() {
return {type: 'inlineCode', value: ''}
}
function definition() {
return {
type: 'definition',
identifier: '',
label: null,
title: null,
url: ''
}
}
function emphasis() {
return {type: 'emphasis', children: []}
}
function heading() {
return {type: 'heading', depth: undefined, children: []}
}
function hardBreak() {
return {type: 'break'}
}
function html() {
return {type: 'html', value: ''}
}
function image() {
return {type: 'image', title: null, url: '', alt: null}
}
function link() {
return {type: 'link', title: null, url: '', children: []}
}
function list(token) {
return {
type: 'list',
ordered: token.type === 'listOrdered',
start: null,
spread: token._spread,
children: []
}
}
function listItem(token) {
return {
type: 'listItem',
spread: token._spread,
checked: null,
children: []
}
}
function paragraph() {
return {type: 'paragraph', children: []}
}
function strong() {
return {type: 'strong', children: []}
}
function text() {
return {type: 'text', value: ''}
}
function thematicBreak() {
return {type: 'thematicBreak'}
}
}
function configure(config, extensions) {
var index = -1
while (++index < extensions.length) {
extension(config, extensions[index])
}
return config
}
function extension(config, extension) {
var key
var left
for (key in extension) {
left = own.call(config, key) ? config[key] : (config[key] = {})
if (key === 'canContainEols' || key === 'transforms') {
config[key] = [].concat(left, extension[key])
} else {
Object.assign(left, extension[key])
}
}
}