Socket
Socket
Sign inDemoInstall

@bbob/parser

Package Overview
Dependencies
Maintainers
0
Versions
53
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@bbob/parser - npm Package Compare versions

Comparing version 3.0.2 to 4.0.0

LICENSE

1680

dist/index.js
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@bbob/plugin-helper')) :
typeof define === 'function' && define.amd ? define(['exports', '@bbob/plugin-helper'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.BbobParser = {}, global.pluginHelper));
})(this, (function (exports, pluginHelper) { 'use strict';
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.BbobParser = {}));
})(this, (function (exports) { 'use strict';
// type, value, line, row,
const TOKEN_TYPE_ID = 'type'; // 0;
const TOKEN_VALUE_ID = 'value'; // 1;
const TOKEN_COLUMN_ID = 'row'; // 2;
const TOKEN_LINE_ID = 'line'; // 3;
const TOKEN_TYPE_WORD = 1; // 'word';
const TOKEN_TYPE_TAG = 2; // 'tag';
const TOKEN_TYPE_ATTR_NAME = 3; // 'attr-name';
const TOKEN_TYPE_ATTR_VALUE = 4; // 'attr-value';
const TOKEN_TYPE_SPACE = 5; // 'space';
const TOKEN_TYPE_NEW_LINE = 6; // 'new-line';
/**
* @param {Token} token
* @returns {string}
*/ const getTokenValue = (token)=>{
if (token && typeof token[TOKEN_VALUE_ID] !== 'undefined') {
return token[TOKEN_VALUE_ID];
}
return '';
};
/**
* @param {Token}token
* @returns {number}
*/ const getTokenLine = (token)=>token && token[TOKEN_LINE_ID] || 0;
const getTokenColumn = (token)=>token && token[TOKEN_COLUMN_ID] || 0;
/**
* @param {Token} token
* @returns {boolean}
*/ const 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}
*/ const isTagToken = (token)=>{
if (token && typeof token[TOKEN_TYPE_ID] !== 'undefined') {
return token[TOKEN_TYPE_ID] === TOKEN_TYPE_TAG;
}
return false;
};
const isTagEnd = (token)=>getTokenValue(token).charCodeAt(0) === pluginHelper.SLASH.charCodeAt(0);
const isTagStart = (token)=>!isTagEnd(token);
const 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}
*/ const isAttrValueToken = (token)=>{
if (token && typeof token[TOKEN_TYPE_ID] !== 'undefined') {
return token[TOKEN_TYPE_ID] === TOKEN_TYPE_ATTR_VALUE;
}
return false;
};
const getTagName = (token)=>{
const value = getTokenValue(token);
return isTagEnd(token) ? value.slice(1) : value;
};
const convertTagToText = (token)=>{
let text = pluginHelper.OPEN_BRAKET;
text += getTokenValue(token);
text += pluginHelper.CLOSE_BRAKET;
return text;
};
class Token {
isEmpty() {
// eslint-disable-next-line no-restricted-globals
return isNaN(this[TOKEN_TYPE_ID]);
}
isText() {
return isTextToken(this);
}
isTag() {
return isTagToken(this);
}
isAttrName() {
return isAttrNameToken(this);
}
isAttrValue() {
return isAttrValueToken(this);
}
isStart() {
return isTagStart(this);
}
isEnd() {
return isTagEnd(this);
}
getName() {
return getTagName(this);
}
getValue() {
return getTokenValue(this);
}
getLine() {
return getTokenLine(this);
}
getColumn() {
return getTokenColumn(this);
}
toString() {
return convertTagToText(this);
}
/**
* @param {String} type
* @param {String} value
* @param line
* @param row
*/ constructor(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);
}
}
const TYPE_WORD = TOKEN_TYPE_WORD;
const TYPE_TAG = TOKEN_TYPE_TAG;
const TYPE_ATTR_NAME = TOKEN_TYPE_ATTR_NAME;
const TYPE_ATTR_VALUE = TOKEN_TYPE_ATTR_VALUE;
const TYPE_SPACE = TOKEN_TYPE_SPACE;
const TYPE_NEW_LINE = TOKEN_TYPE_NEW_LINE;
const N = '\n';
const TAB = '\t';
const EQ = '=';
const QUOTEMARK = '"';
const SPACE = ' ';
const OPEN_BRAKET = '[';
const CLOSE_BRAKET = ']';
const SLASH = '/';
const BACKSLASH = '\\';
function CharGrabber(source, options) {
const cursor = {
pos: 0,
len: source.length
};
const substrUntilChar = (char)=>{
const { pos } = cursor;
const idx = source.indexOf(char, pos);
return idx >= 0 ? source.substring(pos, idx) : '';
};
const includes = (val)=>source.indexOf(val, cursor.pos) >= 0;
const hasNext = ()=>cursor.len > cursor.pos;
const isLast = ()=>cursor.pos === cursor.len;
const skip = (num = 1, silent)=>{
cursor.pos += num;
if (options && options.onSkip && !silent) {
options.onSkip();
}
};
const rest = ()=>source.substring(cursor.pos);
const grabN = (num = 0)=>source.substring(cursor.pos, cursor.pos + num);
const curr = ()=>source[cursor.pos];
const prev = ()=>{
const prevPos = cursor.pos - 1;
return typeof source[prevPos] !== 'undefined' ? source[prevPos] : null;
};
const next = ()=>{
const nextPos = cursor.pos + 1;
return nextPos <= source.length - 1 ? source[nextPos] : null;
};
const grabWhile = (cond, silent)=>{
let start = 0;
if (hasNext()) {
start = cursor.pos;
while(hasNext() && cond(curr())){
skip(1, silent);
}
}
return source.substring(start, cursor.pos);
};
/**
* @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;
/**
* @param {Number} num
* @return {String}
*/ this.grabN = grabN;
/**
* 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
*/ const createCharGrabber = (source, options)=>new CharGrabber(source, options);
/**
* Trims string from start and end by char
* @example
* trimChar('*hello*', '*') ==> 'hello'
* @param {String} str
* @param {String} charToRemove
* @returns {String}
*/ const 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}
*/ const unquote = (str)=>str.replace(pluginHelper.BACKSLASH + pluginHelper.QUOTEMARK, pluginHelper.QUOTEMARK);
function NodeList(values = []) {
const nodes = values;
const getLast = ()=>Array.isArray(nodes) && nodes.length > 0 && typeof nodes[nodes.length - 1] !== 'undefined' ? nodes[nodes.length - 1] : null;
const flushLast = ()=>nodes.length ? nodes.pop() : false;
const push = (value)=>nodes.push(value);
const toArray = ()=>nodes;
this.push = push;
this.toArray = toArray;
this.getLast = getLast;
this.flushLast = flushLast;
}
/**
*
* @param values
* @return {NodeList}
*/ const createList = (values = [])=>new NodeList(values);
function isTagNode(el) {
return typeof el === 'object' && el !== null && 'tag' in el;
}
function isStringNode(el) {
return typeof el === 'string';
}
function keysReduce(obj, reduce, def) {
const keys = Object.keys(obj);
return keys.reduce((acc, key)=>reduce(acc, key, obj), def);
}
function getNodeLength(node) {
if (isTagNode(node) && Array.isArray(node.content)) {
return node.content.reduce((count, contentNode)=>{
return count + getNodeLength(contentNode);
}, 0);
}
if (isStringNode(node)) {
return String(node).length;
}
return 0;
}
function appendToNode(node, value) {
if (Array.isArray(node.content)) {
node.content.push(value);
}
}
/**
* Replaces " to &qquot;
* @param {string} value
*/ function escapeAttrValue(value) {
return value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#039;')// eslint-disable-next-line no-script-url
.replace(/(javascript|data|vbscript):/gi, '$1%3A');
}
/**
* Accept name and value and return valid html5 attribute string
*/ function attrValue(name, value) {
// in case of performance
switch(typeof value){
case 'boolean':
return value ? `${name}` : '';
case 'number':
return `${name}="${value}"`;
case 'string':
return `${name}="${escapeAttrValue(value)}"`;
case 'object':
return `${name}="${escapeAttrValue(JSON.stringify(value))}"`;
default:
return '';
}
}
/**
* Transforms attrs to html params string
* @example
* attrsToString({ 'foo': true, 'bar': bar' }) => 'foo="true" bar="bar"'
*/ function attrsToString(values) {
// To avoid some malformed attributes
if (values == null) {
return '';
}
return keysReduce(values, (arr, key, obj)=>[
...arr,
attrValue(key, obj[key])
], [
''
]).join(' ');
}
/**
* Gets value from
* @example
* getUniqAttr({ 'foo': true, 'bar': bar' }) => 'bar'
*/ function getUniqAttr(attrs) {
return keysReduce(attrs || {}, (res, key, obj)=>obj[key] === key ? obj[key] : null, null);
}
// for cases <!-- -->
const EM = '!';
/**
* Creates a Token entity class
* @param {Number} type
* @param {String} value
* @param {Number} r line number
* @param {Number} cl char number in line
*/ const createToken = (type, value, r = 0, cl = 0)=>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 = {}) {
const STATE_WORD = 0;
const STATE_TAG = 1;
const STATE_TAG_ATTRS = 2;
const TAG_STATE_NAME = 0;
const TAG_STATE_ATTR = 1;
const TAG_STATE_VALUE = 2;
let row = 0;
let col = 0;
let tokenIndex = -1;
let stateMode = STATE_WORD;
let tagMode = TAG_STATE_NAME;
let contextFreeTag = '';
const tokens = new Array(Math.floor(buffer.length));
const openTag = options.openTag || pluginHelper.OPEN_BRAKET;
const closeTag = options.closeTag || pluginHelper.CLOSE_BRAKET;
const escapeTags = !!options.enableEscapeTags;
const contextFreeTags = options.contextFreeTags || [];
const onToken = options.onToken || (()=>{});
const RESERVED_CHARS = [
closeTag,
openTag,
pluginHelper.QUOTEMARK,
pluginHelper.BACKSLASH,
pluginHelper.SPACE,
pluginHelper.TAB,
pluginHelper.EQ,
pluginHelper.N,
EM
];
const NOT_CHAR_TOKENS = [
openTag,
pluginHelper.SPACE,
pluginHelper.TAB,
pluginHelper.N
];
const WHITESPACES = [
pluginHelper.SPACE,
pluginHelper.TAB
];
const SPECIAL_CHARS = [
pluginHelper.EQ,
pluginHelper.SPACE,
pluginHelper.TAB
];
const isCharReserved = (char)=>RESERVED_CHARS.indexOf(char) >= 0;
const isNewLine = (char)=>char === pluginHelper.N;
const isWhiteSpace = (char)=>WHITESPACES.indexOf(char) >= 0;
const isCharToken = (char)=>NOT_CHAR_TOKENS.indexOf(char) === -1;
const isSpecialChar = (char)=>SPECIAL_CHARS.indexOf(char) >= 0;
const isEscapableChar = (char)=>char === openTag || char === closeTag || char === pluginHelper.BACKSLASH;
const isEscapeChar = (char)=>char === pluginHelper.BACKSLASH;
const onSkip = ()=>{
col++;
};
const unq = (val)=>unquote(trimChar(val, pluginHelper.QUOTEMARK));
const checkContextFreeMode = (name, isClosingTag)=>{
if (contextFreeTag !== '' && isClosingTag) {
contextFreeTag = '';
}
if (contextFreeTag === '' && contextFreeTags.includes(name)) {
contextFreeTag = name;
}
};
const chars = createCharGrabber(buffer, {
onSkip
});
/**
* Emits newly created token to subscriber
* @param {Number} type
* @param {String} value
*/ function emitToken(type, value) {
const token = createToken(type, value, row, col);
onToken(token);
tokenIndex += 1;
tokens[tokenIndex] = token;
}
function nextTagState(tagChars, isSingleValueTag) {
if (tagMode === TAG_STATE_ATTR) {
const validAttrName = (char)=>!(char === pluginHelper.EQ || isWhiteSpace(char));
const name = tagChars.grabWhile(validAttrName);
const isEnd = tagChars.isLast();
const isValue = tagChars.getCurr() !== pluginHelper.EQ;
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) {
let stateSpecial = false;
const validAttrValue = (char)=>{
// const isEQ = char === EQ;
const isQM = char === pluginHelper.QUOTEMARK;
const prevChar = tagChars.getPrev();
const nextChar = tagChars.getNext();
const isPrevSLASH = prevChar === pluginHelper.BACKSLASH;
const isNextEQ = nextChar === pluginHelper.EQ;
const isWS = isWhiteSpace(char);
// const isPrevWS = isWhiteSpace(prevChar);
const 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;
};
const name1 = tagChars.grabWhile(validAttrValue);
tagChars.skip();
emitToken(TYPE_ATTR_VALUE, unq(name1));
if (tagChars.isLast()) {
return TAG_STATE_NAME;
}
return TAG_STATE_ATTR;
}
const validName = (char)=>!(char === pluginHelper.EQ || isWhiteSpace(char) || tagChars.isLast());
const name2 = tagChars.grabWhile(validName);
emitToken(TYPE_TAG, name2);
checkContextFreeMode(name2);
tagChars.skip();
// in cases when we has [url=someval]GET[/url] and we dont need to parse all
if (isSingleValueTag) {
return TAG_STATE_VALUE;
}
const hasEQ = tagChars.includes(pluginHelper.EQ);
return hasEQ ? TAG_STATE_ATTR : TAG_STATE_VALUE;
}
function stateTag() {
const currChar = chars.getCurr();
const nextChar = chars.getNext();
chars.skip();
// detect case where we have '[My word [tag][/tag]' or we have '[My last line word'
const substr = chars.substrUntilChar(closeTag);
const hasInvalidChars = substr.length === 0 || substr.indexOf(openTag) >= 0;
if (isCharReserved(nextChar) || hasInvalidChars || chars.isLast()) {
emitToken(TYPE_WORD, currChar);
return STATE_WORD;
}
// [myTag ]
const isNoAttrsInTag = substr.indexOf(pluginHelper.EQ) === -1;
// [/myTag]
const isClosingTag = substr[0] === pluginHelper.SLASH;
if (isNoAttrsInTag || isClosingTag) {
const name = chars.grabWhile((char)=>char !== closeTag);
chars.skip(); // skip closeTag
emitToken(TYPE_TAG, name);
checkContextFreeMode(name, isClosingTag);
return STATE_WORD;
}
return STATE_TAG_ATTRS;
}
function stateAttrs() {
const silent = true;
const tagStr = chars.grabWhile((char)=>char !== closeTag, silent);
const tagGrabber = createCharGrabber(tagStr, {
onSkip
});
const hasSpace = tagGrabber.includes(pluginHelper.SPACE);
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())) {
const word = chars.grabWhile(isWhiteSpace);
emitToken(TYPE_SPACE, word);
return STATE_WORD;
}
if (chars.getCurr() === openTag) {
if (contextFreeTag) {
const fullTagLen = openTag.length + pluginHelper.SLASH.length + contextFreeTag.length;
const fullTagName = `${openTag}${pluginHelper.SLASH}${contextFreeTag}`;
const foundTag = chars.grabN(fullTagLen);
const isEndContextFreeMode = foundTag === fullTagName;
if (isEndContextFreeMode) {
return STATE_TAG;
}
} else if (chars.includes(closeTag)) {
return STATE_TAG;
}
emitToken(TYPE_WORD, chars.getCurr());
chars.skip();
return STATE_WORD;
}
if (escapeTags) {
if (isEscapeChar(chars.getCurr())) {
const currChar = chars.getCurr();
const 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;
}
const isChar = (char)=>isCharToken(char) && !isEscapeChar(char);
const word1 = chars.grabWhile(isChar);
emitToken(TYPE_WORD, word1);
return STATE_WORD;
}
const word2 = chars.grabWhile(isCharToken);
emitToken(TYPE_WORD, word2);
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:
default:
stateMode = stateWord();
break;
}
}
tokens.length = tokenIndex + 1;
return tokens;
}
function isTokenNested(token) {
const value = openTag + pluginHelper.SLASH + token.getValue();
// potential bottleneck
return buffer.indexOf(value) > -1;
}
return {
tokenize,
isTokenNested
};
}
const getTagAttrs = (tag, params)=>{
const uniqAttr = getUniqAttr(params);
if (uniqAttr) {
const tagAttr = attrValue(tag, uniqAttr);
const attrs = {
...params
};
delete attrs[String(uniqAttr)];
const attrsStr = attrsToString(attrs);
return `${tagAttr}${attrsStr}`;
}
return `${tag}${attrsToString(params)}`;
};
const renderContent = (content, openTag, closeTag)=>{
const toString = (node)=>{
if (isTagNode(node)) {
return node.toString({
openTag,
closeTag
});
}
return String(node);
};
if (Array.isArray(content)) {
return content.reduce((r, node)=>{
if (node !== null) {
return r + toString(node);
}
return r;
}, '');
}
if (content) {
return toString(content);
}
return null;
};
class TagNode {
attr(name, value) {
if (typeof value !== 'undefined') {
this.attrs[name] = value;
}
return this.attrs[name];
}
append(value) {
return appendToNode(this, value);
}
get length() {
return getNodeLength(this);
}
toTagStart({ openTag = OPEN_BRAKET, closeTag = CLOSE_BRAKET } = {}) {
const tagAttrs = getTagAttrs(this.tag, this.attrs);
return `${openTag}${tagAttrs}${closeTag}`;
}
toTagEnd({ openTag = OPEN_BRAKET, closeTag = CLOSE_BRAKET } = {}) {
return `${openTag}${SLASH}${this.tag}${closeTag}`;
}
toTagNode() {
return new TagNode(this.tag.toLowerCase(), this.attrs, this.content);
}
toString({ openTag = OPEN_BRAKET, closeTag = CLOSE_BRAKET } = {}) {
const content = this.content ? renderContent(this.content, openTag, closeTag) : '';
const tagStart = this.toTagStart({
openTag,
closeTag
});
if (this.content === null || Array.isArray(this.content) && this.content.length === 0) {
return tagStart;
}
return `${tagStart}${content}${this.toTagEnd({
openTag,
closeTag
})}`;
}
static create(tag, attrs = {}, content = null) {
return new TagNode(tag, attrs, content);
}
static isOf(node, type) {
return node.tag === type;
}
constructor(tag, attrs, content){
this.tag = tag;
this.attrs = attrs;
this.content = content;
}
}
/**
* @public
* @param {string} input
* @param {Object} opts
* @param {Function} opts.createTokenizer
* @param {Array<string>} opts.onlyAllowTags
* @param {Array<string>} opts.contextFreeTags
* @param {Boolean} opts.enableEscapeTags
* @param {string} opts.openTag
* @param {string} opts.closeTag
* @return {Array<string|TagNode>}
*/ const parse = (input, opts = {})=>{
const options = opts;
const openTag = options.openTag || pluginHelper.OPEN_BRAKET;
const closeTag = options.closeTag || pluginHelper.CLOSE_BRAKET;
const onlyAllowTags = (options.onlyAllowTags || []).filter(Boolean).map((tag)=>tag.toLowerCase());
let tokenizer = null;
/**
* Result AST of nodes
* @private
* @type {NodeList}
*/ const nodes = createList();
/**
* Temp buffer of nodes that's nested to another node
* @private
* @type {NodeList}
*/ const nestedNodes = createList();
/**
* Temp buffer of nodes [tag..]...[/tag]
* @private
* @type {NodeList}
*/ const tagNodes = createList();
/**
* Temp buffer of tag attributes
* @private
* @type {NodeList}
*/ const tagNodesAttrName = createList();
/**
* Cache for nested tags checks
* @type Set<string>
*/ const nestedTagsMap = new Set();
/**
* @param {Token} token
* @returns {boolean}
*/ const isTokenNested = (token)=>{
const value = token.getValue();
if (!nestedTagsMap.has(value) && tokenizer.isTokenNested && tokenizer.isTokenNested(token)) {
nestedTagsMap.add(value);
return true;
}
return nestedTagsMap.has(value);
};
/**
* @private
* @param {string} tagName
* @returns {boolean}
*/ const isTagNested = (tagName)=>Boolean(nestedTagsMap.has(tagName));
/**
* @private
* @param {string} value
* @return {boolean}
*/ const isAllowedTag = (value)=>{
if (onlyAllowTags.length) {
return onlyAllowTags.indexOf(value.toLowerCase()) >= 0;
}
return true;
};
/**
* Flushes temp tag nodes and its attributes buffers
* @private
* @return {Array}
*/ const flushTagNodes = ()=>{
if (tagNodes.flushLast()) {
tagNodesAttrName.flushLast();
}
};
/**
* @private
* @return {Array}
*/ const getNodes = ()=>{
const lastNestedNode = nestedNodes.getLast();
if (lastNestedNode && Array.isArray(lastNestedNode.content)) {
return lastNestedNode.content;
}
return nodes.toArray();
};
/**
* @private
* @param {string|TagNode} node
* @param {boolean} isNested
*/ const appendNodeAsString = (node, isNested = true)=>{
const items = getNodes();
if (Array.isArray(items)) {
items.push(node.toTagStart({
openTag,
closeTag
}));
if (node.content.length) {
node.content.forEach((item)=>{
items.push(item);
});
if (isNested) {
items.push(node.toTagEnd({
openTag,
closeTag
}));
}
}
}
};
/**
* @private
* @param {string|TagNode} node
*/ const appendNodes = (node)=>{
const items = getNodes();
if (Array.isArray(items)) {
if (pluginHelper.isTagNode(node)) {
if (isAllowedTag(node.tag)) {
items.push(node.toTagNode());
} else {
appendNodeAsString(node);
}
} else {
items.push(node);
}
}
};
/**
* @private
* @param {Token} token
*/ const handleTagStart = (token)=>{
flushTagNodes();
const tagNode = pluginHelper.TagNode.create(token.getValue());
const isNested = isTokenNested(token);
tagNodes.push(tagNode);
if (isNested) {
nestedNodes.push(tagNode);
} else {
appendNodes(tagNode);
}
};
/**
* @private
* @param {Token} token
*/ const handleTagEnd = (token)=>{
flushTagNodes();
const lastNestedNode = nestedNodes.flushLast();
if (lastNestedNode) {
appendNodes(lastNestedNode);
} else if (typeof options.onError === 'function') {
const tag = token.getValue();
const line = token.getLine();
const 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
*/ const handleTag = (token)=>{
// [tag]
if (token.isStart()) {
handleTagStart(token);
}
// [/tag]
if (token.isEnd()) {
handleTagEnd(token);
}
};
/**
* @private
* @param {Token} token
*/ const handleNode = (token)=>{
/**
* @type {TagNode}
*/ const lastTagNode = tagNodes.getLast();
const tokenValue = token.getValue();
const isNested = isTagNested(token);
if (lastTagNode) {
if (token.isAttrName()) {
tagNodesAttrName.push(tokenValue);
lastTagNode.attr(tagNodesAttrName.getLast(), '');
} else if (token.isAttrValue()) {
const 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
*/ const onToken = (token)=>{
if (token.isTag()) {
handleTag(token);
} else {
handleNode(token);
}
};
tokenizer = (opts.createTokenizer ? opts.createTokenizer : createLexer)(input, {
onToken,
openTag,
closeTag,
onlyAllowTags: options.onlyAllowTags,
contextFreeTags: options.contextFreeTags,
enableEscapeTags: options.enableEscapeTags
});
// eslint-disable-next-line no-unused-vars
tokenizer.tokenize();
// handles situations where we open tag, but forgot close them
// for ex [q]test[/q][u]some[/u][q]some [u]some[/u] // forgot to close [/q]
// so we need to flush nested content to nodes array
const lastNestedNode = nestedNodes.flushLast();
if (lastNestedNode && isTagNested(lastNestedNode.tag)) {
appendNodeAsString(lastNestedNode, false);
}
return nodes.toArray();
};
// type, value, line, row,
const TOKEN_TYPE_ID = 't'; // 0;
const TOKEN_VALUE_ID = 'v'; // 1;
const TOKEN_COLUMN_ID = 'r'; // 2;
const TOKEN_LINE_ID = 'l'; // 3;
const TOKEN_TYPE_WORD = 1; // 'word';
const TOKEN_TYPE_TAG = 2; // 'tag';
const TOKEN_TYPE_ATTR_NAME = 3; // 'attr-name';
const TOKEN_TYPE_ATTR_VALUE = 4; // 'attr-value';
const TOKEN_TYPE_SPACE = 5; // 'space';
const TOKEN_TYPE_NEW_LINE = 6; // 'new-line';
const getTokenValue = (token)=>{
if (token && typeof token[TOKEN_VALUE_ID] !== 'undefined') {
return token[TOKEN_VALUE_ID];
}
return '';
};
const getTokenLine = (token)=>token && token[TOKEN_LINE_ID] || 0;
const getTokenColumn = (token)=>token && token[TOKEN_COLUMN_ID] || 0;
const 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;
};
const isTagToken = (token)=>{
if (token && typeof token[TOKEN_TYPE_ID] !== 'undefined') {
return token[TOKEN_TYPE_ID] === TOKEN_TYPE_TAG;
}
return false;
};
const isTagEnd = (token)=>getTokenValue(token).charCodeAt(0) === SLASH.charCodeAt(0);
const isTagStart = (token)=>!isTagEnd(token);
const isAttrNameToken = (token)=>{
if (token && typeof token[TOKEN_TYPE_ID] !== 'undefined') {
return token[TOKEN_TYPE_ID] === TOKEN_TYPE_ATTR_NAME;
}
return false;
};
const isAttrValueToken = (token)=>{
if (token && typeof token[TOKEN_TYPE_ID] !== 'undefined') {
return token[TOKEN_TYPE_ID] === TOKEN_TYPE_ATTR_VALUE;
}
return false;
};
const getTagName = (token)=>{
const value = getTokenValue(token);
return isTagEnd(token) ? value.slice(1) : value;
};
const tokenToText = (token)=>{
let text = OPEN_BRAKET;
text += getTokenValue(token);
text += CLOSE_BRAKET;
return text;
};
/**
* @export
* @class Token
*/ class Token {
get type() {
return this[TOKEN_TYPE_ID];
}
isEmpty() {
return this[TOKEN_TYPE_ID] === 0 || isNaN(this[TOKEN_TYPE_ID]);
}
isText() {
return isTextToken(this);
}
isTag() {
return isTagToken(this);
}
isAttrName() {
return isAttrNameToken(this);
}
isAttrValue() {
return isAttrValueToken(this);
}
isStart() {
return isTagStart(this);
}
isEnd() {
return isTagEnd(this);
}
getName() {
return getTagName(this);
}
getValue() {
return getTokenValue(this);
}
getLine() {
return getTokenLine(this);
}
getColumn() {
return getTokenColumn(this);
}
toString() {
return tokenToText(this);
}
constructor(type, value, row = 0, col = 0){
this[TOKEN_LINE_ID] = row;
this[TOKEN_COLUMN_ID] = col;
this[TOKEN_TYPE_ID] = type || 0;
this[TOKEN_VALUE_ID] = String(value);
}
}
const TYPE_WORD = TOKEN_TYPE_WORD;
const TYPE_TAG = TOKEN_TYPE_TAG;
const TYPE_ATTR_NAME = TOKEN_TYPE_ATTR_NAME;
const TYPE_ATTR_VALUE = TOKEN_TYPE_ATTR_VALUE;
const TYPE_SPACE = TOKEN_TYPE_SPACE;
const TYPE_NEW_LINE = TOKEN_TYPE_NEW_LINE;
Object.defineProperty(exports, 'TagNode', {
enumerable: true,
get: function () { return pluginHelper.TagNode; }
});
exports.default = parse;
exports.parse = parse;
class CharGrabber {
skip(num = 1, silent) {
this.c.pos += num;
if (this.o && this.o.onSkip && !silent) {
this.o.onSkip();
}
}
hasNext() {
return this.c.len > this.c.pos;
}
getCurr() {
if (typeof this.s[this.c.pos] === 'undefined') {
return '';
}
return this.s[this.c.pos];
}
getRest() {
return this.s.substring(this.c.pos);
}
getNext() {
const nextPos = this.c.pos + 1;
return nextPos <= this.s.length - 1 ? this.s[nextPos] : null;
}
getPrev() {
const prevPos = this.c.pos - 1;
if (typeof this.s[prevPos] === 'undefined') {
return null;
}
return this.s[prevPos];
}
isLast() {
return this.c.pos === this.c.len;
}
includes(val) {
return this.s.indexOf(val, this.c.pos) >= 0;
}
grabWhile(condition, silent) {
let start = 0;
if (this.hasNext()) {
start = this.c.pos;
while(this.hasNext() && condition(this.getCurr())){
this.skip(1, silent);
}
}
return this.s.substring(start, this.c.pos);
}
grabN(num = 0) {
return this.s.substring(this.c.pos, this.c.pos + num);
}
/**
* Grabs rest of string until it find a char
*/ substrUntilChar(char) {
const { pos } = this.c;
const idx = this.s.indexOf(char, pos);
return idx >= 0 ? this.s.substring(pos, idx) : '';
}
constructor(source, options = {}){
this.s = source;
this.c = {
pos: 0,
len: source.length
};
this.o = options;
}
}
/**
* Creates a grabber wrapper for source string, that helps to iterate over string char by char
*/ const createCharGrabber = (source, options)=>new CharGrabber(source, options);
/**
* Trims string from start and end by char
* @example
* trimChar('*hello*', '*') ==> 'hello'
*/ const 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 "
*/ const unquote = (str)=>str.replace(BACKSLASH + QUOTEMARK, QUOTEMARK);
Object.defineProperty(exports, '__esModule', { value: true });
// for cases <!-- -->
const EM = '!';
function createTokenOfType(type, value, r = 0, cl = 0) {
return new Token(type, value, r, cl);
}
const STATE_WORD = 0;
const STATE_TAG = 1;
const STATE_TAG_ATTRS = 2;
const TAG_STATE_NAME = 0;
const TAG_STATE_ATTR = 1;
const TAG_STATE_VALUE = 2;
const WHITESPACES = [
SPACE,
TAB
];
const SPECIAL_CHARS = [
EQ,
SPACE,
TAB
];
const isWhiteSpace = (char)=>WHITESPACES.indexOf(char) >= 0;
const isEscapeChar = (char)=>char === BACKSLASH;
const isSpecialChar = (char)=>SPECIAL_CHARS.indexOf(char) >= 0;
const isNewLine = (char)=>char === N;
const unq = (val)=>unquote(trimChar(val, QUOTEMARK));
function createLexer(buffer, options = {}) {
let row = 0;
let col = 0;
let tokenIndex = -1;
let stateMode = STATE_WORD;
let tagMode = TAG_STATE_NAME;
let contextFreeTag = '';
const tokens = new Array(Math.floor(buffer.length));
const openTag = options.openTag || OPEN_BRAKET;
const closeTag = options.closeTag || CLOSE_BRAKET;
const escapeTags = !!options.enableEscapeTags;
const contextFreeTags = (options.contextFreeTags || []).filter(Boolean).map((tag)=>tag.toLowerCase());
const nestedMap = new Map();
const onToken = options.onToken || (()=>{});
const RESERVED_CHARS = [
closeTag,
openTag,
QUOTEMARK,
BACKSLASH,
SPACE,
TAB,
EQ,
N,
EM
];
const NOT_CHAR_TOKENS = [
openTag,
SPACE,
TAB,
N
];
const isCharReserved = (char)=>RESERVED_CHARS.indexOf(char) >= 0;
const isCharToken = (char)=>NOT_CHAR_TOKENS.indexOf(char) === -1;
const isEscapableChar = (char)=>char === openTag || char === closeTag || char === BACKSLASH;
const onSkip = ()=>{
col++;
};
const checkContextFreeMode = (name, isClosingTag)=>{
if (contextFreeTag !== '' && isClosingTag) {
contextFreeTag = '';
}
if (contextFreeTag === '' && contextFreeTags.includes(name.toLowerCase())) {
contextFreeTag = name;
}
};
const chars = createCharGrabber(buffer, {
onSkip
});
/**
* Emits newly created token to subscriber
* @param {Number} type
* @param {String} value
*/ function emitToken(type, value) {
const token = createTokenOfType(type, value, row, col);
onToken(token);
tokenIndex += 1;
tokens[tokenIndex] = token;
}
function nextTagState(tagChars, isSingleValueTag) {
if (tagMode === TAG_STATE_ATTR) {
const validAttrName = (char)=>!(char === EQ || isWhiteSpace(char));
const name = tagChars.grabWhile(validAttrName);
const isEnd = tagChars.isLast();
const isValue = tagChars.getCurr() !== EQ;
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) {
let stateSpecial = false;
const validAttrValue = (char)=>{
// const isEQ = char === EQ;
const isQM = char === QUOTEMARK;
const prevChar = tagChars.getPrev();
const nextChar = tagChars.getNext();
const isPrevSLASH = prevChar === BACKSLASH;
const isNextEQ = nextChar === EQ;
const isWS = isWhiteSpace(char);
// const isPrevWS = isWhiteSpace(prevChar);
const isNextWS = nextChar && isWhiteSpace(nextChar);
if (stateSpecial && isSpecialChar(char)) {
return true;
}
if (isQM && !isPrevSLASH) {
stateSpecial = !stateSpecial;
if (!stateSpecial && !(isNextEQ || isNextWS)) {
return false;
}
}
if (!isSingleValueTag) {
return !isWS;
// return (isEQ || isWS) === false;
}
return true;
};
const name = tagChars.grabWhile(validAttrValue);
tagChars.skip();
emitToken(TYPE_ATTR_VALUE, unq(name));
if (tagChars.isLast()) {
return TAG_STATE_NAME;
}
return TAG_STATE_ATTR;
}
const validName = (char)=>!(char === EQ || isWhiteSpace(char) || tagChars.isLast());
const name = tagChars.grabWhile(validName);
emitToken(TYPE_TAG, name);
checkContextFreeMode(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;
}
const hasEQ = tagChars.includes(EQ);
return hasEQ ? TAG_STATE_ATTR : TAG_STATE_VALUE;
}
function stateTag() {
const currChar = chars.getCurr();
const nextChar = chars.getNext();
chars.skip();
// detect case where we have '[My word [tag][/tag]' or we have '[My last line word'
const substr = chars.substrUntilChar(closeTag);
const hasInvalidChars = substr.length === 0 || substr.indexOf(openTag) >= 0;
if (nextChar && isCharReserved(nextChar) || hasInvalidChars || chars.isLast()) {
emitToken(TYPE_WORD, currChar);
return STATE_WORD;
}
// [myTag ]
const isNoAttrsInTag = substr.indexOf(EQ) === -1;
// [/myTag]
const isClosingTag = substr[0] === SLASH;
if (isNoAttrsInTag || isClosingTag) {
const name = chars.grabWhile((char)=>char !== closeTag);
chars.skip(); // skip closeTag
emitToken(TYPE_TAG, name);
checkContextFreeMode(name, isClosingTag);
return STATE_WORD;
}
return STATE_TAG_ATTRS;
}
function stateAttrs() {
const silent = true;
const tagStr = chars.grabWhile((char)=>char !== closeTag, silent);
const tagGrabber = createCharGrabber(tagStr, {
onSkip
});
const hasSpace = tagGrabber.includes(SPACE);
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())) {
const word = chars.grabWhile(isWhiteSpace);
emitToken(TYPE_SPACE, word);
return STATE_WORD;
}
if (chars.getCurr() === openTag) {
if (contextFreeTag) {
const fullTagLen = openTag.length + SLASH.length + contextFreeTag.length;
const fullTagName = `${openTag}${SLASH}${contextFreeTag}`;
const foundTag = chars.grabN(fullTagLen);
const isEndContextFreeMode = foundTag === fullTagName;
if (isEndContextFreeMode) {
return STATE_TAG;
}
} else if (chars.includes(closeTag)) {
return STATE_TAG;
}
emitToken(TYPE_WORD, chars.getCurr());
chars.skip();
return STATE_WORD;
}
if (escapeTags) {
if (isEscapeChar(chars.getCurr())) {
const currChar = chars.getCurr();
const nextChar = chars.getNext();
chars.skip(); // skip the \ without emitting anything
if (nextChar && isEscapableChar(nextChar)) {
chars.skip(); // skip past the [, ] or \ as well
emitToken(TYPE_WORD, nextChar);
return STATE_WORD;
}
emitToken(TYPE_WORD, currChar);
return STATE_WORD;
}
const isChar = (char)=>isCharToken(char) && !isEscapeChar(char);
const word = chars.grabWhile(isChar);
emitToken(TYPE_WORD, word);
return STATE_WORD;
}
const word = chars.grabWhile(isCharToken);
emitToken(TYPE_WORD, word);
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:
default:
stateMode = stateWord();
break;
}
}
tokens.length = tokenIndex + 1;
return tokens;
}
function isTokenNested(token) {
const value = openTag + SLASH + token.getValue();
if (nestedMap.has(value)) {
return !!nestedMap.get(value);
} else {
const status = buffer.indexOf(value) > -1;
nestedMap.set(value, status);
return status;
}
}
return {
tokenize,
isTokenNested
};
}
class NodeList {
last() {
if (Array.isArray(this.n) && this.n.length > 0 && typeof this.n[this.n.length - 1] !== "undefined") {
return this.n[this.n.length - 1];
}
return null;
}
flush() {
return this.n.length ? this.n.pop() : false;
}
push(value) {
this.n.push(value);
}
toArray() {
return this.n;
}
constructor(){
this.n = [];
}
}
const createList = ()=>new NodeList();
function parse(input, opts = {}) {
const options = opts;
const openTag = options.openTag || OPEN_BRAKET;
const closeTag = options.closeTag || CLOSE_BRAKET;
const onlyAllowTags = (options.onlyAllowTags || []).filter(Boolean).map((tag)=>tag.toLowerCase());
let tokenizer = null;
/**
* Result AST of nodes
* @private
* @type {NodeList}
*/ const nodes = createList();
/**
* Temp buffer of nodes that's nested to another node
* @private
*/ const nestedNodes = createList();
/**
* Temp buffer of nodes [tag..]...[/tag]
* @private
* @type {NodeList}
*/ const tagNodes = createList();
/**
* Temp buffer of tag attributes
* @private
* @type {NodeList}
*/ const tagNodesAttrName = createList();
/**
* Cache for nested tags checks
*/ const nestedTagsMap = new Set();
function isTokenNested(token) {
const value = token.getValue();
const { isTokenNested } = tokenizer || {};
if (!nestedTagsMap.has(value) && isTokenNested && isTokenNested(token)) {
nestedTagsMap.add(value);
return true;
}
return nestedTagsMap.has(value);
}
/**
* @private
*/ function isTagNested(tagName) {
return Boolean(nestedTagsMap.has(tagName));
}
/**
* @private
*/ function isAllowedTag(value) {
if (onlyAllowTags.length) {
return onlyAllowTags.indexOf(value.toLowerCase()) >= 0;
}
return true;
}
/**
* Flushes temp tag nodes and its attributes buffers
* @private
*/ function flushTagNodes() {
if (tagNodes.flush()) {
tagNodesAttrName.flush();
}
}
/**
* @private
*/ function getNodes() {
const lastNestedNode = nestedNodes.last();
if (lastNestedNode && isTagNode(lastNestedNode)) {
return lastNestedNode.content;
}
return nodes.toArray();
}
/**
* @private
*/ function appendNodeAsString(nodes, node, isNested = true) {
if (Array.isArray(nodes) && typeof node !== "undefined") {
nodes.push(node.toTagStart({
openTag,
closeTag
}));
if (Array.isArray(node.content) && node.content.length) {
node.content.forEach((item)=>{
nodes.push(item);
});
if (isNested) {
nodes.push(node.toTagEnd({
openTag,
closeTag
}));
}
}
}
}
/**
* @private
*/ function appendNodes(nodes, node) {
if (Array.isArray(nodes) && typeof node !== "undefined") {
if (isTagNode(node)) {
if (isAllowedTag(node.tag)) {
nodes.push(node.toTagNode());
} else {
appendNodeAsString(nodes, node);
}
} else {
nodes.push(node);
}
}
}
/**
* @private
* @param {Token} token
*/ function handleTagStart(token) {
flushTagNodes();
const tagNode = TagNode.create(token.getValue(), {}, []);
const isNested = isTokenNested(token);
tagNodes.push(tagNode);
if (isNested) {
nestedNodes.push(tagNode);
} else {
const nodes = getNodes();
appendNodes(nodes, tagNode);
}
}
/**
* @private
* @param {Token} token
*/ function handleTagEnd(token) {
flushTagNodes();
const lastNestedNode = nestedNodes.flush();
if (lastNestedNode) {
const nodes = getNodes();
appendNodes(nodes, lastNestedNode);
} else if (typeof options.onError === "function") {
const tag = token.getValue();
const line = token.getLine();
const column = token.getColumn();
options.onError({
tagName: tag,
lineNumber: line,
columnNumber: column
});
}
}
/**
* @private
* @param {Token} token
*/ function handleTag(token) {
// [tag]
if (token.isStart()) {
handleTagStart(token);
}
// [/tag]
if (token.isEnd()) {
handleTagEnd(token);
}
}
/**
* @private
* @param {Token} token
*/ function handleNode(token) {
/**
* @type {TagNode}
*/ const activeTagNode = tagNodes.last();
const tokenValue = token.getValue();
const isNested = isTagNested(token.toString());
const nodes = getNodes();
if (activeTagNode !== null) {
if (token.isAttrName()) {
tagNodesAttrName.push(tokenValue);
const attrName = tagNodesAttrName.last();
if (attrName) {
activeTagNode.attr(attrName, "");
}
} else if (token.isAttrValue()) {
const attrName = tagNodesAttrName.last();
if (attrName) {
activeTagNode.attr(attrName, tokenValue);
tagNodesAttrName.flush();
} else {
activeTagNode.attr(tokenValue, tokenValue);
}
} else if (token.isText()) {
if (isNested) {
activeTagNode.append(tokenValue);
} else {
appendNodes(nodes, tokenValue);
}
} else if (token.isTag()) {
// if tag is not allowed, just pass it as is
appendNodes(nodes, token.toString());
}
} else if (token.isText()) {
appendNodes(nodes, tokenValue);
} else if (token.isTag()) {
// if tag is not allowed, just pass it as is
appendNodes(nodes, token.toString());
}
}
/**
* @private
* @param {Token} token
*/ function onToken(token) {
if (token.isTag()) {
handleTag(token);
} else {
handleNode(token);
}
}
const lexer = opts.createTokenizer ? opts.createTokenizer : createLexer;
tokenizer = lexer(input, {
onToken,
openTag,
closeTag,
onlyAllowTags: options.onlyAllowTags,
contextFreeTags: options.contextFreeTags,
enableEscapeTags: options.enableEscapeTags
});
// eslint-disable-next-line no-unused-vars
tokenizer.tokenize();
// handles situations where we open tag, but forgot close them
// for ex [q]test[/q][u]some[/u][q]some [u]some[/u] // forgot to close [/q]
// so we need to flush nested content to nodes array
const lastNestedNode = nestedNodes.flush();
if (lastNestedNode !== null && lastNestedNode && isTagNode(lastNestedNode) && isTagNested(lastNestedNode.tag)) {
appendNodeAsString(getNodes(), lastNestedNode, false);
}
return nodes.toArray();
}
exports.TagNode = TagNode;
exports.createLexer = createLexer;
exports.createTokenOfType = createTokenOfType;
exports.default = parse;
exports.parse = parse;
Object.defineProperty(exports, '__esModule', { value: true });
}));

@@ -1,1 +0,1 @@

!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("@bbob/plugin-helper")):"function"==typeof define&&define.amd?define(["exports","@bbob/plugin-helper"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).BbobParser={},e.pluginHelper)}(this,function(e,t){"use strict";let r="type",n="value",s="line",i=e=>e&&void 0!==e[n]?e[n]:"",l=e=>e&&e[s]||0,a=e=>e&&e.row||0,u=e=>!!e&&void 0!==e[r]&&(5===e[r]||6===e[r]||1===e[r]),o=e=>!!e&&void 0!==e[r]&&2===e[r],g=e=>i(e).charCodeAt(0)===t.SLASH.charCodeAt(0),h=e=>!g(e),f=e=>!!e&&void 0!==e[r]&&3===e[r],p=e=>!!e&&void 0!==e[r]&&4===e[r],A=e=>{let t=i(e);return g(e)?t.slice(1):t},c=e=>(t.OPEN_BRAKET,i(e)+t.CLOSE_BRAKET);class d{isEmpty(){return isNaN(this[r])}isText(){return u(this)}isTag(){return o(this)}isAttrName(){return f(this)}isAttrValue(){return p(this)}isStart(){return h(this)}isEnd(){return g(this)}getName(){return A(this)}getValue(){return i(this)}getLine(){return l(this)}getColumn(){return a(this)}toString(){return c(this)}constructor(e,t,i,l){this[r]=Number(e),this[n]=String(t),this[s]=Number(i),this.row=Number(l)}}function T(e,t){let r={pos:0,len:e.length},n=t=>{let{pos:n}=r,s=e.indexOf(t,n);return s>=0?e.substring(n,s):""},s=t=>e.indexOf(t,r.pos)>=0,i=()=>r.len>r.pos,l=(e=1,n)=>{r.pos+=e,t&&t.onSkip&&!n&&t.onSkip()},a=()=>e.substring(r.pos),u=(t=0)=>e.substring(r.pos,r.pos+t),o=()=>e[r.pos],g=()=>{let t=r.pos-1;return void 0!==e[t]?e[t]:null},h=()=>{let t=r.pos+1;return t<=e.length-1?e[t]:null},f=(t,n)=>{let s=0;if(i())for(s=r.pos;i()&&t(o());)l(1,n);return e.substring(s,r.pos)};this.skip=l,this.hasNext=i,this.getCurr=o,this.getRest=a,this.getNext=h,this.getPrev=g,this.isLast=()=>r.pos===r.len,this.includes=s,this.grabWhile=f,this.grabN=u,this.substrUntilChar=n}let b=(e,t)=>new T(e,t),E=(e,t)=>{for(;e.charAt(0)===t;)e=e.substring(1);for(;e.charAt(e.length-1)===t;)e=e.substring(0,e.length-1);return e},S=e=>e.replace(t.BACKSLASH+t.QUOTEMARK,t.QUOTEMARK);function N(e=[]){let t=()=>Array.isArray(e)&&e.length>0&&void 0!==e[e.length-1]?e[e.length-1]:null,r=()=>!!e.length&&e.pop(),n=t=>e.push(t);this.push=n,this.toArray=()=>e,this.getLast=t,this.flushLast=r}let L=(e=[])=>new N(e),C=(e,t,r=0,n=0)=>new d(e,t,r,n);function x(e,r={}){let n=0,s=0,i=-1,l=0,a=0,u="",o=Array(Math.floor(e.length)),g=r.openTag||t.OPEN_BRAKET,h=r.closeTag||t.CLOSE_BRAKET,f=!!r.enableEscapeTags,p=r.contextFreeTags||[],A=r.onToken||(()=>{}),c=[h,g,t.QUOTEMARK,t.BACKSLASH,t.SPACE,t.TAB,t.EQ,t.N,"!"],d=[g,t.SPACE,t.TAB,t.N],T=[t.SPACE,t.TAB],N=[t.EQ,t.SPACE,t.TAB],L=e=>c.indexOf(e)>=0,x=e=>e===t.N,y=e=>T.indexOf(e)>=0,k=e=>-1===d.indexOf(e),O=e=>N.indexOf(e)>=0,m=e=>e===g||e===h||e===t.BACKSLASH,B=e=>e===t.BACKSLASH,K=()=>{s++},P=e=>S(E(e,t.QUOTEMARK)),Q=(e,t)=>{""!==u&&t&&(u=""),""===u&&p.includes(e)&&(u=e)},w=b(e,{onSkip:K});function R(e,t){let r=C(e,t,n,s);A(r),o[i+=1]=r}return{tokenize:function(){for(l=0;w.hasNext();)switch(l){case 1:l=function(){let e=w.getCurr(),r=w.getNext();w.skip();let n=w.substrUntilChar(h),s=0===n.length||n.indexOf(g)>=0;if(L(r)||s||w.isLast())return R(1,e),0;let i=-1===n.indexOf(t.EQ),l=n[0]===t.SLASH;if(i||l){let a=w.grabWhile(e=>e!==h);return w.skip(),R(2,a),Q(a,l),0}return 2}();break;case 2:l=function(){let e=w.grabWhile(e=>e!==h,!0),r=b(e,{onSkip:K}),n=r.includes(t.SPACE);for(a=0;r.hasNext();)a=function(e,r){if(1===a){let n=e=>!(e===t.EQ||y(e)),s=e.grabWhile(n),i=e.isLast(),l=e.getCurr()!==t.EQ;return(e.skip(),i||l?R(4,P(s)):R(3,s),i)?0:l?1:2}if(2===a){let u=!1,o=n=>{let s=n===t.QUOTEMARK,i=e.getPrev(),l=e.getNext(),a=i===t.BACKSLASH,o=l===t.EQ,g=y(n),h=y(l);return!!(u&&O(n))||(!s||!!a||!!(u=!u)||!!o||!!h)&&(!!r||!1===g)},g=e.grabWhile(o);return(e.skip(),R(4,P(g)),e.isLast())?0:1}let h=r=>!(r===t.EQ||y(r)||e.isLast()),f=e.grabWhile(h);if(R(2,f),Q(f),e.skip(),r)return 2;let p=e.includes(t.EQ);return p?1:2}(r,!n);return w.skip(),0}();break;default:l=function(){if(x(w.getCurr()))return R(6,w.getCurr()),w.skip(),s=0,n++,0;if(y(w.getCurr())){let e=w.grabWhile(y);return R(5,e),0}if(w.getCurr()===g){if(u){let r=g.length+t.SLASH.length+u.length,i=`${g}${t.SLASH}${u}`,l=w.grabN(r);if(l===i)return 1}else if(w.includes(h))return 1;return R(1,w.getCurr()),w.skip(),0}if(f){if(B(w.getCurr())){let a=w.getCurr(),o=w.getNext();return(w.skip(),m(o))?(w.skip(),R(1,o),0):(R(1,a),0)}let p=e=>k(e)&&!B(e),A=w.grabWhile(p);return R(1,A),0}let c=w.grabWhile(k);return R(1,c),0}()}return o.length=i+1,o},isTokenNested:function(r){let n=g+t.SLASH+r.getValue();return e.indexOf(n)>-1}}}let y=(e,r={})=>{let n=r.openTag||t.OPEN_BRAKET,s=r.closeTag||t.CLOSE_BRAKET,i=(r.onlyAllowTags||[]).filter(Boolean).map(e=>e.toLowerCase()),l=null,a=L(),u=L(),o=L(),g=L(),h=new Set,f=e=>{let t=e.getValue();return!h.has(t)&&l.isTokenNested&&l.isTokenNested(e)?(h.add(t),!0):h.has(t)},p=e=>Boolean(h.has(e)),A=e=>!i.length||i.indexOf(e.toLowerCase())>=0,c=()=>{o.flushLast()&&g.flushLast()},d=()=>{let e=u.getLast();return e&&Array.isArray(e.content)?e.content:a.toArray()},T=(e,t=!0)=>{let r=d();Array.isArray(r)&&(r.push(e.toTagStart({openTag:n,closeTag:s})),e.content.length&&(e.content.forEach(e=>{r.push(e)}),t&&r.push(e.toTagEnd({openTag:n,closeTag:s}))))},b=e=>{let r=d();Array.isArray(r)&&(t.isTagNode(e)?A(e.tag)?r.push(e.toTagNode()):T(e):r.push(e))},E=e=>{c();let r=t.TagNode.create(e.getValue()),n=f(e);o.push(r),n?u.push(r):b(r)},S=e=>{c();let t=u.flushLast();if(t)b(t);else if("function"==typeof r.onError){let n=e.getValue(),s=e.getLine(),i=e.getColumn();r.onError({message:`Inconsistent tag '${n}' on line ${s} and column ${i}`,tagName:n,lineNumber:s,columnNumber:i})}},N=e=>{e.isStart()&&E(e),e.isEnd()&&S(e)},C=e=>{let t=o.getLast(),r=e.getValue(),n=p(e);if(t){if(e.isAttrName())g.push(r),t.attr(g.getLast(),"");else if(e.isAttrValue()){let s=g.getLast();s?(t.attr(s,r),g.flushLast()):t.attr(r,r)}else e.isText()?n?t.append(r):b(r):e.isTag()&&b(e.toString())}else e.isText()?b(r):e.isTag()&&b(e.toString())},y=e=>{e.isTag()?N(e):C(e)};(l=(r.createTokenizer?r.createTokenizer:x)(e,{onToken:y,openTag:n,closeTag:s,onlyAllowTags:r.onlyAllowTags,contextFreeTags:r.contextFreeTags,enableEscapeTags:r.enableEscapeTags})).tokenize();let k=u.flushLast();return k&&p(k.tag)&&T(k,!1),a.toArray()};Object.defineProperty(e,"TagNode",{enumerable:!0,get:function(){return t.TagNode}}),e.default=y,e.parse=y,Object.defineProperty(e,"__esModule",{value:!0})});
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).BbobParser={})}(this,function(t){"use strict";function e(t){return"object"==typeof t&&null!==t&&"tag"in t}function r(t,e,r){return Object.keys(t).reduce((r,n)=>e(r,n,t),r)}function n(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;").replace(/(javascript|data|vbscript):/gi,"$1%3A")}function s(t,e){switch(typeof e){case"boolean":return e?""+t:"";case"number":return`${t}="${e}"`;case"string":return`${t}="${n(e)}"`;case"object":return`${t}="${n(JSON.stringify(e))}"`;default:return""}}function i(t){return null==t?"":r(t,(t,e,r)=>[...t,s(e,r[e])],[""]).join(" ")}let u=(t,e)=>{let n=r(e||{},(t,e,r)=>r[e]===e?r[e]:null,null);if(n){let r=s(t,n),u={...e};delete u[n+""];let a=i(u);return`${r}${a}`}return`${t}${i(e)}`},a=(t,r,n)=>{let s=t=>e(t)?t.toString({openTag:r,closeTag:n}):t+"";return Array.isArray(t)?t.reduce((t,e)=>null!==e?t+s(e):t,""):t?s(t):null};class l{attr(t,e){return void 0!==e&&(this.attrs[t]=e),this.attrs[t]}append(t){Array.isArray(this.content)&&this.content.push(t)}get length(){return function t(r){return e(r)&&Array.isArray(r.content)?r.content.reduce((e,r)=>e+t(r),0):"string"==typeof r?(r+"").length:0}(this)}toTagStart({openTag:t="[",closeTag:e="]"}={}){let r=u(this.tag,this.attrs);return`${t}${r}${e}`}toTagEnd({openTag:t="[",closeTag:e="]"}={}){return`${t}/${this.tag}${e}`}toTagNode(){return new l(this.tag.toLowerCase(),this.attrs,this.content)}toString({openTag:t="[",closeTag:e="]"}={}){let r=this.content?a(this.content,t,e):"",n=this.toTagStart({openTag:t,closeTag:e});return null===this.content||Array.isArray(this.content)&&0===this.content.length?n:`${n}${r}${this.toTagEnd({openTag:t,closeTag:e})}`}static create(t,e={},r=null){return new l(t,e,r)}static isOf(t,e){return t.tag===e}constructor(t,e,r){this.tag=t,this.attrs=e,this.content=r}}let o=t=>t&&void 0!==t.v?t.v:"",h=t=>t&&t.l||0,c=t=>t&&t.r||0,g=t=>!!t&&void 0!==t.t&&(5===t.t||6===t.t||1===t.t),f=t=>!!t&&void 0!==t.t&&2===t.t,p=t=>47===o(t).charCodeAt(0),d=t=>!p(t),b=t=>!!t&&void 0!==t.t&&3===t.t,T=t=>!!t&&void 0!==t.t&&4===t.t,y=t=>{let e=o(t);return p(t)?e.slice(1):e},A=t=>"["+o(t)+"]";class x{get type(){return this.t}isEmpty(){return 0===this.t||isNaN(this.t)}isText(){return g(this)}isTag(){return f(this)}isAttrName(){return b(this)}isAttrValue(){return T(this)}isStart(){return d(this)}isEnd(){return p(this)}getName(){return y(this)}getValue(){return o(this)}getLine(){return h(this)}getColumn(){return c(this)}toString(){return A(this)}constructor(t,e,r=0,n=0){this.l=r,this.r=n,this.t=t||0,this.v=e+""}}class k{skip(t=1,e){this.c.pos+=t,this.o&&this.o.onSkip&&!e&&this.o.onSkip()}hasNext(){return this.c.len>this.c.pos}getCurr(){return void 0===this.s[this.c.pos]?"":this.s[this.c.pos]}getRest(){return this.s.substring(this.c.pos)}getNext(){let t=this.c.pos+1;return t<=this.s.length-1?this.s[t]:null}getPrev(){let t=this.c.pos-1;return void 0===this.s[t]?null:this.s[t]}isLast(){return this.c.pos===this.c.len}includes(t){return this.s.indexOf(t,this.c.pos)>=0}grabWhile(t,e){let r=0;if(this.hasNext())for(r=this.c.pos;this.hasNext()&&t(this.getCurr());)this.skip(1,e);return this.s.substring(r,this.c.pos)}grabN(t=0){return this.s.substring(this.c.pos,this.c.pos+t)}substrUntilChar(t){let{pos:e}=this.c,r=this.s.indexOf(t,e);return r>=0?this.s.substring(e,r):""}constructor(t,e={}){this.s=t,this.c={pos:0,len:t.length},this.o=e}}let N=(t,e)=>new k(t,e),v=(t,e)=>{for(;t.charAt(0)===e;)t=t.substring(1);for(;t.charAt(t.length-1)===e;)t=t.substring(0,t.length-1);return t},$=t=>t.replace('\\"','"');function C(t,e,r=0,n=0){return new x(t,e,r,n)}let w=[" "," "],m=["="," "," "],O=t=>w.indexOf(t)>=0,S=t=>"\\"===t,L=t=>m.indexOf(t)>=0,E=t=>"\n"===t,W=t=>$(v(t,'"'));function V(t,e={}){let r=0,n=0,s=-1,i=0,u=0,a="",l=Array(Math.floor(t.length)),o=e.openTag||"[",h=e.closeTag||"]",c=!!e.enableEscapeTags,g=(e.contextFreeTags||[]).filter(Boolean).map(t=>t.toLowerCase()),f=new Map,p=e.onToken||(()=>{}),d=[h,o,'"',"\\"," "," ","=","\n","!"],b=[o," "," ","\n"],T=t=>d.indexOf(t)>=0,y=t=>-1===b.indexOf(t),A=t=>t===o||t===h||"\\"===t,x=()=>{n++},k=(t,e)=>{""!==a&&e&&(a=""),""===a&&g.includes(t.toLowerCase())&&(a=t)},v=N(t,{onSkip:x});function $(t,e){let i=C(t,e,r,n);p(i),l[s+=1]=i}return{tokenize:function(){for(i=0;v.hasNext();)switch(i){case 1:i=function(){let t=v.getCurr(),e=v.getNext();v.skip();let r=v.substrUntilChar(h),n=0===r.length||r.indexOf(o)>=0;if(e&&T(e)||n||v.isLast())return $(1,t),0;let s=-1===r.indexOf("="),i="/"===r[0];if(s||i){let t=v.grabWhile(t=>t!==h);return v.skip(),$(2,t),k(t,i),0}return 2}();break;case 2:i=function(){let t=N(v.grabWhile(t=>t!==h,!0),{onSkip:x}),e=t.includes(" ");for(u=0;t.hasNext();)u=function(t,e){if(1===u){let e=t.grabWhile(t=>!("="===t||O(t))),r=t.isLast(),n="="!==t.getCurr();return(t.skip(),r||n?$(4,W(e)):$(3,e),r)?0:n?1:2}if(2===u){let r=!1,n=t.grabWhile(n=>{let s='"'===n,i=t.getPrev(),u=t.getNext(),a="="===u,l=O(n),o=u&&O(u);return!!(r&&L(n))||(!s||"\\"===i||!!(r=!r)||!!a||!!o)&&(!!e||!l)});return(t.skip(),$(4,W(n)),t.isLast())?0:1}let r=t.grabWhile(e=>!("="===e||O(e)||t.isLast()));return($(2,r),k(r),t.skip(),e)?2:t.includes("=")?1:2}(t,!e);return v.skip(),0}();break;default:i=function(){if(E(v.getCurr()))return $(6,v.getCurr()),v.skip(),n=0,r++,0;if(O(v.getCurr()))return $(5,v.grabWhile(O)),0;if(v.getCurr()===o){if(a){let t=o.length+1+a.length,e=`${o}/${a}`;if(v.grabN(t)===e)return 1}else if(v.includes(h))return 1;return $(1,v.getCurr()),v.skip(),0}if(c){if(S(v.getCurr())){let t=v.getCurr(),e=v.getNext();return(v.skip(),e&&A(e))?(v.skip(),$(1,e)):$(1,t),0}return $(1,v.grabWhile(t=>y(t)&&!S(t))),0}return $(1,v.grabWhile(y)),0}()}return l.length=s+1,l},isTokenNested:function(e){let r=o+"/"+e.getValue();if(f.has(r))return!!f.get(r);{let e=t.indexOf(r)>-1;return f.set(r,e),e}}}}class j{last(){return Array.isArray(this.n)&&this.n.length>0&&void 0!==this.n[this.n.length-1]?this.n[this.n.length-1]:null}flush(){return!!this.n.length&&this.n.pop()}push(t){this.n.push(t)}toArray(){return this.n}constructor(){this.n=[]}}let z=()=>new j;function P(t,r={}){var n;let s=r.openTag||"[",i=r.closeTag||"]",u=(r.onlyAllowTags||[]).filter(Boolean).map(t=>t.toLowerCase()),a=null,o=z(),h=z(),c=z(),g=z(),f=new Set;function p(){c.flush()&&g.flush()}function d(){let t=h.last();return t&&e(t)?t.content:o.toArray()}function b(t,e,r=!0){Array.isArray(t)&&void 0!==e&&(t.push(e.toTagStart({openTag:s,closeTag:i})),Array.isArray(e.content)&&e.content.length&&(e.content.forEach(e=>{t.push(e)}),r&&t.push(e.toTagEnd({openTag:s,closeTag:i}))))}function T(t,r){if(Array.isArray(t)&&void 0!==r){if(e(r)){var n;(n=r.tag,!u.length||u.indexOf(n.toLowerCase())>=0)?t.push(r.toTagNode()):b(t,r)}else t.push(r)}}(a=(r.createTokenizer?r.createTokenizer:V)(t,{onToken:function(t){t.isTag()?(t.isStart()&&function(t){p();let e=l.create(t.getValue(),{},[]),r=function(t){let e=t.getValue(),{isTokenNested:r}=a||{};return!f.has(e)&&r&&r(t)?(f.add(e),!0):f.has(e)}(t);c.push(e),r?h.push(e):T(d(),e)}(t),t.isEnd()&&function(t){p();let e=h.flush();if(e)T(d(),e);else if("function"==typeof r.onError){let e=t.getValue(),n=t.getLine(),s=t.getColumn();r.onError({tagName:e,lineNumber:n,columnNumber:s})}}(t)):!function(t){var e;let r=c.last(),n=t.getValue(),s=(e=t.toString(),!!f.has(e)),i=d();if(null!==r){if(t.isAttrName()){g.push(n);let t=g.last();t&&r.attr(t,"")}else if(t.isAttrValue()){let t=g.last();t?(r.attr(t,n),g.flush()):r.attr(n,n)}else t.isText()?s?r.append(n):T(i,n):t.isTag()&&T(i,t.toString())}else t.isText()?T(i,n):t.isTag()&&T(i,t.toString())}(t)},openTag:s,closeTag:i,onlyAllowTags:r.onlyAllowTags,contextFreeTags:r.contextFreeTags,enableEscapeTags:r.enableEscapeTags})).tokenize();let y=h.flush();return null!==y&&y&&e(y)&&(n=y.tag,f.has(n))&&b(d(),y,!1),o.toArray()}t.TagNode=l,t.createLexer=V,t.createTokenOfType=C,t.default=P,t.parse=P,Object.defineProperty(t,"__esModule",{value:!0})});
export { TagNode } from '@bbob/plugin-helper';
export { default, parse } from './parse';
export { default } from './parse';
export * from './parse';
export * from './lexer';

@@ -6,28 +6,26 @@ /* eslint-disable no-plusplus,no-param-reassign */ import { OPEN_BRAKET, CLOSE_BRAKET, QUOTEMARK, BACKSLASH, SLASH, SPACE, TAB, EQ, N } from '@bbob/plugin-helper';

const EM = '!';
/**
* Creates a Token entity class
* @param {Number} type
* @param {String} value
* @param {Number} r line number
* @param {Number} cl char number in line
*/ const createToken = (type, value, r = 0, cl = 0)=>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 = {}) {
const STATE_WORD = 0;
const STATE_TAG = 1;
const STATE_TAG_ATTRS = 2;
const TAG_STATE_NAME = 0;
const TAG_STATE_ATTR = 1;
const TAG_STATE_VALUE = 2;
export function createTokenOfType(type, value, r = 0, cl = 0) {
return new Token(type, value, r, cl);
}
const STATE_WORD = 0;
const STATE_TAG = 1;
const STATE_TAG_ATTRS = 2;
const TAG_STATE_NAME = 0;
const TAG_STATE_ATTR = 1;
const TAG_STATE_VALUE = 2;
const WHITESPACES = [
SPACE,
TAB
];
const SPECIAL_CHARS = [
EQ,
SPACE,
TAB
];
const isWhiteSpace = (char)=>WHITESPACES.indexOf(char) >= 0;
const isEscapeChar = (char)=>char === BACKSLASH;
const isSpecialChar = (char)=>SPECIAL_CHARS.indexOf(char) >= 0;
const isNewLine = (char)=>char === N;
const unq = (val)=>unquote(trimChar(val, QUOTEMARK));
export function createLexer(buffer, options = {}) {
let row = 0;

@@ -43,3 +41,4 @@ let col = 0;

const escapeTags = !!options.enableEscapeTags;
const contextFreeTags = options.contextFreeTags || [];
const contextFreeTags = (options.contextFreeTags || []).filter(Boolean).map((tag)=>tag.toLowerCase());
const nestedMap = new Map();
const onToken = options.onToken || (()=>{});

@@ -63,22 +62,8 @@ const RESERVED_CHARS = [

];
const WHITESPACES = [
SPACE,
TAB
];
const SPECIAL_CHARS = [
EQ,
SPACE,
TAB
];
const isCharReserved = (char)=>RESERVED_CHARS.indexOf(char) >= 0;
const isNewLine = (char)=>char === N;
const isWhiteSpace = (char)=>WHITESPACES.indexOf(char) >= 0;
const isCharToken = (char)=>NOT_CHAR_TOKENS.indexOf(char) === -1;
const isSpecialChar = (char)=>SPECIAL_CHARS.indexOf(char) >= 0;
const isEscapableChar = (char)=>char === openTag || char === closeTag || char === BACKSLASH;
const isEscapeChar = (char)=>char === BACKSLASH;
const onSkip = ()=>{
col++;
};
const unq = (val)=>unquote(trimChar(val, QUOTEMARK));
const checkContextFreeMode = (name, isClosingTag)=>{

@@ -88,3 +73,3 @@ if (contextFreeTag !== '' && isClosingTag) {

}
if (contextFreeTag === '' && contextFreeTags.includes(name)) {
if (contextFreeTag === '' && contextFreeTags.includes(name.toLowerCase())) {
contextFreeTag = name;

@@ -101,3 +86,3 @@ }

*/ function emitToken(type, value) {
const token = createToken(type, value, row, col);
const token = createTokenOfType(type, value, row, col);
onToken(token);

@@ -138,3 +123,3 @@ tokenIndex += 1;

// const isPrevWS = isWhiteSpace(prevChar);
const isNextWS = isWhiteSpace(nextChar);
const isNextWS = nextChar && isWhiteSpace(nextChar);
if (stateSpecial && isSpecialChar(char)) {

@@ -150,3 +135,3 @@ return true;

if (!isSingleValueTag) {
return isWS === false;
return !isWS;
// return (isEQ || isWS) === false;

@@ -156,5 +141,5 @@ }

};
const name1 = tagChars.grabWhile(validAttrValue);
const name = tagChars.grabWhile(validAttrValue);
tagChars.skip();
emitToken(TYPE_ATTR_VALUE, unq(name1));
emitToken(TYPE_ATTR_VALUE, unq(name));
if (tagChars.isLast()) {

@@ -166,5 +151,5 @@ return TAG_STATE_NAME;

const validName = (char)=>!(char === EQ || isWhiteSpace(char) || tagChars.isLast());
const name2 = tagChars.grabWhile(validName);
emitToken(TYPE_TAG, name2);
checkContextFreeMode(name2);
const name = tagChars.grabWhile(validName);
emitToken(TYPE_TAG, name);
checkContextFreeMode(name);
tagChars.skip();

@@ -185,3 +170,3 @@ // in cases when we has [url=someval]GET[/url] and we dont need to parse all

const hasInvalidChars = substr.length === 0 || substr.indexOf(openTag) >= 0;
if (isCharReserved(nextChar) || hasInvalidChars || chars.isLast()) {
if (nextChar && isCharReserved(nextChar) || hasInvalidChars || chars.isLast()) {
emitToken(TYPE_WORD, currChar);

@@ -251,3 +236,3 @@ return STATE_WORD;

chars.skip(); // skip the \ without emitting anything
if (isEscapableChar(nextChar)) {
if (nextChar && isEscapableChar(nextChar)) {
chars.skip(); // skip past the [, ] or \ as well

@@ -261,8 +246,8 @@ emitToken(TYPE_WORD, nextChar);

const isChar = (char)=>isCharToken(char) && !isEscapeChar(char);
const word1 = chars.grabWhile(isChar);
emitToken(TYPE_WORD, word1);
const word = chars.grabWhile(isChar);
emitToken(TYPE_WORD, word);
return STATE_WORD;
}
const word2 = chars.grabWhile(isCharToken);
emitToken(TYPE_WORD, word2);
const word = chars.grabWhile(isCharToken);
emitToken(TYPE_WORD, word);
return STATE_WORD;

@@ -291,4 +276,9 @@ }

const value = openTag + SLASH + token.getValue();
// potential bottleneck
return buffer.indexOf(value) > -1;
if (nestedMap.has(value)) {
return !!nestedMap.get(value);
} else {
const status = buffer.indexOf(value) > -1;
nestedMap.set(value, status);
return status;
}
}

@@ -300,3 +290,1 @@ return {

}
export const createTokenOfType = createToken;
export { createLexer };

@@ -1,16 +0,25 @@

import { TagNode, CLOSE_BRAKET, OPEN_BRAKET, isTagNode } from '@bbob/plugin-helper';
import { createLexer } from './lexer';
import { createList } from './utils';
/**
* @public
* @param {string} input
* @param {Object} opts
* @param {Function} opts.createTokenizer
* @param {Array<string>} opts.onlyAllowTags
* @param {Array<string>} opts.contextFreeTags
* @param {Boolean} opts.enableEscapeTags
* @param {string} opts.openTag
* @param {string} opts.closeTag
* @return {Array<string|TagNode>}
*/ const parse = (input, opts = {})=>{
import { CLOSE_BRAKET, OPEN_BRAKET, TagNode, isTagNode } from "@bbob/plugin-helper";
import { createLexer } from "./lexer";
class NodeList {
last() {
if (Array.isArray(this.n) && this.n.length > 0 && typeof this.n[this.n.length - 1] !== "undefined") {
return this.n[this.n.length - 1];
}
return null;
}
flush() {
return this.n.length ? this.n.pop() : false;
}
push(value) {
this.n.push(value);
}
toArray() {
return this.n;
}
constructor(){
this.n = [];
}
}
const createList = ()=>new NodeList();
function parse(input, opts = {}) {
const options = opts;

@@ -29,3 +38,2 @@ const openTag = options.openTag || OPEN_BRAKET;

* @private
* @type {NodeList}
*/ const nestedNodes = createList();

@@ -44,10 +52,7 @@ /**

* Cache for nested tags checks
* @type Set<string>
*/ const nestedTagsMap = new Set();
/**
* @param {Token} token
* @returns {boolean}
*/ const isTokenNested = (token)=>{
function isTokenNested(token) {
const value = token.getValue();
if (!nestedTagsMap.has(value) && tokenizer.isTokenNested && tokenizer.isTokenNested(token)) {
const { isTokenNested } = tokenizer || {};
if (!nestedTagsMap.has(value) && isTokenNested && isTokenNested(token)) {
nestedTagsMap.add(value);

@@ -57,13 +62,11 @@ return true;

return nestedTagsMap.has(value);
};
}
/**
* @private
* @param {string} tagName
* @returns {boolean}
*/ const isTagNested = (tagName)=>Boolean(nestedTagsMap.has(tagName));
*/ function isTagNested(tagName) {
return Boolean(nestedTagsMap.has(tagName));
}
/**
* @private
* @param {string} value
* @return {boolean}
*/ const isAllowedTag = (value)=>{
*/ function isAllowedTag(value) {
if (onlyAllowTags.length) {

@@ -73,39 +76,34 @@ return onlyAllowTags.indexOf(value.toLowerCase()) >= 0;

return true;
};
}
/**
* Flushes temp tag nodes and its attributes buffers
* @private
* @return {Array}
*/ const flushTagNodes = ()=>{
if (tagNodes.flushLast()) {
tagNodesAttrName.flushLast();
*/ function flushTagNodes() {
if (tagNodes.flush()) {
tagNodesAttrName.flush();
}
};
}
/**
* @private
* @return {Array}
*/ const getNodes = ()=>{
const lastNestedNode = nestedNodes.getLast();
if (lastNestedNode && Array.isArray(lastNestedNode.content)) {
*/ function getNodes() {
const lastNestedNode = nestedNodes.last();
if (lastNestedNode && isTagNode(lastNestedNode)) {
return lastNestedNode.content;
}
return nodes.toArray();
};
}
/**
* @private
* @param {string|TagNode} node
* @param {boolean} isNested
*/ const appendNodeAsString = (node, isNested = true)=>{
const items = getNodes();
if (Array.isArray(items)) {
items.push(node.toTagStart({
*/ function appendNodeAsString(nodes, node, isNested = true) {
if (Array.isArray(nodes) && typeof node !== "undefined") {
nodes.push(node.toTagStart({
openTag,
closeTag
}));
if (node.content.length) {
if (Array.isArray(node.content) && node.content.length) {
node.content.forEach((item)=>{
items.push(item);
nodes.push(item);
});
if (isNested) {
items.push(node.toTagEnd({
nodes.push(node.toTagEnd({
openTag,

@@ -117,26 +115,24 @@ closeTag

}
};
}
/**
* @private
* @param {string|TagNode} node
*/ const appendNodes = (node)=>{
const items = getNodes();
if (Array.isArray(items)) {
*/ function appendNodes(nodes, node) {
if (Array.isArray(nodes) && typeof node !== "undefined") {
if (isTagNode(node)) {
if (isAllowedTag(node.tag)) {
items.push(node.toTagNode());
nodes.push(node.toTagNode());
} else {
appendNodeAsString(node);
appendNodeAsString(nodes, node);
}
} else {
items.push(node);
nodes.push(node);
}
}
};
}
/**
* @private
* @param {Token} token
*/ const handleTagStart = (token)=>{
*/ function handleTagStart(token) {
flushTagNodes();
const tagNode = TagNode.create(token.getValue());
const tagNode = TagNode.create(token.getValue(), {}, []);
const isNested = isTokenNested(token);

@@ -147,14 +143,16 @@ tagNodes.push(tagNode);

} else {
appendNodes(tagNode, token);
const nodes = getNodes();
appendNodes(nodes, tagNode);
}
};
}
/**
* @private
* @param {Token} token
*/ const handleTagEnd = (token)=>{
*/ function handleTagEnd(token) {
flushTagNodes();
const lastNestedNode = nestedNodes.flushLast();
const lastNestedNode = nestedNodes.flush();
if (lastNestedNode) {
appendNodes(lastNestedNode, token);
} else if (typeof options.onError === 'function') {
const nodes = getNodes();
appendNodes(nodes, lastNestedNode);
} else if (typeof options.onError === "function") {
const tag = token.getValue();

@@ -164,3 +162,2 @@ const line = token.getLine();

options.onError({
message: `Inconsistent tag '${tag}' on line ${line} and column ${column}`,
tagName: tag,

@@ -171,7 +168,7 @@ lineNumber: line,

}
};
}
/**
* @private
* @param {Token} token
*/ const handleTag = (token)=>{
*/ function handleTag(token) {
// [tag]

@@ -185,45 +182,49 @@ if (token.isStart()) {

}
};
}
/**
* @private
* @param {Token} token
*/ const handleNode = (token)=>{
*/ function handleNode(token) {
/**
* @type {TagNode}
*/ const lastTagNode = tagNodes.getLast();
*/ const activeTagNode = tagNodes.last();
const tokenValue = token.getValue();
const isNested = isTagNested(token);
if (lastTagNode) {
const isNested = isTagNested(token.toString());
const nodes = getNodes();
if (activeTagNode !== null) {
if (token.isAttrName()) {
tagNodesAttrName.push(tokenValue);
lastTagNode.attr(tagNodesAttrName.getLast(), '');
const attrName = tagNodesAttrName.last();
if (attrName) {
activeTagNode.attr(attrName, "");
}
} else if (token.isAttrValue()) {
const attrName = tagNodesAttrName.getLast();
const attrName = tagNodesAttrName.last();
if (attrName) {
lastTagNode.attr(attrName, tokenValue);
tagNodesAttrName.flushLast();
activeTagNode.attr(attrName, tokenValue);
tagNodesAttrName.flush();
} else {
lastTagNode.attr(tokenValue, tokenValue);
activeTagNode.attr(tokenValue, tokenValue);
}
} else if (token.isText()) {
if (isNested) {
lastTagNode.append(tokenValue);
activeTagNode.append(tokenValue);
} else {
appendNodes(tokenValue);
appendNodes(nodes, tokenValue);
}
} else if (token.isTag()) {
// if tag is not allowed, just past it as is
appendNodes(token.toString());
// if tag is not allowed, just pass it as is
appendNodes(nodes, token.toString());
}
} else if (token.isText()) {
appendNodes(tokenValue);
appendNodes(nodes, tokenValue);
} else if (token.isTag()) {
// if tag is not allowed, just past it as is
appendNodes(token.toString());
// if tag is not allowed, just pass it as is
appendNodes(nodes, token.toString());
}
};
}
/**
* @private
* @param {Token} token
*/ const onToken = (token)=>{
*/ function onToken(token) {
if (token.isTag()) {

@@ -234,4 +235,5 @@ handleTag(token);

}
};
tokenizer = (opts.createTokenizer ? opts.createTokenizer : createLexer)(input, {
}
const lexer = opts.createTokenizer ? opts.createTokenizer : createLexer;
tokenizer = lexer(input, {
onToken,

@@ -249,9 +251,9 @@ openTag,

// so we need to flush nested content to nodes array
const lastNestedNode = nestedNodes.flushLast();
if (lastNestedNode && isTagNested(lastNestedNode.tag)) {
appendNodeAsString(lastNestedNode, false);
const lastNestedNode = nestedNodes.flush();
if (lastNestedNode !== null && lastNestedNode && isTagNode(lastNestedNode) && isTagNested(lastNestedNode.tag)) {
appendNodeAsString(getNodes(), lastNestedNode, false);
}
return nodes.toArray();
};
}
export { parse };
export default parse;
import { OPEN_BRAKET, CLOSE_BRAKET, SLASH } from '@bbob/plugin-helper';
// type, value, line, row,
const TOKEN_TYPE_ID = 'type'; // 0;
const TOKEN_VALUE_ID = 'value'; // 1;
const TOKEN_COLUMN_ID = 'row'; // 2;
const TOKEN_LINE_ID = 'line'; // 3;
const TOKEN_TYPE_ID = 't'; // 0;
const TOKEN_VALUE_ID = 'v'; // 1;
const TOKEN_COLUMN_ID = 'r'; // 2;
const TOKEN_LINE_ID = 'l'; // 3;
const TOKEN_TYPE_WORD = 1; // 'word';

@@ -13,6 +13,3 @@ const TOKEN_TYPE_TAG = 2; // 'tag';

const TOKEN_TYPE_NEW_LINE = 6; // 'new-line';
/**
* @param {Token} token
* @returns {string}
*/ const getTokenValue = (token)=>{
const getTokenValue = (token)=>{
if (token && typeof token[TOKEN_VALUE_ID] !== 'undefined') {

@@ -23,11 +20,5 @@ return token[TOKEN_VALUE_ID];

};
/**
* @param {Token}token
* @returns {number}
*/ const getTokenLine = (token)=>token && token[TOKEN_LINE_ID] || 0;
const getTokenLine = (token)=>token && token[TOKEN_LINE_ID] || 0;
const getTokenColumn = (token)=>token && token[TOKEN_COLUMN_ID] || 0;
/**
* @param {Token} token
* @returns {boolean}
*/ const isTextToken = (token)=>{
const isTextToken = (token)=>{
if (token && typeof token[TOKEN_TYPE_ID] !== 'undefined') {

@@ -38,6 +29,3 @@ return token[TOKEN_TYPE_ID] === TOKEN_TYPE_SPACE || token[TOKEN_TYPE_ID] === TOKEN_TYPE_NEW_LINE || token[TOKEN_TYPE_ID] === TOKEN_TYPE_WORD;

};
/**
* @param {Token} token
* @returns {boolean}
*/ const isTagToken = (token)=>{
const isTagToken = (token)=>{
if (token && typeof token[TOKEN_TYPE_ID] !== 'undefined') {

@@ -56,6 +44,3 @@ return token[TOKEN_TYPE_ID] === TOKEN_TYPE_TAG;

};
/**
* @param {Token} token
* @returns {boolean}
*/ const isAttrValueToken = (token)=>{
const isAttrValueToken = (token)=>{
if (token && typeof token[TOKEN_TYPE_ID] !== 'undefined') {

@@ -70,3 +55,3 @@ return token[TOKEN_TYPE_ID] === TOKEN_TYPE_ATTR_VALUE;

};
const convertTagToText = (token)=>{
const tokenToText = (token)=>{
let text = OPEN_BRAKET;

@@ -77,6 +62,11 @@ text += getTokenValue(token);

};
class Token {
/**
* @export
* @class Token
*/ class Token {
get type() {
return this[TOKEN_TYPE_ID];
}
isEmpty() {
// eslint-disable-next-line no-restricted-globals
return isNaN(this[TOKEN_TYPE_ID]);
return this[TOKEN_TYPE_ID] === 0 || isNaN(this[TOKEN_TYPE_ID]);
}

@@ -114,14 +104,9 @@ isText() {

toString() {
return convertTagToText(this);
return tokenToText(this);
}
/**
* @param {String} type
* @param {String} value
* @param line
* @param row
*/ constructor(type, value, line, row){
this[TOKEN_TYPE_ID] = Number(type);
constructor(type, value, row = 0, col = 0){
this[TOKEN_LINE_ID] = row;
this[TOKEN_COLUMN_ID] = col;
this[TOKEN_TYPE_ID] = type || 0;
this[TOKEN_VALUE_ID] = String(value);
this[TOKEN_LINE_ID] = Number(line);
this[TOKEN_COLUMN_ID] = Number(row);
}

@@ -128,0 +113,0 @@ }

import { QUOTEMARK, BACKSLASH } from '@bbob/plugin-helper';
function CharGrabber(source, options) {
const cursor = {
pos: 0,
len: source.length
};
const substrUntilChar = (char)=>{
const { pos } = cursor;
const idx = source.indexOf(char, pos);
return idx >= 0 ? source.substring(pos, idx) : '';
};
const includes = (val)=>source.indexOf(val, cursor.pos) >= 0;
const hasNext = ()=>cursor.len > cursor.pos;
const isLast = ()=>cursor.pos === cursor.len;
const skip = (num = 1, silent)=>{
cursor.pos += num;
if (options && options.onSkip && !silent) {
options.onSkip();
export class CharGrabber {
skip(num = 1, silent) {
this.c.pos += num;
if (this.o && this.o.onSkip && !silent) {
this.o.onSkip();
}
};
const rest = ()=>source.substring(cursor.pos);
const grabN = (num = 0)=>source.substring(cursor.pos, cursor.pos + num);
const curr = ()=>source[cursor.pos];
const prev = ()=>{
const prevPos = cursor.pos - 1;
return typeof source[prevPos] !== 'undefined' ? source[prevPos] : null;
};
const next = ()=>{
const nextPos = cursor.pos + 1;
return nextPos <= source.length - 1 ? source[nextPos] : null;
};
const grabWhile = (cond, silent)=>{
}
hasNext() {
return this.c.len > this.c.pos;
}
getCurr() {
if (typeof this.s[this.c.pos] === 'undefined') {
return '';
}
return this.s[this.c.pos];
}
getRest() {
return this.s.substring(this.c.pos);
}
getNext() {
const nextPos = this.c.pos + 1;
return nextPos <= this.s.length - 1 ? this.s[nextPos] : null;
}
getPrev() {
const prevPos = this.c.pos - 1;
if (typeof this.s[prevPos] === 'undefined') {
return null;
}
return this.s[prevPos];
}
isLast() {
return this.c.pos === this.c.len;
}
includes(val) {
return this.s.indexOf(val, this.c.pos) >= 0;
}
grabWhile(condition, silent) {
let start = 0;
if (hasNext()) {
start = cursor.pos;
while(hasNext() && cond(curr())){
skip(1, silent);
if (this.hasNext()) {
start = this.c.pos;
while(this.hasNext() && condition(this.getCurr())){
this.skip(1, silent);
}
}
return source.substring(start, cursor.pos);
};
return this.s.substring(start, this.c.pos);
}
grabN(num = 0) {
return this.s.substring(this.c.pos, this.c.pos + num);
}
/**
* @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;
/**
* @param {Number} num
* @return {String}
*/ this.grabN = grabN;
/**
* Grabs rest of string until it find a char
* @param {String} char
* @return {String}
*/ this.substrUntilChar = substrUntilChar;
*/ substrUntilChar(char) {
const { pos } = this.c;
const idx = this.s.indexOf(char, pos);
return idx >= 0 ? this.s.substring(pos, idx) : '';
}
constructor(source, options = {}){
this.s = source;
this.c = {
pos: 0,
len: source.length
};
this.o = options;
}
}
/**
* 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
*/ export const createCharGrabber = (source, options)=>new CharGrabber(source, options);

@@ -92,5 +74,2 @@ /**

* trimChar('*hello*', '*') ==> 'hello'
* @param {String} str
* @param {String} charToRemove
* @returns {String}
*/ export const trimChar = (str, charToRemove)=>{

@@ -109,20 +88,2 @@ while(str.charAt(0) === charToRemove){

* Unquotes \" to "
* @param str
* @return {String}
*/ export const unquote = (str)=>str.replace(BACKSLASH + QUOTEMARK, QUOTEMARK);
function NodeList(values = []) {
const nodes = values;
const getLast = ()=>Array.isArray(nodes) && nodes.length > 0 && typeof nodes[nodes.length - 1] !== 'undefined' ? nodes[nodes.length - 1] : null;
const flushLast = ()=>nodes.length ? nodes.pop() : false;
const push = (value)=>nodes.push(value);
const toArray = ()=>nodes;
this.push = push;
this.toArray = toArray;
this.getLast = getLast;
this.flushLast = flushLast;
}
/**
*
* @param values
* @return {NodeList}
*/ export const createList = (values = [])=>new NodeList(values);

@@ -13,51 +13,28 @@ "use strict";

TagNode: function() {
return _pluginHelper.TagNode;
return _pluginhelper.TagNode;
},
default: function() {
return _parse.default;
},
parse: function() {
return _parse.parse;
}
});
var _pluginHelper = require("@bbob/plugin-helper");
var _parse = /*#__PURE__*/ _interopRequireWildcard(require("./parse"));
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== "function") return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function(nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interopRequireWildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
return {
default: obj
};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {};
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
for(var key in obj){
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
var _pluginhelper = require("@bbob/plugin-helper");
var _parse = /*#__PURE__*/ _interop_require_default(_export_star(require("./parse"), exports));
_export_star(require("./lexer"), exports);
function _export_star(from, to) {
Object.keys(from).forEach(function(k) {
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
Object.defineProperty(to, k, {
enumerable: true,
get: function() {
return from[k];
}
});
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
});
return from;
}
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}

@@ -12,40 +12,107 @@ /* eslint-disable no-plusplus,no-param-reassign */ "use strict";

_export(exports, {
createLexer: function() {
return createLexer;
},
createTokenOfType: function() {
return createTokenOfType;
},
createLexer: function() {
return createLexer;
}
});
var _pluginHelper = require("@bbob/plugin-helper");
var _token = require("./Token");
var _pluginhelper = require("@bbob/plugin-helper");
var _Token = require("./Token");
var _utils = require("./utils");
// for cases <!-- -->
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(type, value, r, cl) {
function createTokenOfType(type, value, r, cl) {
if (r === void 0) r = 0;
if (cl === void 0) cl = 0;
return new _token.Token(type, value, r, cl);
return new _Token.Token(type, value, r, cl);
}
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 WHITESPACES = [
_pluginhelper.SPACE,
_pluginhelper.TAB
];
var SPECIAL_CHARS = [
_pluginhelper.EQ,
_pluginhelper.SPACE,
_pluginhelper.TAB
];
var isWhiteSpace = function(char) {
return WHITESPACES.indexOf(char) >= 0;
};
/**
* @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) {
var isEscapeChar = function(char) {
return char === _pluginhelper.BACKSLASH;
};
var isSpecialChar = function(char) {
return SPECIAL_CHARS.indexOf(char) >= 0;
};
var isNewLine = function(char) {
return char === _pluginhelper.N;
};
var unq = function(val) {
return (0, _utils.unquote)((0, _utils.trimChar)(val, _pluginhelper.QUOTEMARK));
};
function createLexer(buffer, options) {
if (options === void 0) options = {};
var emitToken = /**
var row = 0;
var col = 0;
var tokenIndex = -1;
var stateMode = STATE_WORD;
var tagMode = TAG_STATE_NAME;
var contextFreeTag = "";
var tokens = new Array(Math.floor(buffer.length));
var openTag = options.openTag || _pluginhelper.OPEN_BRAKET;
var closeTag = options.closeTag || _pluginhelper.CLOSE_BRAKET;
var escapeTags = !!options.enableEscapeTags;
var contextFreeTags = (options.contextFreeTags || []).filter(Boolean).map(function(tag) {
return tag.toLowerCase();
});
var nestedMap = new Map();
var onToken = options.onToken || function() {};
var RESERVED_CHARS = [
closeTag,
openTag,
_pluginhelper.QUOTEMARK,
_pluginhelper.BACKSLASH,
_pluginhelper.SPACE,
_pluginhelper.TAB,
_pluginhelper.EQ,
_pluginhelper.N,
EM
];
var NOT_CHAR_TOKENS = [
openTag,
_pluginhelper.SPACE,
_pluginhelper.TAB,
_pluginhelper.N
];
var isCharReserved = function(char) {
return RESERVED_CHARS.indexOf(char) >= 0;
};
var isCharToken = function(char) {
return NOT_CHAR_TOKENS.indexOf(char) === -1;
};
var isEscapableChar = function(char) {
return char === openTag || char === closeTag || char === _pluginhelper.BACKSLASH;
};
var onSkip = function() {
col++;
};
var checkContextFreeMode = function(name, isClosingTag) {
if (contextFreeTag !== "" && isClosingTag) {
contextFreeTag = "";
}
if (contextFreeTag === "" && contextFreeTags.includes(name.toLowerCase())) {
contextFreeTag = name;
}
};
var chars = (0, _utils.createCharGrabber)(buffer, {
onSkip: onSkip
});
/**
* Emits newly created token to subscriber

@@ -55,20 +122,20 @@ * @param {Number} type

*/ function emitToken(type, value) {
var token = createToken(type, value, row, col);
var token = createTokenOfType(type, value, row, col);
onToken(token);
tokenIndex += 1;
tokens[tokenIndex] = token;
};
var nextTagState = function nextTagState(tagChars, isSingleValueTag) {
}
function nextTagState(tagChars, isSingleValueTag) {
if (tagMode === TAG_STATE_ATTR) {
var validAttrName = function(char) {
return !(char === _pluginHelper.EQ || isWhiteSpace(char));
return !(char === _pluginhelper.EQ || isWhiteSpace(char));
};
var name = tagChars.grabWhile(validAttrName);
var isEnd = tagChars.isLast();
var isValue = tagChars.getCurr() !== _pluginHelper.EQ;
var isValue = tagChars.getCurr() !== _pluginhelper.EQ;
tagChars.skip();
if (isEnd || isValue) {
emitToken(_token.TYPE_ATTR_VALUE, unq(name));
emitToken(_Token.TYPE_ATTR_VALUE, unq(name));
} else {
emitToken(_token.TYPE_ATTR_NAME, name);
emitToken(_Token.TYPE_ATTR_NAME, name);
}

@@ -87,10 +154,10 @@ if (isEnd) {

// const isEQ = char === EQ;
var isQM = char === _pluginHelper.QUOTEMARK;
var isQM = char === _pluginhelper.QUOTEMARK;
var prevChar = tagChars.getPrev();
var nextChar = tagChars.getNext();
var isPrevSLASH = prevChar === _pluginHelper.BACKSLASH;
var isNextEQ = nextChar === _pluginHelper.EQ;
var isPrevSLASH = prevChar === _pluginhelper.BACKSLASH;
var isNextEQ = nextChar === _pluginhelper.EQ;
var isWS = isWhiteSpace(char);
// const isPrevWS = isWhiteSpace(prevChar);
var isNextWS = isWhiteSpace(nextChar);
var isNextWS = nextChar && isWhiteSpace(nextChar);
if (stateSpecial && isSpecialChar(char)) {

@@ -106,3 +173,3 @@ return true;

if (!isSingleValueTag) {
return isWS === false;
return !isWS;
// return (isEQ || isWS) === false;

@@ -114,3 +181,3 @@ }

tagChars.skip();
emitToken(_token.TYPE_ATTR_VALUE, unq(name1));
emitToken(_Token.TYPE_ATTR_VALUE, unq(name1));
if (tagChars.isLast()) {

@@ -122,6 +189,6 @@ return TAG_STATE_NAME;

var validName = function(char) {
return !(char === _pluginHelper.EQ || isWhiteSpace(char) || tagChars.isLast());
return !(char === _pluginhelper.EQ || isWhiteSpace(char) || tagChars.isLast());
};
var name2 = tagChars.grabWhile(validName);
emitToken(_token.TYPE_TAG, name2);
emitToken(_Token.TYPE_TAG, name2);
checkContextFreeMode(name2);

@@ -133,6 +200,6 @@ tagChars.skip();

}
var hasEQ = tagChars.includes(_pluginHelper.EQ);
var hasEQ = tagChars.includes(_pluginhelper.EQ);
return hasEQ ? TAG_STATE_ATTR : TAG_STATE_VALUE;
};
var stateTag = function stateTag() {
}
function stateTag() {
var currChar = chars.getCurr();

@@ -144,10 +211,10 @@ var nextChar = chars.getNext();

var hasInvalidChars = substr.length === 0 || substr.indexOf(openTag) >= 0;
if (isCharReserved(nextChar) || hasInvalidChars || chars.isLast()) {
emitToken(_token.TYPE_WORD, currChar);
if (nextChar && isCharReserved(nextChar) || hasInvalidChars || chars.isLast()) {
emitToken(_Token.TYPE_WORD, currChar);
return STATE_WORD;
}
// [myTag ]
var isNoAttrsInTag = substr.indexOf(_pluginHelper.EQ) === -1;
var isNoAttrsInTag = substr.indexOf(_pluginhelper.EQ) === -1;
// [/myTag]
var isClosingTag = substr[0] === _pluginHelper.SLASH;
var isClosingTag = substr[0] === _pluginhelper.SLASH;
if (isNoAttrsInTag || isClosingTag) {

@@ -158,3 +225,3 @@ var name = chars.grabWhile(function(char) {

chars.skip(); // skip closeTag
emitToken(_token.TYPE_TAG, name);
emitToken(_Token.TYPE_TAG, name);
checkContextFreeMode(name, isClosingTag);

@@ -164,4 +231,4 @@ return STATE_WORD;

return STATE_TAG_ATTRS;
};
var stateAttrs = function stateAttrs() {
}
function stateAttrs() {
var silent = true;

@@ -174,3 +241,3 @@ var tagStr = chars.grabWhile(function(char) {

});
var hasSpace = tagGrabber.includes(_pluginHelper.SPACE);
var hasSpace = tagGrabber.includes(_pluginhelper.SPACE);
tagMode = TAG_STATE_NAME;

@@ -182,6 +249,6 @@ while(tagGrabber.hasNext()){

return STATE_WORD;
};
var stateWord = function stateWord() {
}
function stateWord() {
if (isNewLine(chars.getCurr())) {
emitToken(_token.TYPE_NEW_LINE, chars.getCurr());
emitToken(_Token.TYPE_NEW_LINE, chars.getCurr());
chars.skip();

@@ -194,3 +261,3 @@ col = 0;

var word = chars.grabWhile(isWhiteSpace);
emitToken(_token.TYPE_SPACE, word);
emitToken(_Token.TYPE_SPACE, word);
return STATE_WORD;

@@ -200,4 +267,4 @@ }

if (contextFreeTag) {
var fullTagLen = openTag.length + _pluginHelper.SLASH.length + contextFreeTag.length;
var fullTagName = "" + openTag + _pluginHelper.SLASH + contextFreeTag;
var fullTagLen = openTag.length + _pluginhelper.SLASH.length + contextFreeTag.length;
var fullTagName = "" + openTag + _pluginhelper.SLASH + contextFreeTag;
var foundTag = chars.grabN(fullTagLen);

@@ -211,3 +278,3 @@ var isEndContextFreeMode = foundTag === fullTagName;

}
emitToken(_token.TYPE_WORD, chars.getCurr());
emitToken(_Token.TYPE_WORD, chars.getCurr());
chars.skip();

@@ -221,8 +288,8 @@ return STATE_WORD;

chars.skip(); // skip the \ without emitting anything
if (isEscapableChar(nextChar)) {
if (nextChar && isEscapableChar(nextChar)) {
chars.skip(); // skip past the [, ] or \ as well
emitToken(_token.TYPE_WORD, nextChar);
emitToken(_Token.TYPE_WORD, nextChar);
return STATE_WORD;
}
emitToken(_token.TYPE_WORD, currChar);
emitToken(_Token.TYPE_WORD, currChar);
return STATE_WORD;

@@ -234,10 +301,10 @@ }

var word1 = chars.grabWhile(isChar);
emitToken(_token.TYPE_WORD, word1);
emitToken(_Token.TYPE_WORD, word1);
return STATE_WORD;
}
var word2 = chars.grabWhile(isCharToken);
emitToken(_token.TYPE_WORD, word2);
emitToken(_Token.TYPE_WORD, word2);
return STATE_WORD;
};
var tokenize = function tokenize() {
}
function tokenize() {
stateMode = STATE_WORD;

@@ -260,90 +327,13 @@ while(chars.hasNext()){

return tokens;
};
var isTokenNested = function isTokenNested(token) {
var value = openTag + _pluginHelper.SLASH + token.getValue();
// potential bottleneck
return buffer.indexOf(value) > -1;
};
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 contextFreeTag = "";
var tokens = new Array(Math.floor(buffer.length));
var openTag = options.openTag || _pluginHelper.OPEN_BRAKET;
var closeTag = options.closeTag || _pluginHelper.CLOSE_BRAKET;
var escapeTags = !!options.enableEscapeTags;
var contextFreeTags = options.contextFreeTags || [];
var onToken = options.onToken || function() {};
var RESERVED_CHARS = [
closeTag,
openTag,
_pluginHelper.QUOTEMARK,
_pluginHelper.BACKSLASH,
_pluginHelper.SPACE,
_pluginHelper.TAB,
_pluginHelper.EQ,
_pluginHelper.N,
EM
];
var NOT_CHAR_TOKENS = [
openTag,
_pluginHelper.SPACE,
_pluginHelper.TAB,
_pluginHelper.N
];
var WHITESPACES = [
_pluginHelper.SPACE,
_pluginHelper.TAB
];
var SPECIAL_CHARS = [
_pluginHelper.EQ,
_pluginHelper.SPACE,
_pluginHelper.TAB
];
var isCharReserved = function(char) {
return RESERVED_CHARS.indexOf(char) >= 0;
};
var isNewLine = function(char) {
return char === _pluginHelper.N;
};
var isWhiteSpace = function(char) {
return WHITESPACES.indexOf(char) >= 0;
};
var isCharToken = function(char) {
return NOT_CHAR_TOKENS.indexOf(char) === -1;
};
var isSpecialChar = function(char) {
return SPECIAL_CHARS.indexOf(char) >= 0;
};
var isEscapableChar = function(char) {
return char === openTag || char === closeTag || char === _pluginHelper.BACKSLASH;
};
var isEscapeChar = function(char) {
return char === _pluginHelper.BACKSLASH;
};
var onSkip = function() {
col++;
};
var unq = function(val) {
return (0, _utils.unquote)((0, _utils.trimChar)(val, _pluginHelper.QUOTEMARK));
};
var checkContextFreeMode = function(name, isClosingTag) {
if (contextFreeTag !== "" && isClosingTag) {
contextFreeTag = "";
}
function isTokenNested(token) {
var value = openTag + _pluginhelper.SLASH + token.getValue();
if (nestedMap.has(value)) {
return !!nestedMap.get(value);
} else {
var status = buffer.indexOf(value) > -1;
nestedMap.set(value, status);
return status;
}
if (contextFreeTag === "" && contextFreeTags.includes(name)) {
contextFreeTag = name;
}
};
var chars = (0, _utils.createCharGrabber)(buffer, {
onSkip: onSkip
});
}
return {

@@ -354,2 +344,1 @@ tokenize: tokenize,

}
var createTokenOfType = createToken;

@@ -12,28 +12,42 @@ "use strict";

_export(exports, {
default: function() {
return _default;
},
parse: function() {
return parse;
},
default: function() {
return _default;
}
});
var _pluginHelper = require("@bbob/plugin-helper");
var _pluginhelper = require("@bbob/plugin-helper");
var _lexer = require("./lexer");
var _utils = require("./utils");
/**
* @public
* @param {string} input
* @param {Object} opts
* @param {Function} opts.createTokenizer
* @param {Array<string>} opts.onlyAllowTags
* @param {Array<string>} opts.contextFreeTags
* @param {Boolean} opts.enableEscapeTags
* @param {string} opts.openTag
* @param {string} opts.closeTag
* @return {Array<string|TagNode>}
*/ var parse = function(input, opts) {
var NodeList = /*#__PURE__*/ function() {
"use strict";
function NodeList() {
this.n = [];
}
var _proto = NodeList.prototype;
_proto.last = function last() {
if (Array.isArray(this.n) && this.n.length > 0 && typeof this.n[this.n.length - 1] !== "undefined") {
return this.n[this.n.length - 1];
}
return null;
};
_proto.flush = function flush() {
return this.n.length ? this.n.pop() : false;
};
_proto.push = function push(value) {
this.n.push(value);
};
_proto.toArray = function toArray() {
return this.n;
};
return NodeList;
}();
var createList = function() {
return new NodeList();
};
function parse(input, opts) {
if (opts === void 0) opts = {};
var options = opts;
var openTag = options.openTag || _pluginHelper.OPEN_BRAKET;
var closeTag = options.closeTag || _pluginHelper.CLOSE_BRAKET;
var openTag = options.openTag || _pluginhelper.OPEN_BRAKET;
var closeTag = options.closeTag || _pluginhelper.CLOSE_BRAKET;
var onlyAllowTags = (options.onlyAllowTags || []).filter(Boolean).map(function(tag) {

@@ -47,8 +61,7 @@ return tag.toLowerCase();

* @type {NodeList}
*/ var nodes = (0, _utils.createList)();
*/ var nodes = createList();
/**
* Temp buffer of nodes that's nested to another node
* @private
* @type {NodeList}
*/ var nestedNodes = (0, _utils.createList)();
*/ var nestedNodes = createList();
/**

@@ -58,3 +71,3 @@ * Temp buffer of nodes [tag..]...[/tag]

* @type {NodeList}
*/ var tagNodes = (0, _utils.createList)();
*/ var tagNodes = createList();
/**

@@ -64,13 +77,10 @@ * Temp buffer of tag attributes

* @type {NodeList}
*/ var tagNodesAttrName = (0, _utils.createList)();
*/ var tagNodesAttrName = createList();
/**
* Cache for nested tags checks
* @type Set<string>
*/ var nestedTagsMap = new Set();
/**
* @param {Token} token
* @returns {boolean}
*/ var isTokenNested = function(token) {
function isTokenNested(token) {
var value = token.getValue();
if (!nestedTagsMap.has(value) && tokenizer.isTokenNested && tokenizer.isTokenNested(token)) {
var isTokenNested = (tokenizer || {}).isTokenNested;
if (!nestedTagsMap.has(value) && isTokenNested && isTokenNested(token)) {
nestedTagsMap.add(value);

@@ -80,15 +90,11 @@ return true;

return nestedTagsMap.has(value);
};
}
/**
* @private
* @param {string} tagName
* @returns {boolean}
*/ var isTagNested = function(tagName) {
*/ function isTagNested(tagName) {
return Boolean(nestedTagsMap.has(tagName));
};
}
/**
* @private
* @param {string} value
* @return {boolean}
*/ var isAllowedTag = function(value) {
*/ function isAllowedTag(value) {
if (onlyAllowTags.length) {

@@ -98,40 +104,35 @@ return onlyAllowTags.indexOf(value.toLowerCase()) >= 0;

return true;
};
}
/**
* Flushes temp tag nodes and its attributes buffers
* @private
* @return {Array}
*/ var flushTagNodes = function() {
if (tagNodes.flushLast()) {
tagNodesAttrName.flushLast();
*/ function flushTagNodes() {
if (tagNodes.flush()) {
tagNodesAttrName.flush();
}
};
}
/**
* @private
* @return {Array}
*/ var getNodes = function() {
var lastNestedNode = nestedNodes.getLast();
if (lastNestedNode && Array.isArray(lastNestedNode.content)) {
*/ function getNodes() {
var lastNestedNode = nestedNodes.last();
if (lastNestedNode && (0, _pluginhelper.isTagNode)(lastNestedNode)) {
return lastNestedNode.content;
}
return nodes.toArray();
};
}
/**
* @private
* @param {string|TagNode} node
* @param {boolean} isNested
*/ var appendNodeAsString = function(node, isNested) {
*/ function appendNodeAsString(nodes, node, isNested) {
if (isNested === void 0) isNested = true;
var items = getNodes();
if (Array.isArray(items)) {
items.push(node.toTagStart({
if (Array.isArray(nodes) && typeof node !== "undefined") {
nodes.push(node.toTagStart({
openTag: openTag,
closeTag: closeTag
}));
if (node.content.length) {
if (Array.isArray(node.content) && node.content.length) {
node.content.forEach(function(item) {
items.push(item);
nodes.push(item);
});
if (isNested) {
items.push(node.toTagEnd({
nodes.push(node.toTagEnd({
openTag: openTag,

@@ -143,26 +144,24 @@ closeTag: closeTag

}
};
}
/**
* @private
* @param {string|TagNode} node
*/ var appendNodes = function(node) {
var items = getNodes();
if (Array.isArray(items)) {
if ((0, _pluginHelper.isTagNode)(node)) {
*/ function appendNodes(nodes, node) {
if (Array.isArray(nodes) && typeof node !== "undefined") {
if ((0, _pluginhelper.isTagNode)(node)) {
if (isAllowedTag(node.tag)) {
items.push(node.toTagNode());
nodes.push(node.toTagNode());
} else {
appendNodeAsString(node);
appendNodeAsString(nodes, node);
}
} else {
items.push(node);
nodes.push(node);
}
}
};
}
/**
* @private
* @param {Token} token
*/ var handleTagStart = function(token) {
*/ function handleTagStart(token) {
flushTagNodes();
var tagNode = _pluginHelper.TagNode.create(token.getValue());
var tagNode = _pluginhelper.TagNode.create(token.getValue(), {}, []);
var isNested = isTokenNested(token);

@@ -173,13 +172,15 @@ tagNodes.push(tagNode);

} else {
appendNodes(tagNode, token);
var nodes = getNodes();
appendNodes(nodes, tagNode);
}
};
}
/**
* @private
* @param {Token} token
*/ var handleTagEnd = function(token) {
*/ function handleTagEnd(token) {
flushTagNodes();
var lastNestedNode = nestedNodes.flushLast();
var lastNestedNode = nestedNodes.flush();
if (lastNestedNode) {
appendNodes(lastNestedNode, token);
var nodes = getNodes();
appendNodes(nodes, lastNestedNode);
} else if (typeof options.onError === "function") {

@@ -190,3 +191,2 @@ var tag = token.getValue();

options.onError({
message: "Inconsistent tag '" + tag + "' on line " + line + " and column " + column,
tagName: tag,

@@ -197,7 +197,7 @@ lineNumber: line,

}
};
}
/**
* @private
* @param {Token} token
*/ var handleTag = function(token) {
*/ function handleTag(token) {
// [tag]

@@ -211,45 +211,49 @@ if (token.isStart()) {

}
};
}
/**
* @private
* @param {Token} token
*/ var handleNode = function(token) {
*/ function handleNode(token) {
/**
* @type {TagNode}
*/ var lastTagNode = tagNodes.getLast();
*/ var activeTagNode = tagNodes.last();
var tokenValue = token.getValue();
var isNested = isTagNested(token);
if (lastTagNode) {
var isNested = isTagNested(token.toString());
var nodes = getNodes();
if (activeTagNode !== null) {
if (token.isAttrName()) {
tagNodesAttrName.push(tokenValue);
lastTagNode.attr(tagNodesAttrName.getLast(), "");
var attrName = tagNodesAttrName.last();
if (attrName) {
activeTagNode.attr(attrName, "");
}
} else if (token.isAttrValue()) {
var attrName = tagNodesAttrName.getLast();
if (attrName) {
lastTagNode.attr(attrName, tokenValue);
tagNodesAttrName.flushLast();
var attrName1 = tagNodesAttrName.last();
if (attrName1) {
activeTagNode.attr(attrName1, tokenValue);
tagNodesAttrName.flush();
} else {
lastTagNode.attr(tokenValue, tokenValue);
activeTagNode.attr(tokenValue, tokenValue);
}
} else if (token.isText()) {
if (isNested) {
lastTagNode.append(tokenValue);
activeTagNode.append(tokenValue);
} else {
appendNodes(tokenValue);
appendNodes(nodes, tokenValue);
}
} else if (token.isTag()) {
// if tag is not allowed, just past it as is
appendNodes(token.toString());
// if tag is not allowed, just pass it as is
appendNodes(nodes, token.toString());
}
} else if (token.isText()) {
appendNodes(tokenValue);
appendNodes(nodes, tokenValue);
} else if (token.isTag()) {
// if tag is not allowed, just past it as is
appendNodes(token.toString());
// if tag is not allowed, just pass it as is
appendNodes(nodes, token.toString());
}
};
}
/**
* @private
* @param {Token} token
*/ var onToken = function(token) {
*/ function onToken(token) {
if (token.isTag()) {

@@ -260,4 +264,5 @@ handleTag(token);

}
};
tokenizer = (opts.createTokenizer ? opts.createTokenizer : _lexer.createLexer)(input, {
}
var lexer = opts.createTokenizer ? opts.createTokenizer : _lexer.createLexer;
tokenizer = lexer(input, {
onToken: onToken,

@@ -275,8 +280,8 @@ openTag: openTag,

// so we need to flush nested content to nodes array
var lastNestedNode = nestedNodes.flushLast();
if (lastNestedNode && isTagNested(lastNestedNode.tag)) {
appendNodeAsString(lastNestedNode, false);
var lastNestedNode = nestedNodes.flush();
if (lastNestedNode !== null && lastNestedNode && (0, _pluginhelper.isTagNode)(lastNestedNode) && isTagNested(lastNestedNode.tag)) {
appendNodeAsString(getNodes(), lastNestedNode, false);
}
return nodes.toArray();
};
}
var _default = parse;

@@ -12,20 +12,8 @@ "use strict";

_export(exports, {
TYPE_ID: function() {
return TYPE_ID;
COLUMN_ID: function() {
return COLUMN_ID;
},
VALUE_ID: function() {
return VALUE_ID;
},
LINE_ID: function() {
return LINE_ID;
},
COLUMN_ID: function() {
return COLUMN_ID;
},
TYPE_WORD: function() {
return TYPE_WORD;
},
TYPE_TAG: function() {
return TYPE_TAG;
},
TYPE_ATTR_NAME: function() {

@@ -37,4 +25,4 @@ return TYPE_ATTR_NAME;

},
TYPE_SPACE: function() {
return TYPE_SPACE;
TYPE_ID: function() {
return TYPE_ID;
},

@@ -44,5 +32,17 @@ TYPE_NEW_LINE: function() {

},
TYPE_SPACE: function() {
return TYPE_SPACE;
},
TYPE_TAG: function() {
return TYPE_TAG;
},
TYPE_WORD: function() {
return TYPE_WORD;
},
Token: function() {
return Token;
},
VALUE_ID: function() {
return VALUE_ID;
},
default: function() {

@@ -52,8 +52,22 @@ return _default;

});
var _pluginHelper = require("@bbob/plugin-helper");
var _pluginhelper = require("@bbob/plugin-helper");
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 _create_class(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
// type, value, line, row,
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_ID = "t"; // 0;
var TOKEN_VALUE_ID = "v"; // 1;
var TOKEN_COLUMN_ID = "r"; // 2;
var TOKEN_LINE_ID = "l"; // 3;
var TOKEN_TYPE_WORD = 1; // 'word';

@@ -65,6 +79,3 @@ var TOKEN_TYPE_TAG = 2; // 'tag';

var TOKEN_TYPE_NEW_LINE = 6; // 'new-line';
/**
* @param {Token} token
* @returns {string}
*/ var getTokenValue = function(token) {
var getTokenValue = function(token) {
if (token && typeof token[TOKEN_VALUE_ID] !== "undefined") {

@@ -75,6 +86,3 @@ return token[TOKEN_VALUE_ID];

};
/**
* @param {Token}token
* @returns {number}
*/ var getTokenLine = function(token) {
var getTokenLine = function(token) {
return token && token[TOKEN_LINE_ID] || 0;

@@ -85,6 +93,3 @@ };

};
/**
* @param {Token} token
* @returns {boolean}
*/ var isTextToken = function(token) {
var isTextToken = function(token) {
if (token && typeof token[TOKEN_TYPE_ID] !== "undefined") {

@@ -95,6 +100,3 @@ return token[TOKEN_TYPE_ID] === TOKEN_TYPE_SPACE || token[TOKEN_TYPE_ID] === TOKEN_TYPE_NEW_LINE || token[TOKEN_TYPE_ID] === TOKEN_TYPE_WORD;

};
/**
* @param {Token} token
* @returns {boolean}
*/ var isTagToken = function(token) {
var isTagToken = function(token) {
if (token && typeof token[TOKEN_TYPE_ID] !== "undefined") {

@@ -106,3 +108,3 @@ return token[TOKEN_TYPE_ID] === TOKEN_TYPE_TAG;

var isTagEnd = function(token) {
return getTokenValue(token).charCodeAt(0) === _pluginHelper.SLASH.charCodeAt(0);
return getTokenValue(token).charCodeAt(0) === _pluginhelper.SLASH.charCodeAt(0);
};

@@ -118,6 +120,3 @@ var isTagStart = function(token) {

};
/**
* @param {Token} token
* @returns {boolean}
*/ var isAttrValueToken = function(token) {
var isAttrValueToken = function(token) {
if (token && typeof token[TOKEN_TYPE_ID] !== "undefined") {

@@ -132,20 +131,24 @@ return token[TOKEN_TYPE_ID] === TOKEN_TYPE_ATTR_VALUE;

};
var convertTagToText = function(token) {
var text = _pluginHelper.OPEN_BRAKET;
var tokenToText = function(token) {
var text = _pluginhelper.OPEN_BRAKET;
text += getTokenValue(token);
text += _pluginHelper.CLOSE_BRAKET;
text += _pluginhelper.CLOSE_BRAKET;
return text;
};
var Token = /*#__PURE__*/ function() {
/**
* @export
* @class Token
*/ var Token = /*#__PURE__*/ function() {
"use strict";
function Token(type, value, line, row) {
this[TOKEN_TYPE_ID] = Number(type);
function Token(type, value, row, col) {
if (row === void 0) row = 0;
if (col === void 0) col = 0;
this[TOKEN_LINE_ID] = row;
this[TOKEN_COLUMN_ID] = col;
this[TOKEN_TYPE_ID] = type || 0;
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]);
return this[TOKEN_TYPE_ID] === 0 || isNaN(this[TOKEN_TYPE_ID]);
};

@@ -183,4 +186,12 @@ _proto.isText = function isText() {

_proto.toString = function toString() {
return convertTagToText(this);
return tokenToText(this);
};
_create_class(Token, [
{
key: "type",
get: function get() {
return this[TOKEN_TYPE_ID];
}
}
]);
return Token;

@@ -187,0 +198,0 @@ }();

@@ -12,2 +12,5 @@ "use strict";

_export(exports, {
CharGrabber: function() {
return CharGrabber;
},
createCharGrabber: function() {

@@ -21,101 +24,76 @@ return createCharGrabber;

return unquote;
},
createList: function() {
return createList;
}
});
var _pluginHelper = require("@bbob/plugin-helper");
function CharGrabber(source, options) {
var cursor = {
pos: 0,
len: source.length
var _pluginhelper = require("@bbob/plugin-helper");
var CharGrabber = /*#__PURE__*/ function() {
"use strict";
function CharGrabber(source, options) {
if (options === void 0) options = {};
this.s = source;
this.c = {
pos: 0,
len: source.length
};
this.o = options;
}
var _proto = CharGrabber.prototype;
_proto.skip = function skip(num, silent) {
if (num === void 0) num = 1;
this.c.pos += num;
if (this.o && this.o.onSkip && !silent) {
this.o.onSkip();
}
};
var substrUntilChar = function(char) {
var pos = cursor.pos;
var idx = source.indexOf(char, pos);
return idx >= 0 ? source.substring(pos, idx) : "";
_proto.hasNext = function hasNext() {
return this.c.len > this.c.pos;
};
var includes = function(val) {
return source.indexOf(val, cursor.pos) >= 0;
_proto.getCurr = function getCurr() {
if (typeof this.s[this.c.pos] === "undefined") {
return "";
}
return this.s[this.c.pos];
};
var hasNext = function() {
return cursor.len > cursor.pos;
_proto.getRest = function getRest() {
return this.s.substring(this.c.pos);
};
var isLast = function() {
return cursor.pos === cursor.len;
_proto.getNext = function getNext() {
var nextPos = this.c.pos + 1;
return nextPos <= this.s.length - 1 ? this.s[nextPos] : null;
};
var skip = function(num, silent) {
if (num === void 0) num = 1;
cursor.pos += num;
if (options && options.onSkip && !silent) {
options.onSkip();
_proto.getPrev = function getPrev() {
var prevPos = this.c.pos - 1;
if (typeof this.s[prevPos] === "undefined") {
return null;
}
return this.s[prevPos];
};
var rest = function() {
return source.substring(cursor.pos);
_proto.isLast = function isLast() {
return this.c.pos === this.c.len;
};
var grabN = function(num) {
if (num === void 0) num = 0;
return source.substring(cursor.pos, cursor.pos + num);
_proto.includes = function includes(val) {
return this.s.indexOf(val, this.c.pos) >= 0;
};
var curr = function() {
return source[cursor.pos];
};
var prev = function() {
var prevPos = cursor.pos - 1;
return typeof source[prevPos] !== "undefined" ? source[prevPos] : null;
};
var next = function() {
var nextPos = cursor.pos + 1;
return nextPos <= source.length - 1 ? source[nextPos] : null;
};
var grabWhile = function(cond, silent) {
_proto.grabWhile = function grabWhile(condition, silent) {
var start = 0;
if (hasNext()) {
start = cursor.pos;
while(hasNext() && cond(curr())){
skip(1, silent);
if (this.hasNext()) {
start = this.c.pos;
while(this.hasNext() && condition(this.getCurr())){
this.skip(1, silent);
}
}
return source.substring(start, cursor.pos);
return this.s.substring(start, this.c.pos);
};
_proto.grabN = function grabN(num) {
if (num === void 0) num = 0;
return this.s.substring(this.c.pos, this.c.pos + num);
};
/**
* @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;
/**
* @param {Number} num
* @return {String}
*/ this.grabN = grabN;
/**
* Grabs rest of string until it find a char
* @param {String} char
* @return {String}
*/ this.substrUntilChar = substrUntilChar;
}
*/ _proto.substrUntilChar = function substrUntilChar(char) {
var pos = this.c.pos;
var idx = this.s.indexOf(char, pos);
return idx >= 0 ? this.s.substring(pos, idx) : "";
};
return CharGrabber;
}();
var createCharGrabber = function(source, options) {

@@ -136,27 +114,3 @@ return new CharGrabber(source, options);

var unquote = function(str) {
return str.replace(_pluginHelper.BACKSLASH + _pluginHelper.QUOTEMARK, _pluginHelper.QUOTEMARK);
return str.replace(_pluginhelper.BACKSLASH + _pluginhelper.QUOTEMARK, _pluginhelper.QUOTEMARK);
};
function NodeList(values) {
if (values === void 0) values = [];
var nodes = values;
var getLast = function() {
return Array.isArray(nodes) && nodes.length > 0 && typeof nodes[nodes.length - 1] !== "undefined" ? nodes[nodes.length - 1] : null;
};
var flushLast = function() {
return nodes.length ? nodes.pop() : false;
};
var push = function(value) {
return nodes.push(value);
};
var toArray = function() {
return nodes;
};
this.push = push;
this.toArray = toArray;
this.getLast = getLast;
this.flushLast = flushLast;
}
var createList = function(values) {
if (values === void 0) values = [];
return new NodeList(values);
};
{
"name": "@bbob/parser",
"version": "3.0.2",
"version": "4.0.0",
"description": "A BBCode to AST Parser part of @bbob",

@@ -15,4 +15,12 @@ "keywords": [

],
"files": [
"dist",
"lib",
"src",
"es",
"types"
],
"dependencies": {
"@bbob/plugin-helper": "^3.0.2"
"@bbob/plugin-helper": "*",
"@bbob/types": "*"
},

@@ -24,2 +32,40 @@ "main": "lib/index.js",

"browserName": "BbobParser",
"types": "types/index.d.ts",
"exports": {
".": {
"types": "./types/index.d.ts",
"import": "./es/index.js",
"require": "./lib/index.js",
"browser": "./dist/index.min.js",
"umd": "./dist/index.min.js"
},
"./lexer": {
"types": "./types/lexer.d.ts",
"import": "./es/lexer.js",
"require": "./lib/lexer.js",
"browser": "./dist/index.min.js",
"umd": "./dist/index.min.js"
},
"./parse": {
"types": "./types/parse.d.ts",
"import": "./es/parse.js",
"require": "./lib/parse.js",
"browser": "./dist/index.min.js",
"umd": "./dist/index.min.js"
},
"./Token": {
"types": "./types/Token.d.ts",
"import": "./es/Token.js",
"require": "./lib/Token.js",
"browser": "./dist/index.min.js",
"umd": "./dist/index.min.js"
},
"./utils": {
"types": "./types/utils.d.ts",
"import": "./es/utils.js",
"require": "./lib/utils.js",
"browser": "./dist/index.min.js",
"umd": "./dist/index.min.js"
}
},
"homepage": "https://github.com/JiLiZART/bbob",

@@ -35,17 +81,6 @@ "author": "Nikolay Kostyurin <jilizart@gmail.com>",

},
"scripts": {
"build:commonjs": "../../scripts/pkg-task build-commonjs",
"build:es": "../../scripts/pkg-task build-es",
"build:umd": "../../scripts/pkg-task build-umd",
"build": "npm run build:commonjs && npm run build:es && npm run build:umd",
"test": "../../scripts/pkg-task test",
"cover": "../../scripts/pkg-task cover",
"lint": "../../scripts/pkg-task lint",
"size": "../../scripts/pkg-task size",
"bundlesize": "../../scripts/pkg-task bundlesize",
"prepublishOnly": "npm run build"
},
"size-limit": [
{
"path": "lib/index.js"
"path": "./dist/index.min.js",
"size": "3 KB"
}

@@ -62,8 +97,14 @@ ],

},
"files": [
"dist",
"lib",
"src",
"es"
]
}
"scripts": {
"build:commonjs": "pkg-task",
"build:es": "pkg-task",
"build:umd": "pkg-task",
"build": "pkg-task",
"test": "pkg-task",
"cover": "pkg-task",
"lint": "pkg-task",
"size": "pkg-task",
"bundlesize": "pkg-task",
"types": "pkg-task"
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc