UNPKG

@nosto/autocomplete

Version:

Library designed to simplify the implementation of search autocomplete functionality

1 lines 368 kB
{"version":3,"file":"autocomplete.bundle.mjs","sources":["../../node_modules/liquidjs/dist/liquid.browser.mjs","../../src/liquid/fromLiquidTemplate.ts","../../node_modules/@nosto/nosto-js/dist/settings-DN0V2st5.js","../../node_modules/@nosto/nosto-js/dist/index.es.js","../../src/lib/client.ts","../../node_modules/@nosto/search-js/dist/index.es-B8mbAxS4.js","../../node_modules/@nosto/search-js/dist/logger-DVwg4Wor.js","../../node_modules/@nosto/search-js/dist/search-BrR80UbS.js","../../src/lib/search.ts","../../src/lib/config.ts","../../node_modules/@nosto/search-js/dist/utils/utils.es.js","../../src/lib/dropdown.ts","../../src/utils/promise.ts","../../src/utils/state.ts","../../src/utils/dom.ts","../../src/utils/ga.ts","../../src/utils/debounce.ts","../../src/utils/history.ts","../../src/lib/autocomplete.ts","../../node_modules/@nosto/search-js/dist/currencies/currencies.es.js","../../src/lib/components.ts","../../src/liquid/NostoAutocomplete.ts"],"sourcesContent":["/*\n * liquidjs@10.21.1, https://github.com/harttle/liquidjs\n * (c) 2016-2025 harttle\n * Released under the MIT License.\n */\nclass Token {\r\n constructor(kind, input, begin, end, file) {\r\n this.kind = kind;\r\n this.input = input;\r\n this.begin = begin;\r\n this.end = end;\r\n this.file = file;\r\n }\r\n getText() {\r\n return this.input.slice(this.begin, this.end);\r\n }\r\n getPosition() {\r\n let [row, col] = [1, 1];\r\n for (let i = 0; i < this.begin; i++) {\r\n if (this.input[i] === '\\n') {\r\n row++;\r\n col = 1;\r\n }\r\n else\r\n col++;\r\n }\r\n return [row, col];\r\n }\r\n size() {\r\n return this.end - this.begin;\r\n }\r\n}\n\nclass Drop {\r\n liquidMethodMissing(key) {\r\n return undefined;\r\n }\r\n}\n\nconst toString$1 = Object.prototype.toString;\r\nconst toLowerCase = String.prototype.toLowerCase;\r\nconst hasOwnProperty = Object.hasOwnProperty;\r\nfunction isString(value) {\r\n return typeof value === 'string';\r\n}\r\n// eslint-disable-next-line @typescript-eslint/ban-types\r\nfunction isFunction(value) {\r\n return typeof value === 'function';\r\n}\r\nfunction isPromise(val) {\r\n return val && isFunction(val.then);\r\n}\r\nfunction isIterator(val) {\r\n return val && isFunction(val.next) && isFunction(val.throw) && isFunction(val.return);\r\n}\r\nfunction escapeRegex(str) {\r\n return str.replace(/[-/\\\\^$*+?.()|[\\]{}]/g, '\\\\$&');\r\n}\r\nfunction stringify(value) {\r\n value = toValue(value);\r\n if (isString(value))\r\n return value;\r\n if (isNil(value))\r\n return '';\r\n if (isArray(value))\r\n return value.map(x => stringify(x)).join('');\r\n return String(value);\r\n}\r\nfunction toEnumerable(val) {\r\n val = toValue(val);\r\n if (isArray(val))\r\n return val;\r\n if (isString(val) && val.length > 0)\r\n return [val];\r\n if (isIterable(val))\r\n return Array.from(val);\r\n if (isObject(val))\r\n return Object.keys(val).map((key) => [key, val[key]]);\r\n return [];\r\n}\r\nfunction toArray(val) {\r\n val = toValue(val);\r\n if (isNil(val))\r\n return [];\r\n if (isArray(val))\r\n return val;\r\n return [val];\r\n}\r\nfunction toValue(value) {\r\n return (value instanceof Drop && isFunction(value.valueOf)) ? value.valueOf() : value;\r\n}\r\nfunction toNumber(value) {\r\n value = Number(value);\r\n return isNaN(value) ? 0 : value;\r\n}\r\nfunction isNumber(value) {\r\n return typeof value === 'number';\r\n}\r\nfunction toLiquid(value) {\r\n if (value && isFunction(value.toLiquid))\r\n return toLiquid(value.toLiquid());\r\n return value;\r\n}\r\nfunction isNil(value) {\r\n return value == null;\r\n}\r\nfunction isUndefined(value) {\r\n return value === undefined;\r\n}\r\nfunction isArray(value) {\r\n // be compatible with IE 8\r\n return toString$1.call(value) === '[object Array]';\r\n}\r\nfunction isArrayLike(value) {\r\n return value && isNumber(value.length);\r\n}\r\nfunction isIterable(value) {\r\n return isObject(value) && Symbol.iterator in value;\r\n}\r\n/*\r\n * Iterates over own enumerable string keyed properties of an object and invokes iteratee for each property.\r\n * The iteratee is invoked with three arguments: (value, key, object).\r\n * Iteratee functions may exit iteration early by explicitly returning false.\r\n * @param {Object} object The object to iterate over.\r\n * @param {Function} iteratee The function invoked per iteration.\r\n * @return {Object} Returns object.\r\n */\r\nfunction forOwn(obj, iteratee) {\r\n obj = obj || {};\r\n for (const k in obj) {\r\n if (hasOwnProperty.call(obj, k)) {\r\n if (iteratee(obj[k], k, obj) === false)\r\n break;\r\n }\r\n }\r\n return obj;\r\n}\r\nfunction last(arr) {\r\n return arr[arr.length - 1];\r\n}\r\n/*\r\n * Checks if value is the language type of Object.\r\n * (e.g. arrays, functions, objects, regexes, new Number(0), and new String(''))\r\n * @param {any} value The value to check.\r\n * @return {Boolean} Returns true if value is an object, else false.\r\n */\r\nfunction isObject(value) {\r\n const type = typeof value;\r\n return value !== null && (type === 'object' || type === 'function');\r\n}\r\nfunction range(start, stop, step = 1) {\r\n const arr = [];\r\n for (let i = start; i < stop; i += step) {\r\n arr.push(i);\r\n }\r\n return arr;\r\n}\r\nfunction padStart(str, length, ch = ' ') {\r\n return pad(str, length, ch, (str, ch) => ch + str);\r\n}\r\nfunction padEnd(str, length, ch = ' ') {\r\n return pad(str, length, ch, (str, ch) => str + ch);\r\n}\r\nfunction pad(str, length, ch, add) {\r\n str = String(str);\r\n let n = length - str.length;\r\n while (n-- > 0)\r\n str = add(str, ch);\r\n return str;\r\n}\r\nfunction identify(val) {\r\n return val;\r\n}\r\nfunction changeCase(str) {\r\n const hasLowerCase = [...str].some(ch => ch >= 'a' && ch <= 'z');\r\n return hasLowerCase ? str.toUpperCase() : str.toLowerCase();\r\n}\r\nfunction ellipsis(str, N) {\r\n return str.length > N ? str.slice(0, N - 3) + '...' : str;\r\n}\r\n// compare string in case-insensitive way, undefined values to the tail\r\nfunction caseInsensitiveCompare(a, b) {\r\n if (a == null && b == null)\r\n return 0;\r\n if (a == null)\r\n return 1;\r\n if (b == null)\r\n return -1;\r\n a = toLowerCase.call(a);\r\n b = toLowerCase.call(b);\r\n if (a < b)\r\n return -1;\r\n if (a > b)\r\n return 1;\r\n return 0;\r\n}\r\nfunction argumentsToValue(fn) {\r\n return function (...args) { return fn.call(this, ...args.map(toValue)); };\r\n}\r\nfunction escapeRegExp(text) {\r\n return text.replace(/[-[\\]{}()*+?.,\\\\^$|#\\s]/g, '\\\\$&');\r\n}\r\n/** Return an array containing unique elements from _array_. Works with nested arrays and objects. */\r\nfunction* strictUniq(array) {\r\n const seen = new Set();\r\n for (const element of array) {\r\n const key = JSON.stringify(element);\r\n if (!seen.has(key)) {\r\n seen.add(key);\r\n yield element;\r\n }\r\n }\r\n}\n\n/**\r\n * targeting ES5, extends Error won't create a proper prototype chain, need a trait to keep track of classes\r\n */\r\nconst TRAIT = '__liquidClass__';\r\nclass LiquidError extends Error {\r\n constructor(err, token) {\r\n /**\r\n * note: for ES5 targeting, `this` will be replaced by return value of Error(),\r\n * thus everything on `this` will be lost, avoid calling `LiquidError` methods here\r\n */\r\n super(typeof err === 'string' ? err : err.message);\r\n this.context = '';\r\n if (typeof err !== 'string')\r\n Object.defineProperty(this, 'originalError', { value: err, enumerable: false });\r\n Object.defineProperty(this, 'token', { value: token, enumerable: false });\r\n Object.defineProperty(this, TRAIT, { value: 'LiquidError', enumerable: false });\r\n }\r\n update() {\r\n Object.defineProperty(this, 'context', { value: mkContext(this.token), enumerable: false });\r\n this.message = mkMessage(this.message, this.token);\r\n this.stack = this.message + '\\n' + this.context +\r\n '\\n' + this.stack;\r\n if (this.originalError)\r\n this.stack += '\\nFrom ' + this.originalError.stack;\r\n }\r\n static is(obj) {\r\n return (obj === null || obj === void 0 ? void 0 : obj[TRAIT]) === 'LiquidError';\r\n }\r\n}\r\nclass TokenizationError extends LiquidError {\r\n constructor(message, token) {\r\n super(message, token);\r\n this.name = 'TokenizationError';\r\n super.update();\r\n }\r\n}\r\nclass ParseError extends LiquidError {\r\n constructor(err, token) {\r\n super(err, token);\r\n this.name = 'ParseError';\r\n this.message = err.message;\r\n super.update();\r\n }\r\n}\r\nclass RenderError extends LiquidError {\r\n constructor(err, tpl) {\r\n super(err, tpl.token);\r\n this.name = 'RenderError';\r\n this.message = err.message;\r\n super.update();\r\n }\r\n static is(obj) {\r\n return obj.name === 'RenderError';\r\n }\r\n}\r\nclass LiquidErrors extends LiquidError {\r\n constructor(errors) {\r\n super(errors[0], errors[0].token);\r\n this.errors = errors;\r\n this.name = 'LiquidErrors';\r\n const s = errors.length > 1 ? 's' : '';\r\n this.message = `${errors.length} error${s} found`;\r\n super.update();\r\n }\r\n static is(obj) {\r\n return obj.name === 'LiquidErrors';\r\n }\r\n}\r\nclass UndefinedVariableError extends LiquidError {\r\n constructor(err, token) {\r\n super(err, token);\r\n this.name = 'UndefinedVariableError';\r\n this.message = err.message;\r\n super.update();\r\n }\r\n}\r\n// only used internally; raised where we don't have token information,\r\n// so it can't be an UndefinedVariableError.\r\nclass InternalUndefinedVariableError extends Error {\r\n constructor(variableName) {\r\n super(`undefined variable: ${variableName}`);\r\n this.name = 'InternalUndefinedVariableError';\r\n this.variableName = variableName;\r\n }\r\n}\r\nclass AssertionError extends Error {\r\n constructor(message) {\r\n super(message);\r\n this.name = 'AssertionError';\r\n this.message = message + '';\r\n }\r\n}\r\nfunction mkContext(token) {\r\n const [line, col] = token.getPosition();\r\n const lines = token.input.split('\\n');\r\n const begin = Math.max(line - 2, 1);\r\n const end = Math.min(line + 3, lines.length);\r\n const context = range(begin, end + 1)\r\n .map(lineNumber => {\r\n const rowIndicator = (lineNumber === line) ? '>> ' : ' ';\r\n const num = padStart(String(lineNumber), String(end).length);\r\n let text = `${rowIndicator}${num}| `;\r\n const colIndicator = lineNumber === line\r\n ? '\\n' + padStart('^', col + text.length)\r\n : '';\r\n text += lines[lineNumber - 1];\r\n text += colIndicator;\r\n return text;\r\n })\r\n .join('\\n');\r\n return context;\r\n}\r\nfunction mkMessage(msg, token) {\r\n if (token.file)\r\n msg += `, file:${token.file}`;\r\n const [line, col] = token.getPosition();\r\n msg += `, line:${line}, col:${col}`;\r\n return msg;\r\n}\n\n// **DO NOT CHANGE THIS FILE**\r\n//\r\n// This file is generated by bin/character-gen.js\r\n// bitmask character types to boost performance\r\nconst 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];\r\nconst WORD = 1;\r\nconst BLANK = 4;\r\nconst QUOTE = 8;\r\nconst INLINE_BLANK = 16;\r\nconst NUMBER = 32;\r\nconst SIGN = 64;\r\nconst PUNCTUATION = 128;\r\nfunction isWord(char) {\r\n const code = char.charCodeAt(0);\r\n return code >= 128 ? !TYPES[code] : !!(TYPES[code] & WORD);\r\n}\r\nTYPES[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;\r\nTYPES[8220] = TYPES[8221] = PUNCTUATION;\n\nfunction assert(predicate, message) {\r\n if (!predicate) {\r\n const msg = typeof message === 'function'\r\n ? message()\r\n : (message || `expect ${predicate} to be true`);\r\n throw new AssertionError(msg);\r\n }\r\n}\r\nfunction assertEmpty(predicate, message = `unexpected ${JSON.stringify(predicate)}`) {\r\n assert(!predicate, message);\r\n}\n\nclass NullDrop extends Drop {\r\n equals(value) {\r\n return isNil(toValue(value));\r\n }\r\n gt() {\r\n return false;\r\n }\r\n geq() {\r\n return false;\r\n }\r\n lt() {\r\n return false;\r\n }\r\n leq() {\r\n return false;\r\n }\r\n valueOf() {\r\n return null;\r\n }\r\n}\n\nclass EmptyDrop extends Drop {\r\n equals(value) {\r\n if (value instanceof EmptyDrop)\r\n return false;\r\n value = toValue(value);\r\n if (isString(value) || isArray(value))\r\n return value.length === 0;\r\n if (isObject(value))\r\n return Object.keys(value).length === 0;\r\n return false;\r\n }\r\n gt() {\r\n return false;\r\n }\r\n geq() {\r\n return false;\r\n }\r\n lt() {\r\n return false;\r\n }\r\n leq() {\r\n return false;\r\n }\r\n valueOf() {\r\n return '';\r\n }\r\n static is(value) {\r\n return value instanceof EmptyDrop;\r\n }\r\n}\n\nclass BlankDrop extends EmptyDrop {\r\n equals(value) {\r\n if (value === false)\r\n return true;\r\n if (isNil(toValue(value)))\r\n return true;\r\n if (isString(value))\r\n return /^\\s*$/.test(value);\r\n return super.equals(value);\r\n }\r\n static is(value) {\r\n return value instanceof BlankDrop;\r\n }\r\n}\n\nclass ForloopDrop extends Drop {\r\n constructor(length, collection, variable) {\r\n super();\r\n this.i = 0;\r\n this.length = length;\r\n this.name = `${variable}-${collection}`;\r\n }\r\n next() {\r\n this.i++;\r\n }\r\n index0() {\r\n return this.i;\r\n }\r\n index() {\r\n return this.i + 1;\r\n }\r\n first() {\r\n return this.i === 0;\r\n }\r\n last() {\r\n return this.i === this.length - 1;\r\n }\r\n rindex() {\r\n return this.length - this.i;\r\n }\r\n rindex0() {\r\n return this.length - this.i - 1;\r\n }\r\n valueOf() {\r\n return JSON.stringify(this);\r\n }\r\n}\n\nclass SimpleEmitter {\r\n constructor() {\r\n this.buffer = '';\r\n }\r\n write(html) {\r\n this.buffer += stringify(html);\r\n }\r\n}\n\nclass StreamedEmitter {\r\n constructor() {\r\n this.buffer = '';\r\n this.stream = null;\r\n throw new Error('streaming not supported in browser');\r\n }\r\n}\n\nclass KeepingTypeEmitter {\r\n constructor() {\r\n this.buffer = '';\r\n }\r\n write(html) {\r\n html = toValue(html);\r\n // This will only preserve the type if the value is isolated.\r\n // I.E:\r\n // {{ my-port }} -> 42\r\n // {{ my-host }}:{{ my-port }} -> 'host:42'\r\n if (typeof html !== 'string' && this.buffer === '') {\r\n this.buffer = html;\r\n }\r\n else {\r\n this.buffer = stringify(this.buffer) + stringify(html);\r\n }\r\n }\r\n}\n\nclass BlockDrop extends Drop {\r\n constructor(\r\n // the block render from layout template\r\n superBlockRender = () => '') {\r\n super();\r\n this.superBlockRender = superBlockRender;\r\n }\r\n /**\r\n * Provide parent access in child block by\r\n * {{ block.super }}\r\n */\r\n *super() {\r\n const emitter = new SimpleEmitter();\r\n yield this.superBlockRender(emitter);\r\n return emitter.buffer;\r\n }\r\n}\n\nfunction isComparable(arg) {\r\n return (arg &&\r\n isFunction(arg.equals) &&\r\n isFunction(arg.gt) &&\r\n isFunction(arg.geq) &&\r\n isFunction(arg.lt) &&\r\n isFunction(arg.leq));\r\n}\n\nconst nil = new NullDrop();\r\nconst literalValues = {\r\n 'true': true,\r\n 'false': false,\r\n 'nil': nil,\r\n 'null': nil,\r\n 'empty': new EmptyDrop(),\r\n 'blank': new BlankDrop()\r\n};\n\nfunction createTrie(input) {\r\n const trie = {};\r\n for (const [name, data] of Object.entries(input)) {\r\n let node = trie;\r\n for (let i = 0; i < name.length; i++) {\r\n const c = name[i];\r\n node[c] = node[c] || {};\r\n if (i === name.length - 1 && isWord(name[i])) {\r\n node[c].needBoundary = true;\r\n }\r\n node = node[c];\r\n }\r\n node.data = data;\r\n node.end = true;\r\n }\r\n return trie;\r\n}\n\n/******************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n\r\nvar __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n };\r\n return __assign.apply(this, arguments);\r\n};\r\n\r\nfunction __awaiter(thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\n\n// convert an async iterator to a Promise\r\nfunction toPromise(val) {\r\n return __awaiter(this, void 0, void 0, function* () {\r\n if (!isIterator(val))\r\n return val;\r\n let value;\r\n let done = false;\r\n let next = 'next';\r\n do {\r\n const state = val[next](value);\r\n done = state.done;\r\n value = state.value;\r\n next = 'next';\r\n try {\r\n if (isIterator(value))\r\n value = toPromise(value);\r\n if (isPromise(value))\r\n value = yield value;\r\n }\r\n catch (err) {\r\n next = 'throw';\r\n value = err;\r\n }\r\n } while (!done);\r\n return value;\r\n });\r\n}\r\n// convert an async iterator to a value in a synchronous manner\r\nfunction toValueSync(val) {\r\n if (!isIterator(val))\r\n return val;\r\n let value;\r\n let done = false;\r\n let next = 'next';\r\n do {\r\n const state = val[next](value);\r\n done = state.done;\r\n value = state.value;\r\n next = 'next';\r\n if (isIterator(value)) {\r\n try {\r\n value = toValueSync(value);\r\n }\r\n catch (err) {\r\n next = 'throw';\r\n value = err;\r\n }\r\n }\r\n } while (!done);\r\n return value;\r\n}\n\nconst rFormat = /%([-_0^#:]+)?(\\d+)?([EO])?(.)/;\r\n// prototype extensions\r\nfunction daysInMonth(d) {\r\n const feb = isLeapYear(d) ? 29 : 28;\r\n return [31, feb, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\r\n}\r\nfunction getDayOfYear(d) {\r\n let num = 0;\r\n for (let i = 0; i < d.getMonth(); ++i) {\r\n num += daysInMonth(d)[i];\r\n }\r\n return num + d.getDate();\r\n}\r\nfunction getWeekOfYear(d, startDay) {\r\n // Skip to startDay of this week\r\n const now = getDayOfYear(d) + (startDay - d.getDay());\r\n // Find the first startDay of the year\r\n const jan1 = new Date(d.getFullYear(), 0, 1);\r\n const then = (7 - jan1.getDay() + startDay);\r\n return String(Math.floor((now - then) / 7) + 1);\r\n}\r\nfunction isLeapYear(d) {\r\n const year = d.getFullYear();\r\n return !!((year & 3) === 0 && (year % 100 || (year % 400 === 0 && year)));\r\n}\r\nfunction ordinal(d) {\r\n const date = d.getDate();\r\n if ([11, 12, 13].includes(date))\r\n return 'th';\r\n switch (date % 10) {\r\n case 1: return 'st';\r\n case 2: return 'nd';\r\n case 3: return 'rd';\r\n default: return 'th';\r\n }\r\n}\r\nfunction century(d) {\r\n return parseInt(d.getFullYear().toString().substring(0, 2), 10);\r\n}\r\n// default to 0\r\nconst padWidths = {\r\n d: 2,\r\n e: 2,\r\n H: 2,\r\n I: 2,\r\n j: 3,\r\n k: 2,\r\n l: 2,\r\n L: 3,\r\n m: 2,\r\n M: 2,\r\n S: 2,\r\n U: 2,\r\n W: 2\r\n};\r\nconst padSpaceChars = new Set('aAbBceklpP');\r\nfunction getTimezoneOffset(d, opts) {\r\n const nOffset = Math.abs(d.getTimezoneOffset());\r\n const h = Math.floor(nOffset / 60);\r\n const m = nOffset % 60;\r\n return (d.getTimezoneOffset() > 0 ? '-' : '+') +\r\n padStart(h, 2, '0') +\r\n (opts.flags[':'] ? ':' : '') +\r\n padStart(m, 2, '0');\r\n}\r\nconst formatCodes = {\r\n a: (d) => d.getShortWeekdayName(),\r\n A: (d) => d.getLongWeekdayName(),\r\n b: (d) => d.getShortMonthName(),\r\n B: (d) => d.getLongMonthName(),\r\n c: (d) => d.toLocaleString(),\r\n C: (d) => century(d),\r\n d: (d) => d.getDate(),\r\n e: (d) => d.getDate(),\r\n H: (d) => d.getHours(),\r\n I: (d) => String(d.getHours() % 12 || 12),\r\n j: (d) => getDayOfYear(d),\r\n k: (d) => d.getHours(),\r\n l: (d) => String(d.getHours() % 12 || 12),\r\n L: (d) => d.getMilliseconds(),\r\n m: (d) => d.getMonth() + 1,\r\n M: (d) => d.getMinutes(),\r\n N: (d, opts) => {\r\n const width = Number(opts.width) || 9;\r\n const str = String(d.getMilliseconds()).slice(0, width);\r\n return padEnd(str, width, '0');\r\n },\r\n p: (d) => (d.getHours() < 12 ? 'AM' : 'PM'),\r\n P: (d) => (d.getHours() < 12 ? 'am' : 'pm'),\r\n q: (d) => ordinal(d),\r\n s: (d) => Math.round(d.getTime() / 1000),\r\n S: (d) => d.getSeconds(),\r\n u: (d) => d.getDay() || 7,\r\n U: (d) => getWeekOfYear(d, 0),\r\n w: (d) => d.getDay(),\r\n W: (d) => getWeekOfYear(d, 1),\r\n x: (d) => d.toLocaleDateString(),\r\n X: (d) => d.toLocaleTimeString(),\r\n y: (d) => d.getFullYear().toString().slice(2, 4),\r\n Y: (d) => d.getFullYear(),\r\n z: getTimezoneOffset,\r\n Z: (d, opts) => d.getTimeZoneName() || getTimezoneOffset(d, opts),\r\n 't': () => '\\t',\r\n 'n': () => '\\n',\r\n '%': () => '%'\r\n};\r\nformatCodes.h = formatCodes.b;\r\nfunction strftime(d, formatStr) {\r\n let output = '';\r\n let remaining = formatStr;\r\n let match;\r\n while ((match = rFormat.exec(remaining))) {\r\n output += remaining.slice(0, match.index);\r\n remaining = remaining.slice(match.index + match[0].length);\r\n output += format(d, match);\r\n }\r\n return output + remaining;\r\n}\r\nfunction format(d, match) {\r\n const [input, flagStr = '', width, modifier, conversion] = match;\r\n const convert = formatCodes[conversion];\r\n if (!convert)\r\n return input;\r\n const flags = {};\r\n for (const flag of flagStr)\r\n flags[flag] = true;\r\n let ret = String(convert(d, { flags, width, modifier }));\r\n let padChar = padSpaceChars.has(conversion) ? ' ' : '0';\r\n let padWidth = width || padWidths[conversion] || 0;\r\n if (flags['^'])\r\n ret = ret.toUpperCase();\r\n else if (flags['#'])\r\n ret = changeCase(ret);\r\n if (flags['_'])\r\n padChar = ' ';\r\n else if (flags['0'])\r\n padChar = '0';\r\n if (flags['-'])\r\n padWidth = 0;\r\n return padStart(ret, padWidth, padChar);\r\n}\n\nfunction getDateTimeFormat() {\r\n return (typeof Intl !== 'undefined' ? Intl.DateTimeFormat : undefined);\r\n}\n\n// one minute in milliseconds\r\nconst OneMinute = 60000;\r\n/**\r\n * Need support both ISO8601 and RFC2822 as in major browsers & NodeJS\r\n * RFC2822: https://datatracker.ietf.org/doc/html/rfc2822#section-3.3\r\n */\r\nconst TIMEZONE_PATTERN = /([zZ]|([+-])(\\d{2}):?(\\d{2}))$/;\r\nconst monthNames = [\r\n 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August',\r\n 'September', 'October', 'November', 'December'\r\n];\r\nconst monthNamesShort = monthNames.map(name => name.slice(0, 3));\r\nconst dayNames = [\r\n 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'\r\n];\r\nconst dayNamesShort = dayNames.map(name => name.slice(0, 3));\r\n/**\r\n * A date implementation with timezone info, just like Ruby date\r\n *\r\n * Implementation:\r\n * - create a Date offset by it's timezone difference, avoiding overriding a bunch of methods\r\n * - rewrite getTimezoneOffset() to trick strftime\r\n */\r\nclass LiquidDate {\r\n constructor(init, locale, timezone) {\r\n this.locale = locale;\r\n this.DateTimeFormat = getDateTimeFormat();\r\n this.date = new Date(init);\r\n this.timezoneFixed = timezone !== undefined;\r\n if (timezone === undefined) {\r\n timezone = this.date.getTimezoneOffset();\r\n }\r\n this.timezoneOffset = isString(timezone) ? LiquidDate.getTimezoneOffset(timezone, this.date) : timezone;\r\n this.timezoneName = isString(timezone) ? timezone : '';\r\n const diff = (this.date.getTimezoneOffset() - this.timezoneOffset) * OneMinute;\r\n const time = this.date.getTime() + diff;\r\n this.displayDate = new Date(time);\r\n }\r\n getTime() {\r\n return this.displayDate.getTime();\r\n }\r\n getMilliseconds() {\r\n return this.displayDate.getMilliseconds();\r\n }\r\n getSeconds() {\r\n return this.displayDate.getSeconds();\r\n }\r\n getMinutes() {\r\n return this.displayDate.getMinutes();\r\n }\r\n getHours() {\r\n return this.displayDate.getHours();\r\n }\r\n getDay() {\r\n return this.displayDate.getDay();\r\n }\r\n getDate() {\r\n return this.displayDate.getDate();\r\n }\r\n getMonth() {\r\n return this.displayDate.getMonth();\r\n }\r\n getFullYear() {\r\n return this.displayDate.getFullYear();\r\n }\r\n toLocaleString(locale, init) {\r\n if (init === null || init === void 0 ? void 0 : init.timeZone) {\r\n return this.date.toLocaleString(locale, init);\r\n }\r\n return this.displayDate.toLocaleString(locale, init);\r\n }\r\n toLocaleTimeString(locale) {\r\n return this.displayDate.toLocaleTimeString(locale);\r\n }\r\n toLocaleDateString(locale) {\r\n return this.displayDate.toLocaleDateString(locale);\r\n }\r\n getTimezoneOffset() {\r\n return this.timezoneOffset;\r\n }\r\n getTimeZoneName() {\r\n if (this.timezoneFixed)\r\n return this.timezoneName;\r\n if (!this.DateTimeFormat)\r\n return;\r\n return this.DateTimeFormat().resolvedOptions().timeZone;\r\n }\r\n getLongMonthName() {\r\n var _a;\r\n return (_a = this.format({ month: 'long' })) !== null && _a !== void 0 ? _a : monthNames[this.getMonth()];\r\n }\r\n getShortMonthName() {\r\n var _a;\r\n return (_a = this.format({ month: 'short' })) !== null && _a !== void 0 ? _a : monthNamesShort[this.getMonth()];\r\n }\r\n getLongWeekdayName() {\r\n var _a;\r\n return (_a = this.format({ weekday: 'long' })) !== null && _a !== void 0 ? _a : dayNames[this.displayDate.getDay()];\r\n }\r\n getShortWeekdayName() {\r\n var _a;\r\n return (_a = this.format({ weekday: 'short' })) !== null && _a !== void 0 ? _a : dayNamesShort[this.displayDate.getDay()];\r\n }\r\n valid() {\r\n return !isNaN(this.getTime());\r\n }\r\n format(options) {\r\n return this.DateTimeFormat && this.DateTimeFormat(this.locale, options).format(this.displayDate);\r\n }\r\n /**\r\n * Create a Date object fixed to it's declared Timezone. Both\r\n * - 2021-08-06T02:29:00.000Z and\r\n * - 2021-08-06T02:29:00.000+08:00\r\n * will always be displayed as\r\n * - 2021-08-06 02:29:00\r\n * regardless timezoneOffset in JavaScript realm\r\n *\r\n * The implementation hack:\r\n * Instead of calling `.getMonth()`/`.getUTCMonth()` respect to `preserveTimezones`,\r\n * we create a different Date to trick strftime, it's both simpler and more performant.\r\n * Given that a template is expected to be parsed fewer times than rendered.\r\n */\r\n static createDateFixedToTimezone(dateString, locale) {\r\n const m = dateString.match(TIMEZONE_PATTERN);\r\n // representing a UTC timestamp\r\n if (m && m[1] === 'Z') {\r\n return new LiquidDate(+new Date(dateString), locale, 0);\r\n }\r\n // has a timezone specified\r\n if (m && m[2] && m[3] && m[4]) {\r\n const [, , sign, hours, minutes] = m;\r\n const offset = (sign === '+' ? -1 : 1) * (parseInt(hours, 10) * 60 + parseInt(minutes, 10));\r\n return new LiquidDate(+new Date(dateString), locale, offset);\r\n }\r\n return new LiquidDate(dateString, locale);\r\n }\r\n static getTimezoneOffset(timezoneName, date) {\r\n const localDateString = date.toLocaleString('en-US', { timeZone: timezoneName });\r\n const utcDateString = date.toLocaleString('en-US', { timeZone: 'UTC' });\r\n const localDate = new Date(localDateString);\r\n const utcDate = new Date(utcDateString);\r\n return (+utcDate - +localDate) / (60 * 1000);\r\n }\r\n}\n\nclass Limiter {\r\n constructor(resource, limit) {\r\n this.base = 0;\r\n this.message = `${resource} limit exceeded`;\r\n this.limit = limit;\r\n }\r\n use(count) {\r\n count = toNumber(count);\r\n assert(this.base + count <= this.limit, this.message);\r\n this.base += count;\r\n }\r\n check(count) {\r\n count = toNumber(count);\r\n assert(count <= this.limit, this.message);\r\n }\r\n}\n\nclass DelimitedToken extends Token {\r\n constructor(kind, [contentBegin, contentEnd], input, begin, end, trimLeft, trimRight, file) {\r\n super(kind, input, begin, end, file);\r\n this.trimLeft = false;\r\n this.trimRight = false;\r\n const tl = input[contentBegin] === '-';\r\n const tr = input[contentEnd - 1] === '-';\r\n let l = tl ? contentBegin + 1 : contentBegin;\r\n let r = tr ? contentEnd - 1 : contentEnd;\r\n while (l < r && (TYPES[input.charCodeAt(l)] & BLANK))\r\n l++;\r\n while (r > l && (TYPES[input.charCodeAt(r - 1)] & BLANK))\r\n r--;\r\n this.contentRange = [l, r];\r\n this.trimLeft = tl || trimLeft;\r\n this.trimRight = tr || trimRight;\r\n }\r\n get content() {\r\n return this.input.slice(this.contentRange[0], this.contentRange[1]);\r\n }\r\n}\n\nclass TagToken extends DelimitedToken {\r\n constructor(input, begin, end, options, file) {\r\n const { trimTagLeft, trimTagRight, tagDelimiterLeft, tagDelimiterRight } = options;\r\n const [valueBegin, valueEnd] = [begin + tagDelimiterLeft.length, end - tagDelimiterRight.length];\r\n super(TokenKind.Tag, [valueBegin, valueEnd], input, begin, end, trimTagLeft, trimTagRight, file);\r\n this.tokenizer = new Tokenizer(input, options.operators, file, this.contentRange);\r\n this.name = this.tokenizer.readTagName();\r\n this.tokenizer.assert(this.name, `illegal tag syntax, tag name expected`);\r\n this.tokenizer.skipBlank();\r\n this.args = this.tokenizer.input.slice(this.tokenizer.p, this.contentRange[1]);\r\n }\r\n}\n\nclass OutputToken extends DelimitedToken {\r\n constructor(input, begin, end, options, file) {\r\n const { trimOutputLeft, trimOutputRight, outputDelimiterLeft, outputDelimiterRight } = options;\r\n const valueRange = [begin + outputDelimiterLeft.length, end - outputDelimiterRight.length];\r\n super(TokenKind.Output, valueRange, input, begin, end, trimOutputLeft, trimOutputRight, file);\r\n }\r\n}\n\nclass HTMLToken extends Token {\r\n constructor(input, begin, end, file) {\r\n super(TokenKind.HTML, input, begin, end, file);\r\n this.input = input;\r\n this.begin = begin;\r\n this.end = end;\r\n this.file = file;\r\n this.trimLeft = 0;\r\n this.trimRight = 0;\r\n }\r\n getContent() {\r\n return this.input.slice(this.begin + this.trimLeft, this.end - this.trimRight);\r\n }\r\n}\n\nclass NumberToken extends Token {\r\n constructor(input, begin, end, file) {\r\n super(TokenKind.Number, input, begin, end, file);\r\n this.input = input;\r\n this.begin = begin;\r\n this.end = end;\r\n this.file = file;\r\n this.content = Number(this.getText());\r\n }\r\n}\n\nclass IdentifierToken extends Token {\r\n constructor(input, begin, end, file) {\r\n super(TokenKind.Word, input, begin, end, file);\r\n this.input = input;\r\n this.begin = begin;\r\n this.end = end;\r\n this.file = file;\r\n this.content = this.getText();\r\n }\r\n}\n\nclass LiteralToken extends Token {\r\n constructor(input, begin, end, file) {\r\n super(TokenKind.Literal, input, begin, end, file);\r\n this.input = input;\r\n this.begin = begin;\r\n this.end = end;\r\n this.file = file;\r\n this.literal = this.getText();\r\n this.content = literalValues[this.literal];\r\n }\r\n}\n\nconst operatorPrecedences = {\r\n '==': 2,\r\n '!=': 2,\r\n '>': 2,\r\n '<': 2,\r\n '>=': 2,\r\n '<=': 2,\r\n 'contains': 2,\r\n 'not': 1,\r\n 'and': 0,\r\n 'or': 0\r\n};\r\nconst operatorTypes = {\r\n '==': 0 /* OperatorType.Binary */,\r\n '!=': 0 /* OperatorType.Binary */,\r\n '>': 0 /* OperatorType.Binary */,\r\n '<': 0 /* OperatorType.Binary */,\r\n '>=': 0 /* OperatorType.Binary */,\r\n '<=': 0 /* OperatorType.Binary */,\r\n 'contains': 0 /* OperatorType.Binary */,\r\n 'not': 1 /* OperatorType.Unary */,\r\n 'and': 0 /* OperatorType.Binary */,\r\n 'or': 0 /* OperatorType.Binary */\r\n};\r\nclass OperatorToken extends Token {\r\n constructor(input, begin, end, file) {\r\n super(TokenKind.Operator, input, begin, end, file);\r\n this.input = input;\r\n this.begin = begin;\r\n this.end = end;\r\n this.file = file;\r\n this.operator = this.getText();\r\n }\r\n getPrecedence() {\r\n const key = this.getText();\r\n return key in operatorPrecedences ? operatorPrecedences[key] : 1;\r\n }\r\n}\n\nclass PropertyAccessToken extends Token {\r\n constructor(variable, props, input, begin, end, file) {\r\n super(TokenKind.PropertyAccess, input, begin, end, file);\r\n this.variable = variable;\r\n this.props = props;\r\n }\r\n}\n\nclass FilterToken extends Token {\r\n constructor(name, args, input, begin, end, file) {\r\n super(TokenKind.Filter, input, begin, end, file);\r\n this.name = name;\r\n this.args = args;\r\n }\r\n}\n\nclass HashToken extends Token {\r\n constructor(input, begin, end, name, value, file) {\r\n super(TokenKind.Hash, input, begin, end, file);\r\n this.input = input;\r\n this.begin = begin;\r\n this.end = end;\r\n this.name = name;\r\n this.value = value;\r\n this.file = file;\r\n }\r\n}\n\nconst rHex = /[\\da-fA-F]/;\r\nconst rOct = /[0-7]/;\r\nconst escapeChar = {\r\n b: '\\b',\r\n f: '\\f',\r\n n: '\\n',\r\n r: '\\r',\r\n t: '\\t',\r\n v: '\\x0B'\r\n};\r\nfunction hexVal(c) {\r\n const code = c.charCodeAt(0);\r\n if (code >= 97)\r\n return code - 87;\r\n if (code >= 65)\r\n return code - 55;\r\n return code - 48;\r\n}\r\nfunction parseStringLiteral(str) {\r\n let ret = '';\r\n for (let i = 1; i < str.length - 1; i++) {\r\n if (str[i] !== '\\\\') {\r\n ret += str[i];\r\n continue;\r\n }\r\n if (escapeChar[str[i + 1]] !== undefined) {\r\n ret += escapeChar[str[++i]];\r\n }\r\n else if (str[i + 1] === 'u') {\r\n let val = 0;\r\n let j = i + 2;\r\n while (j <= i + 5 && rHex.test(str[j])) {\r\n val = val * 16 + hexVal(str[j++]);\r\n }\r\n i = j - 1;\r\n ret += String.fromCharCode(val);\r\n }\r\n else if (!rOct.test(str[i + 1])) {\r\n ret += str[++i];\r\n }\r\n else {\r\n let j = i + 1;\r\n let val = 0;\r\n while (j <= i + 3 && rOct.test(str[j])) {\r\n val = val * 8 + hexVal(str[j++]);\r\n }\r\n i = j - 1;\r\n ret += String.fromCharCode(val);\r\n }\r\n }\r\n return ret;\r\n}\n\nclass QuotedToken extends Token {\r\n constructor(input, begin, end, file) {\r\n super(TokenKind.Quoted, input, begin, end, file);\r\n this.input = input;\r\n this.begin = begin;\r\n this.end = end;\r\n this.file = file;\r\n this.content = parseStringLiteral(this.getText());\r\n }\r\n}\n\nclass RangeToken extends Token {\r\n constructor(input, begin, end, lhs, rhs, file) {\r\n super(TokenKind.Range, input, begin, end, file);\r\n this.input = input;\r\n this.begin = begin;\r\n this.end = end;\r\n this.lhs = lhs;\r\n this.rhs = rhs;\r\n this.file = file;\r\n }\r\n}\n\n/**\r\n * LiquidTagToken is different from TagToken by not having delimiters `{%` or `%}`\r\n */\r\nclass LiquidTagToken extends DelimitedToken {\r\n constructor(input, begin, end, options, file) {\r\n super(TokenKind.Tag, [begin, end], input, begin, end, false, false, file);\r\n this.tokenizer = new Tokenizer(input, options.operators, file, this.contentRange);\r\n this.name = this.tokenizer.readTagName();\r\n this.tokenizer.assert(this.name, 'illegal liquid tag syntax');\r\n this.tokenizer.skipBlank();\r\n }\r\n get args() {\r\n return this.tokenizer.input.slice(this.tokenizer.p, this.contentRange[1]);\r\n }\r\n}\n\n/**\r\n * value expression with optional filters\r\n * e.g.\r\n * {% assign foo=\"bar\" | append: \"coo\" %}\r\n */\r\nclass FilteredValueToken extends Token {\r\n constructor(initial, filters, input, begin, end, file) {\r\n super(TokenKind.FilteredValue, input, begin, end, file);\r\n this.initial = initial;\r\n this.filters = filters;\r\n this.input = input;\r\n this.begin = begin;\r\n this.end = end;\r\n this.file = file;\r\n }\r\n}\n\nconst polyfill = {\r\n now: () => Date.now()\r\n};\r\nfunction getPerformance() {\r\n return (typeof global === 'object' && global.performance) ||\r\n (typeof window === 'object' && window.performance) ||\r\n polyfill;\r\n}\n\nclass Render {\r\n renderTemplatesToNodeStream(templates, ctx) {\r\n const emitter = new StreamedEmitter();\r\n Promise.resolve().then(() => toPromise(this.renderTemplates(templates, ctx, emitter)))\r\n .then(() => emitter.end(), err => emitter.error(err));\r\n return emitter.stream;\r\n }\r\n *renderTemplates(templates, ctx, emitter) {\r\n if (!emitter) {\r\n emitter = ctx.opts.keepOutputType ? new KeepingTypeEmitter() : new SimpleEmitter();\r\n }\r\n const errors = [];\r\n for (const tpl of templates) {\r\n ctx.renderLimit.check(getPerformance().now());\r\n try {\r\n // if tpl.render supports emitter, it'll return empty `html`\r\n const html = yield tpl.render(ctx, emitter);\r\n // if not, it'll return an `html`, write to the emitter for it\r\n html && emitter.write(html);\r\n if (ctx.breakCalled || ctx.continueCalled)\r\n break;\r\n }\r\n catch (e) {\r\n const err = LiquidError.is(e) ? e : new RenderError(e, tpl);\r\n if (ctx.opts.catchAllErrors)\r\n errors.push(err);\r\n else\r\n throw err;\r\n }\r\n }\r\n if (errors.length) {\r\n throw new LiquidErrors(errors);\r\n }\r\n return emitter.buffer;\r\n }\r\n}\n\nclass Expression {\r\n constructor(tokens) {\r\n this.postfix = [...toPostfix(tokens)];\r\n }\r\n *evaluate(ctx, lenient) {\r\n assert(ctx, 'unable to evaluate: context not defined');\r\n const operands = [];\r\n for (const token of this.postfix) {\r\n if (isOperatorToken(token)) {\r\n const r = operands.pop();\r\n let result;\r\n if (operatorTypes[token.operator] === 1 /* OperatorType.Unary */) {\r\n result = yield ctx.opts.operators[token.operator](r, ctx);\r\n }\r\n else {\r\n const l = operands.pop();\r\n result = yield ctx.opts.operators[token.operator](l, r, ctx);\r\n }\r\n operands.push(result);\r\n }\r\n else {\r\n operands.push(yield evalToken(token, ctx, lenient));\r\n }\r\n }\r\n return operands[0];\r\n }\r\n valid() {\r\n return !!this.postfix.length;\r\n }\r\n}\r\nfunction* evalToken(token, ctx, lenient = false) {\r\n if (!token)\r\n return;\r\n if ('content' in token)\r\n return token.content;\r\n if (isPropertyAccessToken(token))\r\n return yield evalPropertyAccessToken(token, ctx, lenient);\r\n if (isRangeToken(token))\r\n return yield evalRangeToken(token, ctx);\r\n}\r\nfunction* evalPropertyAccessToken(token, ctx, lenient) {\r\n const props = [];\r\n for (const prop of token.props) {\r\n props.push((yield evalToken(prop, ctx, false)));\r\n }\r\n try {\r\n if (token.variable) {\r\n const variable = yield evalToken(token.variable, ctx, lenient);\r\n return yield ctx._getFromScope(variable, props);\r\n }\r\n else {\r\n return yield ctx._get(props);\r\n }\r\n }\r\n catch (e) {\r\n if (lenient && e.name === 'InternalUndefinedVariableError')\r\n return null;\r\n throw (new UndefinedVariableError(e, token));\r\n }\r\n}\r\nfunction evalQuotedToken(token) {\r\n return token.content;\r\n}\r\nfunction* evalRangeToken(token, ctx) {\r\n const low = yield evalToken(token.lhs, ctx);\r\n const high = yield evalToken(token.rhs, ctx);\r\n ctx.memoryLimit.use(high - low + 1);\r\n return range(+low, +high + 1);\r\n}\r\nfunction* toPostfix(tokens) {\r\n const ops = [];\r\n for (const token of tokens) {\r\n if (isOperatorToken(token)) {\r\n while (ops.length && ops[ops.length - 1].getPrecedence() > token.getPrecedence()) {\r\n yield ops.pop();\r\n }\r\n ops.push(token);\r\n }\r\n else\r\n yield token;\r\n }\r\n while (ops.length) {\r\n yield ops.pop();\r\n }\r\n}\n\nfunction isTruthy(val, ctx) {\r\n return !isFalsy(val, ctx);\r\n}\r\nfunction isFalsy(val, ctx) {\r\n val = toValue(val);\r\n if (ctx.opts.jsTruthy) {\r\n return !val;\r\n }\r\n else {\r\n return val === false || undefined === val || val === null;\r\n }\r\n}\n\nconst defaultOperators = {\r\n '==': equals,\r\n '!=': (l, r) => !equals(l, r),\r\n '>': (l, r) => {\r\n if (isComparable(l))\r\n return l.gt(r);\r\n if (isComparable(r))\r\n return r.lt(l);\r\n return toValue(l) > toValue(r);\r\n },\r\n '<': (l, r) => {\r\n if (isComparable(l))\r\n return l.lt(r);\r\n if (isComparable(r))\r\n return r.gt(l);\r\n return toValue(l) < toValue(r);\r\n },\r\n '>=': (l, r) => {\r\n if (isComparable(l))\r\n return l.geq(r);\r\n if (isComparable(r))\r\n return r.leq(l);\r\n return toValue(l) >= toValue(r);\r\n },\r\n '<=': (l, r) => {\r\n if (isComparable(l))\r\n return l.leq(r);\r\n if (isComparable(r))\r\n return r.geq(l);\r\n return toValue(l) <= toValue(r);\r\n },\r\n 'contains': (l, r) => {\r\n l = toValue(l);\r\n if (isArray(l))\r\n return l.some((i) => equals(i, r));\r\n if (isFunction(l === null || l === void 0 ? void 0 : l.indexOf))\r\n return l.indexOf(toValue(r)) > -1;\r\n return false;\r\n },\r\n 'not': (v, ctx) => isFalsy(toValue(v), ctx),\r\n 'and': (l, r, ctx) => isTruthy(toValue(l), ctx) && isTruthy(toValue(r), ctx),\r\n 'or': (l, r, ctx) => isTruthy(toValue(l), ctx) || isTruthy(toValue(r), ctx)\r\n};\r\nfunction equals(lhs, rhs) {\r\n if (isComparable(lhs))\r\n return lhs.equals(rhs);\r\n if (isComparable(rhs))\r\n return rhs.equals(lhs);\r\n lhs = toValue(lhs);\r\n rhs = toValue(rhs);\r\n if (isArray(lhs)) {\r\n return isArray(rhs) && arrayEquals(lhs, rhs);\r\n }\r\n return lhs === rhs;\r\n}\r\nfunction arrayEquals(lhs, rhs) {\r\n if (lhs.length !== rhs.length)\r\n return false;\r\n return !lhs.some((value, i) => !equals(value, rhs[i]));\r\n}\r\nfunction arrayIncludes(arr, item) {\r\n return arr.some(value => equals(value, item));\r\n}\n\nclass Node {\r\n constructor(key, value, next, prev) {\r\n this.key = key;\r\n this.value = value;\r\n this.next = next;\r\n this.prev = prev;\r\n }\r\n}\r\nclass LRU {\r\n constructor(limit, size = 0) {\r\n this.limit = limit;\r\n this.size = size;\r\n this.cache = {};\r\n this.head = new Node('HEAD', null, null, null);\r\n this.tail = new Node('TAIL', null, null, null);\r\n this.head.next = this.tail;\r\n this.tail.prev = this.head;\r\n }\r\n write(key, value) {\r\n if (this.cache[key]) {\r\n this.cache[key].value = value;\r\n }\r\n else {\r\n const node = new Node(key, value, this.head.next, this.head);\r\n this.head.next.prev = node;\r\n this.head.next = node;\r\n this.cache[key] = node;\r\n this.size++;\r\n this.ensureLimit();\r\n }\r\n }\r\n read(key) {\r\n if (!this.cache[key])\r\n return;\r\n const { value } = this.cache[key];\r\n this.remove(key);\r\n this.write(key, value);\r\n return value;\r\n }\r\n remove(key) {\r\n const node = this.cache[key];\r\n node.prev.next = node.next;\r\n node.next.prev = node.prev;\r\n delete this.cache[key];\r\n this.size--;\r\n }\r\n clear() {\r\n this.head.next = this.tail;\r\n this.tail.prev = this.head;\r\n this.size = 0;\r\n this.cache = {};\r\n }\r\n ensureLimit() {\r\n if (this.size > this.limit)\r\n this.remove(this.tail.prev.key);\r\n }\r\n}\n\nfunction domResolve(root, path) {\r\n const base = document.createElement('base');\r\n base.href = root;\r\n const head = document.getElementsByTagName('head')[0];\r\n