UNPKG

liquidjs

Version:

A simple, expressive, safe and Shopify compatible template engine in pure JavaScript.

1,322 lines (1,271 loc) 161 kB
/* * liquidjs@9.24.2, https://github.com/harttle/liquidjs * (c) 2016-2021 harttle * Released under the MIT License. */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = global || self, factory(global.liquidjs = {})); }(this, function (exports) { 'use strict'; /*! ***************************************************************************** Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. ***************************************************************************** */ /* global Reflect, Promise */ var extendStatics = function(d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; function __extends(d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __awaiter(thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function __generator(thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } } function __values(o) { var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; if (m) return m.call(o); return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; } function __read(o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; } function __spread() { for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); return ar; } var Drop = /** @class */ (function () { function Drop() { } Drop.prototype.valueOf = function () { return undefined; }; Drop.prototype.liquidMethodMissing = function (key) { return undefined; }; return Drop; }()); var toStr = Object.prototype.toString; var toLowerCase = String.prototype.toLowerCase; /* * Checks if value is classified as a String primitive or object. * @param {any} value The value to check. * @return {Boolean} Returns true if value is a string, else false. */ function isString(value) { return toStr.call(value) === '[object String]'; } function isFunction(value) { return typeof value === 'function'; } function stringify(value) { value = toValue(value); return isNil(value) ? '' : String(value); } function toValue(value) { return value instanceof Drop ? value.valueOf() : value; } function isNumber(value) { return typeof value === 'number'; } function toLiquid(value) { if (value && isFunction(value.toLiquid)) return toLiquid(value.toLiquid()); return value; } function isNil(value) { return value === null || value === undefined; } function isArray(value) { // be compatible with IE 8 return toStr.call(value) === '[object Array]'; } /* * Iterates over own enumerable string keyed properties of an object and invokes iteratee for each property. * The iteratee is invoked with three arguments: (value, key, object). * Iteratee functions may exit iteration early by explicitly returning false. * @param {Object} object The object to iterate over. * @param {Function} iteratee The function invoked per iteration. * @return {Object} Returns object. */ function forOwn(object, iteratee) { object = object || {}; for (var k in object) { if (object.hasOwnProperty(k)) { if (iteratee(object[k], k, object) === false) break; } } return object; } function last(arr) { return arr[arr.length - 1]; } /* * Checks if value is the language type of Object. * (e.g. arrays, functions, objects, regexes, new Number(0), and new String('')) * @param {any} value The value to check. * @return {Boolean} Returns true if value is an object, else false. */ function isObject(value) { var type = typeof value; return value !== null && (type === 'object' || type === 'function'); } function range(start, stop, step) { if (step === void 0) { step = 1; } var arr = []; for (var i = start; i < stop; i += step) { arr.push(i); } return arr; } function padStart(str, length, ch) { if (ch === void 0) { ch = ' '; } return pad(str, length, ch, function (str, ch) { return ch + str; }); } function padEnd(str, length, ch) { if (ch === void 0) { ch = ' '; } return pad(str, length, ch, function (str, ch) { return str + ch; }); } function pad(str, length, ch, add) { str = String(str); var n = length - str.length; while (n-- > 0) str = add(str, ch); return str; } function identify(val) { return val; } function snakeCase(str) { return str.replace(/(\w?)([A-Z])/g, function (_, a, b) { return (a ? a + '_' : '') + b.toLowerCase(); }); } function changeCase(str) { var hasLowerCase = __spread(str).some(function (ch) { return ch >= 'a' && ch <= 'z'; }); return hasLowerCase ? str.toUpperCase() : str.toLowerCase(); } function ellipsis(str, N) { return str.length > N ? str.substr(0, N - 3) + '...' : str; } // compare string in case-insensitive way, undefined values to the tail function caseInsensitiveCompare(a, b) { if (a == null && b == null) return 0; if (a == null) return 1; if (b == null) return -1; a = toLowerCase.call(a); b = toLowerCase.call(b); if (a < b) return -1; if (a > b) return 1; return 0; } var Node = /** @class */ (function () { function Node(key, value, next, prev) { this.key = key; this.value = value; this.next = next; this.prev = prev; } return Node; }()); var LRU = /** @class */ (function () { function LRU(limit, size) { if (size === void 0) { size = 0; } this.limit = limit; this.size = size; this.cache = {}; this.head = new Node('HEAD', null, null, null); this.tail = new Node('TAIL', null, null, null); this.head.next = this.tail; this.tail.prev = this.head; } LRU.prototype.write = function (key, value) { if (this.cache[key]) { this.cache[key].value = value; } else { var node = new Node(key, value, this.head.next, this.head); this.head.next.prev = node; this.head.next = node; this.cache[key] = node; this.size++; this.ensureLimit(); } }; LRU.prototype.read = function (key) { if (!this.cache[key]) return; var value = this.cache[key].value; this.remove(key); this.write(key, value); return value; }; LRU.prototype.remove = function (key) { var node = this.cache[key]; node.prev.next = node.next; node.next.prev = node.prev; delete this.cache[key]; this.size--; }; LRU.prototype.clear = function () { this.head.next = this.tail; this.tail.prev = this.head; this.size = 0; this.cache = {}; }; LRU.prototype.ensureLimit = function () { if (this.size > this.limit) this.remove(this.tail.prev.key); }; return LRU; }()); function domResolve(root, path) { var base = document.createElement('base'); base.href = root; var head = document.getElementsByTagName('head')[0]; head.insertBefore(base, head.firstChild); var a = document.createElement('a'); a.href = path; var resolved = a.href; head.removeChild(base); return resolved; } function resolve(root, filepath, ext) { if (root.length && last(root) !== '/') root += '/'; var url = domResolve(root, filepath); return url.replace(/^(\w+:\/\/[^/]+)(\/[^?]+)/, function (str, origin, path) { var last = path.split('/').pop(); if (/\.\w+$/.test(last)) return str; return origin + path + ext; }); } function readFile(url) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, new Promise(function (resolve, reject) { var xhr = new XMLHttpRequest(); xhr.onload = function () { if (xhr.status >= 200 && xhr.status < 300) { resolve(xhr.responseText); } else { reject(new Error(xhr.statusText)); } }; xhr.onerror = function () { reject(new Error('An error occurred whilst receiving the response.')); }; xhr.open('GET', url); xhr.send(); })]; }); }); } function readFileSync(url) { var xhr = new XMLHttpRequest(); xhr.open('GET', url, false); xhr.send(); if (xhr.status < 200 || xhr.status >= 300) { throw new Error(xhr.statusText); } return xhr.responseText; } function exists(filepath) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, true]; }); }); } function existsSync(filepath) { return true; } var fs = /*#__PURE__*/Object.freeze({ resolve: resolve, readFile: readFile, readFileSync: readFileSync, exists: exists, existsSync: existsSync }); function isComparable(arg) { return arg && isFunction(arg.equals); } function isTruthy(val, ctx) { return !isFalsy(val, ctx); } function isFalsy(val, ctx) { if (ctx.opts.jsTruthy) { return !val; } else { return val === false || undefined === val || val === null; } } var defaultOperators = { '==': function (l, r) { if (isComparable(l)) return l.equals(r); if (isComparable(r)) return r.equals(l); return l === r; }, '!=': function (l, r) { if (isComparable(l)) return !l.equals(r); if (isComparable(r)) return !r.equals(l); return l !== r; }, '>': function (l, r) { if (isComparable(l)) return l.gt(r); if (isComparable(r)) return r.lt(l); return l > r; }, '<': function (l, r) { if (isComparable(l)) return l.lt(r); if (isComparable(r)) return r.gt(l); return l < r; }, '>=': function (l, r) { if (isComparable(l)) return l.geq(r); if (isComparable(r)) return r.leq(l); return l >= r; }, '<=': function (l, r) { if (isComparable(l)) return l.leq(r); if (isComparable(r)) return r.geq(l); return l <= r; }, 'contains': function (l, r) { return l && isFunction(l.indexOf) ? l.indexOf(r) > -1 : false; }, 'and': function (l, r, ctx) { return isTruthy(l, ctx) && isTruthy(r, ctx); }, 'or': function (l, r, ctx) { return isTruthy(l, ctx) || isTruthy(r, ctx); } }; // **DO NOT CHANGE THIS FILE** // // This file is generated by bin/character-gen.js // bitmask character types to boost performance var TYPES = [0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 4, 4, 4, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 2, 8, 0, 0, 0, 0, 8, 0, 0, 0, 64, 0, 65, 0, 0, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 0, 0, 2, 2, 2, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0]; var IDENTIFIER = 1; var BLANK = 4; var QUOTE = 8; var INLINE_BLANK = 16; var NUMBER = 32; var SIGN = 64; TYPES[160] = TYPES[5760] = TYPES[6158] = TYPES[8192] = TYPES[8193] = TYPES[8194] = TYPES[8195] = TYPES[8196] = TYPES[8197] = TYPES[8198] = TYPES[8199] = TYPES[8200] = TYPES[8201] = TYPES[8202] = TYPES[8232] = TYPES[8233] = TYPES[8239] = TYPES[8287] = TYPES[12288] = BLANK; function createTrie(operators) { var e_1, _a; var trie = {}; try { for (var _b = __values(Object.entries(operators)), _c = _b.next(); !_c.done; _c = _b.next()) { var _d = __read(_c.value, 2), name_1 = _d[0], handler = _d[1]; var node = trie; for (var i = 0; i < name_1.length; i++) { var c = name_1[i]; node[c] = node[c] || {}; if (i === name_1.length - 1 && (TYPES[name_1.charCodeAt(i)] & IDENTIFIER)) { node[c].needBoundary = true; } node = node[c]; } node.handler = handler; node.end = true; } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_1) throw e_1.error; } } return trie; } var defaultOptions = { root: ['.'], cache: undefined, extname: '', fs: fs, dynamicPartials: true, jsTruthy: false, trimTagRight: false, trimTagLeft: false, trimOutputRight: false, trimOutputLeft: false, greedy: true, tagDelimiterLeft: '{%', tagDelimiterRight: '%}', outputDelimiterLeft: '{{', outputDelimiterRight: '}}', preserveTimezones: false, strictFilters: false, strictVariables: false, lenientIf: false, globals: {}, keepOutputType: false, operators: defaultOperators, operatorsTrie: createTrie(defaultOperators) }; function normalize(options) { options = options || {}; if (options.hasOwnProperty('root')) { options.root = normalizeStringArray(options.root); } if (options.hasOwnProperty('cache')) { var cache = void 0; if (typeof options.cache === 'number') cache = options.cache > 0 ? new LRU(options.cache) : undefined; else if (typeof options.cache === 'object') cache = options.cache; else cache = options.cache ? new LRU(1024) : undefined; options.cache = cache; } if (options.hasOwnProperty('operators')) { options.operatorsTrie = createTrie(options.operators); } return options; } function applyDefault(options) { return __assign({}, defaultOptions, options); } function normalizeStringArray(value) { if (isArray(value)) return value; if (isString(value)) return [value]; return []; } var LiquidError = /** @class */ (function (_super) { __extends(LiquidError, _super); function LiquidError(err, token) { var _this = _super.call(this, err.message) || this; _this.originalError = err; _this.token = token; _this.context = ''; return _this; } LiquidError.prototype.update = function () { var err = this.originalError; this.context = mkContext(this.token); this.message = mkMessage(err.message, this.token); this.stack = this.message + '\n' + this.context + '\n' + this.stack + '\nFrom ' + err.stack; }; return LiquidError; }(Error)); var TokenizationError = /** @class */ (function (_super) { __extends(TokenizationError, _super); function TokenizationError(message, token) { var _this = _super.call(this, new Error(message), token) || this; _this.name = 'TokenizationError'; _super.prototype.update.call(_this); return _this; } return TokenizationError; }(LiquidError)); var ParseError = /** @class */ (function (_super) { __extends(ParseError, _super); function ParseError(err, token) { var _this = _super.call(this, err, token) || this; _this.name = 'ParseError'; _this.message = err.message; _super.prototype.update.call(_this); return _this; } return ParseError; }(LiquidError)); var RenderError = /** @class */ (function (_super) { __extends(RenderError, _super); function RenderError(err, tpl) { var _this = _super.call(this, err, tpl.token) || this; _this.name = 'RenderError'; _this.message = err.message; _super.prototype.update.call(_this); return _this; } RenderError.is = function (obj) { return obj.name === 'RenderError'; }; return RenderError; }(LiquidError)); var UndefinedVariableError = /** @class */ (function (_super) { __extends(UndefinedVariableError, _super); function UndefinedVariableError(err, token) { var _this = _super.call(this, err, token) || this; _this.name = 'UndefinedVariableError'; _this.message = err.message; _super.prototype.update.call(_this); return _this; } return UndefinedVariableError; }(LiquidError)); // only used internally; raised where we don't have token information, // so it can't be an UndefinedVariableError. var InternalUndefinedVariableError = /** @class */ (function (_super) { __extends(InternalUndefinedVariableError, _super); function InternalUndefinedVariableError(variableName) { var _this = _super.call(this, "undefined variable: " + variableName) || this; _this.name = 'InternalUndefinedVariableError'; _this.variableName = variableName; return _this; } return InternalUndefinedVariableError; }(Error)); var AssertionError = /** @class */ (function (_super) { __extends(AssertionError, _super); function AssertionError(message) { var _this = _super.call(this, message) || this; _this.name = 'AssertionError'; _this.message = message + ''; return _this; } return AssertionError; }(Error)); function mkContext(token) { var _a = __read(token.getPosition(), 1), line = _a[0]; var lines = token.input.split('\n'); var begin = Math.max(line - 2, 1); var end = Math.min(line + 3, lines.length); var context = range(begin, end + 1) .map(function (lineNumber) { var indicator = (lineNumber === line) ? '>> ' : ' '; var num = padStart(String(lineNumber), String(end).length); var text = lines[lineNumber - 1]; return "" + indicator + num + "| " + text; }) .join('\n'); return context; } function mkMessage(msg, token) { if (token.file) msg += ", file:" + token.file; var _a = __read(token.getPosition(), 2), line = _a[0], col = _a[1]; msg += ", line:" + line + ", col:" + col; return msg; } var Context = /** @class */ (function () { function Context(env, opts, sync) { if (env === void 0) { env = {}; } if (opts === void 0) { opts = defaultOptions; } if (sync === void 0) { sync = false; } this.scopes = [{}]; this.registers = {}; this.sync = sync; this.opts = opts; this.globals = opts.globals; this.environments = env; } Context.prototype.getRegister = function (key, defaultValue) { if (defaultValue === void 0) { defaultValue = {}; } return (this.registers[key] = this.registers[key] || defaultValue); }; Context.prototype.setRegister = function (key, value) { return (this.registers[key] = value); }; Context.prototype.saveRegister = function () { var _this = this; var keys = []; for (var _i = 0; _i < arguments.length; _i++) { keys[_i] = arguments[_i]; } return keys.map(function (key) { return [key, _this.getRegister(key)]; }); }; Context.prototype.restoreRegister = function (keyValues) { var _this = this; return keyValues.forEach(function (_a) { var _b = __read(_a, 2), key = _b[0], value = _b[1]; return _this.setRegister(key, value); }); }; Context.prototype.getAll = function () { return __spread([this.globals, this.environments], this.scopes).reduce(function (ctx, val) { return __assign(ctx, val); }, {}); }; Context.prototype.get = function (paths) { var scope = this.findScope(paths[0]); return this.getFromScope(scope, paths); }; Context.prototype.getFromScope = function (scope, paths) { var _this = this; if (typeof paths === 'string') paths = paths.split('.'); return paths.reduce(function (scope, path) { scope = readProperty(scope, path); if (isNil(scope) && _this.opts.strictVariables) { throw new InternalUndefinedVariableError(path); } return scope; }, scope); }; Context.prototype.push = function (ctx) { return this.scopes.push(ctx); }; Context.prototype.pop = function () { return this.scopes.pop(); }; Context.prototype.bottom = function () { return this.scopes[0]; }; Context.prototype.findScope = function (key) { for (var i = this.scopes.length - 1; i >= 0; i--) { var candidate = this.scopes[i]; if (key in candidate) return candidate; } if (key in this.environments) return this.environments; return this.globals; }; return Context; }()); function readProperty(obj, key) { if (isNil(obj)) return obj; obj = toLiquid(obj); if (isFunction(obj[key])) return obj[key](); if (obj instanceof Drop) { if (obj.hasOwnProperty(key)) return obj[key]; return obj.liquidMethodMissing(key); } if (key === 'size') return readSize(obj); if (key === 'first') return readFirst(obj); if (key === 'last') return readLast(obj); return obj[key]; } function readFirst(obj) { if (isArray(obj)) return obj[0]; return obj['first']; } function readLast(obj) { if (isArray(obj)) return obj[obj.length - 1]; return obj['last']; } function readSize(obj) { if (isArray(obj) || isString(obj)) return obj.length; return obj['size']; } (function (TokenKind) { TokenKind[TokenKind["Number"] = 1] = "Number"; TokenKind[TokenKind["Literal"] = 2] = "Literal"; TokenKind[TokenKind["Tag"] = 4] = "Tag"; TokenKind[TokenKind["Output"] = 8] = "Output"; TokenKind[TokenKind["HTML"] = 16] = "HTML"; TokenKind[TokenKind["Filter"] = 32] = "Filter"; TokenKind[TokenKind["Hash"] = 64] = "Hash"; TokenKind[TokenKind["PropertyAccess"] = 128] = "PropertyAccess"; TokenKind[TokenKind["Word"] = 256] = "Word"; TokenKind[TokenKind["Range"] = 512] = "Range"; TokenKind[TokenKind["Quoted"] = 1024] = "Quoted"; TokenKind[TokenKind["Operator"] = 2048] = "Operator"; TokenKind[TokenKind["Delimited"] = 12] = "Delimited"; })(exports.TokenKind || (exports.TokenKind = {})); function isDelimitedToken(val) { return !!(getKind(val) & exports.TokenKind.Delimited); } function isOperatorToken(val) { return getKind(val) === exports.TokenKind.Operator; } function isHTMLToken(val) { return getKind(val) === exports.TokenKind.HTML; } function isOutputToken(val) { return getKind(val) === exports.TokenKind.Output; } function isTagToken(val) { return getKind(val) === exports.TokenKind.Tag; } function isQuotedToken(val) { return getKind(val) === exports.TokenKind.Quoted; } function isLiteralToken(val) { return getKind(val) === exports.TokenKind.Literal; } function isNumberToken(val) { return getKind(val) === exports.TokenKind.Number; } function isPropertyAccessToken(val) { return getKind(val) === exports.TokenKind.PropertyAccess; } function isWordToken(val) { return getKind(val) === exports.TokenKind.Word; } function isRangeToken(val) { return getKind(val) === exports.TokenKind.Range; } function getKind(val) { return val ? val.kind : -1; } var typeGuards = /*#__PURE__*/Object.freeze({ isDelimitedToken: isDelimitedToken, isOperatorToken: isOperatorToken, isHTMLToken: isHTMLToken, isOutputToken: isOutputToken, isTagToken: isTagToken, isQuotedToken: isQuotedToken, isLiteralToken: isLiteralToken, isNumberToken: isNumberToken, isPropertyAccessToken: isPropertyAccessToken, isWordToken: isWordToken, isRangeToken: isRangeToken }); function whiteSpaceCtrl(tokens, options) { var inRaw = false; for (var i = 0; i < tokens.length; i++) { var token = tokens[i]; if (!isDelimitedToken(token)) continue; if (!inRaw && token.trimLeft) { trimLeft(tokens[i - 1], options.greedy); } if (isTagToken(token)) { if (token.name === 'raw') inRaw = true; else if (token.name === 'endraw') inRaw = false; } if (!inRaw && token.trimRight) { trimRight(tokens[i + 1], options.greedy); } } } function trimLeft(token, greedy) { if (!token || !isHTMLToken(token)) return; var mask = greedy ? BLANK : INLINE_BLANK; while (TYPES[token.input.charCodeAt(token.end - 1 - token.trimRight)] & mask) token.trimRight++; } function trimRight(token, greedy) { if (!token || !isHTMLToken(token)) return; var mask = greedy ? BLANK : INLINE_BLANK; while (TYPES[token.input.charCodeAt(token.begin + token.trimLeft)] & mask) token.trimLeft++; if (token.input.charAt(token.begin + token.trimLeft) === '\n') token.trimLeft++; } var Token = /** @class */ (function () { function Token(kind, input, begin, end, file) { this.kind = kind; this.input = input; this.begin = begin; this.end = end; this.file = file; } Token.prototype.getText = function () { return this.input.slice(this.begin, this.end); }; Token.prototype.getPosition = function () { var _a = __read([1, 1], 2), row = _a[0], col = _a[1]; for (var i = 0; i < this.begin; i++) { if (this.input[i] === '\n') { row++; col = 1; } else col++; } return [row, col]; }; Token.prototype.size = function () { return this.end - this.begin; }; return Token; }()); var NumberToken = /** @class */ (function (_super) { __extends(NumberToken, _super); function NumberToken(whole, decimal) { var _this = _super.call(this, exports.TokenKind.Number, whole.input, whole.begin, decimal ? decimal.end : whole.end, whole.file) || this; _this.whole = whole; _this.decimal = decimal; return _this; } return NumberToken; }(Token)); var IdentifierToken = /** @class */ (function (_super) { __extends(IdentifierToken, _super); function IdentifierToken(input, begin, end, file) { var _this = _super.call(this, exports.TokenKind.Word, input, begin, end, file) || this; _this.input = input; _this.begin = begin; _this.end = end; _this.file = file; _this.content = _this.getText(); return _this; } IdentifierToken.prototype.isNumber = function (allowSign) { if (allowSign === void 0) { allowSign = false; } var begin = allowSign && TYPES[this.input.charCodeAt(this.begin)] & SIGN ? this.begin + 1 : this.begin; for (var i = begin; i < this.end; i++) { if (!(TYPES[this.input.charCodeAt(i)] & NUMBER)) return false; } return true; }; return IdentifierToken; }(Token)); var NullDrop = /** @class */ (function (_super) { __extends(NullDrop, _super); function NullDrop() { return _super !== null && _super.apply(this, arguments) || this; } NullDrop.prototype.equals = function (value) { return isNil(toValue(value)); }; NullDrop.prototype.gt = function () { return false; }; NullDrop.prototype.geq = function () { return false; }; NullDrop.prototype.lt = function () { return false; }; NullDrop.prototype.leq = function () { return false; }; NullDrop.prototype.valueOf = function () { return null; }; return NullDrop; }(Drop)); var EmptyDrop = /** @class */ (function (_super) { __extends(EmptyDrop, _super); function EmptyDrop() { return _super !== null && _super.apply(this, arguments) || this; } EmptyDrop.prototype.equals = function (value) { if (value instanceof EmptyDrop) return false; value = toValue(value); if (isString(value) || isArray(value)) return value.length === 0; if (isObject(value)) return Object.keys(value).length === 0; return false; }; EmptyDrop.prototype.gt = function () { return false; }; EmptyDrop.prototype.geq = function () { return false; }; EmptyDrop.prototype.lt = function () { return false; }; EmptyDrop.prototype.leq = function () { return false; }; EmptyDrop.prototype.valueOf = function () { return ''; }; return EmptyDrop; }(Drop)); var BlankDrop = /** @class */ (function (_super) { __extends(BlankDrop, _super); function BlankDrop() { return _super !== null && _super.apply(this, arguments) || this; } BlankDrop.prototype.equals = function (value) { if (value === false) return true; if (isNil(toValue(value))) return true; if (isString(value)) return /^\s*$/.test(value); return _super.prototype.equals.call(this, value); }; return BlankDrop; }(EmptyDrop)); var nil = new NullDrop(); var literalValues = { 'true': true, 'false': false, 'nil': nil, 'null': nil, 'empty': new EmptyDrop(), 'blank': new BlankDrop() }; var LiteralToken = /** @class */ (function (_super) { __extends(LiteralToken, _super); function LiteralToken(input, begin, end, file) { var _this = _super.call(this, exports.TokenKind.Literal, input, begin, end, file) || this; _this.input = input; _this.begin = begin; _this.end = end; _this.file = file; _this.literal = _this.getText(); return _this; } return LiteralToken; }(Token)); var precedence = { '==': 1, '!=': 1, '>': 1, '<': 1, '>=': 1, '<=': 1, 'contains': 1, 'and': 0, 'or': 0 }; var OperatorToken = /** @class */ (function (_super) { __extends(OperatorToken, _super); function OperatorToken(input, begin, end, file) { var _this = _super.call(this, exports.TokenKind.Operator, input, begin, end, file) || this; _this.input = input; _this.begin = begin; _this.end = end; _this.file = file; _this.operator = _this.getText(); return _this; } OperatorToken.prototype.getPrecedence = function () { var key = this.getText(); return key in precedence ? precedence[key] : 1; }; return OperatorToken; }(Token)); var rHex = /[\da-fA-F]/; var rOct = /[0-7]/; var escapeChar = { b: '\b', f: '\f', n: '\n', r: '\r', t: '\t', v: '\x0B' }; function hexVal(c) { var code = c.charCodeAt(0); if (code >= 97) return code - 87; if (code >= 65) return code - 55; return code - 48; } function parseStringLiteral(str) { var ret = ''; for (var i = 1; i < str.length - 1; i++) { if (str[i] !== '\\') { ret += str[i]; continue; } if (escapeChar[str[i + 1]] !== undefined) { ret += escapeChar[str[++i]]; } else if (str[i + 1] === 'u') { var val = 0; var j = i + 2; while (j <= i + 5 && rHex.test(str[j])) { val = val * 16 + hexVal(str[j++]); } i = j - 1; ret += String.fromCharCode(val); } else if (!rOct.test(str[i + 1])) { ret += str[++i]; } else { var j = i + 1; var val = 0; while (j <= i + 3 && rOct.test(str[j])) { val = val * 8 + hexVal(str[j++]); } i = j - 1; ret += String.fromCharCode(val); } } return ret; } var PropertyAccessToken = /** @class */ (function (_super) { __extends(PropertyAccessToken, _super); function PropertyAccessToken(variable, props, end) { var _this = _super.call(this, exports.TokenKind.PropertyAccess, variable.input, variable.begin, end, variable.file) || this; _this.variable = variable; _this.props = props; return _this; } PropertyAccessToken.prototype.getVariableAsText = function () { if (this.variable instanceof IdentifierToken) { return this.variable.getText(); } else { return parseStringLiteral(this.variable.getText()); } }; return PropertyAccessToken; }(Token)); function assert(predicate, message) { if (!predicate) { var msg = message ? message() : "expect " + predicate + " to be true"; throw new AssertionError(msg); } } var FilterToken = /** @class */ (function (_super) { __extends(FilterToken, _super); function FilterToken(name, args, input, begin, end, file) { var _this = _super.call(this, exports.TokenKind.Filter, input, begin, end, file) || this; _this.name = name; _this.args = args; return _this; } return FilterToken; }(Token)); var HashToken = /** @class */ (function (_super) { __extends(HashToken, _super); function HashToken(input, begin, end, name, value, file) { var _this = _super.call(this, exports.TokenKind.Hash, input, begin, end, file) || this; _this.input = input; _this.begin = begin; _this.end = end; _this.name = name; _this.value = value; _this.file = file; return _this; } return HashToken; }(Token)); var QuotedToken = /** @class */ (function (_super) { __extends(QuotedToken, _super); function QuotedToken(input, begin, end, file) { var _this = _super.call(this, exports.TokenKind.Quoted, input, begin, end, file) || this; _this.input = input; _this.begin = begin; _this.end = end; _this.file = file; return _this; } return QuotedToken; }(Token)); var HTMLToken = /** @class */ (function (_super) { __extends(HTMLToken, _super); function HTMLToken(input, begin, end, file) { var _this = _super.call(this, exports.TokenKind.HTML, input, begin, end, file) || this; _this.input = input; _this.begin = begin; _this.end = end; _this.file = file; _this.trimLeft = 0; _this.trimRight = 0; return _this; } HTMLToken.prototype.getContent = function () { return this.input.slice(this.begin + this.trimLeft, this.end - this.trimRight); }; return HTMLToken; }(Token)); var DelimitedToken = /** @class */ (function (_super) { __extends(DelimitedToken, _super); function DelimitedToken(kind, content, input, begin, end, trimLeft, trimRight, file) { var _this = _super.call(this, kind, input, begin, end, file) || this; _this.trimLeft = false; _this.trimRight = false; _this.content = _this.getText(); var tl = content[0] === '-'; var tr = last(content) === '-'; _this.content = content .slice(tl ? 1 : 0, tr ? -1 : content.length) .trim(); _this.trimLeft = tl || trimLeft; _this.trimRight = tr || trimRight; return _this; } return DelimitedToken; }(Token)); var TagToken = /** @class */ (function (_super) { __extends(TagToken, _super); function TagToken(input, begin, end, options, file) { var _this = this; var trimTagLeft = options.trimTagLeft, trimTagRight = options.trimTagRight, tagDelimiterLeft = options.tagDelimiterLeft, tagDelimiterRight = options.tagDelimiterRight; var value = input.slice(begin + tagDelimiterLeft.length, end - tagDelimiterRight.length); _this = _super.call(this, exports.TokenKind.Tag, value, input, begin, end, trimTagLeft, trimTagRight, file) || this; var tokenizer = new Tokenizer(_this.content, options.operatorsTrie); _this.name = tokenizer.readIdentifier().getText(); if (!_this.name) throw new TokenizationError("illegal tag syntax", _this); tokenizer.skipBlank(); _this.args = tokenizer.remaining(); return _this; } return TagToken; }(DelimitedToken)); var RangeToken = /** @class */ (function (_super) { __extends(RangeToken, _super); function RangeToken(input, begin, end, lhs, rhs, file) { var _this = _super.call(this, exports.TokenKind.Range, input, begin, end, file) || this; _this.input = input; _this.begin = begin; _this.end = end; _this.lhs = lhs; _this.rhs = rhs; _this.file = file; return _this; } return RangeToken; }(Token)); var OutputToken = /** @class */ (function (_super) { __extends(OutputToken, _super); function OutputToken(input, begin, end, options, file) { var _this = this; var trimOutputLeft = options.trimOutputLeft, trimOutputRight = options.trimOutputRight, outputDelimiterLeft = options.outputDelimiterLeft, outputDelimiterRight = options.outputDelimiterRight; var value = input.slice(begin + outputDelimiterLeft.length, end - outputDelimiterRight.length); _this = _super.call(this, exports.TokenKind.Output, value, input, begin, end, trimOutputLeft, trimOutputRight, file) || this; return _this; } return OutputToken; }(DelimitedToken)); function matchOperator(str, begin, trie, end) { if (end === void 0) { end = str.length; } var node = trie; var i = begin; var info; while (node[str[i]] && i < end) { node = node[str[i++]]; if (node['end']) info = node; } if (!info) return -1; if (info['needBoundary'] && (TYPES[str.charCodeAt(i)] & IDENTIFIER)) return -1; return i; } var Expression = /** @class */ (function () { function Expression(tokens) { this.postfix = __spread(toPostfix(tokens)); } Expression.prototype.evaluate = function (ctx, lenient) { var operands, _a, _b, token, r, l, result, _c, _d, e_1_1; var e_1, _e; return __generator(this, function (_f) { switch (_f.label) { case 0: assert(ctx, function () { return 'unable to evaluate: context not defined'; }); operands = []; _f.label = 1; case 1: _f.trys.push([1, 9, 10, 11]); _a = __values(this.postfix), _b = _a.next(); _f.label = 2; case 2: if (!!_b.done) return [3 /*break*/, 8]; token = _b.value; if (!isOperatorToken(token)) return [3 /*break*/, 5]; return [4 /*yield*/, operands.pop()]; case 3: r = _f.sent(); return [4 /*yield*/, operands.pop()]; case 4: l = _f.sent(); result = evalOperatorToken(ctx.opts.operators, token, l, r, ctx); operands.push(result); return [3 /*break*/, 7]; case 5: _d = (_c = operands).push; return [4 /*yield*/, evalToken(token, ctx, lenient && this.postfix.length === 1)]; case 6: _d.apply(_c, [_f.sent()]); _f.label = 7; case 7: _b = _a.next();