UNPKG

arc-templates

Version:

Fully powered JavaScript template engine with halfway-decent syntax.

757 lines (598 loc) 27.3 kB
'use strict'; var _createClass = require('babel-runtime/helpers/create-class')['default']; var _classCallCheck = require('babel-runtime/helpers/class-call-check')['default']; var _regeneratorRuntime = require('babel-runtime/regenerator')['default']; var _getIterator = require('babel-runtime/core-js/get-iterator')['default']; var _interopRequireDefault = require('babel-runtime/helpers/interop-require-default')['default']; Object.defineProperty(exports, '__esModule', { value: true }); var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash); var _tokens = require('./tokens'); var _tokens2 = _interopRequireDefault(_tokens); var _Location = require('./Location'); var _Location2 = _interopRequireDefault(_Location); var BEGIN_EXPRESSION = '${'; var END_EXPRESSION = '}'; var BEGIN_JAVASCRIPT = '<%'; var END_JAVASCRIPT = '%>'; var BEGIN_COMMENT = '</*'; var END_COMMENT = '*/>'; var BEGIN_BLOCK = '<['; var END_BLOCK = ']>'; var BEGIN_DOCUMENT = '<:'; var END_DOCUMENT = ':>'; var BEGIN_BLOCK_REFERENCE = '<*'; var END_BLOCK_REFERENCE = '*>'; var BEGIN_LAYOUT = '<!'; var END_LAYOUT = '!>'; var BEGIN_PARTIAL = '<('; var END_PARTIAL = ')>'; function regex() { for (var _len = arguments.length, values = Array(_len), _key = 0; _key < _len; _key++) { values[_key] = arguments[_key]; } return new RegExp(values.map(function (x) { return _lodash2['default'].escapeRegExp(x); }).join('|'), 'g'); } var rootContextRegex = regex(BEGIN_EXPRESSION, BEGIN_JAVASCRIPT, BEGIN_COMMENT, BEGIN_BLOCK_REFERENCE, BEGIN_PARTIAL, BEGIN_BLOCK, BEGIN_LAYOUT); var documentContextRegex = regex(END_DOCUMENT, BEGIN_EXPRESSION, BEGIN_JAVASCRIPT, BEGIN_COMMENT, BEGIN_BLOCK_REFERENCE, BEGIN_PARTIAL); var javascriptContextRegex = regex(END_JAVASCRIPT, BEGIN_COMMENT, BEGIN_DOCUMENT); var commentContextRegex = regex(BEGIN_COMMENT, END_COMMENT); var Lexer = (function () { function Lexer(text, filename) { _classCallCheck(this, Lexer); this.text = text; this.index = 0; this.lineIndex = 0; this.line = 1; this.filename = filename; } _createClass(Lexer, [{ key: 'currentLocation', value: function currentLocation() { return new _Location2['default'](this.filename, this.line, this.index - this.lineIndex + 1); } }, { key: 'moveForward', value: function moveForward(toIndex, str) { str = str || this.text.substring(this.index, toIndex); var re = /[\n\v\f\r\x85\u2028\u2029]/g; var match = undefined; while (match = re.exec(str)) { ++this.line; this.lineIndex = re.lastIndex; } this.index = toIndex; } // TODO: Remove token values that aren't actually used (.end, etc). }, { key: 'getToken', value: function getToken(newIndex, token, matchIndex) { if (this.index === matchIndex) { switch (token) { case _tokens2['default'].DOCUMENT: this.index = newIndex; return null; case _tokens2['default'].BLOCK_REFERENCE: break; default: throw new Error(token + ' tag cannot be empty.'); } } var result = { token: token, value: this.text.substring(this.index, matchIndex), begin: this.currentLocation() }; this.moveForward(newIndex, result.value); result.end = this.currentLocation(); return result; } }, { key: 'comment', value: _regeneratorRuntime.mark(function comment() { var openLocation, match; return _regeneratorRuntime.wrap(function comment$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: openLocation = this.currentLocation(); this.index += BEGIN_COMMENT.length; commentContextRegex.lastIndex = this.index; case 3: if (!true) { context$2$0.next = 20; break; } match = commentContextRegex.exec(this.text); if (!(match === null)) { context$2$0.next = 7; break; } throw new Error('Comment tag opened at ' + openLocation.locationString() + ' missing closing tag ' + END_COMMENT); case 7: this.moveForward(commentContextRegex.lastIndex); if (!(match[0] === END_COMMENT)) { context$2$0.next = 12; break; } return context$2$0.abrupt('return'); case 12: if (!(match[0] === BEGIN_COMMENT)) { context$2$0.next = 17; break; } return context$2$0.delegateYield(this.comment(), 't0', 14); case 14: commentContextRegex.lastIndex = this.index; context$2$0.next = 18; break; case 17: throw new Error("Internal error."); case 18: context$2$0.next = 3; break; case 20: case 'end': return context$2$0.stop(); } }, comment, this); }) }, { key: 'javascript', value: _regeneratorRuntime.mark(function javascript() { var openLocation, match; return _regeneratorRuntime.wrap(function javascript$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: openLocation = this.currentLocation(); javascriptContextRegex.lastIndex = this.index; case 2: if (!true) { context$2$0.next = 23; break; } match = javascriptContextRegex.exec(this.text); if (!(match === null)) { context$2$0.next = 6; break; } throw new Error('Javascript tag opened at ' + openLocation.locationString() + ' missing closing tag ' + END_JAVASCRIPT); case 6: context$2$0.next = 8; return this.getToken(javascriptContextRegex.lastIndex, _tokens2['default'].JAVASCRIPT, match.index); case 8: if (!(match[0] === END_JAVASCRIPT)) { context$2$0.next = 10; break; } return context$2$0.abrupt('return'); case 10: if (!(match[0] === BEGIN_COMMENT)) { context$2$0.next = 15; break; } return context$2$0.delegateYield(this.comment(), 't0', 12); case 12: javascriptContextRegex.lastIndex = this.index; context$2$0.next = 21; break; case 15: if (!(match[0] === BEGIN_DOCUMENT)) { context$2$0.next = 20; break; } return context$2$0.delegateYield(this.document(), 't1', 17); case 17: javascriptContextRegex.lastIndex = this.index; context$2$0.next = 21; break; case 20: throw new Error("Internal error."); case 21: context$2$0.next = 2; break; case 23: case 'end': return context$2$0.stop(); } }, javascript, this); }) }, { key: 'expression', value: _regeneratorRuntime.mark(function expression() { var openLocation, matchIndex; return _regeneratorRuntime.wrap(function expression$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: openLocation = this.currentLocation(); matchIndex = this.text.indexOf(END_EXPRESSION, this.index); if (!(matchIndex === -1)) { context$2$0.next = 4; break; } throw new Error('Expression tag opened at ' + openLocation.locationString() + ' missing closing tag ' + END_EXPRESSION); case 4: context$2$0.next = 6; return this.getToken(matchIndex + END_EXPRESSION.length, _tokens2['default'].EXPRESSION, matchIndex); case 6: case 'end': return context$2$0.stop(); } }, expression, this); }) }, { key: 'layout', value: _regeneratorRuntime.mark(function layout() { var openLocation, matchIndex; return _regeneratorRuntime.wrap(function layout$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: openLocation = this.currentLocation(); matchIndex = this.text.indexOf(END_LAYOUT, this.index); if (!(matchIndex === -1)) { context$2$0.next = 4; break; } throw new Error('Layout tag opened at ' + openLocation.locationString() + ' missing closing tag ' + END_LAYOUT); case 4: context$2$0.next = 6; return this.getToken(matchIndex + END_LAYOUT.length, _tokens2['default'].LAYOUT, matchIndex); case 6: case 'end': return context$2$0.stop(); } }, layout, this); }) }, { key: 'blockReference', value: _regeneratorRuntime.mark(function blockReference() { var openLocation, matchIndex; return _regeneratorRuntime.wrap(function blockReference$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: openLocation = this.currentLocation(); matchIndex = this.text.indexOf(END_BLOCK_REFERENCE, this.index); if (!(matchIndex === -1)) { context$2$0.next = 4; break; } throw new Error('Block Reference tag opened at ' + openLocation.locationString() + ' missing closing tag ' + END_BLOCK_REFERENCE); case 4: context$2$0.next = 6; return this.getToken(matchIndex + END_BLOCK_REFERENCE.length, _tokens2['default'].BLOCK_REFERENCE, matchIndex); case 6: case 'end': return context$2$0.stop(); } }, blockReference, this); }) }, { key: 'partial', value: _regeneratorRuntime.mark(function partial() { var openLocation, matchIndex; return _regeneratorRuntime.wrap(function partial$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: openLocation = this.currentLocation(); matchIndex = this.text.indexOf(END_PARTIAL, this.index); if (!(matchIndex === -1)) { context$2$0.next = 4; break; } throw new Error('Partial tag opened at ' + openLocation.locationString() + ' missing closing tag ' + END_PARTIAL); case 4: context$2$0.next = 6; return this.getToken(matchIndex + END_PARTIAL.length, _tokens2['default'].PARTIAL, matchIndex); case 6: case 'end': return context$2$0.stop(); } }, partial, this); }) }, { key: 'block', value: _regeneratorRuntime.mark(function block() { var openLocation, matchIndex; return _regeneratorRuntime.wrap(function block$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: openLocation = this.currentLocation(); matchIndex = this.text.indexOf(BEGIN_DOCUMENT, this.index); if (!(matchIndex === -1)) { context$2$0.next = 4; break; } throw new Error('Block tag opened at ' + openLocation.locationString() + ' missing opening document tag ' + BEGIN_DOCUMENT); case 4: context$2$0.next = 6; return this.getToken(matchIndex + BEGIN_DOCUMENT.length, _tokens2['default'].BLOCK_NAME, matchIndex); case 6: return context$2$0.delegateYield(this.document(), 't0', 7); case 7: matchIndex = this.text.indexOf(END_BLOCK, this.index); if (!(matchIndex === -1)) { context$2$0.next = 10; break; } throw new Error('Block tag opened at ' + openLocation.locationString() + ' missing closing tag ' + END_BLOCK); case 10: this.moveForward(matchIndex + END_BLOCK.length); case 11: case 'end': return context$2$0.stop(); } }, block, this); }) }, { key: 'document', value: _regeneratorRuntime.mark(function document() { var openLocation, match; return _regeneratorRuntime.wrap(function document$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: openLocation = this.currentLocation(); documentContextRegex.lastIndex = this.index; case 2: if (!true) { context$2$0.next = 38; break; } match = documentContextRegex.exec(this.text); if (!(match === null)) { context$2$0.next = 6; break; } throw new Error('Document tag opened at ' + openLocation.locationString() + ' missing closing tag ' + END_DOCUMENT); case 6: context$2$0.next = 8; return this.getToken(documentContextRegex.lastIndex, _tokens2['default'].DOCUMENT, match.index); case 8: if (!(match[0] === END_DOCUMENT)) { context$2$0.next = 10; break; } return context$2$0.abrupt('return'); case 10: if (!(match[0] === BEGIN_EXPRESSION)) { context$2$0.next = 15; break; } return context$2$0.delegateYield(this.expression(), 't0', 12); case 12: documentContextRegex.lastIndex = this.index; context$2$0.next = 36; break; case 15: if (!(match[0] === BEGIN_JAVASCRIPT)) { context$2$0.next = 20; break; } return context$2$0.delegateYield(this.javascript(), 't1', 17); case 17: documentContextRegex.lastIndex = this.index; context$2$0.next = 36; break; case 20: if (!(match[0] === BEGIN_COMMENT)) { context$2$0.next = 25; break; } return context$2$0.delegateYield(this.comment(), 't2', 22); case 22: documentContextRegex.lastIndex = this.index; context$2$0.next = 36; break; case 25: if (!(match[0] === BEGIN_BLOCK_REFERENCE)) { context$2$0.next = 30; break; } return context$2$0.delegateYield(this.blockReference(), 't3', 27); case 27: documentContextRegex.lastIndex = this.index; context$2$0.next = 36; break; case 30: if (!(match[0] === BEGIN_PARTIAL)) { context$2$0.next = 35; break; } return context$2$0.delegateYield(this.partial(), 't4', 32); case 32: rootContextRegex.lastIndex = this.index; context$2$0.next = 36; break; case 35: throw new Error("Internal error."); case 36: context$2$0.next = 2; break; case 38: case 'end': return context$2$0.stop(); } }, document, this); }) }, { key: 'root', value: _regeneratorRuntime.mark(function root() { var match; return _regeneratorRuntime.wrap(function root$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: rootContextRegex.lastIndex = this.index; case 1: if (!true) { context$2$0.next = 47; break; } match = rootContextRegex.exec(this.text); if (!(match === null)) { context$2$0.next = 7; break; } context$2$0.next = 6; return this.getToken(this.text.length, _tokens2['default'].DOCUMENT, this.text.length); case 6: return context$2$0.abrupt('return'); case 7: context$2$0.next = 9; return this.getToken(rootContextRegex.lastIndex, _tokens2['default'].DOCUMENT, match.index); case 9: if (!(match[0] === BEGIN_EXPRESSION)) { context$2$0.next = 14; break; } return context$2$0.delegateYield(this.expression(), 't0', 11); case 11: rootContextRegex.lastIndex = this.index; context$2$0.next = 45; break; case 14: if (!(match[0] === BEGIN_JAVASCRIPT)) { context$2$0.next = 19; break; } return context$2$0.delegateYield(this.javascript(), 't1', 16); case 16: rootContextRegex.lastIndex = this.index; context$2$0.next = 45; break; case 19: if (!(match[0] === BEGIN_COMMENT)) { context$2$0.next = 24; break; } return context$2$0.delegateYield(this.comment(), 't2', 21); case 21: rootContextRegex.lastIndex = this.index; context$2$0.next = 45; break; case 24: if (!(match[0] === BEGIN_BLOCK)) { context$2$0.next = 29; break; } return context$2$0.delegateYield(this.block(), 't3', 26); case 26: rootContextRegex.lastIndex = this.index; context$2$0.next = 45; break; case 29: if (!(match[0] === BEGIN_BLOCK_REFERENCE)) { context$2$0.next = 34; break; } return context$2$0.delegateYield(this.blockReference(), 't4', 31); case 31: rootContextRegex.lastIndex = this.index; context$2$0.next = 45; break; case 34: if (!(match[0] === BEGIN_PARTIAL)) { context$2$0.next = 39; break; } return context$2$0.delegateYield(this.partial(), 't5', 36); case 36: rootContextRegex.lastIndex = this.index; context$2$0.next = 45; break; case 39: if (!(match[0] === BEGIN_LAYOUT)) { context$2$0.next = 44; break; } return context$2$0.delegateYield(this.layout(), 't6', 41); case 41: rootContextRegex.lastIndex = this.index; context$2$0.next = 45; break; case 44: throw new Error("Internal error."); case 45: context$2$0.next = 1; break; case 47: case 'end': return context$2$0.stop(); } }, root, this); }) }, { key: 'lex', value: _regeneratorRuntime.mark(function lex() { var _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, token; return _regeneratorRuntime.wrap(function lex$(context$2$0) { while (1) switch (context$2$0.prev = context$2$0.next) { case 0: context$2$0.prev = 0; _iteratorNormalCompletion = true; _didIteratorError = false; _iteratorError = undefined; context$2$0.prev = 4; _iterator = _getIterator(this.root()); case 6: if (_iteratorNormalCompletion = (_step = _iterator.next()).done) { context$2$0.next = 14; break; } token = _step.value; if (!(token !== null)) { context$2$0.next = 11; break; } context$2$0.next = 11; return token; case 11: _iteratorNormalCompletion = true; context$2$0.next = 6; break; case 14: context$2$0.next = 20; break; case 16: context$2$0.prev = 16; context$2$0.t0 = context$2$0['catch'](4); _didIteratorError = true; _iteratorError = context$2$0.t0; case 20: context$2$0.prev = 20; context$2$0.prev = 21; if (!_iteratorNormalCompletion && _iterator['return']) { _iterator['return'](); } case 23: context$2$0.prev = 23; if (!_didIteratorError) { context$2$0.next = 26; break; } throw _iteratorError; case 26: return context$2$0.finish(23); case 27: return context$2$0.finish(20); case 28: context$2$0.next = 34; break; case 30: context$2$0.prev = 30; context$2$0.t1 = context$2$0['catch'](0); context$2$0.t1.message = this.currentLocation() + ': ' + context$2$0.t1.message; throw context$2$0.t1; case 34: case 'end': return context$2$0.stop(); } }, lex, this, [[0, 30], [4, 16, 20, 28], [21,, 23, 27]]); }) }]); return Lexer; })(); exports['default'] = Lexer; module.exports = exports['default']; //# sourceMappingURL=Lexer.js.map