UNPKG

meta-shortcodes

Version:

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

289 lines (206 loc) 4.43 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 = function(parser, thisObj){ var thisCtx = thisObj || this; this.parser = parser; while(this.parser){ this.parser = this.parser.call(thisCtx, this, this.getContext()); } }; //Export module.exports = function(source){ return new Tokenizer(source); };