UNPKG

swig

Version:

A simple, powerful, and extendable templating engine for node.js and browsers, similar to Django, Jinja2, and Twig.

131 lines (116 loc) 4.54 kB
var ctx = '_ctx.', ctxloop = ctx + 'loop'; /** * Loop over objects and arrays. * * @alias for * * @example * // obj = { one: 'hi', two: 'bye' }; * {% for x in obj %} * {% if loop.first %}<ul>{% endif %} * <li>{{ loop.index }} - {{ loop.key }}: {{ x }}</li> * {% if loop.last %}</ul>{% endif %} * {% endfor %} * // => <ul> * // <li>1 - one: hi</li> * // <li>2 - two: bye</li> * // </ul> * * @example * // arr = [1, 2, 3] * // Reverse the array, shortcut the key/index to `key` * {% for key, val in arr|reverse %} * {{ key }} -- {{ val }} * {% endfor %} * // => 0 -- 3 * // 1 -- 2 * // 2 -- 1 * * @param {literal} [key] A shortcut to the index of the array or current key accessor. * @param {literal} variable The current value will be assigned to this variable name temporarily. The variable will be reset upon ending the for tag. * @param {literal} in Literally, "in". This token is required. * @param {object} object An enumerable object that will be iterated over. * * @return {loop.index} The current iteration of the loop (1-indexed) * @return {loop.index0} The current iteration of the loop (0-indexed) * @return {loop.revindex} The number of iterations from the end of the loop (1-indexed) * @return {loop.revindex0} The number of iterations from the end of the loop (0-indexed) * @return {loop.key} If the iterator is an object, this will be the key of the current item, otherwise it will be the same as the loop.index. * @return {loop.first} True if the current object is the first in the object or array. * @return {loop.last} True if the current object is the last in the object or array. */ exports.compile = function (compiler, args, content, parents, options, blockName) { var val = args.shift(), key = '__k', ctxloopcache = (ctx + '__loopcache' + Math.random()).replace(/\./g, ''), last; if (args[0] && args[0] === ',') { args.shift(); key = val; val = args.shift(); } last = args.join(''); return [ '(function () {\n', ' var __l = ' + last + ', __len = (_utils.isArray(__l) || typeof __l === "string") ? __l.length : _utils.keys(__l).length;\n', ' if (!__l) { return; }\n', ' var ' + ctxloopcache + ' = { loop: ' + ctxloop + ', ' + val + ': ' + ctx + val + ', ' + key + ': ' + ctx + key + ' };\n', ' ' + ctxloop + ' = { first: false, index: 1, index0: 0, revindex: __len, revindex0: __len - 1, length: __len, last: false };\n', ' _utils.each(__l, function (' + val + ', ' + key + ') {\n', ' ' + ctx + val + ' = ' + val + ';\n', ' ' + ctx + key + ' = ' + key + ';\n', ' ' + ctxloop + '.key = ' + key + ';\n', ' ' + ctxloop + '.first = (' + ctxloop + '.index0 === 0);\n', ' ' + ctxloop + '.last = (' + ctxloop + '.revindex0 === 0);\n', ' ' + compiler(content, parents, options, blockName), ' ' + ctxloop + '.index += 1; ' + ctxloop + '.index0 += 1; ' + ctxloop + '.revindex -= 1; ' + ctxloop + '.revindex0 -= 1;\n', ' });\n', ' ' + ctxloop + ' = ' + ctxloopcache + '.loop;\n', ' ' + ctx + val + ' = ' + ctxloopcache + '.' + val + ';\n', ' ' + ctx + key + ' = ' + ctxloopcache + '.' + key + ';\n', ' ' + ctxloopcache + ' = undefined;\n', '})();\n' ].join(''); }; exports.parse = function (str, line, parser, types) { var firstVar, ready; parser.on(types.NUMBER, function (token) { var lastState = this.state.length ? this.state[this.state.length - 1] : null; if (!ready || (lastState !== types.ARRAYOPEN && lastState !== types.CURLYOPEN && lastState !== types.CURLYCLOSE && lastState !== types.FUNCTION && lastState !== types.FILTER) ) { throw new Error('Unexpected number "' + token.match + '" on line ' + line + '.'); } return true; }); parser.on(types.VAR, function (token) { if (ready && firstVar) { return true; } if (!this.out.length) { firstVar = true; } this.out.push(token.match); }); parser.on(types.COMMA, function (token) { if (firstVar && this.prevToken.type === types.VAR) { this.out.push(token.match); return; } return true; }); parser.on(types.COMPARATOR, function (token) { if (token.match !== 'in' || !firstVar) { throw new Error('Unexpected token "' + token.match + '" on line ' + line + '.'); } ready = true; this.filterApplyIdx.push(this.out.length); }); return true; }; exports.ends = true;