diff options
Diffstat (limited to 'toolkit/components/utils/FilterExpressions.sys.mjs')
-rw-r--r-- | toolkit/components/utils/FilterExpressions.sys.mjs | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/toolkit/components/utils/FilterExpressions.sys.mjs b/toolkit/components/utils/FilterExpressions.sys.mjs new file mode 100644 index 0000000000..0dba44ec70 --- /dev/null +++ b/toolkit/components/utils/FilterExpressions.sys.mjs @@ -0,0 +1,137 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + Sampling: "resource://gre/modules/components-utils/Sampling.sys.mjs", +}); +ChromeUtils.defineModuleGetter( + lazy, + "mozjexl", + "resource://gre/modules/components-utils/mozjexl.js" +); + +function getPrefValue(prefKey, defaultValue) { + switch (Services.prefs.getPrefType(prefKey)) { + case Ci.nsIPrefBranch.PREF_STRING: + return Services.prefs.getStringPref(prefKey); + + case Ci.nsIPrefBranch.PREF_INT: + return Services.prefs.getIntPref(prefKey); + + case Ci.nsIPrefBranch.PREF_BOOL: + return Services.prefs.getBoolPref(prefKey); + + case Ci.nsIPrefBranch.PREF_INVALID: + return defaultValue; + + default: + throw new Error(`Error getting pref ${prefKey}.`); + } +} + +ChromeUtils.defineLazyGetter(lazy, "jexl", () => { + const jexl = new lazy.mozjexl.Jexl(); + jexl.addTransforms({ + date: dateString => new Date(dateString), + stableSample: lazy.Sampling.stableSample, + bucketSample: lazy.Sampling.bucketSample, + preferenceValue: getPrefValue, + preferenceIsUserSet: prefKey => Services.prefs.prefHasUserValue(prefKey), + preferenceExists: prefKey => + Services.prefs.getPrefType(prefKey) != Ci.nsIPrefBranch.PREF_INVALID, + keys, + length, + mapToProperty, + regExpMatch, + versionCompare, + }); + jexl.addBinaryOp("intersect", 40, operatorIntersect); + return jexl; +}); + +export var FilterExpressions = { + getAvailableTransforms() { + return Object.keys(lazy.jexl._transforms); + }, + + eval(expr, context = {}) { + const onelineExpr = expr.replace(/[\t\n\r]/g, " "); + return lazy.jexl.eval(onelineExpr, context); + }, +}; + +/** + * Return an array of the given object's own keys (specifically, its enumerable + * properties), or undefined if the argument isn't an object. + * @param {Object} obj + * @return {Array[String]|undefined} + */ +function keys(obj) { + if (typeof obj !== "object" || obj === null) { + return undefined; + } + + return Object.keys(obj); +} + +/** + * Return the length of an array + * @param {Array} arr + * @return {number} + */ +function length(arr) { + return Array.isArray(arr) ? arr.length : undefined; +} + +/** + * Given an input array and property name, return an array with each element of + * the original array replaced with the given property of that element. + * @param {Array} arr + * @param {string} prop + * @return {Array} + */ +function mapToProperty(arr, prop) { + return Array.isArray(arr) ? arr.map(elem => elem[prop]) : undefined; +} + +/** + * Find all the values that are present in both lists. Returns undefined if + * the arguments are not both Arrays. + * @param {Array} listA + * @param {Array} listB + * @return {Array|undefined} + */ +function operatorIntersect(listA, listB) { + if (!Array.isArray(listA) || !Array.isArray(listB)) { + return undefined; + } + + return listA.filter(item => listB.includes(item)); +} + +/** + * Matches a string against a regular expression. Returns null if there are + * no matches or an Array of matches. + * @param {string} str + * @param {string} pattern + * @param {string} flags + * @return {Array|null} + */ +function regExpMatch(str, pattern, flags) { + const re = new RegExp(pattern, flags); + return str.match(re); +} + +/** + * Compares v1 to v2 and returns 0 if they are equal, a negative number if + * v1 < v2 or a positive number if v1 > v2. + * @param {string} v1 + * @param {string} v2 + * @return {number} + */ +function versionCompare(v1, v2) { + return Services.vc.compare(v1, v2); +} |