@bbob/parser
Version:
Just parses BBcode to AST array. Part of @bbob bbcode parser
1,424 lines (1,129 loc) • 33.6 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = global || self, factory(global.BbobParser = {}));
}(this, (function (exports) { 'use strict';
function unwrapExports (x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
function createCommonjsModule(fn, module) {
return module = { exports: {} }, fn(module, module.exports), module.exports;
}
var char_1 = createCommonjsModule(function (module, exports) {
exports.__esModule = true;
exports.BACKSLASH = exports.PLACEHOLDER_SPACE = exports.PLACEHOLDER_SPACE_TAB = exports.SLASH = exports.CLOSE_BRAKET = exports.OPEN_BRAKET = exports.SPACE = exports.QUOTEMARK = exports.EQ = exports.TAB = exports.R = exports.F = exports.N = void 0;
var N = '\n';
exports.N = N;
var TAB = '\t';
exports.TAB = TAB;
var F = '\f';
exports.F = F;
var R = '\r';
exports.R = R;
var EQ = '=';
exports.EQ = EQ;
var QUOTEMARK = '"';
exports.QUOTEMARK = QUOTEMARK;
var SPACE = ' ';
exports.SPACE = SPACE;
var OPEN_BRAKET = '[';
exports.OPEN_BRAKET = OPEN_BRAKET;
var CLOSE_BRAKET = ']';
exports.CLOSE_BRAKET = CLOSE_BRAKET;
var SLASH = '/';
exports.SLASH = SLASH;
var BACKSLASH = '\\';
exports.BACKSLASH = BACKSLASH;
var PLACEHOLDER_SPACE_TAB = ' ';
exports.PLACEHOLDER_SPACE_TAB = PLACEHOLDER_SPACE_TAB;
var PLACEHOLDER_SPACE = ' '; // const getChar = String.fromCharCode;
exports.PLACEHOLDER_SPACE = PLACEHOLDER_SPACE;
});
unwrapExports(char_1);
var char_2 = char_1.BACKSLASH;
var char_3 = char_1.PLACEHOLDER_SPACE;
var char_4 = char_1.PLACEHOLDER_SPACE_TAB;
var char_5 = char_1.SLASH;
var char_6 = char_1.CLOSE_BRAKET;
var char_7 = char_1.OPEN_BRAKET;
var char_8 = char_1.SPACE;
var char_9 = char_1.QUOTEMARK;
var char_10 = char_1.EQ;
var char_11 = char_1.TAB;
var char_12 = char_1.R;
var char_13 = char_1.F;
var char_14 = char_1.N;
var lib = createCommonjsModule(function (module, exports) {
exports.__esModule = true;
exports.isEOL = exports.isStringNode = exports.isTagNode = exports.getUniqAttr = exports.getNodeLength = exports.escapeHTML = exports.appendToNode = exports.attrValue = exports.attrsToString = void 0;
var isTagNode = function isTagNode(el) {
return typeof el === 'object' && !!el.tag;
};
exports.isTagNode = isTagNode;
var isStringNode = function isStringNode(el) {
return typeof el === 'string';
};
exports.isStringNode = isStringNode;
var isEOL = function isEOL(el) {
return el === char_1.N;
};
exports.isEOL = isEOL;
var keysReduce = function keysReduce(obj, reduce, def) {
return Object.keys(obj).reduce(reduce, def);
};
var getNodeLength = function getNodeLength(node) {
if (isTagNode(node)) {
return node.content.reduce(function (count, contentNode) {
return count + getNodeLength(contentNode);
}, 0);
}
if (isStringNode(node)) {
return node.length;
}
return 0;
};
/**
* Appends value to Tag Node
* @param {TagNode} node
* @param value
*/
exports.getNodeLength = getNodeLength;
var appendToNode = function appendToNode(node, value) {
node.content.push(value);
};
/**
* Replaces " to &qquot;
* @param {String} value
*/
exports.appendToNode = appendToNode;
var escapeHTML = function escapeHTML(value) {
return value.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''') // eslint-disable-next-line no-script-url
.replace(/(javascript):/gi, '$1%3A');
};
/**
* Acept name and value and return valid html5 attribute string
* @param {String} name
* @param {String} value
* @return {string}
*/
exports.escapeHTML = escapeHTML;
var attrValue = function attrValue(name, value) {
var type = typeof value;
var types = {
"boolean": function boolean() {
return value ? "" + name : '';
},
number: function number() {
return name + "=\"" + value + "\"";
},
string: function string() {
return name + "=\"" + escapeHTML(value) + "\"";
},
object: function object() {
return name + "=\"" + escapeHTML(JSON.stringify(value)) + "\"";
}
};
return types[type] ? types[type]() : '';
};
/**
* Transforms attrs to html params string
* @param values
*/
exports.attrValue = attrValue;
var attrsToString = function attrsToString(values) {
// To avoid some malformed attributes
if (values == null) {
return '';
}
return keysReduce(values, function (arr, key) {
return [].concat(arr, [attrValue(key, values[key])]);
}, ['']).join(' ');
};
/**
* Gets value from
* @example
* getUniqAttr({ 'foo': true, 'bar': bar' }) => 'bar'
* @param attrs
* @returns {string}
*/
exports.attrsToString = attrsToString;
var getUniqAttr = function getUniqAttr(attrs) {
return keysReduce(attrs, function (res, key) {
return attrs[key] === key ? attrs[key] : null;
}, null);
};
exports.getUniqAttr = getUniqAttr;
});
unwrapExports(lib);
var lib_1 = lib.isEOL;
var lib_2 = lib.isStringNode;
var lib_3 = lib.isTagNode;
var lib_4 = lib.getUniqAttr;
var lib_5 = lib.getNodeLength;
var lib_6 = lib.escapeHTML;
var lib_7 = lib.appendToNode;
var lib_8 = lib.attrValue;
var lib_9 = lib.attrsToString;
var TagNode_1 = createCommonjsModule(function (module, exports) {
exports.__esModule = true;
exports["default"] = exports.TagNode = void 0;
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _extends() {
_extends = Object.assign || function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
var getTagAttrs = function getTagAttrs(tag, params) {
var uniqAattr = (0, lib.getUniqAttr)(params);
if (uniqAattr) {
var tagAttr = (0, lib.attrValue)(tag, uniqAattr);
var attrs = _extends({}, params);
delete attrs[uniqAattr];
var attrsStr = (0, lib.attrsToString)(attrs);
return "" + tagAttr + attrsStr;
}
return "" + tag + (0, lib.attrsToString)(params);
};
var TagNode =
/*#__PURE__*/
function () {
function TagNode(tag, attrs, content) {
this.tag = tag;
this.attrs = attrs;
this.content = Array.isArray(content) ? content : [content];
}
var _proto = TagNode.prototype;
_proto.attr = function attr(name, value) {
if (typeof value !== 'undefined') {
this.attrs[name] = value;
}
return this.attrs[name];
};
_proto.append = function append(value) {
return (0, lib.appendToNode)(this, value);
};
_proto.toTagStart = function toTagStart(_temp) {
var _ref = _temp === void 0 ? {} : _temp,
_ref$openTag = _ref.openTag,
openTag = _ref$openTag === void 0 ? char_1.OPEN_BRAKET : _ref$openTag,
_ref$closeTag = _ref.closeTag,
closeTag = _ref$closeTag === void 0 ? char_1.CLOSE_BRAKET : _ref$closeTag;
var tagAttrs = getTagAttrs(this.tag, this.attrs);
return "" + openTag + tagAttrs + closeTag;
};
_proto.toTagEnd = function toTagEnd(_temp2) {
var _ref2 = _temp2 === void 0 ? {} : _temp2,
_ref2$openTag = _ref2.openTag,
openTag = _ref2$openTag === void 0 ? char_1.OPEN_BRAKET : _ref2$openTag,
_ref2$closeTag = _ref2.closeTag,
closeTag = _ref2$closeTag === void 0 ? char_1.CLOSE_BRAKET : _ref2$closeTag;
return "" + openTag + char_1.SLASH + this.tag + closeTag;
};
_proto.toTagNode = function toTagNode() {
return new TagNode(this.tag.toLowerCase(), this.attrs, this.content);
};
_proto.toString = function toString(_temp3) {
var _ref3 = _temp3 === void 0 ? {} : _temp3,
_ref3$openTag = _ref3.openTag,
openTag = _ref3$openTag === void 0 ? char_1.OPEN_BRAKET : _ref3$openTag,
_ref3$closeTag = _ref3.closeTag,
closeTag = _ref3$closeTag === void 0 ? char_1.CLOSE_BRAKET : _ref3$closeTag;
var isEmpty = this.content.length === 0;
var content = this.content.reduce(function (r, node) {
return r + node.toString({
openTag: openTag,
closeTag: closeTag
});
}, '');
var tagStart = this.toTagStart({
openTag: openTag,
closeTag: closeTag
});
if (isEmpty) {
return tagStart;
}
return "" + tagStart + content + this.toTagEnd({
openTag: openTag,
closeTag: closeTag
});
};
_createClass(TagNode, [{
key: "length",
get: function get() {
return (0, lib.getNodeLength)(this);
}
}]);
return TagNode;
}();
exports.TagNode = TagNode;
TagNode.create = function (tag, attrs, content) {
if (attrs === void 0) {
attrs = {};
}
if (content === void 0) {
content = [];
}
return new TagNode(tag, attrs, content);
};
TagNode.isOf = function (node, type) {
return node.tag === type;
};
var _default = TagNode;
exports["default"] = _default;
});
var TagNode = unwrapExports(TagNode_1);
var TagNode_2 = TagNode_1.TagNode;
var TOKEN_TYPE_ID = 'type'; // 0;
var TOKEN_VALUE_ID = 'value'; // 1;
var TOKEN_COLUMN_ID = 'row'; // 2;
var TOKEN_LINE_ID = 'line'; // 3;
var TOKEN_TYPE_WORD = 1; // 'word';
var TOKEN_TYPE_TAG = 2; // 'tag';
var TOKEN_TYPE_ATTR_NAME = 3; // 'attr-name';
var TOKEN_TYPE_ATTR_VALUE = 4; // 'attr-value';
var TOKEN_TYPE_SPACE = 5; // 'space';
var TOKEN_TYPE_NEW_LINE = 6; // 'new-line';
/**
* @param {Token} token
* @returns {string}
*/
var getTokenValue = function getTokenValue(token) {
if (token && typeof token[TOKEN_VALUE_ID] !== 'undefined') {
return token[TOKEN_VALUE_ID];
}
return '';
};
/**
* @param {Token}token
* @returns {number}
*/
var getTokenLine = function getTokenLine(token) {
return token && token[TOKEN_LINE_ID] || 0;
};
var getTokenColumn = function getTokenColumn(token) {
return token && token[TOKEN_COLUMN_ID] || 0;
};
/**
* @param {Token} token
* @returns {boolean}
*/
var isTextToken = function isTextToken(token) {
if (token && typeof token[TOKEN_TYPE_ID] !== 'undefined') {
return token[TOKEN_TYPE_ID] === TOKEN_TYPE_SPACE || token[TOKEN_TYPE_ID] === TOKEN_TYPE_NEW_LINE || token[TOKEN_TYPE_ID] === TOKEN_TYPE_WORD;
}
return false;
};
/**
* @param {Token} token
* @returns {boolean}
*/
var isTagToken = function isTagToken(token) {
if (token && typeof token[TOKEN_TYPE_ID] !== 'undefined') {
return token[TOKEN_TYPE_ID] === TOKEN_TYPE_TAG;
}
return false;
};
var isTagEnd = function isTagEnd(token) {
return getTokenValue(token).charCodeAt(0) === char_5.charCodeAt(0);
};
var isTagStart = function isTagStart(token) {
return !isTagEnd(token);
};
var isAttrNameToken = function isAttrNameToken(token) {
if (token && typeof token[TOKEN_TYPE_ID] !== 'undefined') {
return token[TOKEN_TYPE_ID] === TOKEN_TYPE_ATTR_NAME;
}
return false;
};
/**
* @param {Token} token
* @returns {boolean}
*/
var isAttrValueToken = function isAttrValueToken(token) {
if (token && typeof token[TOKEN_TYPE_ID] !== 'undefined') {
return token[TOKEN_TYPE_ID] === TOKEN_TYPE_ATTR_VALUE;
}
return false;
};
var getTagName = function getTagName(token) {
var value = getTokenValue(token);
return isTagEnd(token) ? value.slice(1) : value;
};
var convertTagToText = function convertTagToText(token) {
var text = char_7;
text += getTokenValue(token);
text += char_6;
return text;
};
var Token =
/*#__PURE__*/
function () {
/**
* @param {String} type
* @param {String} value
* @param line
* @param row
*/
function Token(type, value, line, row) {
this[TOKEN_TYPE_ID] = Number(type);
this[TOKEN_VALUE_ID] = String(value);
this[TOKEN_LINE_ID] = Number(line);
this[TOKEN_COLUMN_ID] = Number(row);
}
var _proto = Token.prototype;
_proto.isEmpty = function isEmpty() {
// eslint-disable-next-line no-restricted-globals
return isNaN(this[TOKEN_TYPE_ID]);
};
_proto.isText = function isText() {
return isTextToken(this);
};
_proto.isTag = function isTag() {
return isTagToken(this);
};
_proto.isAttrName = function isAttrName() {
return isAttrNameToken(this);
};
_proto.isAttrValue = function isAttrValue() {
return isAttrValueToken(this);
};
_proto.isStart = function isStart() {
return isTagStart(this);
};
_proto.isEnd = function isEnd() {
return isTagEnd(this);
};
_proto.getName = function getName() {
return getTagName(this);
};
_proto.getValue = function getValue() {
return getTokenValue(this);
};
_proto.getLine = function getLine() {
return getTokenLine(this);
};
_proto.getColumn = function getColumn() {
return getTokenColumn(this);
};
_proto.toString = function toString() {
return convertTagToText(this);
};
return Token;
}();
var TYPE_WORD = TOKEN_TYPE_WORD;
var TYPE_TAG = TOKEN_TYPE_TAG;
var TYPE_ATTR_NAME = TOKEN_TYPE_ATTR_NAME;
var TYPE_ATTR_VALUE = TOKEN_TYPE_ATTR_VALUE;
var TYPE_SPACE = TOKEN_TYPE_SPACE;
var TYPE_NEW_LINE = TOKEN_TYPE_NEW_LINE;
function CharGrabber(source, options) {
var cursor = {
pos: 0,
len: source.length
};
var substrUntilChar = function substrUntilChar(char) {
var pos = cursor.pos;
var idx = source.indexOf(char, pos);
return idx >= 0 ? source.substr(pos, idx - pos) : '';
};
var includes = function includes(val) {
return source.indexOf(val, cursor.pos) >= 0;
};
var hasNext = function hasNext() {
return cursor.len > cursor.pos;
};
var isLast = function isLast() {
return cursor.pos === cursor.len;
};
var skip = function skip(num, silent) {
if (num === void 0) {
num = 1;
}
cursor.pos += num;
if (options && options.onSkip && !silent) {
options.onSkip();
}
};
var rest = function rest() {
return source.substr(cursor.pos);
};
var curr = function curr() {
return source[cursor.pos];
};
var prev = function prev() {
var prevPos = cursor.pos - 1;
return typeof source[prevPos] !== 'undefined' ? source[prevPos] : null;
};
var next = function next() {
var nextPos = cursor.pos + 1;
return nextPos <= source.length - 1 ? source[nextPos] : null;
};
var grabWhile = function grabWhile(cond, silent) {
var start = 0;
if (hasNext()) {
start = cursor.pos;
while (hasNext() && cond(curr())) {
skip(1, silent);
}
}
return source.substr(start, cursor.pos - start);
};
/**
* @type {skip}
*/
this.skip = skip;
/**
* @returns {Boolean}
*/
this.hasNext = hasNext;
/**
* @returns {String}
*/
this.getCurr = curr;
/**
* @returns {String}
*/
this.getRest = rest;
/**
* @returns {String}
*/
this.getNext = next;
/**
* @returns {String}
*/
this.getPrev = prev;
/**
* @returns {Boolean}
*/
this.isLast = isLast;
/**
* @returns {Boolean}
*/
this.includes = includes;
/**
* @param {Function} cond
* @param {Boolean} silent
* @return {String}
*/
this.grabWhile = grabWhile;
/**
* Grabs rest of string until it find a char
* @param {String} char
* @return {String}
*/
this.substrUntilChar = substrUntilChar;
}
/**
* Creates a grabber wrapper for source string, that helps to iterate over string char by char
* @param {String} source
* @param {Object} options
* @param {Function} options.onSkip
* @return CharGrabber
*/
var createCharGrabber = function createCharGrabber(source, options) {
return new CharGrabber(source, options);
};
/**
* Trims string from start and end by char
* @example
* trimChar('*hello*', '*') ==> 'hello'
* @param {String} str
* @param {String} charToRemove
* @returns {String}
*/
var trimChar = function trimChar(str, charToRemove) {
while (str.charAt(0) === charToRemove) {
// eslint-disable-next-line no-param-reassign
str = str.substring(1);
}
while (str.charAt(str.length - 1) === charToRemove) {
// eslint-disable-next-line no-param-reassign
str = str.substring(0, str.length - 1);
}
return str;
};
/**
* Unquotes \" to "
* @param str
* @return {String}
*/
var unquote = function unquote(str) {
return str.replace(char_2 + char_9, char_9);
};
function NodeList(values) {
if (values === void 0) {
values = [];
}
var nodes = values;
var getLast = function getLast() {
return Array.isArray(nodes) && nodes.length > 0 && typeof nodes[nodes.length - 1] !== 'undefined' ? nodes[nodes.length - 1] : null;
};
var flushLast = function flushLast() {
return nodes.length ? nodes.pop() : false;
};
var push = function push(value) {
return nodes.push(value);
};
var toArray = function toArray() {
return nodes;
};
this.push = push;
this.toArray = toArray;
this.getLast = getLast;
this.flushLast = flushLast;
}
/**
*
* @param values
* @return {NodeList}
*/
var createList = function createList(values) {
if (values === void 0) {
values = [];
}
return new NodeList(values);
};
/* eslint-disable no-plusplus,no-param-reassign */
var EM = '!';
/**
* Creates a Token entity class
* @param {Number} type
* @param {String} value
* @param {Number} r line number
* @param {Number} cl char number in line
*/
var createToken = function createToken(type, value, r, cl) {
if (r === void 0) {
r = 0;
}
if (cl === void 0) {
cl = 0;
}
return new Token(type, value, r, cl);
};
/**
* @typedef {Object} Lexer
* @property {Function} tokenize
* @property {Function} isTokenNested
*/
/**
* @param {String} buffer
* @param {Object} options
* @param {Function} options.onToken
* @param {String} options.openTag
* @param {String} options.closeTag
* @param {Boolean} options.enableEscapeTags
* @return {Lexer}
*/
function createLexer(buffer, options) {
if (options === void 0) {
options = {};
}
var STATE_WORD = 0;
var STATE_TAG = 1;
var STATE_TAG_ATTRS = 2;
var TAG_STATE_NAME = 0;
var TAG_STATE_ATTR = 1;
var TAG_STATE_VALUE = 2;
var row = 0;
var col = 0;
var tokenIndex = -1;
var stateMode = STATE_WORD;
var tagMode = TAG_STATE_NAME;
var tokens = new Array(Math.floor(buffer.length));
var openTag = options.openTag || char_7;
var closeTag = options.closeTag || char_6;
var escapeTags = !!options.enableEscapeTags;
var onToken = options.onToken || function () {};
var RESERVED_CHARS = [closeTag, openTag, char_9, char_2, char_8, char_11, char_10, char_14, EM];
var NOT_CHAR_TOKENS = [// ...(options.enableEscapeTags ? [BACKSLASH] : []),
openTag, char_8, char_11, char_14];
var WHITESPACES = [char_8, char_11];
var SPECIAL_CHARS = [char_10, char_8, char_11];
var isCharReserved = function isCharReserved(char) {
return RESERVED_CHARS.indexOf(char) >= 0;
};
var isNewLine = function isNewLine(char) {
return char === char_14;
};
var isWhiteSpace = function isWhiteSpace(char) {
return WHITESPACES.indexOf(char) >= 0;
};
var isCharToken = function isCharToken(char) {
return NOT_CHAR_TOKENS.indexOf(char) === -1;
};
var isSpecialChar = function isSpecialChar(char) {
return SPECIAL_CHARS.indexOf(char) >= 0;
};
var isEscapableChar = function isEscapableChar(char) {
return char === openTag || char === closeTag || char === char_2;
};
var isEscapeChar = function isEscapeChar(char) {
return char === char_2;
};
var onSkip = function onSkip() {
col++;
};
var unq = function unq(val) {
return unquote(trimChar(val, char_9));
};
var chars = createCharGrabber(buffer, {
onSkip: onSkip
});
/**
* Emits newly created token to subscriber
* @param {Number} type
* @param {String} value
*/
function emitToken(type, value) {
var token = createToken(type, value, row, col);
onToken(token);
tokenIndex += 1;
tokens[tokenIndex] = token;
}
function nextTagState(tagChars, isSingleValueTag) {
if (tagMode === TAG_STATE_ATTR) {
var validAttrName = function validAttrName(char) {
return !(char === char_10 || isWhiteSpace(char));
};
var _name = tagChars.grabWhile(validAttrName);
var isEnd = tagChars.isLast();
var isValue = tagChars.getCurr() !== char_10;
tagChars.skip();
if (isEnd || isValue) {
emitToken(TYPE_ATTR_VALUE, unq(_name));
} else {
emitToken(TYPE_ATTR_NAME, _name);
}
if (isEnd) {
return TAG_STATE_NAME;
}
if (isValue) {
return TAG_STATE_ATTR;
}
return TAG_STATE_VALUE;
}
if (tagMode === TAG_STATE_VALUE) {
var stateSpecial = false;
var validAttrValue = function validAttrValue(char) {
// const isEQ = char === EQ;
var isQM = char === char_9;
var prevChar = tagChars.getPrev();
var nextChar = tagChars.getNext();
var isPrevSLASH = prevChar === char_2;
var isNextEQ = nextChar === char_10;
var isWS = isWhiteSpace(char); // const isPrevWS = isWhiteSpace(prevChar);
var isNextWS = isWhiteSpace(nextChar);
if (stateSpecial && isSpecialChar(char)) {
return true;
}
if (isQM && !isPrevSLASH) {
stateSpecial = !stateSpecial;
if (!stateSpecial && !(isNextEQ || isNextWS)) {
return false;
}
}
if (!isSingleValueTag) {
return isWS === false; // return (isEQ || isWS) === false;
}
return true;
};
var _name2 = tagChars.grabWhile(validAttrValue);
tagChars.skip();
emitToken(TYPE_ATTR_VALUE, unq(_name2));
if (tagChars.isLast()) {
return TAG_STATE_NAME;
}
return TAG_STATE_ATTR;
}
var validName = function validName(char) {
return !(char === char_10 || isWhiteSpace(char) || tagChars.isLast());
};
var name = tagChars.grabWhile(validName);
emitToken(TYPE_TAG, name);
tagChars.skip(); // in cases when we has [url=someval]GET[/url] and we dont need to parse all
if (isSingleValueTag) {
return TAG_STATE_VALUE;
}
var hasEQ = tagChars.includes(char_10);
return hasEQ ? TAG_STATE_ATTR : TAG_STATE_VALUE;
}
function stateTag() {
var currChar = chars.getCurr();
if (currChar === openTag) {
var nextChar = chars.getNext();
chars.skip(); // detect case where we have '[My word [tag][/tag]' or we have '[My last line word'
var substr = chars.substrUntilChar(closeTag);
var hasInvalidChars = substr.length === 0 || substr.indexOf(openTag) >= 0;
if (isCharReserved(nextChar) || hasInvalidChars || chars.isLast()) {
emitToken(TYPE_WORD, currChar);
return STATE_WORD;
} // [myTag ]
var isNoAttrsInTag = substr.indexOf(char_10) === -1; // [/myTag]
var isClosingTag = substr[0] === char_5;
if (isNoAttrsInTag || isClosingTag) {
var name = chars.grabWhile(function (char) {
return char !== closeTag;
});
chars.skip(); // skip closeTag
emitToken(TYPE_TAG, name);
return STATE_WORD;
}
return STATE_TAG_ATTRS;
}
return STATE_WORD;
}
function stateAttrs() {
var silent = true;
var tagStr = chars.grabWhile(function (char) {
return char !== closeTag;
}, silent);
var tagGrabber = createCharGrabber(tagStr, {
onSkip: onSkip
});
var hasSpace = tagGrabber.includes(char_8);
tagMode = TAG_STATE_NAME;
while (tagGrabber.hasNext()) {
tagMode = nextTagState(tagGrabber, !hasSpace);
}
chars.skip(); // skip closeTag
return STATE_WORD;
}
function stateWord() {
if (isNewLine(chars.getCurr())) {
emitToken(TYPE_NEW_LINE, chars.getCurr());
chars.skip();
col = 0;
row++;
return STATE_WORD;
}
if (isWhiteSpace(chars.getCurr())) {
emitToken(TYPE_SPACE, chars.grabWhile(isWhiteSpace));
return STATE_WORD;
}
if (chars.getCurr() === openTag) {
if (chars.includes(closeTag)) {
return STATE_TAG;
}
emitToken(TYPE_WORD, chars.getCurr());
chars.skip();
return STATE_WORD;
}
if (escapeTags) {
if (isEscapeChar(chars.getCurr())) {
var currChar = chars.getCurr();
var nextChar = chars.getNext();
chars.skip(); // skip the \ without emitting anything
if (isEscapableChar(nextChar)) {
chars.skip(); // skip past the [, ] or \ as well
emitToken(TYPE_WORD, nextChar);
return STATE_WORD;
}
emitToken(TYPE_WORD, currChar);
return STATE_WORD;
}
var isChar = function isChar(char) {
return isCharToken(char) && !isEscapeChar(char);
};
emitToken(TYPE_WORD, chars.grabWhile(isChar));
return STATE_WORD;
}
emitToken(TYPE_WORD, chars.grabWhile(isCharToken));
return STATE_WORD;
}
function tokenize() {
stateMode = STATE_WORD;
while (chars.hasNext()) {
switch (stateMode) {
case STATE_TAG:
stateMode = stateTag();
break;
case STATE_TAG_ATTRS:
stateMode = stateAttrs();
break;
case STATE_WORD:
stateMode = stateWord();
break;
default:
stateMode = STATE_WORD;
break;
}
}
tokens.length = tokenIndex + 1;
return tokens;
}
function isTokenNested(token) {
var value = openTag + char_5 + token.getValue(); // potential bottleneck
return buffer.indexOf(value) > -1;
}
return {
tokenize: tokenize,
isTokenNested: isTokenNested
};
}
/**
* @public
* @param {String} input
* @param {Object} opts
* @param {Function} opts.createTokenizer
* @param {Array<string>} opts.onlyAllowTags
* @param {String} opts.openTag
* @param {String} opts.closeTag
* @param {Boolean} opts.enableEscapeTags
* @return {Array}
*/
var parse = function parse(input, opts) {
if (opts === void 0) {
opts = {};
}
var options = opts;
var openTag = options.openTag || char_7;
var closeTag = options.closeTag || char_6;
var tokenizer = null;
/**
* Result AST of nodes
* @private
* @type {NodeList}
*/
var nodes = createList();
/**
* Temp buffer of nodes that's nested to another node
* @private
* @type {NodeList}
*/
var nestedNodes = createList();
/**
* Temp buffer of nodes [tag..]...[/tag]
* @private
* @type {NodeList}
*/
var tagNodes = createList();
/**
* Temp buffer of tag attributes
* @private
* @type {NodeList}
*/
var tagNodesAttrName = createList();
/**
* Cache for nested tags checks
*/
var nestedTagsMap = new Set();
/**
*
* @param token
* @returns {boolean}
*/
var isTokenNested = function isTokenNested(token) {
var value = token.getValue();
if (!nestedTagsMap.has(value) && tokenizer.isTokenNested && tokenizer.isTokenNested(token)) {
nestedTagsMap.add(value);
return true;
}
return nestedTagsMap.has(value);
};
/**
* @param tagName
* @returns {boolean}
*/
var isTagNested = function isTagNested(tagName) {
return Boolean(nestedTagsMap.has(tagName));
};
/**
* @private
* @param {String} value
* @return {boolean}
*/
var isAllowedTag = function isAllowedTag(value) {
if (options.onlyAllowTags && options.onlyAllowTags.length) {
return options.onlyAllowTags.indexOf(value) >= 0;
}
return true;
};
/**
* Flushes temp tag nodes and its attributes buffers
* @private
* @return {Array}
*/
var flushTagNodes = function flushTagNodes() {
if (tagNodes.flushLast()) {
tagNodesAttrName.flushLast();
}
};
/**
* @private
* @return {Array}
*/
var getNodes = function getNodes() {
var lastNestedNode = nestedNodes.getLast();
if (lastNestedNode && Array.isArray(lastNestedNode.content)) {
return lastNestedNode.content;
}
return nodes.toArray();
};
/**
* @private
* @param {string|TagNode} node
*/
var appendNodes = function appendNodes(node) {
var items = getNodes();
if (Array.isArray(items)) {
if (lib_3(node)) {
if (isAllowedTag(node.tag)) {
items.push(node.toTagNode());
} else {
items.push(node.toTagStart({
openTag: openTag,
closeTag: closeTag
}));
if (node.content.length) {
node.content.forEach(function (item) {
items.push(item);
});
items.push(node.toTagEnd({
openTag: openTag,
closeTag: closeTag
}));
}
}
} else {
items.push(node);
}
}
};
/**
* @private
* @param {Token} token
*/
var handleTagStart = function handleTagStart(token) {
flushTagNodes();
var tagNode = TagNode.create(token.getValue());
var isNested = isTokenNested(token);
tagNodes.push(tagNode);
if (isNested) {
nestedNodes.push(tagNode);
} else {
appendNodes(tagNode);
}
};
/**
* @private
* @param {Token} token
*/
var handleTagEnd = function handleTagEnd(token) {
flushTagNodes();
var lastNestedNode = nestedNodes.flushLast();
if (lastNestedNode) {
appendNodes(lastNestedNode);
} else if (typeof options.onError === 'function') {
var tag = token.getValue();
var line = token.getLine();
var column = token.getColumn();
options.onError({
message: "Inconsistent tag '" + tag + "' on line " + line + " and column " + column,
tagName: tag,
lineNumber: line,
columnNumber: column
});
}
};
/**
* @private
* @param {Token} token
*/
var handleTag = function handleTag(token) {
// [tag]
if (token.isStart()) {
handleTagStart(token);
} // [/tag]
if (token.isEnd()) {
handleTagEnd(token);
}
};
/**
* @private
* @param {Token} token
*/
var handleNode = function handleNode(token) {
/**
* @type {TagNode}
*/
var lastTagNode = tagNodes.getLast();
var tokenValue = token.getValue();
var isNested = isTagNested(token);
if (lastTagNode) {
if (token.isAttrName()) {
tagNodesAttrName.push(tokenValue);
lastTagNode.attr(tagNodesAttrName.getLast(), '');
} else if (token.isAttrValue()) {
var attrName = tagNodesAttrName.getLast();
if (attrName) {
lastTagNode.attr(attrName, tokenValue);
tagNodesAttrName.flushLast();
} else {
lastTagNode.attr(tokenValue, tokenValue);
}
} else if (token.isText()) {
if (isNested) {
lastTagNode.append(tokenValue);
} else {
appendNodes(tokenValue);
}
} else if (token.isTag()) {
// if tag is not allowed, just past it as is
appendNodes(token.toString());
}
} else if (token.isText()) {
appendNodes(tokenValue);
} else if (token.isTag()) {
// if tag is not allowed, just past it as is
appendNodes(token.toString());
}
};
/**
* @private
* @param {Token} token
*/
var onToken = function onToken(token) {
if (token.isTag()) {
handleTag(token);
} else {
handleNode(token);
}
};
tokenizer = (opts.createTokenizer ? opts.createTokenizer : createLexer)(input, {
onToken: onToken,
onlyAllowTags: options.onlyAllowTags,
openTag: openTag,
closeTag: closeTag,
enableEscapeTags: options.enableEscapeTags
}); // eslint-disable-next-line no-unused-vars
var tokens = tokenizer.tokenize();
return nodes.toArray();
};
exports.TagNode = TagNode_2;
exports.default = parse;
exports.parse = parse;
Object.defineProperty(exports, '__esModule', { value: true });
})));