153 lines
4.2 KiB
JavaScript
153 lines
4.2 KiB
JavaScript
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports["default"] = parser;
|
|
exports.hasTerminalParent = hasTerminalParent;
|
|
exports.parse = parse;
|
|
exports.rewindStack = rewindStack;
|
|
var _compat = require("./compat");
|
|
function parser(tokens, options) {
|
|
var root = {
|
|
tagName: null,
|
|
children: []
|
|
};
|
|
var state = {
|
|
tokens: tokens,
|
|
options: options,
|
|
cursor: 0,
|
|
stack: [root]
|
|
};
|
|
parse(state);
|
|
return root.children;
|
|
}
|
|
function hasTerminalParent(tagName, stack, terminals) {
|
|
var tagParents = terminals[tagName];
|
|
if (tagParents) {
|
|
var currentIndex = stack.length - 1;
|
|
while (currentIndex >= 0) {
|
|
var parentTagName = stack[currentIndex].tagName;
|
|
if (parentTagName === tagName) {
|
|
break;
|
|
}
|
|
if ((0, _compat.arrayIncludes)(tagParents, parentTagName)) {
|
|
return true;
|
|
}
|
|
currentIndex--;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function rewindStack(stack, newLength, childrenEndPosition, endPosition) {
|
|
stack[newLength].position.end = endPosition;
|
|
for (var i = newLength + 1, len = stack.length; i < len; i++) {
|
|
stack[i].position.end = childrenEndPosition;
|
|
}
|
|
stack.splice(newLength);
|
|
}
|
|
function parse(state) {
|
|
var tokens = state.tokens,
|
|
options = state.options;
|
|
var stack = state.stack;
|
|
var nodes = stack[stack.length - 1].children;
|
|
var len = tokens.length;
|
|
var cursor = state.cursor;
|
|
while (cursor < len) {
|
|
var token = tokens[cursor];
|
|
if (token.type !== 'tag-start') {
|
|
nodes.push(token);
|
|
cursor++;
|
|
continue;
|
|
}
|
|
var tagToken = tokens[++cursor];
|
|
cursor++;
|
|
var tagName = tagToken.content.toLowerCase();
|
|
if (token.close) {
|
|
var index = stack.length;
|
|
var shouldRewind = false;
|
|
while (--index > -1) {
|
|
if (stack[index].tagName === tagName) {
|
|
shouldRewind = true;
|
|
break;
|
|
}
|
|
}
|
|
while (cursor < len) {
|
|
var endToken = tokens[cursor];
|
|
if (endToken.type !== 'tag-end') break;
|
|
cursor++;
|
|
}
|
|
if (shouldRewind) {
|
|
rewindStack(stack, index, token.position.start, tokens[cursor - 1].position.end);
|
|
break;
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
var isClosingTag = (0, _compat.arrayIncludes)(options.closingTags, tagName);
|
|
var shouldRewindToAutoClose = isClosingTag;
|
|
if (shouldRewindToAutoClose) {
|
|
var terminals = options.closingTagAncestorBreakers;
|
|
shouldRewindToAutoClose = !hasTerminalParent(tagName, stack, terminals);
|
|
}
|
|
if (shouldRewindToAutoClose) {
|
|
// rewind the stack to just above the previous
|
|
// closing tag of the same name
|
|
var currentIndex = stack.length - 1;
|
|
while (currentIndex > 0) {
|
|
if (tagName === stack[currentIndex].tagName) {
|
|
rewindStack(stack, currentIndex, token.position.start, token.position.start);
|
|
var previousIndex = currentIndex - 1;
|
|
nodes = stack[previousIndex].children;
|
|
break;
|
|
}
|
|
currentIndex = currentIndex - 1;
|
|
}
|
|
}
|
|
var attributes = [];
|
|
var attrToken = void 0;
|
|
while (cursor < len) {
|
|
attrToken = tokens[cursor];
|
|
if (attrToken.type === 'tag-end') break;
|
|
attributes.push(attrToken.content);
|
|
cursor++;
|
|
}
|
|
cursor++;
|
|
var children = [];
|
|
var position = {
|
|
start: token.position.start,
|
|
end: attrToken.position.end
|
|
};
|
|
var elementNode = {
|
|
type: 'element',
|
|
tagName: tagToken.content,
|
|
attributes: attributes,
|
|
children: children,
|
|
position: position
|
|
};
|
|
nodes.push(elementNode);
|
|
var hasChildren = !(attrToken.close || (0, _compat.arrayIncludes)(options.voidTags, tagName));
|
|
if (hasChildren) {
|
|
var size = stack.push({
|
|
tagName: tagName,
|
|
children: children,
|
|
position: position
|
|
});
|
|
var innerState = {
|
|
tokens: tokens,
|
|
options: options,
|
|
cursor: cursor,
|
|
stack: stack
|
|
};
|
|
parse(innerState);
|
|
cursor = innerState.cursor;
|
|
var rewoundInElement = stack.length === size;
|
|
if (rewoundInElement) {
|
|
elementNode.position.end = tokens[cursor - 1].position.end;
|
|
}
|
|
}
|
|
}
|
|
state.cursor = cursor;
|
|
}
|
|
//# sourceMappingURL=parser.js.map
|