liquidjs
Version:
A simple, expressive, safe and Shopify compatible template engine in pure JavaScript.
1,322 lines (1,271 loc) • 161 kB
JavaScript
/*
* 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();