UNPKG

blended-nunjucks

Version:

A powerful templating engine with inheritance, asynchronous control, and more (jinja2 inspired)

351 lines (347 loc) 10.2 kB
'use strict'; function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } } function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _inheritsLoose(t, o) { t.prototype = Object.create(o.prototype), t.prototype.constructor = t, _setPrototypeOf(t, o); } function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); } var _require = require('./object'), Obj = _require.Obj; function traverseAndCheck(obj, type, results) { if (obj instanceof type) { results.push(obj); } if (obj instanceof Node) { obj.findAll(type, results); } } var Node = /*#__PURE__*/function (_Obj) { function Node() { return _Obj.apply(this, arguments) || this; } _inheritsLoose(Node, _Obj); var _proto = Node.prototype; _proto.init = function init(lineno, colno) { var _arguments = arguments, _this = this; for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { args[_key - 2] = arguments[_key]; } this.lineno = lineno; this.colno = colno; this.fields.forEach(function (field, i) { // The first two args are line/col numbers, so offset by 2 var val = _arguments[i + 2]; // Fields should never be undefined, but null. It makes // testing easier to normalize values. if (val === undefined) { val = null; } _this[field] = val; }); }; _proto.findAll = function findAll(type, results) { var _this2 = this; results = results || []; if (this instanceof NodeList) { this.children.forEach(function (child) { return traverseAndCheck(child, type, results); }); } else { this.fields.forEach(function (field) { return traverseAndCheck(_this2[field], type, results); }); } return results; }; _proto.iterFields = function iterFields(func) { var _this3 = this; this.fields.forEach(function (field) { func(_this3[field], field); }); }; return Node; }(Obj); // Abstract nodes var Value = /*#__PURE__*/function (_Node) { function Value() { return _Node.apply(this, arguments) || this; } _inheritsLoose(Value, _Node); return _createClass(Value, [{ key: "typename", get: function get() { return 'Value'; } }, { key: "fields", get: function get() { return ['value']; } }]); }(Node); // Concrete nodes var NodeList = /*#__PURE__*/function (_Node2) { function NodeList() { return _Node2.apply(this, arguments) || this; } _inheritsLoose(NodeList, _Node2); var _proto2 = NodeList.prototype; _proto2.init = function init(lineno, colno, nodes) { _Node2.prototype.init.call(this, lineno, colno, nodes || []); }; _proto2.addChild = function addChild(node) { this.children.push(node); }; return _createClass(NodeList, [{ key: "typename", get: function get() { return 'NodeList'; } }, { key: "fields", get: function get() { return ['children']; } }]); }(Node); var Root = NodeList.extend('Root'); var Literal = Value.extend('Literal'); var _Symbol = Value.extend('Symbol'); var Group = NodeList.extend('Group'); var ArrayNode = NodeList.extend('Array'); var Pair = Node.extend('Pair', { fields: ['key', 'value'] }); var Dict = NodeList.extend('Dict'); var LookupVal = Node.extend('LookupVal', { fields: ['target', 'val'] }); var If = Node.extend('If', { fields: ['cond', 'body', 'else_'] }); var IfAsync = If.extend('IfAsync'); var InlineIf = Node.extend('InlineIf', { fields: ['cond', 'body', 'else_'] }); var For = Node.extend('For', { fields: ['arr', 'name', 'body', 'else_'] }); var AsyncEach = For.extend('AsyncEach'); var AsyncAll = For.extend('AsyncAll'); var Macro = Node.extend('Macro', { fields: ['name', 'args', 'body'] }); var Caller = Macro.extend('Caller'); var Import = Node.extend('Import', { fields: ['template', 'target', 'withContext'] }); var FromImport = /*#__PURE__*/function (_Node3) { function FromImport() { return _Node3.apply(this, arguments) || this; } _inheritsLoose(FromImport, _Node3); var _proto3 = FromImport.prototype; _proto3.init = function init(lineno, colno, template, names, withContext) { _Node3.prototype.init.call(this, lineno, colno, template, names || new NodeList(), withContext); }; return _createClass(FromImport, [{ key: "typename", get: function get() { return 'FromImport'; } }, { key: "fields", get: function get() { return ['template', 'names', 'withContext']; } }]); }(Node); var FunCall = Node.extend('FunCall', { fields: ['name', 'args'] }); var FunCallAsync = FunCall.extend('FunCallAsync', { fields: ['name', 'args', 'symbol', 'contextflag'] }); var Filter = FunCall.extend('Filter'); var FilterAsync = Filter.extend('FilterAsync', { fields: ['name', 'args', 'symbol'] }); var KeywordArgs = Dict.extend('KeywordArgs'); var Block = Node.extend('Block', { fields: ['name', 'body'] }); var Super = Node.extend('Super', { fields: ['blockName', 'symbol'] }); var TemplateRef = Node.extend('TemplateRef', { fields: ['template'] }); var Extends = TemplateRef.extend('Extends'); var Include = Node.extend('Include', { fields: ['template', 'ignoreMissing'] }); var Set = Node.extend('Set', { fields: ['targets', 'value'] }); var Switch = Node.extend('Switch', { fields: ['expr', 'cases', 'default'] }); var Case = Node.extend('Case', { fields: ['cond', 'body'] }); var Output = NodeList.extend('Output'); var Capture = Node.extend('Capture', { fields: ['body'] }); var TemplateData = Literal.extend('TemplateData'); var UnaryOp = Node.extend('UnaryOp', { fields: ['target'] }); var BinOp = Node.extend('BinOp', { fields: ['left', 'right'] }); var In = BinOp.extend('In'); var Is = BinOp.extend('Is'); var Or = BinOp.extend('Or'); var And = BinOp.extend('And'); var Not = UnaryOp.extend('Not'); var Add = BinOp.extend('Add'); var Concat = BinOp.extend('Concat'); var Sub = BinOp.extend('Sub'); var Mul = BinOp.extend('Mul'); var Div = BinOp.extend('Div'); var FloorDiv = BinOp.extend('FloorDiv'); var Mod = BinOp.extend('Mod'); var Pow = BinOp.extend('Pow'); var Neg = UnaryOp.extend('Neg'); var Pos = UnaryOp.extend('Pos'); var Compare = Node.extend('Compare', { fields: ['expr', 'ops'] }); var CompareOperand = Node.extend('CompareOperand', { fields: ['expr', 'type'] }); var CallExtension = Node.extend('CallExtension', { init: function init(ext, prop, args, contentArgs) { this.parent(); this.extName = ext.__name || ext; this.prop = prop; this.args = args || new NodeList(); this.contentArgs = contentArgs || []; this.autoescape = ext.autoescape; }, fields: ['extName', 'prop', 'args', 'contentArgs'] }); var CallExtensionAsync = CallExtension.extend('CallExtensionAsync'); // This is hacky, but this is just a debugging function anyway function print(str, indent, inline) { var lines = str.split('\n'); lines.forEach(function (line, i) { if (line && (inline && i > 0 || !inline)) { process.stdout.write(' '.repeat(indent)); } var nl = i === lines.length - 1 ? '' : '\n'; process.stdout.write("" + line + nl); }); } // Print the AST in a nicely formatted tree format for debuggin function printNodes(node, indent) { indent = indent || 0; print(node.typename + ': ', indent); if (node instanceof NodeList) { print('\n'); node.children.forEach(function (n) { printNodes(n, indent + 2); }); } else if (node instanceof CallExtension) { print(node.extName + "." + node.prop + "\n"); if (node.args) { printNodes(node.args, indent + 2); } if (node.contentArgs) { node.contentArgs.forEach(function (n) { printNodes(n, indent + 2); }); } } else { var nodes = []; var props = null; node.iterFields(function (val, fieldName) { if (val instanceof Node) { nodes.push([fieldName, val]); } else { props = props || {}; props[fieldName] = val; } }); if (props) { print(JSON.stringify(props, null, 2) + '\n', null, true); } else { print('\n'); } nodes.forEach(function (_ref) { var fieldName = _ref[0], n = _ref[1]; print("[" + fieldName + "] =>", indent + 2); printNodes(n, indent + 4); }); } } module.exports = { Node: Node, Root: Root, NodeList: NodeList, Value: Value, Literal: Literal, Symbol: _Symbol, Group: Group, Array: ArrayNode, Pair: Pair, Dict: Dict, Output: Output, Capture: Capture, TemplateData: TemplateData, If: If, IfAsync: IfAsync, InlineIf: InlineIf, For: For, AsyncEach: AsyncEach, AsyncAll: AsyncAll, Macro: Macro, Caller: Caller, Import: Import, FromImport: FromImport, FunCall: FunCall, FunCallAsync: FunCallAsync, Filter: Filter, FilterAsync: FilterAsync, KeywordArgs: KeywordArgs, Block: Block, Super: Super, Extends: Extends, Include: Include, Set: Set, Switch: Switch, Case: Case, LookupVal: LookupVal, BinOp: BinOp, In: In, Is: Is, Or: Or, And: And, Not: Not, Add: Add, Concat: Concat, Sub: Sub, Mul: Mul, Div: Div, FloorDiv: FloorDiv, Mod: Mod, Pow: Pow, Neg: Neg, Pos: Pos, Compare: Compare, CompareOperand: CompareOperand, CallExtension: CallExtension, CallExtensionAsync: CallExtensionAsync, printNodes: printNodes };