diff options
| author | Shipwreckt <me@shipwreckt.co.uk> | 2025-10-31 20:02:14 +0000 |
|---|---|---|
| committer | Shipwreckt <me@shipwreckt.co.uk> | 2025-10-31 20:02:14 +0000 |
| commit | 7a52ddeba2a68388b544f529d2d92104420f77b0 (patch) | |
| tree | 15ddd47457a2cb4a96060747437d36474e4f6b4e /node_modules/nunjucks/src/compiler.js | |
| parent | 53d6ae2b5568437afa5e4995580a3fb679b7b91b (diff) | |
Changed from static to 11ty!
Diffstat (limited to 'node_modules/nunjucks/src/compiler.js')
| -rw-r--r-- | node_modules/nunjucks/src/compiler.js | 1027 |
1 files changed, 1027 insertions, 0 deletions
diff --git a/node_modules/nunjucks/src/compiler.js b/node_modules/nunjucks/src/compiler.js new file mode 100644 index 0000000..4958283 --- /dev/null +++ b/node_modules/nunjucks/src/compiler.js @@ -0,0 +1,1027 @@ +'use strict'; + +function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); } +function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } +var parser = require('./parser'); +var transformer = require('./transformer'); +var nodes = require('./nodes'); +var _require = require('./lib'), + TemplateError = _require.TemplateError; +var _require2 = require('./runtime'), + Frame = _require2.Frame; +var _require3 = require('./object'), + Obj = _require3.Obj; + +// These are all the same for now, but shouldn't be passed straight +// through +var compareOps = { + '==': '==', + '===': '===', + '!=': '!=', + '!==': '!==', + '<': '<', + '>': '>', + '<=': '<=', + '>=': '>=' +}; +var Compiler = /*#__PURE__*/function (_Obj) { + _inheritsLoose(Compiler, _Obj); + function Compiler() { + return _Obj.apply(this, arguments) || this; + } + var _proto = Compiler.prototype; + _proto.init = function init(templateName, throwOnUndefined) { + this.templateName = templateName; + this.codebuf = []; + this.lastId = 0; + this.buffer = null; + this.bufferStack = []; + this._scopeClosers = ''; + this.inBlock = false; + this.throwOnUndefined = throwOnUndefined; + }; + _proto.fail = function fail(msg, lineno, colno) { + if (lineno !== undefined) { + lineno += 1; + } + if (colno !== undefined) { + colno += 1; + } + throw new TemplateError(msg, lineno, colno); + }; + _proto._pushBuffer = function _pushBuffer() { + var id = this._tmpid(); + this.bufferStack.push(this.buffer); + this.buffer = id; + this._emit("var " + this.buffer + " = \"\";"); + return id; + }; + _proto._popBuffer = function _popBuffer() { + this.buffer = this.bufferStack.pop(); + }; + _proto._emit = function _emit(code) { + this.codebuf.push(code); + }; + _proto._emitLine = function _emitLine(code) { + this._emit(code + '\n'); + }; + _proto._emitLines = function _emitLines() { + var _this = this; + for (var _len = arguments.length, lines = new Array(_len), _key = 0; _key < _len; _key++) { + lines[_key] = arguments[_key]; + } + lines.forEach(function (line) { + return _this._emitLine(line); + }); + }; + _proto._emitFuncBegin = function _emitFuncBegin(node, name) { + this.buffer = 'output'; + this._scopeClosers = ''; + this._emitLine("function " + name + "(env, context, frame, runtime, cb) {"); + this._emitLine("var lineno = " + node.lineno + ";"); + this._emitLine("var colno = " + node.colno + ";"); + this._emitLine("var " + this.buffer + " = \"\";"); + this._emitLine('try {'); + }; + _proto._emitFuncEnd = function _emitFuncEnd(noReturn) { + if (!noReturn) { + this._emitLine('cb(null, ' + this.buffer + ');'); + } + this._closeScopeLevels(); + this._emitLine('} catch (e) {'); + this._emitLine(' cb(runtime.handleError(e, lineno, colno));'); + this._emitLine('}'); + this._emitLine('}'); + this.buffer = null; + }; + _proto._addScopeLevel = function _addScopeLevel() { + this._scopeClosers += '})'; + }; + _proto._closeScopeLevels = function _closeScopeLevels() { + this._emitLine(this._scopeClosers + ';'); + this._scopeClosers = ''; + }; + _proto._withScopedSyntax = function _withScopedSyntax(func) { + var _scopeClosers = this._scopeClosers; + this._scopeClosers = ''; + func.call(this); + this._closeScopeLevels(); + this._scopeClosers = _scopeClosers; + }; + _proto._makeCallback = function _makeCallback(res) { + var err = this._tmpid(); + return 'function(' + err + (res ? ',' + res : '') + ') {\n' + 'if(' + err + ') { cb(' + err + '); return; }'; + }; + _proto._tmpid = function _tmpid() { + this.lastId++; + return 't_' + this.lastId; + }; + _proto._templateName = function _templateName() { + return this.templateName == null ? 'undefined' : JSON.stringify(this.templateName); + }; + _proto._compileChildren = function _compileChildren(node, frame) { + var _this2 = this; + node.children.forEach(function (child) { + _this2.compile(child, frame); + }); + }; + _proto._compileAggregate = function _compileAggregate(node, frame, startChar, endChar) { + var _this3 = this; + if (startChar) { + this._emit(startChar); + } + node.children.forEach(function (child, i) { + if (i > 0) { + _this3._emit(','); + } + _this3.compile(child, frame); + }); + if (endChar) { + this._emit(endChar); + } + }; + _proto._compileExpression = function _compileExpression(node, frame) { + // TODO: I'm not really sure if this type check is worth it or + // not. + this.assertType(node, nodes.Literal, nodes.Symbol, nodes.Group, nodes.Array, nodes.Dict, nodes.FunCall, nodes.Caller, nodes.Filter, nodes.LookupVal, nodes.Compare, nodes.InlineIf, nodes.In, nodes.Is, nodes.And, nodes.Or, nodes.Not, nodes.Add, nodes.Concat, nodes.Sub, nodes.Mul, nodes.Div, nodes.FloorDiv, nodes.Mod, nodes.Pow, nodes.Neg, nodes.Pos, nodes.Compare, nodes.NodeList); + this.compile(node, frame); + }; + _proto.assertType = function assertType(node) { + for (var _len2 = arguments.length, types = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { + types[_key2 - 1] = arguments[_key2]; + } + if (!types.some(function (t) { + return node instanceof t; + })) { + this.fail("assertType: invalid type: " + node.typename, node.lineno, node.colno); + } + }; + _proto.compileCallExtension = function compileCallExtension(node, frame, async) { + var _this4 = this; + var args = node.args; + var contentArgs = node.contentArgs; + var autoescape = typeof node.autoescape === 'boolean' ? node.autoescape : true; + if (!async) { + this._emit(this.buffer + " += runtime.suppressValue("); + } + this._emit("env.getExtension(\"" + node.extName + "\")[\"" + node.prop + "\"]("); + this._emit('context'); + if (args || contentArgs) { + this._emit(','); + } + if (args) { + if (!(args instanceof nodes.NodeList)) { + this.fail('compileCallExtension: arguments must be a NodeList, ' + 'use `parser.parseSignature`'); + } + args.children.forEach(function (arg, i) { + // Tag arguments are passed normally to the call. Note + // that keyword arguments are turned into a single js + // object as the last argument, if they exist. + _this4._compileExpression(arg, frame); + if (i !== args.children.length - 1 || contentArgs.length) { + _this4._emit(','); + } + }); + } + if (contentArgs.length) { + contentArgs.forEach(function (arg, i) { + if (i > 0) { + _this4._emit(','); + } + if (arg) { + _this4._emitLine('function(cb) {'); + _this4._emitLine('if(!cb) { cb = function(err) { if(err) { throw err; }}}'); + var id = _this4._pushBuffer(); + _this4._withScopedSyntax(function () { + _this4.compile(arg, frame); + _this4._emitLine("cb(null, " + id + ");"); + }); + _this4._popBuffer(); + _this4._emitLine("return " + id + ";"); + _this4._emitLine('}'); + } else { + _this4._emit('null'); + } + }); + } + if (async) { + var res = this._tmpid(); + this._emitLine(', ' + this._makeCallback(res)); + this._emitLine(this.buffer + " += runtime.suppressValue(" + res + ", " + autoescape + " && env.opts.autoescape);"); + this._addScopeLevel(); + } else { + this._emit(')'); + this._emit(", " + autoescape + " && env.opts.autoescape);\n"); + } + }; + _proto.compileCallExtensionAsync = function compileCallExtensionAsync(node, frame) { + this.compileCallExtension(node, frame, true); + }; + _proto.compileNodeList = function compileNodeList(node, frame) { + this._compileChildren(node, frame); + }; + _proto.compileLiteral = function compileLiteral(node) { + if (typeof node.value === 'string') { + var val = node.value.replace(/\\/g, '\\\\'); + val = val.replace(/"/g, '\\"'); + val = val.replace(/\n/g, '\\n'); + val = val.replace(/\r/g, '\\r'); + val = val.replace(/\t/g, '\\t'); + val = val.replace(/\u2028/g, "\\u2028"); + this._emit("\"" + val + "\""); + } else if (node.value === null) { + this._emit('null'); + } else { + this._emit(node.value.toString()); + } + }; + _proto.compileSymbol = function compileSymbol(node, frame) { + var name = node.value; + var v = frame.lookup(name); + if (v) { + this._emit(v); + } else { + this._emit('runtime.contextOrFrameLookup(' + 'context, frame, "' + name + '")'); + } + }; + _proto.compileGroup = function compileGroup(node, frame) { + this._compileAggregate(node, frame, '(', ')'); + }; + _proto.compileArray = function compileArray(node, frame) { + this._compileAggregate(node, frame, '[', ']'); + }; + _proto.compileDict = function compileDict(node, frame) { + this._compileAggregate(node, frame, '{', '}'); + }; + _proto.compilePair = function compilePair(node, frame) { + var key = node.key; + var val = node.value; + if (key instanceof nodes.Symbol) { + key = new nodes.Literal(key.lineno, key.colno, key.value); + } else if (!(key instanceof nodes.Literal && typeof key.value === 'string')) { + this.fail('compilePair: Dict keys must be strings or names', key.lineno, key.colno); + } + this.compile(key, frame); + this._emit(': '); + this._compileExpression(val, frame); + }; + _proto.compileInlineIf = function compileInlineIf(node, frame) { + this._emit('('); + this.compile(node.cond, frame); + this._emit('?'); + this.compile(node.body, frame); + this._emit(':'); + if (node.else_ !== null) { + this.compile(node.else_, frame); + } else { + this._emit('""'); + } + this._emit(')'); + }; + _proto.compileIn = function compileIn(node, frame) { + this._emit('runtime.inOperator('); + this.compile(node.left, frame); + this._emit(','); + this.compile(node.right, frame); + this._emit(')'); + }; + _proto.compileIs = function compileIs(node, frame) { + // first, we need to try to get the name of the test function, if it's a + // callable (i.e., has args) and not a symbol. + var right = node.right.name ? node.right.name.value + // otherwise go with the symbol value + : node.right.value; + this._emit('env.getTest("' + right + '").call(context, '); + this.compile(node.left, frame); + // compile the arguments for the callable if they exist + if (node.right.args) { + this._emit(','); + this.compile(node.right.args, frame); + } + this._emit(') === true'); + }; + _proto._binOpEmitter = function _binOpEmitter(node, frame, str) { + this.compile(node.left, frame); + this._emit(str); + this.compile(node.right, frame); + } + + // ensure concatenation instead of addition + // by adding empty string in between + ; + _proto.compileOr = function compileOr(node, frame) { + return this._binOpEmitter(node, frame, ' || '); + }; + _proto.compileAnd = function compileAnd(node, frame) { + return this._binOpEmitter(node, frame, ' && '); + }; + _proto.compileAdd = function compileAdd(node, frame) { + return this._binOpEmitter(node, frame, ' + '); + }; + _proto.compileConcat = function compileConcat(node, frame) { + return this._binOpEmitter(node, frame, ' + "" + '); + }; + _proto.compileSub = function compileSub(node, frame) { + return this._binOpEmitter(node, frame, ' - '); + }; + _proto.compileMul = function compileMul(node, frame) { + return this._binOpEmitter(node, frame, ' * '); + }; + _proto.compileDiv = function compileDiv(node, frame) { + return this._binOpEmitter(node, frame, ' / '); + }; + _proto.compileMod = function compileMod(node, frame) { + return this._binOpEmitter(node, frame, ' % '); + }; + _proto.compileNot = function compileNot(node, frame) { + this._emit('!'); + this.compile(node.target, frame); + }; + _proto.compileFloorDiv = function compileFloorDiv(node, frame) { + this._emit('Math.floor('); + this.compile(node.left, frame); + this._emit(' / '); + this.compile(node.right, frame); + this._emit(')'); + }; + _proto.compilePow = function compilePow(node, frame) { + this._emit('Math.pow('); + this.compile(node.left, frame); + this._emit(', '); + this.compile(node.right, frame); + this._emit(')'); + }; + _proto.compileNeg = function compileNeg(node, frame) { + this._emit('-'); + this.compile(node.target, frame); + }; + _proto.compilePos = function compilePos(node, frame) { + this._emit('+'); + this.compile(node.target, frame); + }; + _proto.compileCompare = function compileCompare(node, frame) { + var _this5 = this; + this.compile(node.expr, frame); + node.ops.forEach(function (op) { + _this5._emit(" " + compareOps[op.type] + " "); + _this5.compile(op.expr, frame); + }); + }; + _proto.compileLookupVal = function compileLookupVal(node, frame) { + this._emit('runtime.memberLookup(('); + this._compileExpression(node.target, frame); + this._emit('),'); + this._compileExpression(node.val, frame); + this._emit(')'); + }; + _proto._getNodeName = function _getNodeName(node) { + switch (node.typename) { + case 'Symbol': + return node.value; + case 'FunCall': + return 'the return value of (' + this._getNodeName(node.name) + ')'; + case 'LookupVal': + return this._getNodeName(node.target) + '["' + this._getNodeName(node.val) + '"]'; + case 'Literal': + return node.value.toString(); + default: + return '--expression--'; + } + }; + _proto.compileFunCall = function compileFunCall(node, frame) { + // Keep track of line/col info at runtime by settings + // variables within an expression. An expression in javascript + // like (x, y, z) returns the last value, and x and y can be + // anything + this._emit('(lineno = ' + node.lineno + ', colno = ' + node.colno + ', '); + this._emit('runtime.callWrap('); + // Compile it as normal. + this._compileExpression(node.name, frame); + + // Output the name of what we're calling so we can get friendly errors + // if the lookup fails. + this._emit(', "' + this._getNodeName(node.name).replace(/"/g, '\\"') + '", context, '); + this._compileAggregate(node.args, frame, '[', '])'); + this._emit(')'); + }; + _proto.compileFilter = function compileFilter(node, frame) { + var name = node.name; + this.assertType(name, nodes.Symbol); + this._emit('env.getFilter("' + name.value + '").call(context, '); + this._compileAggregate(node.args, frame); + this._emit(')'); + }; + _proto.compileFilterAsync = function compileFilterAsync(node, frame) { + var name = node.name; + var symbol = node.symbol.value; + this.assertType(name, nodes.Symbol); + frame.set(symbol, symbol); + this._emit('env.getFilter("' + name.value + '").call(context, '); + this._compileAggregate(node.args, frame); + this._emitLine(', ' + this._makeCallback(symbol)); + this._addScopeLevel(); + }; + _proto.compileKeywordArgs = function compileKeywordArgs(node, frame) { + this._emit('runtime.makeKeywordArgs('); + this.compileDict(node, frame); + this._emit(')'); + }; + _proto.compileSet = function compileSet(node, frame) { + var _this6 = this; + var ids = []; + + // Lookup the variable names for each identifier and create + // new ones if necessary + node.targets.forEach(function (target) { + var name = target.value; + var id = frame.lookup(name); + if (id === null || id === undefined) { + id = _this6._tmpid(); + + // Note: This relies on js allowing scope across + // blocks, in case this is created inside an `if` + _this6._emitLine('var ' + id + ';'); + } + ids.push(id); + }); + if (node.value) { + this._emit(ids.join(' = ') + ' = '); + this._compileExpression(node.value, frame); + this._emitLine(';'); + } else { + this._emit(ids.join(' = ') + ' = '); + this.compile(node.body, frame); + this._emitLine(';'); + } + node.targets.forEach(function (target, i) { + var id = ids[i]; + var name = target.value; + + // We are running this for every var, but it's very + // uncommon to assign to multiple vars anyway + _this6._emitLine("frame.set(\"" + name + "\", " + id + ", true);"); + _this6._emitLine('if(frame.topLevel) {'); + _this6._emitLine("context.setVariable(\"" + name + "\", " + id + ");"); + _this6._emitLine('}'); + if (name.charAt(0) !== '_') { + _this6._emitLine('if(frame.topLevel) {'); + _this6._emitLine("context.addExport(\"" + name + "\", " + id + ");"); + _this6._emitLine('}'); + } + }); + }; + _proto.compileSwitch = function compileSwitch(node, frame) { + var _this7 = this; + this._emit('switch ('); + this.compile(node.expr, frame); + this._emit(') {'); + node.cases.forEach(function (c, i) { + _this7._emit('case '); + _this7.compile(c.cond, frame); + _this7._emit(': '); + _this7.compile(c.body, frame); + // preserve fall-throughs + if (c.body.children.length) { + _this7._emitLine('break;'); + } + }); + if (node.default) { + this._emit('default:'); + this.compile(node.default, frame); + } + this._emit('}'); + }; + _proto.compileIf = function compileIf(node, frame, async) { + var _this8 = this; + this._emit('if('); + this._compileExpression(node.cond, frame); + this._emitLine(') {'); + this._withScopedSyntax(function () { + _this8.compile(node.body, frame); + if (async) { + _this8._emit('cb()'); + } + }); + if (node.else_) { + this._emitLine('}\nelse {'); + this._withScopedSyntax(function () { + _this8.compile(node.else_, frame); + if (async) { + _this8._emit('cb()'); + } + }); + } else if (async) { + this._emitLine('}\nelse {'); + this._emit('cb()'); + } + this._emitLine('}'); + }; + _proto.compileIfAsync = function compileIfAsync(node, frame) { + this._emit('(function(cb) {'); + this.compileIf(node, frame, true); + this._emit('})(' + this._makeCallback()); + this._addScopeLevel(); + }; + _proto._emitLoopBindings = function _emitLoopBindings(node, arr, i, len) { + var _this9 = this; + var bindings = [{ + name: 'index', + val: i + " + 1" + }, { + name: 'index0', + val: i + }, { + name: 'revindex', + val: len + " - " + i + }, { + name: 'revindex0', + val: len + " - " + i + " - 1" + }, { + name: 'first', + val: i + " === 0" + }, { + name: 'last', + val: i + " === " + len + " - 1" + }, { + name: 'length', + val: len + }]; + bindings.forEach(function (b) { + _this9._emitLine("frame.set(\"loop." + b.name + "\", " + b.val + ");"); + }); + }; + _proto.compileFor = function compileFor(node, frame) { + var _this10 = this; + // Some of this code is ugly, but it keeps the generated code + // as fast as possible. ForAsync also shares some of this, but + // not much. + + var i = this._tmpid(); + var len = this._tmpid(); + var arr = this._tmpid(); + frame = frame.push(); + this._emitLine('frame = frame.push();'); + this._emit("var " + arr + " = "); + this._compileExpression(node.arr, frame); + this._emitLine(';'); + this._emit("if(" + arr + ") {"); + this._emitLine(arr + ' = runtime.fromIterator(' + arr + ');'); + + // If multiple names are passed, we need to bind them + // appropriately + if (node.name instanceof nodes.Array) { + this._emitLine("var " + i + ";"); + + // The object could be an arroy or object. Note that the + // body of the loop is duplicated for each condition, but + // we are optimizing for speed over size. + this._emitLine("if(runtime.isArray(" + arr + ")) {"); + this._emitLine("var " + len + " = " + arr + ".length;"); + this._emitLine("for(" + i + "=0; " + i + " < " + arr + ".length; " + i + "++) {"); + + // Bind each declared var + node.name.children.forEach(function (child, u) { + var tid = _this10._tmpid(); + _this10._emitLine("var " + tid + " = " + arr + "[" + i + "][" + u + "];"); + _this10._emitLine("frame.set(\"" + child + "\", " + arr + "[" + i + "][" + u + "]);"); + frame.set(node.name.children[u].value, tid); + }); + this._emitLoopBindings(node, arr, i, len); + this._withScopedSyntax(function () { + _this10.compile(node.body, frame); + }); + this._emitLine('}'); + this._emitLine('} else {'); + // Iterate over the key/values of an object + var _node$name$children = node.name.children, + key = _node$name$children[0], + val = _node$name$children[1]; + var k = this._tmpid(); + var v = this._tmpid(); + frame.set(key.value, k); + frame.set(val.value, v); + this._emitLine(i + " = -1;"); + this._emitLine("var " + len + " = runtime.keys(" + arr + ").length;"); + this._emitLine("for(var " + k + " in " + arr + ") {"); + this._emitLine(i + "++;"); + this._emitLine("var " + v + " = " + arr + "[" + k + "];"); + this._emitLine("frame.set(\"" + key.value + "\", " + k + ");"); + this._emitLine("frame.set(\"" + val.value + "\", " + v + ");"); + this._emitLoopBindings(node, arr, i, len); + this._withScopedSyntax(function () { + _this10.compile(node.body, frame); + }); + this._emitLine('}'); + this._emitLine('}'); + } else { + // Generate a typical array iteration + var _v = this._tmpid(); + frame.set(node.name.value, _v); + this._emitLine("var " + len + " = " + arr + ".length;"); + this._emitLine("for(var " + i + "=0; " + i + " < " + arr + ".length; " + i + "++) {"); + this._emitLine("var " + _v + " = " + arr + "[" + i + "];"); + this._emitLine("frame.set(\"" + node.name.value + "\", " + _v + ");"); + this._emitLoopBindings(node, arr, i, len); + this._withScopedSyntax(function () { + _this10.compile(node.body, frame); + }); + this._emitLine('}'); + } + this._emitLine('}'); + if (node.else_) { + this._emitLine('if (!' + len + ') {'); + this.compile(node.else_, frame); + this._emitLine('}'); + } + this._emitLine('frame = frame.pop();'); + }; + _proto._compileAsyncLoop = function _compileAsyncLoop(node, frame, parallel) { + var _this11 = this; + // This shares some code with the For tag, but not enough to + // worry about. This iterates across an object asynchronously, + // but not in parallel. + + var i = this._tmpid(); + var len = this._tmpid(); + var arr = this._tmpid(); + var asyncMethod = parallel ? 'asyncAll' : 'asyncEach'; + frame = frame.push(); + this._emitLine('frame = frame.push();'); + this._emit('var ' + arr + ' = runtime.fromIterator('); + this._compileExpression(node.arr, frame); + this._emitLine(');'); + if (node.name instanceof nodes.Array) { + var arrayLen = node.name.children.length; + this._emit("runtime." + asyncMethod + "(" + arr + ", " + arrayLen + ", function("); + node.name.children.forEach(function (name) { + _this11._emit(name.value + ","); + }); + this._emit(i + ',' + len + ',next) {'); + node.name.children.forEach(function (name) { + var id = name.value; + frame.set(id, id); + _this11._emitLine("frame.set(\"" + id + "\", " + id + ");"); + }); + } else { + var id = node.name.value; + this._emitLine("runtime." + asyncMethod + "(" + arr + ", 1, function(" + id + ", " + i + ", " + len + ",next) {"); + this._emitLine('frame.set("' + id + '", ' + id + ');'); + frame.set(id, id); + } + this._emitLoopBindings(node, arr, i, len); + this._withScopedSyntax(function () { + var buf; + if (parallel) { + buf = _this11._pushBuffer(); + } + _this11.compile(node.body, frame); + _this11._emitLine('next(' + i + (buf ? ',' + buf : '') + ');'); + if (parallel) { + _this11._popBuffer(); + } + }); + var output = this._tmpid(); + this._emitLine('}, ' + this._makeCallback(output)); + this._addScopeLevel(); + if (parallel) { + this._emitLine(this.buffer + ' += ' + output + ';'); + } + if (node.else_) { + this._emitLine('if (!' + arr + '.length) {'); + this.compile(node.else_, frame); + this._emitLine('}'); + } + this._emitLine('frame = frame.pop();'); + }; + _proto.compileAsyncEach = function compileAsyncEach(node, frame) { + this._compileAsyncLoop(node, frame); + }; + _proto.compileAsyncAll = function compileAsyncAll(node, frame) { + this._compileAsyncLoop(node, frame, true); + }; + _proto._compileMacro = function _compileMacro(node, frame) { + var _this12 = this; + var args = []; + var kwargs = null; + var funcId = 'macro_' + this._tmpid(); + var keepFrame = frame !== undefined; + + // Type check the definition of the args + node.args.children.forEach(function (arg, i) { + if (i === node.args.children.length - 1 && arg instanceof nodes.Dict) { + kwargs = arg; + } else { + _this12.assertType(arg, nodes.Symbol); + args.push(arg); + } + }); + var realNames = [].concat(args.map(function (n) { + return "l_" + n.value; + }), ['kwargs']); + + // Quoted argument names + var argNames = args.map(function (n) { + return "\"" + n.value + "\""; + }); + var kwargNames = (kwargs && kwargs.children || []).map(function (n) { + return "\"" + n.key.value + "\""; + }); + + // We pass a function to makeMacro which destructures the + // arguments so support setting positional args with keywords + // args and passing keyword args as positional args + // (essentially default values). See runtime.js. + var currFrame; + if (keepFrame) { + currFrame = frame.push(true); + } else { + currFrame = new Frame(); + } + this._emitLines("var " + funcId + " = runtime.makeMacro(", "[" + argNames.join(', ') + "], ", "[" + kwargNames.join(', ') + "], ", "function (" + realNames.join(', ') + ") {", 'var callerFrame = frame;', 'frame = ' + (keepFrame ? 'frame.push(true);' : 'new runtime.Frame();'), 'kwargs = kwargs || {};', 'if (Object.prototype.hasOwnProperty.call(kwargs, "caller")) {', 'frame.set("caller", kwargs.caller); }'); + + // Expose the arguments to the template. Don't need to use + // random names because the function + // will create a new run-time scope for us + args.forEach(function (arg) { + _this12._emitLine("frame.set(\"" + arg.value + "\", l_" + arg.value + ");"); + currFrame.set(arg.value, "l_" + arg.value); + }); + + // Expose the keyword arguments + if (kwargs) { + kwargs.children.forEach(function (pair) { + var name = pair.key.value; + _this12._emit("frame.set(\"" + name + "\", "); + _this12._emit("Object.prototype.hasOwnProperty.call(kwargs, \"" + name + "\")"); + _this12._emit(" ? kwargs[\"" + name + "\"] : "); + _this12._compileExpression(pair.value, currFrame); + _this12._emit(');'); + }); + } + var bufferId = this._pushBuffer(); + this._withScopedSyntax(function () { + _this12.compile(node.body, currFrame); + }); + this._emitLine('frame = ' + (keepFrame ? 'frame.pop();' : 'callerFrame;')); + this._emitLine("return new runtime.SafeString(" + bufferId + ");"); + this._emitLine('});'); + this._popBuffer(); + return funcId; + }; + _proto.compileMacro = function compileMacro(node, frame) { + var funcId = this._compileMacro(node); + + // Expose the macro to the templates + var name = node.name.value; + frame.set(name, funcId); + if (frame.parent) { + this._emitLine("frame.set(\"" + name + "\", " + funcId + ");"); + } else { + if (node.name.value.charAt(0) !== '_') { + this._emitLine("context.addExport(\"" + name + "\");"); + } + this._emitLine("context.setVariable(\"" + name + "\", " + funcId + ");"); + } + }; + _proto.compileCaller = function compileCaller(node, frame) { + // basically an anonymous "macro expression" + this._emit('(function (){'); + var funcId = this._compileMacro(node, frame); + this._emit("return " + funcId + ";})()"); + }; + _proto._compileGetTemplate = function _compileGetTemplate(node, frame, eagerCompile, ignoreMissing) { + var parentTemplateId = this._tmpid(); + var parentName = this._templateName(); + var cb = this._makeCallback(parentTemplateId); + var eagerCompileArg = eagerCompile ? 'true' : 'false'; + var ignoreMissingArg = ignoreMissing ? 'true' : 'false'; + this._emit('env.getTemplate('); + this._compileExpression(node.template, frame); + this._emitLine(", " + eagerCompileArg + ", " + parentName + ", " + ignoreMissingArg + ", " + cb); + return parentTemplateId; + }; + _proto.compileImport = function compileImport(node, frame) { + var target = node.target.value; + var id = this._compileGetTemplate(node, frame, false, false); + this._addScopeLevel(); + this._emitLine(id + '.getExported(' + (node.withContext ? 'context.getVariables(), frame, ' : '') + this._makeCallback(id)); + this._addScopeLevel(); + frame.set(target, id); + if (frame.parent) { + this._emitLine("frame.set(\"" + target + "\", " + id + ");"); + } else { + this._emitLine("context.setVariable(\"" + target + "\", " + id + ");"); + } + }; + _proto.compileFromImport = function compileFromImport(node, frame) { + var _this13 = this; + var importedId = this._compileGetTemplate(node, frame, false, false); + this._addScopeLevel(); + this._emitLine(importedId + '.getExported(' + (node.withContext ? 'context.getVariables(), frame, ' : '') + this._makeCallback(importedId)); + this._addScopeLevel(); + node.names.children.forEach(function (nameNode) { + var name; + var alias; + var id = _this13._tmpid(); + if (nameNode instanceof nodes.Pair) { + name = nameNode.key.value; + alias = nameNode.value.value; + } else { + name = nameNode.value; + alias = name; + } + _this13._emitLine("if(Object.prototype.hasOwnProperty.call(" + importedId + ", \"" + name + "\")) {"); + _this13._emitLine("var " + id + " = " + importedId + "." + name + ";"); + _this13._emitLine('} else {'); + _this13._emitLine("cb(new Error(\"cannot import '" + name + "'\")); return;"); + _this13._emitLine('}'); + frame.set(alias, id); + if (frame.parent) { + _this13._emitLine("frame.set(\"" + alias + "\", " + id + ");"); + } else { + _this13._emitLine("context.setVariable(\"" + alias + "\", " + id + ");"); + } + }); + }; + _proto.compileBlock = function compileBlock(node) { + var id = this._tmpid(); + + // If we are executing outside a block (creating a top-level + // block), we really don't want to execute its code because it + // will execute twice: once when the child template runs and + // again when the parent template runs. Note that blocks + // within blocks will *always* execute immediately *and* + // wherever else they are invoked (like used in a parent + // template). This may have behavioral differences from jinja + // because blocks can have side effects, but it seems like a + // waste of performance to always execute huge top-level + // blocks twice + if (!this.inBlock) { + this._emit('(parentTemplate ? function(e, c, f, r, cb) { cb(""); } : '); + } + this._emit("context.getBlock(\"" + node.name.value + "\")"); + if (!this.inBlock) { + this._emit(')'); + } + this._emitLine('(env, context, frame, runtime, ' + this._makeCallback(id)); + this._emitLine(this.buffer + " += " + id + ";"); + this._addScopeLevel(); + }; + _proto.compileSuper = function compileSuper(node, frame) { + var name = node.blockName.value; + var id = node.symbol.value; + var cb = this._makeCallback(id); + this._emitLine("context.getSuper(env, \"" + name + "\", b_" + name + ", frame, runtime, " + cb); + this._emitLine(id + " = runtime.markSafe(" + id + ");"); + this._addScopeLevel(); + frame.set(id, id); + }; + _proto.compileExtends = function compileExtends(node, frame) { + var k = this._tmpid(); + var parentTemplateId = this._compileGetTemplate(node, frame, true, false); + + // extends is a dynamic tag and can occur within a block like + // `if`, so if this happens we need to capture the parent + // template in the top-level scope + this._emitLine("parentTemplate = " + parentTemplateId); + this._emitLine("for(var " + k + " in parentTemplate.blocks) {"); + this._emitLine("context.addBlock(" + k + ", parentTemplate.blocks[" + k + "]);"); + this._emitLine('}'); + this._addScopeLevel(); + }; + _proto.compileInclude = function compileInclude(node, frame) { + this._emitLine('var tasks = [];'); + this._emitLine('tasks.push('); + this._emitLine('function(callback) {'); + var id = this._compileGetTemplate(node, frame, false, node.ignoreMissing); + this._emitLine("callback(null," + id + ");});"); + this._emitLine('});'); + var id2 = this._tmpid(); + this._emitLine('tasks.push('); + this._emitLine('function(template, callback){'); + this._emitLine('template.render(context.getVariables(), frame, ' + this._makeCallback(id2)); + this._emitLine('callback(null,' + id2 + ');});'); + this._emitLine('});'); + this._emitLine('tasks.push('); + this._emitLine('function(result, callback){'); + this._emitLine(this.buffer + " += result;"); + this._emitLine('callback(null);'); + this._emitLine('});'); + this._emitLine('env.waterfall(tasks, function(){'); + this._addScopeLevel(); + }; + _proto.compileTemplateData = function compileTemplateData(node, frame) { + this.compileLiteral(node, frame); + }; + _proto.compileCapture = function compileCapture(node, frame) { + var _this14 = this; + // we need to temporarily override the current buffer id as 'output' + // so the set block writes to the capture output instead of the buffer + var buffer = this.buffer; + this.buffer = 'output'; + this._emitLine('(function() {'); + this._emitLine('var output = "";'); + this._withScopedSyntax(function () { + _this14.compile(node.body, frame); + }); + this._emitLine('return output;'); + this._emitLine('})()'); + // and of course, revert back to the old buffer id + this.buffer = buffer; + }; + _proto.compileOutput = function compileOutput(node, frame) { + var _this15 = this; + var children = node.children; + children.forEach(function (child) { + // TemplateData is a special case because it is never + // autoescaped, so simply output it for optimization + if (child instanceof nodes.TemplateData) { + if (child.value) { + _this15._emit(_this15.buffer + " += "); + _this15.compileLiteral(child, frame); + _this15._emitLine(';'); + } + } else { + _this15._emit(_this15.buffer + " += runtime.suppressValue("); + if (_this15.throwOnUndefined) { + _this15._emit('runtime.ensureDefined('); + } + _this15.compile(child, frame); + if (_this15.throwOnUndefined) { + _this15._emit("," + node.lineno + "," + node.colno + ")"); + } + _this15._emit(', env.opts.autoescape);\n'); + } + }); + }; + _proto.compileRoot = function compileRoot(node, frame) { + var _this16 = this; + if (frame) { + this.fail('compileRoot: root node can\'t have frame'); + } + frame = new Frame(); + this._emitFuncBegin(node, 'root'); + this._emitLine('var parentTemplate = null;'); + this._compileChildren(node, frame); + this._emitLine('if(parentTemplate) {'); + this._emitLine('parentTemplate.rootRenderFunc(env, context, frame, runtime, cb);'); + this._emitLine('} else {'); + this._emitLine("cb(null, " + this.buffer + ");"); + this._emitLine('}'); + this._emitFuncEnd(true); + this.inBlock = true; + var blockNames = []; + var blocks = node.findAll(nodes.Block); + blocks.forEach(function (block, i) { + var name = block.name.value; + if (blockNames.indexOf(name) !== -1) { + throw new Error("Block \"" + name + "\" defined more than once."); + } + blockNames.push(name); + _this16._emitFuncBegin(block, "b_" + name); + var tmpFrame = new Frame(); + _this16._emitLine('var frame = frame.push(true);'); + _this16.compile(block.body, tmpFrame); + _this16._emitFuncEnd(); + }); + this._emitLine('return {'); + blocks.forEach(function (block, i) { + var blockName = "b_" + block.name.value; + _this16._emitLine(blockName + ": " + blockName + ","); + }); + this._emitLine('root: root\n};'); + }; + _proto.compile = function compile(node, frame) { + var _compile = this['compile' + node.typename]; + if (_compile) { + _compile.call(this, node, frame); + } else { + this.fail("compile: Cannot compile node: " + node.typename, node.lineno, node.colno); + } + }; + _proto.getCode = function getCode() { + return this.codebuf.join(''); + }; + return Compiler; +}(Obj); +module.exports = { + compile: function compile(src, asyncFilters, extensions, name, opts) { + if (opts === void 0) { + opts = {}; + } + var c = new Compiler(name, opts.throwOnUndefined); + + // Run the extension preprocessors against the source. + var preprocessors = (extensions || []).map(function (ext) { + return ext.preprocess; + }).filter(function (f) { + return !!f; + }); + var processedSrc = preprocessors.reduce(function (s, processor) { + return processor(s); + }, src); + c.compile(transformer.transform(parser.parse(processedSrc, extensions, opts), asyncFilters, name)); + return c.getCode(); + }, + Compiler: Compiler +};
\ No newline at end of file |
