UNPKG

@elderjs/shortcodes

Version:

An Shortcode parser with support of arguments, key-value attributes, nesting, and async.

259 lines (215 loc) 4.66 kB
/* * META Platform library * Shortcode parser * * @author META Platform <www.meta-platform.com> * @license See LICENSE file distributed with this source code */ /** * Tokenizer constructor */ var Tokenizer = function (source) { this.source = source; this.output = ""; this.buffer = ""; this.cursor = 0; this.parser = null; this.context = []; }; /** * Move cursor by offset * * @param int offset */ Tokenizer.prototype.skip = function (offset) { this.cursor += offset; }; /** * Returns next character * * @param bool toBuffer * @param bool skipEscape * @param bool skip * @return string|false */ Tokenizer.prototype.next = function (toBuffer, skip) { if (skip === undefined) skip = true; var c = this.source.substr(this.cursor, 1); if (toBuffer) this.toBuffer(c); if (skip) this.skip(1); return c; }; /** * Adds specified character count to buffer and skip * * @param int offset * @return string|false */ Tokenizer.prototype.eat = function (offset) { var str = this.source.substr(this.cursor, offset); this.toBuffer(str); this.skip(offset); return str; }; /** * Match string in source * * @param string pattern * @param bool prevToBuffer * @param bool tokenToBuffer * @param bool skip * @param bool ignoreEscape * @return string|false */ Tokenizer.prototype.match = function ( pattern, prevToBuffer, tokenToBuffer, skip, ignoreEscape ) { if (skip === undefined) skip = true; var str = this.source.substr(this.cursor); var rx = new RegExp(pattern); var match = rx.exec(str); if (match === null) return false; if ( !ignoreEscape && this.source.substr(this.cursor + match.index - 1, 1) == "\\" ) { if (prevToBuffer) { this.buffer += this.source.substr(this.cursor, match.index - 1); this.buffer += this.source.substr( this.cursor + match.index, match[0].length ); } this.skip(match.index); this.skip(match[0].length); return this.match(pattern, prevToBuffer, tokenToBuffer, skip, ignoreEscape); } if (prevToBuffer) this.buffer += this.source.substr(this.cursor, match.index); if (tokenToBuffer) this.buffer += match[0]; if (skip) { this.skip(match.index); this.skip(match[0].length); } return match[0]; }; /** * Returns buffer contents * * @return string */ Tokenizer.prototype.getBuffer = function () { return this.buffer; }; /** * Add string to buffer * * @param string str */ Tokenizer.prototype.toBuffer = function (str) { this.buffer += str; }; /** * Flush buffer to output and reset buffer */ Tokenizer.prototype.flushBuffer = function () { this.output += this.buffer; this.buffer = ""; }; /** * Set buffer to empty string and return it previous contents * * @return string */ Tokenizer.prototype.clearBuffer = function () { var b = this.buffer; this.buffer = ""; return b; }; /** * Flush remaining contents to output buffer */ Tokenizer.prototype.flushRest = function (skip) { if (skip === undefined) skip = true; this.output += this.source.substr(this.cursor); if (skip) this.skip(this.source.length - this.cursor); }; /** * Returns output contents * * @return string */ Tokenizer.prototype.getOutput = function () { return this.output; }; /** * Add string to output * * @param string str */ Tokenizer.prototype.toOutput = function (str) { this.output += str; }; /** * Return cursor * * @return int */ Tokenizer.prototype.getCursor = function () { return this.cursor; }; /** * Return if cursor is at end * * @return bool */ Tokenizer.prototype.isEnd = function () { return this.cursor >= this.source.length ? true : false; }; /** * Open new nested context * * @param Object ctx */ Tokenizer.prototype.openContext = function (ctx) { this.context.push(ctx); }; /** * Close last context and return it * * @return Object */ Tokenizer.prototype.closeContext = function () { return this.context.pop(); }; /** * Return current (last) context * * @return Object */ Tokenizer.prototype.getContext = function () { return this.context[this.context.length - 1] || null; }; /** * Start parsing using specified parser * * @param Function parser * @param Object thisObj */ Tokenizer.prototype.tokenize = async function (parser, thisObj) { var thisCtx = thisObj || this; this.parser = parser; while (this.parser) { if (typeof this.parser.call !== "function") { this.parser = await this.parser; } this.parser = this.parser.call(thisCtx, this, this.getContext()); } }; //Export module.exports = function (source) { return new Tokenizer(source); };