micromark-extension-directive/dev/lib/html.js
2021-06-08 16:19:30 +02:00

180 lines
5 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.

import {decodeEntity} from 'parse-entities/decode-entity.js'
const own = {}.hasOwnProperty
export function directiveHtml(options = {}) {
return {
enter: {
directiveContainer() {
return enter.call(this, 'containerDirective')
},
directiveContainerAttributes: enterAttributes,
directiveContainerLabel: enterLabel,
directiveContainerContent() {
this.buffer()
},
directiveLeaf() {
return enter.call(this, 'leafDirective')
},
directiveLeafAttributes: enterAttributes,
directiveLeafLabel: enterLabel,
directiveText() {
return enter.call(this, 'textDirective')
},
directiveTextAttributes: enterAttributes,
directiveTextLabel: enterLabel
},
exit: {
directiveContainer: exit,
directiveContainerAttributeClassValue: exitAttributeClassValue,
directiveContainerAttributeIdValue: exitAttributeIdValue,
directiveContainerAttributeName: exitAttributeName,
directiveContainerAttributeValue: exitAttributeValue,
directiveContainerAttributes: exitAttributes,
directiveContainerContent: exitContainerContent,
directiveContainerFence: exitContainerFence,
directiveContainerLabel: exitLabel,
directiveContainerName: exitName,
directiveLeaf: exit,
directiveLeafAttributeClassValue: exitAttributeClassValue,
directiveLeafAttributeIdValue: exitAttributeIdValue,
directiveLeafAttributeName: exitAttributeName,
directiveLeafAttributeValue: exitAttributeValue,
directiveLeafAttributes: exitAttributes,
directiveLeafLabel: exitLabel,
directiveLeafName: exitName,
directiveText: exit,
directiveTextAttributeClassValue: exitAttributeClassValue,
directiveTextAttributeIdValue: exitAttributeIdValue,
directiveTextAttributeName: exitAttributeName,
directiveTextAttributeValue: exitAttributeValue,
directiveTextAttributes: exitAttributes,
directiveTextLabel: exitLabel,
directiveTextName: exitName
}
}
function enter(type) {
let stack = this.getData('directiveStack')
if (!stack) this.setData('directiveStack', (stack = []))
stack.push({type})
}
function exitName(token) {
const stack = this.getData('directiveStack')
stack[stack.length - 1].name = this.sliceSerialize(token)
}
function enterLabel() {
this.buffer()
}
function exitLabel() {
const data = this.resume()
const stack = this.getData('directiveStack')
stack[stack.length - 1].label = data
}
function enterAttributes() {
this.buffer()
this.setData('directiveAttributes', [])
}
function exitAttributeIdValue(token) {
this.getData('directiveAttributes').push([
'id',
decodeLight(this.sliceSerialize(token))
])
}
function exitAttributeClassValue(token) {
this.getData('directiveAttributes').push([
'class',
decodeLight(this.sliceSerialize(token))
])
}
function exitAttributeName(token) {
// Attribute names in CommonMark are significantly limited, so character
// references cant exist.
this.getData('directiveAttributes').push([this.sliceSerialize(token), ''])
}
function exitAttributeValue(token) {
const attributes = this.getData('directiveAttributes')
attributes[attributes.length - 1][1] = decodeLight(
this.sliceSerialize(token)
)
}
function exitAttributes() {
const stack = this.getData('directiveStack')
const attributes = this.getData('directiveAttributes')
const cleaned = {}
let index = -1
let attribute
while (++index < attributes.length) {
attribute = attributes[index]
if (attribute[0] === 'class' && cleaned.class) {
cleaned.class += ' ' + attribute[1]
} else {
cleaned[attribute[0]] = attribute[1]
}
}
this.resume()
this.setData('directiveAttributes')
stack[stack.length - 1].attributes = cleaned
}
function exitContainerContent() {
const data = this.resume()
const stack = this.getData('directiveStack')
stack[stack.length - 1].content = data
}
function exitContainerFence() {
const stack = this.getData('directiveStack')
const directive = stack[stack.length - 1]
if (!directive.fenceCount) directive.fenceCount = 0
directive.fenceCount++
if (directive.fenceCount === 1) this.setData('slurpOneLineEnding', true)
}
function exit() {
const directive = this.getData('directiveStack').pop()
let found
let result
if (own.call(options, directive.name)) {
result = options[directive.name].call(this, directive)
found = result !== false
}
if (!found && own.call(options, '*')) {
result = options['*'].call(this, directive)
found = result !== false
}
if (!found && directive.type !== 'textDirective') {
this.setData('slurpOneLineEnding', true)
}
}
}
function decodeLight(value) {
return value.replace(
/&(#(\d{1,7}|x[\da-f]{1,6})|[\da-z]{1,31});/gi,
decodeIfPossible
)
}
function decodeIfPossible($0, $1) {
return decodeEntity($1) || $0
}