Source: registry/matchers.js

/**
 * "Match" test functions used to compare two values for filtering (what to render) and matching
 *  (comparison and finding related points across data layers)
 *
 * ### How do matching and filtering work?
 * See the Interactivity Tutorial for details.
 *
 * ## Adding a new function
 * LocusZoom allows users to write their own plugins, so that "does this point match" logic can incorporate
 *  user-defined code. (via `LocusZoom.MatchFunctions.add('my_function', my_function);`)
 *
 * All "matcher" functions have the call signature (item_value, target_value) => {boolean}
 *
 * Both filtering and matching depend on asking "is this field interesting to me", which is inherently a problem of
 *  making comparisons. The registry allows any arbitrary function (with a field value as the first argument), but that
 *  function doesn't have to use either argument.
 *
 * @module LocusZoom_MatchFunctions
 */
import {RegistryBase} from './base';

/**
 * A plugin registry that allows plots to use both pre-defined and user-provided "match" functions, used by filtering and matching behavior.
 * @alias module:LocusZoom~MatchFunctions
 * @type {module:registry/base~RegistryBase}
 */
const registry = new RegistryBase();

// Most of the filter syntax uses things that are JS reserved operators. Instead of exporting symbols from another
//  module, just define and register them here.

/**
 * Check if two values are (strictly) equal
 * @function
 * @name '='
 * @param item_value
 * @param target_value
 */
registry.add('=', (item_value, target_value) => item_value === target_value);

/**
 * Check if two values are not equal. This allows weak comparisons (eg undefined/null), so it can also be used to test for the absence of a value
 * @function
 * @name '!='
 * @param item_value
 * @param target_value
 */
// eslint-disable-next-line eqeqeq
registry.add('!=', (a, b) => a != b); // For absence of a value, deliberately allow weak comparisons (eg undefined/null)

/**
 * Less-than comparison
 * @function
 * @name '<'
 * @param item_value
 * @param target_value
 */
registry.add('<', (a, b) => a < b);

/**
 * Less than or equals to comparison
 * @function
 * @name '<='
 * @param item_value
 * @param target_value
 */
registry.add('<=', (a, b) => a <= b);

/**
 * Greater-than comparison
 * @function
 * @name '>'
 * @param item_value
 * @param target_value
 */
registry.add('>', (a, b) => a > b);

/**
 * Greater than or equals to comparison
 * @function
 * @name '>='
 * @param item_value
 * @param target_value
 */
registry.add('>=', (a, b) => a >= b);

/**
 * Modulo: tests for whether the remainder a % b is nonzero
 * @function
 * @name '%'
 * @param item_value
 * @param target_value
 */
registry.add('%', (a, b) => a % b);

/**
 * Check whether the provided value (a) is in the string or array of values (b)
 *
 * This can be used to check if a field value is one of a set of predefined choices
 *  Eg, `gene_type` is one of the allowed types of interest
 * @function
 * @name 'in'
 * @param item_value A scalar value
 * @param {String|Array} target_value A container that implements the `includes` method
 */
registry.add('in', (a, b) => b && b.includes(a));

/**
 * Partial-match function. Can be used for free text search ("find all gene names that contain the user-entered string 'TCF'")
 * @function
 * @name 'match'
 * @param {String|Array} item_value A container (like a string) that implements the `includes` method
 * @param target_value A scalar value, like a string
 */
registry.add('match', (a, b) => a && a.includes(b)); // useful for text search: "find all gene names that contain the user-entered value HLA"


export default registry;