Files
30-seconds-of-code/node_modules/hast-util-raw/index.js
2019-08-20 15:52:05 +02:00

286 lines
6.9 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'
var Parser = require('parse5/lib/parser')
var pos = require('unist-util-position')
var fromParse5 = require('hast-util-from-parse5')
var toParse5 = require('hast-util-to-parse5')
var voids = require('html-void-elements')
var ns = require('web-namespaces')
var zwitch = require('zwitch')
var xtend = require('xtend')
module.exports = wrap
var IN_TEMPLATE_MODE = 'IN_TEMPLATE_MODE'
var DATA_MODE = 'DATA_STATE'
var CHARACTER_TOKEN = 'CHARACTER_TOKEN'
var START_TAG_TOKEN = 'START_TAG_TOKEN'
var END_TAG_TOKEN = 'END_TAG_TOKEN'
var COMMENT_TOKEN = 'COMMENT_TOKEN'
var DOCTYPE_TOKEN = 'DOCTYPE_TOKEN'
var parseOptions = {
sourceCodeLocationInfo: true,
scriptingEnabled: false
}
function wrap(tree, file) {
var parser = new Parser(parseOptions)
var one = zwitch('type')
var tokenizer
var preprocessor
var posTracker
var locationTracker
var result
one.handlers.root = root
one.handlers.element = element
one.handlers.text = text
one.handlers.comment = comment
one.handlers.doctype = doctype
one.handlers.raw = raw
one.unknown = unknown
result = fromParse5(documentMode(tree) ? document() : fragment(), file)
/* Unpack if possible and when not given a `root`. */
if (tree.type !== 'root' && result.children.length === 1) {
return result.children[0]
}
return result
function fragment() {
var context
var mock
var doc
context = {
nodeName: 'template',
tagName: 'template',
attrs: [],
namespaceURI: ns.html,
childNodes: []
}
mock = {
nodeName: 'documentmock',
tagName: 'documentmock',
attrs: [],
namespaceURI: ns.html,
childNodes: []
}
doc = {
nodeName: '#document-fragment',
childNodes: []
}
parser._bootstrap(mock, context)
parser._pushTmplInsertionMode(IN_TEMPLATE_MODE)
parser._initTokenizerForFragmentParsing()
parser._insertFakeRootElement()
parser._resetInsertionMode()
parser._findFormInFragmentContext()
tokenizer = parser.tokenizer
preprocessor = tokenizer.preprocessor
locationTracker = tokenizer.__mixins[0]
posTracker = locationTracker.posTracker
one(tree)
parser._adoptNodes(mock.childNodes[0], doc)
return doc
}
function document() {
var doc = parser.treeAdapter.createDocument()
parser._bootstrap(doc, null)
tokenizer = parser.tokenizer
preprocessor = tokenizer.preprocessor
locationTracker = tokenizer.__mixins[0]
posTracker = locationTracker.posTracker
one(tree)
return doc
}
function all(nodes) {
var length = 0
var index = -1
/* istanbul ignore else - invalid nodes, see rehypejs/rehype-raw#7. */
if (nodes) {
length = nodes.length
}
while (++index < length) {
one(nodes[index])
}
}
function root(node) {
all(node.children)
}
function element(node) {
var empty = voids.indexOf(node.tagName) !== -1
parser._processToken(startTag(node), ns.html)
all(node.children)
if (!empty) {
parser._processToken(endTag(node))
// Put the parser back in data mode: some elements, like
// textareas and iframes, change the state.
// See syntax-tree/hast-util-raw/issues/7.
// See https://github.com/inikulin/parse5/blob/2528196/packages/parse5/lib/tokenizer/index.js#L222
tokenizer.state = DATA_MODE
}
}
function text(node) {
parser._processToken({
type: CHARACTER_TOKEN,
chars: node.value,
location: createParse5Location(node)
})
}
function doctype(node) {
var p5 = toParse5(node)
parser._processToken({
type: DOCTYPE_TOKEN,
name: p5.name,
forceQuirks: false,
publicId: p5.publicId,
systemId: p5.systemId,
location: createParse5Location(node)
})
}
function comment(node) {
parser._processToken({
type: COMMENT_TOKEN,
data: node.value,
location: createParse5Location(node)
})
}
function raw(node) {
var start = pos.start(node)
var token
// Reset preprocessor:
// https://github.com/inikulin/parse5/blob/0491902/packages/parse5/lib/tokenizer/preprocessor.js
preprocessor.html = null
preprocessor.endOfChunkHit = false
preprocessor.lastChunkWritten = false
preprocessor.lastCharPos = -1
preprocessor.pos = -1
// Reset preprocessor mixin:
// https://github.com/inikulin/parse5/blob/0491902/packages/parse5/lib/extensions/position-tracking/preprocessor-mixin.js
posTracker.droppedBufferSize = 0
posTracker.line = start.line
posTracker.col = 1
posTracker.offset = 0
posTracker.lineStartPos = -start.column + 1
posTracker.droppedBufferSize = start.offset
// Reset location tracker:
// https://github.com/inikulin/parse5/blob/0491902/packages/parse5/lib/extensions/location-info/tokenizer-mixin.js
locationTracker.currentAttrLocation = null
locationTracker.ctLoc = createParse5Location(node)
// See the code for `parse` and `parseFragment`:
// https://github.com/inikulin/parse5/blob/0491902/packages/parse5/lib/parser/index.js#L371
tokenizer.write(node.value)
parser._runParsingLoop(null)
// Process final characters if theyre still there after hibernating.
// Similar to:
// https://github.com/inikulin/parse5/blob/3bfa7d9/packages/parse5/lib/extensions/location-info/tokenizer-mixin.js#L95
token = tokenizer.currentCharacterToken
if (token) {
token.location.endLine = posTracker.line
token.location.endCol = posTracker.col + 1
token.location.endOffset = posTracker.offset + 1
parser._processToken(token)
}
// Reset tokenizer:
// https://github.com/inikulin/parse5/blob/8b0048e/packages/parse5/lib/tokenizer/index.js#L215
tokenizer.currentToken = null
tokenizer.currentCharacterToken = null
tokenizer.currentAttr = null
}
}
function startTag(node) {
var location = createParse5Location(node)
location.startTag = xtend(location)
return {
type: START_TAG_TOKEN,
tagName: node.tagName,
selfClosing: false,
attrs: attributes(node),
location: location
}
}
function attributes(node) {
return toParse5({
tagName: node.tagName,
type: 'element',
properties: node.properties
}).attrs
}
function endTag(node) {
var location = createParse5Location(node)
location.endTag = xtend(location)
return {
type: END_TAG_TOKEN,
tagName: node.tagName,
attrs: [],
location: location
}
}
function unknown(node) {
throw new Error('Cannot compile `' + node.type + '` node')
}
function documentMode(node) {
var head = node.type === 'root' ? node.children[0] : node
return head && (head.type === 'doctype' || head.tagName === 'html')
}
function createParse5Location(node) {
var start = pos.start(node)
var end = pos.end(node)
return {
startLine: start.line,
startCol: start.column,
startOffset: start.offset,
endLine: end.line,
endCol: end.column,
endOffset: end.offset
}
}