forked from lix-project/lix-website
820 lines
21 KiB
JavaScript
820 lines
21 KiB
JavaScript
|
'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}) +
|
|||
|
'): it’s 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 we’re 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])
|
|||
|
}
|
|||
|
}
|
|||
|
}
|