text: "use strict";
  /**
   * Higher order functions
   *
   * These utility functions are exported, but are subject to change without notice.
   *
   * @packageDocumentation
   */
  var __spreadArrays = (this && this.__spreadArrays) || function () {
      for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
      for (var r = Array(s), k = 0, i = 0; i < il; i++)
          for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
              r[k] = a[j];
      return r;
  };
  Object.defineProperty(exports, "__esModule", { value: true });
  exports.pattern = exports.invoke = exports.val = exports.eq = exports.is = exports.any = exports.all = exports.or = exports.and = exports.not = exports.parse = exports.propEq = exports.prop = exports.pipe = exports.compose = exports.curry = void 0;
  /**
   * Returns a new function for [Partial Application](https://en.wikipedia.org/wiki/Partial_application) of the original function.
   *
   * Given a function with N parameters, returns a new function that supports partial application.
   * The new function accepts anywhere from 1 to N parameters.  When that function is called with M parameters,
   * where M is less than N, it returns a new function that accepts the remaining parameters.  It continues to
   * accept more parameters until all N parameters have been supplied.
   *
   *
   * This contrived example uses a partially applied function as an predicate, which returns true
   * if an object is found in both arrays.
   * @example
   * ```
   * // returns true if an object is in both of the two arrays
   * function inBoth(array1, array2, object) {
   *   return array1.indexOf(object) !== -1 &&
   *          array2.indexOf(object) !== 1;
   * }
   * let obj1, obj2, obj3, obj4, obj5, obj6, obj7
   * let foos = [obj1, obj3]
   * let bars = [obj3, obj4, obj5]
   *
   * // A curried "copy" of inBoth
   * let curriedInBoth = curry(inBoth);
   * // Partially apply both the array1 and array2
   * let inFoosAndBars = curriedInBoth(foos, bars);
   *
   * // Supply the final argument; since all arguments are
   * // supplied, the original inBoth function is then called.
   * let obj1InBoth = inFoosAndBars(obj1); // false
   *
   * // Use the inFoosAndBars as a predicate.
   * // Filter, on each iteration, supplies the final argument
   * let allObjs = [ obj1, obj2, obj3, obj4, obj5, obj6, obj7 ];
   * let foundInBoth = allObjs.filter(inFoosAndBars); // [ obj3 ]
   *
   * ```
   *
   * @param fn
   * @returns {*|function(): (*|any)}
   */
  function curry(fn) {
      return function curried() {
          if (arguments.length >= fn.length) {
              return fn.apply(this, arguments);
          }
          var args = Array.prototype.slice.call(arguments);
          return curried.bind.apply(curried, __spreadArrays([this], args));
      };
  }
  exports.curry = curry;
  /**
   * Given a varargs list of functions, returns a function that composes the argument functions, right-to-left
   * given: f(x), g(x), h(x)
   * let composed = compose(f,g,h)
   * then, composed is: f(g(h(x)))
   */
  function compose() {
      var args = arguments;
      var start = args.length - 1;
      return function () {
          var i = start, result = args[start].apply(this, arguments);
          while (i--)
              result = args[i].call(this, result);
          return result;
      };
  }
  exports.compose = compose;
  /**
   * Given a varargs list of functions, returns a function that is composes the argument functions, left-to-right
   * given: f(x), g(x), h(x)
   * let piped = pipe(f,g,h);
   * then, piped is: h(g(f(x)))
   */
  function pipe() {
      var funcs = [];
      for (var _i = 0; _i < arguments.length; _i++) {
          funcs[_i] = arguments[_i];
      }
      return compose.apply(null, [].slice.call(arguments).reverse());
  }
  exports.pipe = pipe;
  /**
   * Given a property name, returns a function that returns that property from an object
   * let obj = { foo: 1, name: "blarg" };
   * let getName = prop("name");
   * getName(obj) === "blarg"
   */
  exports.prop = function (name) { return function (obj) { return obj && obj[name]; }; };
  /**
   * Given a property name and a value, returns a function that returns a boolean based on whether
   * the passed object has a property that matches the value
   * let obj = { foo: 1, name: "blarg" };
   * let getName = propEq("name", "blarg");
   * getName(obj) === true
   */
  exports.propEq = curry(function (name, _val, obj) { return obj && obj[name] === _val; });
  /**
   * Given a dotted property name, returns a function that returns a nested property from an object, or undefined
   * let obj = { id: 1, nestedObj: { foo: 1, name: "blarg" }, };
   * let getName = prop("nestedObj.name");
   * getName(obj) === "blarg"
   * let propNotFound = prop("this.property.doesnt.exist");
   * propNotFound(obj) === undefined
   */
  exports.parse = function (name) { return pipe.apply(null, name.split('.').map(exports.prop)); };
  /**
   * Given a function that returns a truthy or falsey value, returns a
   * function that returns the opposite (falsey or truthy) value given the same inputs
   */
  exports.not = function (fn) { return function () {
      var args = [];
      for (var _i = 0; _i < arguments.length; _i++) {
          args[_i] = arguments[_i];
      }
      return !fn.apply(null, args);
  }; };
  /**
   * Given two functions that return truthy or falsey values, returns a function that returns truthy
   * if both functions return truthy for the given arguments
   */
  function and(fn1, fn2) {
      return function () {
          var args = [];
          for (var _i = 0; _i < arguments.length; _i++) {
              args[_i] = arguments[_i];
          }
          return fn1.apply(null, args) && fn2.apply(null, args);
      };
  }
  exports.and = and;
  /**
   * Given two functions that return truthy or falsey values, returns a function that returns truthy
   * if at least one of the functions returns truthy for the given arguments
   */
  function or(fn1, fn2) {
      return function () {
          var args = [];
          for (var _i = 0; _i < arguments.length; _i++) {
              args[_i] = arguments[_i];
          }
          return fn1.apply(null, args) || fn2.apply(null, args);
      };
  }
  exports.or = or;
  /**
   * Check if all the elements of an array match a predicate function
   *
   * @param fn1 a predicate function `fn1`
   * @returns a function which takes an array and returns true if `fn1` is true for all elements of the array
   */
  exports.all = function (fn1) { return function (arr) { return arr.reduce(function (b, x) { return b && !!fn1(x); }, true); }; };
  // tslint:disable-next-line:variable-name
  exports.any = function (fn1) { return function (arr) { return arr.reduce(function (b, x) { return b || !!fn1(x); }, false); }; };
  /** Given a class, returns a Predicate function that returns true if the object is of that class */
  exports.is = function (ctor) { return function (obj) {
      return (obj != null && obj.constructor === ctor) || obj instanceof ctor;
  }; };
  /** Given a value, returns a Predicate function that returns true if another value is === equal to the original value */
  exports.eq = function (value) { return function (other) { return value === other; }; };
  /** Given a value, returns a function which returns the value */
  exports.val = function (v) { return function () { return v; }; };
  function invoke(fnName, args) {
      return function (obj) { return obj[fnName].apply(obj, args); };
  }
  exports.invoke = invoke;
  /**
   * Sorta like Pattern Matching (a functional programming conditional construct)
   *
   * See http://c2.com/cgi/wiki?PatternMatching
   *
   * This is a conditional construct which allows a series of predicates and output functions
   * to be checked and then applied.  Each predicate receives the input.  If the predicate
   * returns truthy, then its matching output function (mapping function) is provided with
   * the input and, then the result is returned.
   *
   * Each combination (2-tuple) of predicate + output function should be placed in an array
   * of size 2: [ predicate, mapFn ]
   *
   * These 2-tuples should be put in an outer array.
   *
   * @example
   * ```
   *
   * // Here's a 2-tuple where the first element is the isString predicate
   * // and the second element is a function that returns a description of the input
   * let firstTuple = [ angular.isString, (input) => `Heres your string ${input}` ];
   *
   * // Second tuple: predicate "isNumber", mapfn returns a description
   * let secondTuple = [ angular.isNumber, (input) => `(${input}) That's a number!` ];
   *
   * let third = [ (input) => input === null,  (input) => `Oh, null...` ];
   *
   * let fourth = [ (input) => input === undefined,  (input) => `notdefined` ];
   *
   * let descriptionOf = pattern([ firstTuple, secondTuple, third, fourth ]);
   *
   * console.log(descriptionOf(undefined)); // 'notdefined'
   * console.log(descriptionOf(55)); // '(55) That's a number!'
   * console.log(descriptionOf("foo")); // 'Here's your string foo'
   * ```
   *
   * @param struct A 2D array.  Each element of the array should be an array, a 2-tuple,
   * with a Predicate and a mapping/output function
   * @returns {function(any): *}
   */
  function pattern(struct) {
      return function (x) {
          for (var i = 0; i < struct.length; i++) {
              if (struct[i][0](x))
                  return struct[i][1](x);
          }
      };
  }
  exports.pattern = pattern;
  //# sourceMappingURL=hof.js.map