From d2084892b45b63f9cfec25d6c344d4f2d49d76e4 Mon Sep 17 00:00:00 2001 From: Mihail Diordiev Date: Wed, 19 Dec 2018 15:16:11 +0200 Subject: [PATCH] Merge d3tooltip package (#423) * Merge d3tooltip from romseguy/d3tooltip * Dependences and npm package config * Add credits --- packages/d3tooltip/.babelrc | 3 + packages/d3tooltip/.eslintignore | 4 + packages/d3tooltip/.eslintrc | 16 + packages/d3tooltip/LICENSE.md | 21 + packages/d3tooltip/README.md | 55 + packages/d3tooltip/dist/d3tooltip.js | 7736 +++++++++++++++++ packages/d3tooltip/dist/d3tooltip.min.js | 2 + packages/d3tooltip/package.json | 54 + packages/d3tooltip/src/index.js | 84 + packages/d3tooltip/src/utils/functor.js | 5 + packages/d3tooltip/src/utils/index.js | 7 + packages/d3tooltip/src/utils/prependClass.js | 20 + packages/d3tooltip/webpack.config.base.js | 16 + .../d3tooltip/webpack.config.development.js | 14 + .../d3tooltip/webpack.config.production.js | 20 + yarn.lock | 69 +- 16 files changed, 8119 insertions(+), 7 deletions(-) create mode 100644 packages/d3tooltip/.babelrc create mode 100644 packages/d3tooltip/.eslintignore create mode 100644 packages/d3tooltip/.eslintrc create mode 100644 packages/d3tooltip/LICENSE.md create mode 100644 packages/d3tooltip/README.md create mode 100644 packages/d3tooltip/dist/d3tooltip.js create mode 100644 packages/d3tooltip/dist/d3tooltip.min.js create mode 100644 packages/d3tooltip/package.json create mode 100644 packages/d3tooltip/src/index.js create mode 100644 packages/d3tooltip/src/utils/functor.js create mode 100644 packages/d3tooltip/src/utils/index.js create mode 100644 packages/d3tooltip/src/utils/prependClass.js create mode 100644 packages/d3tooltip/webpack.config.base.js create mode 100644 packages/d3tooltip/webpack.config.development.js create mode 100644 packages/d3tooltip/webpack.config.production.js diff --git a/packages/d3tooltip/.babelrc b/packages/d3tooltip/.babelrc new file mode 100644 index 00000000..9d06ebbb --- /dev/null +++ b/packages/d3tooltip/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["es2015-loose", "stage-0"] +} diff --git a/packages/d3tooltip/.eslintignore b/packages/d3tooltip/.eslintignore new file mode 100644 index 00000000..0d38857e --- /dev/null +++ b/packages/d3tooltip/.eslintignore @@ -0,0 +1,4 @@ +lib +**/node_modules +**/webpack.config.js +examples/**/server.js \ No newline at end of file diff --git a/packages/d3tooltip/.eslintrc b/packages/d3tooltip/.eslintrc new file mode 100644 index 00000000..8132e1fa --- /dev/null +++ b/packages/d3tooltip/.eslintrc @@ -0,0 +1,16 @@ +{ + "extends": "eslint-config-airbnb", + "env": { + "browser": true, + "mocha": true, + "node": true + }, + "rules": { + "react/jsx-uses-react": 2, + "react/jsx-uses-vars": 2, + "react/react-in-jsx-scope": 2 + }, + "plugins": [ + "react" + ] +} diff --git a/packages/d3tooltip/LICENSE.md b/packages/d3tooltip/LICENSE.md new file mode 100644 index 00000000..ee3e925d --- /dev/null +++ b/packages/d3tooltip/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 romseguy + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/d3tooltip/README.md b/packages/d3tooltip/README.md new file mode 100644 index 00000000..645b8ec1 --- /dev/null +++ b/packages/d3tooltip/README.md @@ -0,0 +1,55 @@ +d3tooltip +========================= + +This tooltip aims for a minimal yet highly configurable API. It has a long way to go, but the essentials are there. +It was created by [@romseguy](https://github.com/romseguy) and merged from [`romseguy/d3tooltip`](https://github.com/romseguy/d3tooltip). + +## Installation + +`npm install d3-state-visualizer` + +## Quick usage + +```javascript +import d3 from 'd3'; +import d3tooltip from 'd3tooltip'; + +const DOMNode = document.getElementById('chart'); +const root = d3.select(DOMNode); +const vis = root.append('svg'); + +let options = { + offset: {left: 30, top: 10} +}; + +vis.selectAll('circle').data(someData).enter() + .append('circle') + .attr('r', 10) + .call( + d3tooltip(d3, 'tooltipClassName', options) + .text((d, i) => toStringOrHtml(d)) + .attr({ 'class': 'anotherClassName' }) + .style({ 'min-width': '50px', 'border-radius: 5px' }) + ) + .on({ + mouseover(d, i) { + d3.select(this).style({ + fill: 'skyblue' + }); + }, + mouseout(d, i) { + d3.select(this).style({ + fill: 'black' + }); + } + }); +``` + +## API + +Option | Type | Default | Description +--------------------------|--------------|---------------------|-------------------------------------------------------------- +`root` | DOM.Element | `body` | The tooltip will be added as a child of that element. You can also use a D3 [selection](https://github.com/mbostock/d3/wiki/Selections#d3_select) +`left` | Number | `undefined` | Sets the tooltip `x` absolute position instead of the mouse `x` position, relative to the `root` element +`top` | Number | `undefined` | Sets the tooltip `y` absolute position instead of the mouse `y` position, relative to the `root` element +`offset` | Object | `{left: 0, top: 0}` | Sets the distance, starting from the cursor position, until the tooltip is rendered. **Warning**: only applicable if you don't provide a `left` or `top` option diff --git a/packages/d3tooltip/dist/d3tooltip.js b/packages/d3tooltip/dist/d3tooltip.js new file mode 100644 index 00000000..f0b224a7 --- /dev/null +++ b/packages/d3tooltip/dist/d3tooltip.js @@ -0,0 +1,7736 @@ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports["d3tooltip"] = factory(); + else + root["d3tooltip"] = factory(); +})(this, function() { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; + +/******/ // The require function +/******/ function __webpack_require__(moduleId) { + +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) +/******/ return installedModules[moduleId].exports; + +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ exports: {}, +/******/ id: moduleId, +/******/ loaded: false +/******/ }; + +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); + +/******/ // Flag the module as loaded +/******/ module.loaded = true; + +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } + + +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; + +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; + +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; + +/******/ // Load entry module and return exports +/******/ return __webpack_require__(0); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + + var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + + exports.default = tooltip; + + var _ramda = __webpack_require__(1); + + var _utils = __webpack_require__(3); + + var _utils2 = _interopRequireDefault(_utils); + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + + var _ref = _utils2.default.default || _utils2.default, + prependClass = _ref.prependClass, + functor = _ref.functor; + + var defaultOptions = { + left: undefined, // mouseX + top: undefined, // mouseY + offset: { left: 0, top: 0 }, + root: undefined + }; + + function tooltip(d3) { + var className = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'tooltip'; + var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + + var _defaultOptions$optio = _extends({}, defaultOptions, options), + left = _defaultOptions$optio.left, + top = _defaultOptions$optio.top, + offset = _defaultOptions$optio.offset, + root = _defaultOptions$optio.root; + + var attrs = { 'class': className }; + var text = function text() { + return ''; + }; + var styles = {}; + + var el = void 0; + var anchor = root || d3.select('body'); + var rootNode = anchor.node(); + + function tip(selection) { + selection.on({ + 'mouseover.tip': function mouseoverTip(node) { + var _d3$mouse = d3.mouse(rootNode), + mouseX = _d3$mouse[0], + mouseY = _d3$mouse[1]; + + var x = left || mouseX + offset.left, + y = top || mouseY - offset.top; + + + anchor.selectAll('div.' + className).remove(); + + el = anchor.append('div').attr(prependClass(className)(attrs)).style(_extends({ + position: 'absolute', + 'z-index': 1001, + left: x + 'px', + top: y + 'px' + }, styles)).html(function () { + return text(node); + }); + }, + + 'mousemove.tip': function mousemoveTip(node) { + var _d3$mouse2 = d3.mouse(rootNode), + mouseX = _d3$mouse2[0], + mouseY = _d3$mouse2[1]; + + var x = left || mouseX + offset.left, + y = top || mouseY - offset.top; + + + el.style({ + left: x + 'px', + top: y + 'px' + }).html(function () { + return text(node); + }); + }, + + 'mouseout.tip': function mouseoutTip() { + return el.remove(); + } + }); + } + + tip.attr = function setAttr(d) { + if ((0, _ramda.is)(Object, d)) { + attrs = _extends({}, attrs, d); + } + return this; + }; + + tip.style = function setStyle(d) { + if ((0, _ramda.is)(Object, d)) { + styles = _extends({}, styles, d); + } + return this; + }; + + tip.text = function setText(d) { + text = functor(d); + return this; + }; + + return tip; + } + +/***/ }), +/* 1 */ +/***/ (function(module, exports, __webpack_require__) { + + // Ramda v0.17.1 + // https://github.com/ramda/ramda + // (c) 2013-2015 Scott Sauyet, Michael Hurley, and David Chambers + // Ramda may be freely distributed under the MIT license. + + ;(function() { + + 'use strict'; + + /** + * A special placeholder value used to specify "gaps" within curried functions, + * allowing partial application of any combination of arguments, + * regardless of their positions. + * + * If `g` is a curried ternary function and `_` is `R.__`, the following are equivalent: + * + * - `g(1, 2, 3)` + * - `g(_, 2, 3)(1)` + * - `g(_, _, 3)(1)(2)` + * - `g(_, _, 3)(1, 2)` + * - `g(_, 2, _)(1, 3)` + * - `g(_, 2)(1)(3)` + * - `g(_, 2)(1, 3)` + * - `g(_, 2)(_, 3)(1)` + * + * @constant + * @memberOf R + * @category Function + * @example + * + * var greet = R.replace('{name}', R.__, 'Hello, {name}!'); + * greet('Alice'); //=> 'Hello, Alice!' + */ + var __ = { '@@functional/placeholder': true }; + + // jshint unused:vars + var _arity = function _arity(n, fn) { + // jshint unused:vars + switch (n) { + case 0: + return function () { + return fn.apply(this, arguments); + }; + case 1: + return function (a0) { + return fn.apply(this, arguments); + }; + case 2: + return function (a0, a1) { + return fn.apply(this, arguments); + }; + case 3: + return function (a0, a1, a2) { + return fn.apply(this, arguments); + }; + case 4: + return function (a0, a1, a2, a3) { + return fn.apply(this, arguments); + }; + case 5: + return function (a0, a1, a2, a3, a4) { + return fn.apply(this, arguments); + }; + case 6: + return function (a0, a1, a2, a3, a4, a5) { + return fn.apply(this, arguments); + }; + case 7: + return function (a0, a1, a2, a3, a4, a5, a6) { + return fn.apply(this, arguments); + }; + case 8: + return function (a0, a1, a2, a3, a4, a5, a6, a7) { + return fn.apply(this, arguments); + }; + case 9: + return function (a0, a1, a2, a3, a4, a5, a6, a7, a8) { + return fn.apply(this, arguments); + }; + case 10: + return function (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) { + return fn.apply(this, arguments); + }; + default: + throw new Error('First argument to _arity must be a non-negative integer no greater than ten'); + } + }; + + var _cloneRegExp = function _cloneRegExp(pattern) { + return new RegExp(pattern.source, (pattern.global ? 'g' : '') + (pattern.ignoreCase ? 'i' : '') + (pattern.multiline ? 'm' : '') + (pattern.sticky ? 'y' : '') + (pattern.unicode ? 'u' : '')); + }; + + var _complement = function _complement(f) { + return function () { + return !f.apply(this, arguments); + }; + }; + + /** + * Private `concat` function to merge two array-like objects. + * + * @private + * @param {Array|Arguments} [set1=[]] An array-like object. + * @param {Array|Arguments} [set2=[]] An array-like object. + * @return {Array} A new, merged array. + * @example + * + * _concat([4, 5, 6], [1, 2, 3]); //=> [4, 5, 6, 1, 2, 3] + */ + var _concat = function _concat(set1, set2) { + set1 = set1 || []; + set2 = set2 || []; + var idx; + var len1 = set1.length; + var len2 = set2.length; + var result = []; + idx = 0; + while (idx < len1) { + result[result.length] = set1[idx]; + idx += 1; + } + idx = 0; + while (idx < len2) { + result[result.length] = set2[idx]; + idx += 1; + } + return result; + }; + + var _containsWith = function _containsWith(pred, x, list) { + var idx = 0, len = list.length; + while (idx < len) { + if (pred(x, list[idx])) { + return true; + } + idx += 1; + } + return false; + }; + + /** + * Optimized internal two-arity curry function. + * + * @private + * @category Function + * @param {Function} fn The function to curry. + * @return {Function} The curried function. + */ + var _curry1 = function _curry1(fn) { + return function f1(a) { + if (arguments.length === 0) { + return f1; + } else if (a != null && a['@@functional/placeholder'] === true) { + return f1; + } else { + return fn.apply(this, arguments); + } + }; + }; + + /** + * Optimized internal two-arity curry function. + * + * @private + * @category Function + * @param {Function} fn The function to curry. + * @return {Function} The curried function. + */ + var _curry2 = function _curry2(fn) { + return function f2(a, b) { + var n = arguments.length; + if (n === 0) { + return f2; + } else if (n === 1 && a != null && a['@@functional/placeholder'] === true) { + return f2; + } else if (n === 1) { + return _curry1(function (b) { + return fn(a, b); + }); + } else if (n === 2 && a != null && a['@@functional/placeholder'] === true && b != null && b['@@functional/placeholder'] === true) { + return f2; + } else if (n === 2 && a != null && a['@@functional/placeholder'] === true) { + return _curry1(function (a) { + return fn(a, b); + }); + } else if (n === 2 && b != null && b['@@functional/placeholder'] === true) { + return _curry1(function (b) { + return fn(a, b); + }); + } else { + return fn(a, b); + } + }; + }; + + /** + * Optimized internal three-arity curry function. + * + * @private + * @category Function + * @param {Function} fn The function to curry. + * @return {Function} The curried function. + */ + var _curry3 = function _curry3(fn) { + return function f3(a, b, c) { + var n = arguments.length; + if (n === 0) { + return f3; + } else if (n === 1 && a != null && a['@@functional/placeholder'] === true) { + return f3; + } else if (n === 1) { + return _curry2(function (b, c) { + return fn(a, b, c); + }); + } else if (n === 2 && a != null && a['@@functional/placeholder'] === true && b != null && b['@@functional/placeholder'] === true) { + return f3; + } else if (n === 2 && a != null && a['@@functional/placeholder'] === true) { + return _curry2(function (a, c) { + return fn(a, b, c); + }); + } else if (n === 2 && b != null && b['@@functional/placeholder'] === true) { + return _curry2(function (b, c) { + return fn(a, b, c); + }); + } else if (n === 2) { + return _curry1(function (c) { + return fn(a, b, c); + }); + } else if (n === 3 && a != null && a['@@functional/placeholder'] === true && b != null && b['@@functional/placeholder'] === true && c != null && c['@@functional/placeholder'] === true) { + return f3; + } else if (n === 3 && a != null && a['@@functional/placeholder'] === true && b != null && b['@@functional/placeholder'] === true) { + return _curry2(function (a, b) { + return fn(a, b, c); + }); + } else if (n === 3 && a != null && a['@@functional/placeholder'] === true && c != null && c['@@functional/placeholder'] === true) { + return _curry2(function (a, c) { + return fn(a, b, c); + }); + } else if (n === 3 && b != null && b['@@functional/placeholder'] === true && c != null && c['@@functional/placeholder'] === true) { + return _curry2(function (b, c) { + return fn(a, b, c); + }); + } else if (n === 3 && a != null && a['@@functional/placeholder'] === true) { + return _curry1(function (a) { + return fn(a, b, c); + }); + } else if (n === 3 && b != null && b['@@functional/placeholder'] === true) { + return _curry1(function (b) { + return fn(a, b, c); + }); + } else if (n === 3 && c != null && c['@@functional/placeholder'] === true) { + return _curry1(function (c) { + return fn(a, b, c); + }); + } else { + return fn(a, b, c); + } + }; + }; + + /** + * Internal curryN function. + * + * @private + * @category Function + * @param {Number} length The arity of the curried function. + * @return {array} An array of arguments received thus far. + * @param {Function} fn The function to curry. + */ + var _curryN = function _curryN(length, received, fn) { + return function () { + var combined = []; + var argsIdx = 0; + var left = length; + var combinedIdx = 0; + while (combinedIdx < received.length || argsIdx < arguments.length) { + var result; + if (combinedIdx < received.length && (received[combinedIdx] == null || received[combinedIdx]['@@functional/placeholder'] !== true || argsIdx >= arguments.length)) { + result = received[combinedIdx]; + } else { + result = arguments[argsIdx]; + argsIdx += 1; + } + combined[combinedIdx] = result; + if (result == null || result['@@functional/placeholder'] !== true) { + left -= 1; + } + combinedIdx += 1; + } + return left <= 0 ? fn.apply(this, combined) : _arity(left, _curryN(length, combined, fn)); + }; + }; + + var _filter = function _filter(fn, list) { + var idx = 0, len = list.length, result = []; + while (idx < len) { + if (fn(list[idx])) { + result[result.length] = list[idx]; + } + idx += 1; + } + return result; + }; + + var _forceReduced = function _forceReduced(x) { + return { + '@@transducer/value': x, + '@@transducer/reduced': true + }; + }; + + /** + * @private + * @param {Function} fn The strategy for extracting function names from an object + * @return {Function} A function that takes an object and returns an array of function names. + */ + var _functionsWith = function _functionsWith(fn) { + return function (obj) { + return _filter(function (key) { + return typeof obj[key] === 'function'; + }, fn(obj)); + }; + }; + + var _has = function _has(prop, obj) { + return Object.prototype.hasOwnProperty.call(obj, prop); + }; + + var _identity = function _identity(x) { + return x; + }; + + /** + * Tests whether or not an object is an array. + * + * @private + * @param {*} val The object to test. + * @return {Boolean} `true` if `val` is an array, `false` otherwise. + * @example + * + * _isArray([]); //=> true + * _isArray(null); //=> false + * _isArray({}); //=> false + */ + var _isArray = Array.isArray || function _isArray(val) { + return val != null && val.length >= 0 && Object.prototype.toString.call(val) === '[object Array]'; + }; + + /** + * Determine if the passed argument is an integer. + * + * @private + * @param {*} n + * @category Type + * @return {Boolean} + */ + var _isInteger = Number.isInteger || function _isInteger(n) { + return n << 0 === n; + }; + + var _isNumber = function _isNumber(x) { + return Object.prototype.toString.call(x) === '[object Number]'; + }; + + var _isString = function _isString(x) { + return Object.prototype.toString.call(x) === '[object String]'; + }; + + var _isTransformer = function _isTransformer(obj) { + return typeof obj['@@transducer/step'] === 'function'; + }; + + var _map = function _map(fn, list) { + var idx = 0, len = list.length, result = Array(len); + while (idx < len) { + result[idx] = fn(list[idx]); + idx += 1; + } + return result; + }; + + var _pipe = function _pipe(f, g) { + return function () { + return g.call(this, f.apply(this, arguments)); + }; + }; + + var _pipeP = function _pipeP(f, g) { + return function () { + var ctx = this; + return f.apply(ctx, arguments).then(function (x) { + return g.call(ctx, x); + }); + }; + }; + + var _quote = function _quote(s) { + return '"' + s.replace(/"/g, '\\"') + '"'; + }; + + var _reduced = function _reduced(x) { + return x && x['@@transducer/reduced'] ? x : { + '@@transducer/value': x, + '@@transducer/reduced': true + }; + }; + + /** + * An optimized, private array `slice` implementation. + * + * @private + * @param {Arguments|Array} args The array or arguments object to consider. + * @param {Number} [from=0] The array index to slice from, inclusive. + * @param {Number} [to=args.length] The array index to slice to, exclusive. + * @return {Array} A new, sliced array. + * @example + * + * _slice([1, 2, 3, 4, 5], 1, 3); //=> [2, 3] + * + * var firstThreeArgs = function(a, b, c, d) { + * return _slice(arguments, 0, 3); + * }; + * firstThreeArgs(1, 2, 3, 4); //=> [1, 2, 3] + */ + var _slice = function _slice(args, from, to) { + switch (arguments.length) { + case 1: + return _slice(args, 0, args.length); + case 2: + return _slice(args, from, args.length); + default: + var list = []; + var idx = 0; + var len = Math.max(0, Math.min(args.length, to) - from); + while (idx < len) { + list[idx] = args[from + idx]; + idx += 1; + } + return list; + } + }; + + /** + * Polyfill from . + */ + var _toISOString = function () { + var pad = function pad(n) { + return (n < 10 ? '0' : '') + n; + }; + return typeof Date.prototype.toISOString === 'function' ? function _toISOString(d) { + return d.toISOString(); + } : function _toISOString(d) { + return d.getUTCFullYear() + '-' + pad(d.getUTCMonth() + 1) + '-' + pad(d.getUTCDate()) + 'T' + pad(d.getUTCHours()) + ':' + pad(d.getUTCMinutes()) + ':' + pad(d.getUTCSeconds()) + '.' + (d.getUTCMilliseconds() / 1000).toFixed(3).slice(2, 5) + 'Z'; + }; + }(); + + var _xdropRepeatsWith = function () { + function XDropRepeatsWith(pred, xf) { + this.xf = xf; + this.pred = pred; + this.lastValue = undefined; + this.seenFirstValue = false; + } + XDropRepeatsWith.prototype['@@transducer/init'] = function () { + return this.xf['@@transducer/init'](); + }; + XDropRepeatsWith.prototype['@@transducer/result'] = function (result) { + return this.xf['@@transducer/result'](result); + }; + XDropRepeatsWith.prototype['@@transducer/step'] = function (result, input) { + var sameAsLast = false; + if (!this.seenFirstValue) { + this.seenFirstValue = true; + } else if (this.pred(this.lastValue, input)) { + sameAsLast = true; + } + this.lastValue = input; + return sameAsLast ? result : this.xf['@@transducer/step'](result, input); + }; + return _curry2(function _xdropRepeatsWith(pred, xf) { + return new XDropRepeatsWith(pred, xf); + }); + }(); + + var _xfBase = { + init: function () { + return this.xf['@@transducer/init'](); + }, + result: function (result) { + return this.xf['@@transducer/result'](result); + } + }; + + var _xfilter = function () { + function XFilter(f, xf) { + this.xf = xf; + this.f = f; + } + XFilter.prototype['@@transducer/init'] = _xfBase.init; + XFilter.prototype['@@transducer/result'] = _xfBase.result; + XFilter.prototype['@@transducer/step'] = function (result, input) { + return this.f(input) ? this.xf['@@transducer/step'](result, input) : result; + }; + return _curry2(function _xfilter(f, xf) { + return new XFilter(f, xf); + }); + }(); + + var _xfind = function () { + function XFind(f, xf) { + this.xf = xf; + this.f = f; + this.found = false; + } + XFind.prototype['@@transducer/init'] = _xfBase.init; + XFind.prototype['@@transducer/result'] = function (result) { + if (!this.found) { + result = this.xf['@@transducer/step'](result, void 0); + } + return this.xf['@@transducer/result'](result); + }; + XFind.prototype['@@transducer/step'] = function (result, input) { + if (this.f(input)) { + this.found = true; + result = _reduced(this.xf['@@transducer/step'](result, input)); + } + return result; + }; + return _curry2(function _xfind(f, xf) { + return new XFind(f, xf); + }); + }(); + + var _xfindIndex = function () { + function XFindIndex(f, xf) { + this.xf = xf; + this.f = f; + this.idx = -1; + this.found = false; + } + XFindIndex.prototype['@@transducer/init'] = _xfBase.init; + XFindIndex.prototype['@@transducer/result'] = function (result) { + if (!this.found) { + result = this.xf['@@transducer/step'](result, -1); + } + return this.xf['@@transducer/result'](result); + }; + XFindIndex.prototype['@@transducer/step'] = function (result, input) { + this.idx += 1; + if (this.f(input)) { + this.found = true; + result = _reduced(this.xf['@@transducer/step'](result, this.idx)); + } + return result; + }; + return _curry2(function _xfindIndex(f, xf) { + return new XFindIndex(f, xf); + }); + }(); + + var _xfindLast = function () { + function XFindLast(f, xf) { + this.xf = xf; + this.f = f; + } + XFindLast.prototype['@@transducer/init'] = _xfBase.init; + XFindLast.prototype['@@transducer/result'] = function (result) { + return this.xf['@@transducer/result'](this.xf['@@transducer/step'](result, this.last)); + }; + XFindLast.prototype['@@transducer/step'] = function (result, input) { + if (this.f(input)) { + this.last = input; + } + return result; + }; + return _curry2(function _xfindLast(f, xf) { + return new XFindLast(f, xf); + }); + }(); + + var _xfindLastIndex = function () { + function XFindLastIndex(f, xf) { + this.xf = xf; + this.f = f; + this.idx = -1; + this.lastIdx = -1; + } + XFindLastIndex.prototype['@@transducer/init'] = _xfBase.init; + XFindLastIndex.prototype['@@transducer/result'] = function (result) { + return this.xf['@@transducer/result'](this.xf['@@transducer/step'](result, this.lastIdx)); + }; + XFindLastIndex.prototype['@@transducer/step'] = function (result, input) { + this.idx += 1; + if (this.f(input)) { + this.lastIdx = this.idx; + } + return result; + }; + return _curry2(function _xfindLastIndex(f, xf) { + return new XFindLastIndex(f, xf); + }); + }(); + + var _xmap = function () { + function XMap(f, xf) { + this.xf = xf; + this.f = f; + } + XMap.prototype['@@transducer/init'] = _xfBase.init; + XMap.prototype['@@transducer/result'] = _xfBase.result; + XMap.prototype['@@transducer/step'] = function (result, input) { + return this.xf['@@transducer/step'](result, this.f(input)); + }; + return _curry2(function _xmap(f, xf) { + return new XMap(f, xf); + }); + }(); + + var _xtake = function () { + function XTake(n, xf) { + this.xf = xf; + this.n = n; + } + XTake.prototype['@@transducer/init'] = _xfBase.init; + XTake.prototype['@@transducer/result'] = _xfBase.result; + XTake.prototype['@@transducer/step'] = function (result, input) { + if (this.n === 0) { + return _reduced(result); + } else { + this.n -= 1; + return this.xf['@@transducer/step'](result, input); + } + }; + return _curry2(function _xtake(n, xf) { + return new XTake(n, xf); + }); + }(); + + var _xtakeWhile = function () { + function XTakeWhile(f, xf) { + this.xf = xf; + this.f = f; + } + XTakeWhile.prototype['@@transducer/init'] = _xfBase.init; + XTakeWhile.prototype['@@transducer/result'] = _xfBase.result; + XTakeWhile.prototype['@@transducer/step'] = function (result, input) { + return this.f(input) ? this.xf['@@transducer/step'](result, input) : _reduced(result); + }; + return _curry2(function _xtakeWhile(f, xf) { + return new XTakeWhile(f, xf); + }); + }(); + + var _xwrap = function () { + function XWrap(fn) { + this.f = fn; + } + XWrap.prototype['@@transducer/init'] = function () { + throw new Error('init not implemented on XWrap'); + }; + XWrap.prototype['@@transducer/result'] = function (acc) { + return acc; + }; + XWrap.prototype['@@transducer/step'] = function (acc, x) { + return this.f(acc, x); + }; + return function _xwrap(fn) { + return new XWrap(fn); + }; + }(); + + /** + * Adds two numbers. Equivalent to `a + b` but curried. + * + * @func + * @memberOf R + * @category Math + * @sig Number -> Number -> Number + * @param {Number} a + * @param {Number} b + * @return {Number} + * @see R.subtract + * @example + * + * R.add(2, 3); //=> 5 + * R.add(7)(10); //=> 17 + */ + var add = _curry2(function add(a, b) { + return a + b; + }); + + /** + * Applies a function to the value at the given index of an array, + * returning a new copy of the array with the element at the given + * index replaced with the result of the function application. + * @see R.update + * + * @func + * @memberOf R + * @category List + * @sig (a -> a) -> Number -> [a] -> [a] + * @param {Function} fn The function to apply. + * @param {Number} idx The index. + * @param {Array|Arguments} list An array-like object whose value + * at the supplied index will be replaced. + * @return {Array} A copy of the supplied array-like object with + * the element at index `idx` replaced with the value + * returned by applying `fn` to the existing element. + * @example + * + * R.adjust(R.add(10), 1, [0, 1, 2]); //=> [0, 11, 2] + * R.adjust(R.add(10))(1)([0, 1, 2]); //=> [0, 11, 2] + */ + var adjust = _curry3(function adjust(fn, idx, list) { + if (idx >= list.length || idx < -list.length) { + return list; + } + var start = idx < 0 ? list.length : 0; + var _idx = start + idx; + var _list = _concat(list); + _list[_idx] = fn(list[_idx]); + return _list; + }); + + /** + * Returns a function that always returns the given value. Note that for + * non-primitives the value returned is a reference to the original value. + * + * This function is known as `const`, `constant`, or `K` (for K combinator) + * in other languages and libraries. + * + * @func + * @memberOf R + * @category Function + * @sig a -> (* -> a) + * @param {*} val The value to wrap in a function + * @return {Function} A Function :: * -> val. + * @example + * + * var t = R.always('Tee'); + * t(); //=> 'Tee' + */ + var always = _curry1(function always(val) { + return function () { + return val; + }; + }); + + /** + * Returns a new list, composed of n-tuples of consecutive elements + * If `n` is greater than the length of the list, an empty list is returned. + * + * @func + * @memberOf R + * @category List + * @sig Number -> [a] -> [[a]] + * @param {Number} n The size of the tuples to create + * @param {Array} list The list to split into `n`-tuples + * @return {Array} The new list. + * @example + * + * R.aperture(2, [1, 2, 3, 4, 5]); //=> [[1, 2], [2, 3], [3, 4], [4, 5]] + * R.aperture(3, [1, 2, 3, 4, 5]); //=> [[1, 2, 3], [2, 3, 4], [3, 4, 5]] + * R.aperture(7, [1, 2, 3, 4, 5]); //=> [] + */ + var aperture = _curry2(function aperture(n, list) { + var idx = 0; + var limit = list.length - (n - 1); + var acc = new Array(limit >= 0 ? limit : 0); + while (idx < limit) { + acc[idx] = _slice(list, idx, idx + n); + idx += 1; + } + return acc; + }); + + /** + * Returns a new list containing the contents of the given list, followed by the given + * element. + * + * @func + * @memberOf R + * @category List + * @sig a -> [a] -> [a] + * @param {*} el The element to add to the end of the new list. + * @param {Array} list The list whose contents will be added to the beginning of the output + * list. + * @return {Array} A new list containing the contents of the old list followed by `el`. + * @see R.prepend + * @example + * + * R.append('tests', ['write', 'more']); //=> ['write', 'more', 'tests'] + * R.append('tests', []); //=> ['tests'] + * R.append(['tests'], ['write', 'more']); //=> ['write', 'more', ['tests']] + */ + var append = _curry2(function append(el, list) { + return _concat(list, [el]); + }); + + /** + * Applies function `fn` to the argument list `args`. This is useful for + * creating a fixed-arity function from a variadic function. `fn` should + * be a bound function if context is significant. + * + * @func + * @memberOf R + * @category Function + * @sig (*... -> a) -> [*] -> a + * @param {Function} fn + * @param {Array} args + * @return {*} + * @see R.call, R.unapply + * @example + * + * var nums = [1, 2, 3, -99, 42, 6, 7]; + * R.apply(Math.max, nums); //=> 42 + */ + var apply = _curry2(function apply(fn, args) { + return fn.apply(this, args); + }); + + /** + * Makes a shallow clone of an object, setting or overriding the specified + * property with the given value. Note that this copies and flattens + * prototype properties onto the new object as well. All non-primitive + * properties are copied by reference. + * + * @func + * @memberOf R + * @category Object + * @sig String -> a -> {k: v} -> {k: v} + * @param {String} prop the property name to set + * @param {*} val the new value + * @param {Object} obj the object to clone + * @return {Object} a new object similar to the original except for the specified property. + * @see R.dissoc + * @example + * + * R.assoc('c', 3, {a: 1, b: 2}); //=> {a: 1, b: 2, c: 3} + */ + var assoc = _curry3(function assoc(prop, val, obj) { + var result = {}; + for (var p in obj) { + result[p] = obj[p]; + } + result[prop] = val; + return result; + }); + + /** + * Makes a shallow clone of an object, setting or overriding the nodes + * required to create the given path, and placing the specific value at the + * tail end of that path. Note that this copies and flattens prototype + * properties onto the new object as well. All non-primitive properties + * are copied by reference. + * + * @func + * @memberOf R + * @category Object + * @sig [String] -> a -> {k: v} -> {k: v} + * @param {Array} path the path to set + * @param {*} val the new value + * @param {Object} obj the object to clone + * @return {Object} a new object similar to the original except along the specified path. + * @see R.dissocPath + * @example + * + * R.assocPath(['a', 'b', 'c'], 42, {a: {b: {c: 0}}}); //=> {a: {b: {c: 42}}} + */ + var assocPath = _curry3(function assocPath(path, val, obj) { + switch (path.length) { + case 0: + return obj; + case 1: + return assoc(path[0], val, obj); + default: + return assoc(path[0], assocPath(_slice(path, 1), val, Object(obj[path[0]])), obj); + } + }); + + /** + * Creates a function that is bound to a context. + * Note: `R.bind` does not provide the additional argument-binding capabilities of + * [Function.prototype.bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind). + * + * @func + * @memberOf R + * @category Function + * @category Object + * @see R.partial + * @sig (* -> *) -> {*} -> (* -> *) + * @param {Function} fn The function to bind to context + * @param {Object} thisObj The context to bind `fn` to + * @return {Function} A function that will execute in the context of `thisObj`. + */ + var bind = _curry2(function bind(fn, thisObj) { + return _arity(fn.length, function () { + return fn.apply(thisObj, arguments); + }); + }); + + /** + * A function wrapping calls to the two functions in an `&&` operation, returning the result of the first + * function if it is false-y and the result of the second function otherwise. Note that this is + * short-circuited, meaning that the second function will not be invoked if the first returns a false-y + * value. + * + * @func + * @memberOf R + * @category Logic + * @sig (*... -> Boolean) -> (*... -> Boolean) -> (*... -> Boolean) + * @param {Function} f a predicate + * @param {Function} g another predicate + * @return {Function} a function that applies its arguments to `f` and `g` and `&&`s their outputs together. + * @see R.and + * @example + * + * var gt10 = function(x) { return x > 10; }; + * var even = function(x) { return x % 2 === 0 }; + * var f = R.both(gt10, even); + * f(100); //=> true + * f(101); //=> false + */ + var both = _curry2(function both(f, g) { + return function _both() { + return f.apply(this, arguments) && g.apply(this, arguments); + }; + }); + + /** + * Makes a comparator function out of a function that reports whether the first element is less than the second. + * + * @func + * @memberOf R + * @category Function + * @sig (a, b -> Boolean) -> (a, b -> Number) + * @param {Function} pred A predicate function of arity two. + * @return {Function} A Function :: a -> b -> Int that returns `-1` if a < b, `1` if b < a, otherwise `0`. + * @example + * + * var cmp = R.comparator(function(a, b) { + * return a.age < b.age; + * }); + * var people = [ + * // ... + * ]; + * R.sort(cmp, people); + */ + var comparator = _curry1(function comparator(pred) { + return function (a, b) { + return pred(a, b) ? -1 : pred(b, a) ? 1 : 0; + }; + }); + + /** + * Takes a function `f` and returns a function `g` such that: + * + * - applying `g` to zero or more arguments will give __true__ if applying + * the same arguments to `f` gives a logical __false__ value; and + * + * - applying `g` to zero or more arguments will give __false__ if applying + * the same arguments to `f` gives a logical __true__ value. + * + * @func + * @memberOf R + * @category Logic + * @sig (*... -> *) -> (*... -> Boolean) + * @param {Function} f + * @return {Function} + * @see R.not + * @example + * + * var isEven = function(n) { return n % 2 === 0; }; + * var isOdd = R.complement(isEven); + * isOdd(21); //=> true + * isOdd(42); //=> false + */ + var complement = _curry1(_complement); + + /** + * Returns a function, `fn`, which encapsulates if/else-if/else logic. + * `R.cond` takes a list of [predicate, transform] pairs. All of the + * arguments to `fn` are applied to each of the predicates in turn + * until one returns a "truthy" value, at which point `fn` returns the + * result of applying its arguments to the corresponding transformer. + * If none of the predicates matches, `fn` returns undefined. + * + * @func + * @memberOf R + * @category Logic + * @sig [[(*... -> Boolean),(*... -> *)]] -> (*... -> *) + * @param {Array} pairs + * @return {Function} + * @example + * + * var fn = R.cond([ + * [R.equals(0), R.always('water freezes at 0°C')], + * [R.equals(100), R.always('water boils at 100°C')], + * [R.T, function(temp) { return 'nothing special happens at ' + temp + '°C'; }] + * ]); + * fn(0); //=> 'water freezes at 0°C' + * fn(50); //=> 'nothing special happens at 50°C' + * fn(100); //=> 'water boils at 100°C' + */ + var cond = _curry1(function cond(pairs) { + return function () { + var idx = 0; + while (idx < pairs.length) { + if (pairs[idx][0].apply(this, arguments)) { + return pairs[idx][1].apply(this, arguments); + } + idx += 1; + } + }; + }); + + /** + * Returns `true` if the `x` is found in the `list`, using `pred` as an + * equality predicate for `x`. + * + * @func + * @memberOf R + * @category List + * @sig (a, a -> Boolean) -> a -> [a] -> Boolean + * @param {Function} pred A predicate used to test whether two items are equal. + * @param {*} x The item to find + * @param {Array} list The list to iterate over + * @return {Boolean} `true` if `x` is in `list`, else `false`. + * @example + * + * var xs = [{x: 12}, {x: 11}, {x: 10}]; + * R.containsWith(function(a, b) { return a.x === b.x; }, {x: 10}, xs); //=> true + * R.containsWith(function(a, b) { return a.x === b.x; }, {x: 1}, xs); //=> false + */ + var containsWith = _curry3(_containsWith); + + /** + * Counts the elements of a list according to how many match each value + * of a key generated by the supplied function. Returns an object + * mapping the keys produced by `fn` to the number of occurrences in + * the list. Note that all keys are coerced to strings because of how + * JavaScript objects work. + * + * @func + * @memberOf R + * @category Relation + * @sig (a -> String) -> [a] -> {*} + * @param {Function} fn The function used to map values to keys. + * @param {Array} list The list to count elements from. + * @return {Object} An object mapping keys to number of occurrences in the list. + * @example + * + * var numbers = [1.0, 1.1, 1.2, 2.0, 3.0, 2.2]; + * var letters = R.split('', 'abcABCaaaBBc'); + * R.countBy(Math.floor)(numbers); //=> {'1': 3, '2': 2, '3': 1} + * R.countBy(R.toLower)(letters); //=> {'a': 5, 'b': 4, 'c': 3} + */ + var countBy = _curry2(function countBy(fn, list) { + var counts = {}; + var len = list.length; + var idx = 0; + while (idx < len) { + var key = fn(list[idx]); + counts[key] = (_has(key, counts) ? counts[key] : 0) + 1; + idx += 1; + } + return counts; + }); + + /** + * Creates an object containing a single key:value pair. + * + * @func + * @memberOf R + * @category Object + * @sig String -> a -> {String:a} + * @param {String} key + * @param {*} val + * @return {Object} + * @example + * + * var matchPhrases = R.compose( + * R.createMapEntry('must'), + * R.map(R.createMapEntry('match_phrase')) + * ); + * matchPhrases(['foo', 'bar', 'baz']); //=> {must: [{match_phrase: 'foo'}, {match_phrase: 'bar'}, {match_phrase: 'baz'}]} + */ + var createMapEntry = _curry2(function createMapEntry(key, val) { + var obj = {}; + obj[key] = val; + return obj; + }); + + /** + * Returns a curried equivalent of the provided function, with the + * specified arity. The curried function has two unusual capabilities. + * First, its arguments needn't be provided one at a time. If `g` is + * `R.curryN(3, f)`, the following are equivalent: + * + * - `g(1)(2)(3)` + * - `g(1)(2, 3)` + * - `g(1, 2)(3)` + * - `g(1, 2, 3)` + * + * Secondly, the special placeholder value `R.__` may be used to specify + * "gaps", allowing partial application of any combination of arguments, + * regardless of their positions. If `g` is as above and `_` is `R.__`, + * the following are equivalent: + * + * - `g(1, 2, 3)` + * - `g(_, 2, 3)(1)` + * - `g(_, _, 3)(1)(2)` + * - `g(_, _, 3)(1, 2)` + * - `g(_, 2)(1)(3)` + * - `g(_, 2)(1, 3)` + * - `g(_, 2)(_, 3)(1)` + * + * @func + * @memberOf R + * @category Function + * @sig Number -> (* -> a) -> (* -> a) + * @param {Number} length The arity for the returned function. + * @param {Function} fn The function to curry. + * @return {Function} A new, curried function. + * @see R.curry + * @example + * + * var addFourNumbers = function() { + * return R.sum([].slice.call(arguments, 0, 4)); + * }; + * + * var curriedAddFourNumbers = R.curryN(4, addFourNumbers); + * var f = curriedAddFourNumbers(1, 2); + * var g = f(3); + * g(4); //=> 10 + */ + var curryN = _curry2(function curryN(length, fn) { + if (length === 1) { + return _curry1(fn); + } + return _arity(length, _curryN(length, [], fn)); + }); + + /** + * Decrements its argument. + * + * @func + * @memberOf R + * @category Math + * @sig Number -> Number + * @param {Number} n + * @return {Number} + * @see R.inc + * @example + * + * R.dec(42); //=> 41 + */ + var dec = add(-1); + + /** + * Returns the second argument if it is not null or undefined. If it is null + * or undefined, the first (default) argument is returned. + * + * @func + * @memberOf R + * @category Logic + * @sig a -> b -> a | b + * @param {a} val The default value. + * @param {b} val The value to return if it is not null or undefined + * @return {*} The the second value or the default value + * @example + * + * var defaultTo42 = defaultTo(42); + * + * defaultTo42(null); //=> 42 + * defaultTo42(undefined); //=> 42 + * defaultTo42('Ramda'); //=> 'Ramda' + */ + var defaultTo = _curry2(function defaultTo(d, v) { + return v == null ? d : v; + }); + + /** + * Finds the set (i.e. no duplicates) of all elements in the first list not contained in the second list. + * Duplication is determined according to the value returned by applying the supplied predicate to two list + * elements. + * + * @func + * @memberOf R + * @category Relation + * @sig (a,a -> Boolean) -> [a] -> [a] -> [a] + * @param {Function} pred A predicate used to test whether two items are equal. + * @param {Array} list1 The first list. + * @param {Array} list2 The second list. + * @see R.difference + * @return {Array} The elements in `list1` that are not in `list2`. + * @example + * + * function cmp(x, y) { return x.a === y.a; } + * var l1 = [{a: 1}, {a: 2}, {a: 3}]; + * var l2 = [{a: 3}, {a: 4}]; + * R.differenceWith(cmp, l1, l2); //=> [{a: 1}, {a: 2}] + */ + var differenceWith = _curry3(function differenceWith(pred, first, second) { + var out = []; + var idx = 0; + var firstLen = first.length; + var containsPred = containsWith(pred); + while (idx < firstLen) { + if (!containsPred(first[idx], second) && !containsPred(first[idx], out)) { + out[out.length] = first[idx]; + } + idx += 1; + } + return out; + }); + + /** + * Returns a new object that does not contain a `prop` property. + * + * @func + * @memberOf R + * @category Object + * @sig String -> {k: v} -> {k: v} + * @param {String} prop the name of the property to dissociate + * @param {Object} obj the object to clone + * @return {Object} a new object similar to the original but without the specified property + * @see R.assoc + * @example + * + * R.dissoc('b', {a: 1, b: 2, c: 3}); //=> {a: 1, c: 3} + */ + var dissoc = _curry2(function dissoc(prop, obj) { + var result = {}; + for (var p in obj) { + if (p !== prop) { + result[p] = obj[p]; + } + } + return result; + }); + + /** + * Makes a shallow clone of an object, omitting the property at the + * given path. Note that this copies and flattens prototype properties + * onto the new object as well. All non-primitive properties are copied + * by reference. + * + * @func + * @memberOf R + * @category Object + * @sig [String] -> {k: v} -> {k: v} + * @param {Array} path the path to set + * @param {Object} obj the object to clone + * @return {Object} a new object without the property at path + * @see R.assocPath + * @example + * + * R.dissocPath(['a', 'b', 'c'], {a: {b: {c: 42}}}); //=> {a: {b: {}}} + */ + var dissocPath = _curry2(function dissocPath(path, obj) { + switch (path.length) { + case 0: + return obj; + case 1: + return dissoc(path[0], obj); + default: + var head = path[0]; + var tail = _slice(path, 1); + return obj[head] == null ? obj : assoc(head, dissocPath(tail, obj[head]), obj); + } + }); + + /** + * Divides two numbers. Equivalent to `a / b`. + * + * @func + * @memberOf R + * @category Math + * @sig Number -> Number -> Number + * @param {Number} a The first value. + * @param {Number} b The second value. + * @return {Number} The result of `a / b`. + * @see R.multiply + * @example + * + * R.divide(71, 100); //=> 0.71 + * + * var half = R.divide(R.__, 2); + * half(42); //=> 21 + * + * var reciprocal = R.divide(1); + * reciprocal(4); //=> 0.25 + */ + var divide = _curry2(function divide(a, b) { + return a / b; + }); + + /** + * Returns a new list containing all but last the`n` elements of a given list, + * passing each value from the right to the supplied predicate function, skipping + * elements while the predicate function returns `true`. The predicate function + * is passed one argument: (value)*. + * + * @func + * @memberOf R + * @category List + * @sig (a -> Boolean) -> [a] -> [a] + * @param {Function} fn The function called per iteration. + * @param {Array} list The collection to iterate over. + * @return {Array} A new array. + * @see R.takeLastWhile + * @example + * + * var lteThree = function(x) { + * return x <= 3; + * }; + * + * R.dropLastWhile(lteThree, [1, 2, 3, 4, 3, 2, 1]); //=> [1, 2] + */ + var dropLastWhile = _curry2(function dropLastWhile(pred, list) { + var idx = list.length - 1; + while (idx >= 0 && pred(list[idx])) { + idx -= 1; + } + return _slice(list, 0, idx + 1); + }); + + /** + * A function wrapping calls to the two functions in an `||` operation, returning the result of the first + * function if it is truth-y and the result of the second function otherwise. Note that this is + * short-circuited, meaning that the second function will not be invoked if the first returns a truth-y + * value. + * + * @func + * @memberOf R + * @category Logic + * @sig (*... -> Boolean) -> (*... -> Boolean) -> (*... -> Boolean) + * @param {Function} f a predicate + * @param {Function} g another predicate + * @return {Function} a function that applies its arguments to `f` and `g` and `||`s their outputs together. + * @see R.or + * @example + * + * var gt10 = function(x) { return x > 10; }; + * var even = function(x) { return x % 2 === 0 }; + * var f = R.either(gt10, even); + * f(101); //=> true + * f(8); //=> true + */ + var either = _curry2(function either(f, g) { + return function _either() { + return f.apply(this, arguments) || g.apply(this, arguments); + }; + }); + + /** + * Returns the empty value of its argument's type. Ramda defines the empty + * value of Array (`[]`), Object (`{}`), and String (`''`). Other types are + * supported if they define `.empty` and/or `.prototype.empty`. + * + * @func + * @memberOf R + * @category Function + * @sig a -> a + * @param {*} x + * @return {*} + * @example + * + * R.empty(Just(42)); //=> Nothing() + * R.empty([1, 2, 3]); //=> [] + * R.empty('unicorns'); //=> '' + * R.empty({x: 1, y: 2}); //=> {} + */ + var empty = _curry1(function empty(x) { + if (x != null && typeof x.empty === 'function') { + return x.empty(); + } else if (x != null && typeof x.constructor != null && typeof x.constructor.empty === 'function') { + return x.constructor.empty(); + } else { + switch (Object.prototype.toString.call(x)) { + case '[object Array]': + return []; + case '[object Object]': + return {}; + case '[object String]': + return ''; + } + } + }); + + /** + * Creates a new object by recursively evolving a shallow copy of `object`, according to the + * `transformation` functions. All non-primitive properties are copied by reference. + * + * A `tranformation` function will not be invoked if its corresponding key does not exist in + * the evolved object. + * + * @func + * @memberOf R + * @category Object + * @sig {k: (v -> v)} -> {k: v} -> {k: v} + * @param {Object} transformations The object specifying transformation functions to apply + * to the object. + * @param {Object} object The object to be transformed. + * @return {Object} The transformed object. + * @example + * + * var tomato = {firstName: ' Tomato ', data: {elapsed: 100, remaining: 1400}, id:123}; + * var transformations = { + * firstName: R.trim, + * lastName: R.trim, // Will not get invoked. + * data: {elapsed: R.add(1), remaining: R.add(-1)} + * }; + * R.evolve(transformations, tomato); //=> {firstName: 'Tomato', data: {elapsed: 101, remaining: 1399}, id:123} + */ + var evolve = _curry2(function evolve(transformations, object) { + var transformation, key, type, result = {}; + for (key in object) { + transformation = transformations[key]; + type = typeof transformation; + result[key] = type === 'function' ? transformation(object[key]) : type === 'object' ? evolve(transformations[key], object[key]) : object[key]; + } + return result; + }); + + /** + * Creates a new object out of a list key-value pairs. + * + * @func + * @memberOf R + * @category List + * @sig [[k,v]] -> {k: v} + * @param {Array} pairs An array of two-element arrays that will be the keys and values of the output object. + * @return {Object} The object made by pairing up `keys` and `values`. + * @see R.toPairs + * @example + * + * R.fromPairs([['a', 1], ['b', 2], ['c', 3]]); //=> {a: 1, b: 2, c: 3} + */ + var fromPairs = _curry1(function fromPairs(pairs) { + var idx = 0, len = pairs.length, out = {}; + while (idx < len) { + if (_isArray(pairs[idx]) && pairs[idx].length) { + out[pairs[idx][0]] = pairs[idx][1]; + } + idx += 1; + } + return out; + }); + + /** + * Returns `true` if the first argument is greater than the second; + * `false` otherwise. + * + * @func + * @memberOf R + * @category Relation + * @sig Ord a => a -> a -> Boolean + * @param {*} a + * @param {*} b + * @return {Boolean} + * @see R.lt + * @example + * + * R.gt(2, 1); //=> true + * R.gt(2, 2); //=> false + * R.gt(2, 3); //=> false + * R.gt('a', 'z'); //=> false + * R.gt('z', 'a'); //=> true + */ + var gt = _curry2(function gt(a, b) { + return a > b; + }); + + /** + * Returns `true` if the first argument is greater than or equal to the second; + * `false` otherwise. + * + * @func + * @memberOf R + * @category Relation + * @sig Ord a => a -> a -> Boolean + * @param {Number} a + * @param {Number} b + * @return {Boolean} + * @see R.lte + * @example + * + * R.gte(2, 1); //=> true + * R.gte(2, 2); //=> true + * R.gte(2, 3); //=> false + * R.gte('a', 'z'); //=> false + * R.gte('z', 'a'); //=> true + */ + var gte = _curry2(function gte(a, b) { + return a >= b; + }); + + /** + * Returns whether or not an object has an own property with + * the specified name + * + * @func + * @memberOf R + * @category Object + * @sig s -> {s: x} -> Boolean + * @param {String} prop The name of the property to check for. + * @param {Object} obj The object to query. + * @return {Boolean} Whether the property exists. + * @example + * + * var hasName = R.has('name'); + * hasName({name: 'alice'}); //=> true + * hasName({name: 'bob'}); //=> true + * hasName({}); //=> false + * + * var point = {x: 0, y: 0}; + * var pointHas = R.has(R.__, point); + * pointHas('x'); //=> true + * pointHas('y'); //=> true + * pointHas('z'); //=> false + */ + var has = _curry2(_has); + + /** + * Returns whether or not an object or its prototype chain has + * a property with the specified name + * + * @func + * @memberOf R + * @category Object + * @sig s -> {s: x} -> Boolean + * @param {String} prop The name of the property to check for. + * @param {Object} obj The object to query. + * @return {Boolean} Whether the property exists. + * @example + * + * function Rectangle(width, height) { + * this.width = width; + * this.height = height; + * } + * Rectangle.prototype.area = function() { + * return this.width * this.height; + * }; + * + * var square = new Rectangle(2, 2); + * R.hasIn('width', square); //=> true + * R.hasIn('area', square); //=> true + */ + var hasIn = _curry2(function hasIn(prop, obj) { + return prop in obj; + }); + + /** + * Returns true if its arguments are identical, false otherwise. Values are + * identical if they reference the same memory. `NaN` is identical to `NaN`; + * `0` and `-0` are not identical. + * + * @func + * @memberOf R + * @category Relation + * @sig a -> a -> Boolean + * @param {*} a + * @param {*} b + * @return {Boolean} + * @example + * + * var o = {}; + * R.identical(o, o); //=> true + * R.identical(1, 1); //=> true + * R.identical(1, '1'); //=> false + * R.identical([], []); //=> false + * R.identical(0, -0); //=> false + * R.identical(NaN, NaN); //=> true + */ + // SameValue algorithm + // Steps 1-5, 7-10 + // Steps 6.b-6.e: +0 != -0 + // Step 6.a: NaN == NaN + var identical = _curry2(function identical(a, b) { + // SameValue algorithm + if (a === b) { + // Steps 1-5, 7-10 + // Steps 6.b-6.e: +0 != -0 + return a !== 0 || 1 / a === 1 / b; + } else { + // Step 6.a: NaN == NaN + return a !== a && b !== b; + } + }); + + /** + * A function that does nothing but return the parameter supplied to it. Good as a default + * or placeholder function. + * + * @func + * @memberOf R + * @category Function + * @sig a -> a + * @param {*} x The value to return. + * @return {*} The input value, `x`. + * @example + * + * R.identity(1); //=> 1 + * + * var obj = {}; + * R.identity(obj) === obj; //=> true + */ + var identity = _curry1(_identity); + + /** + * Creates a function that will process either the `onTrue` or the `onFalse` function depending + * upon the result of the `condition` predicate. + * + * @func + * @memberOf R + * @category Logic + * @sig (*... -> Boolean) -> (*... -> *) -> (*... -> *) -> (*... -> *) + * @param {Function} condition A predicate function + * @param {Function} onTrue A function to invoke when the `condition` evaluates to a truthy value. + * @param {Function} onFalse A function to invoke when the `condition` evaluates to a falsy value. + * @return {Function} A new unary function that will process either the `onTrue` or the `onFalse` + * function depending upon the result of the `condition` predicate. + * @example + * + * // Flatten all arrays in the list but leave other values alone. + * var flattenArrays = R.map(R.ifElse(Array.isArray, R.flatten, R.identity)); + * + * flattenArrays([[0], [[10], [8]], 1234, {}]); //=> [[0], [10, 8], 1234, {}] + * flattenArrays([[[10], 123], [8, [10]], "hello"]); //=> [[10, 123], [8, 10], "hello"] + */ + var ifElse = _curry3(function ifElse(condition, onTrue, onFalse) { + return curryN(Math.max(condition.length, onTrue.length, onFalse.length), function _ifElse() { + return condition.apply(this, arguments) ? onTrue.apply(this, arguments) : onFalse.apply(this, arguments); + }); + }); + + /** + * Increments its argument. + * + * @func + * @memberOf R + * @category Math + * @sig Number -> Number + * @param {Number} n + * @return {Number} + * @see R.dec + * @example + * + * R.inc(42); //=> 43 + */ + var inc = add(1); + + /** + * Inserts the supplied element into the list, at index `index`. _Note + * that this is not destructive_: it returns a copy of the list with the changes. + * No lists have been harmed in the application of this function. + * + * @func + * @memberOf R + * @category List + * @sig Number -> a -> [a] -> [a] + * @param {Number} index The position to insert the element + * @param {*} elt The element to insert into the Array + * @param {Array} list The list to insert into + * @return {Array} A new Array with `elt` inserted at `index`. + * @example + * + * R.insert(2, 'x', [1,2,3,4]); //=> [1,2,'x',3,4] + */ + var insert = _curry3(function insert(idx, elt, list) { + idx = idx < list.length && idx >= 0 ? idx : list.length; + var result = _slice(list); + result.splice(idx, 0, elt); + return result; + }); + + /** + * Inserts the sub-list into the list, at index `index`. _Note that this + * is not destructive_: it returns a copy of the list with the changes. + * No lists have been harmed in the application of this function. + * + * @func + * @memberOf R + * @category List + * @sig Number -> [a] -> [a] -> [a] + * @param {Number} index The position to insert the sub-list + * @param {Array} elts The sub-list to insert into the Array + * @param {Array} list The list to insert the sub-list into + * @return {Array} A new Array with `elts` inserted starting at `index`. + * @example + * + * R.insertAll(2, ['x','y','z'], [1,2,3,4]); //=> [1,2,'x','y','z',3,4] + */ + var insertAll = _curry3(function insertAll(idx, elts, list) { + idx = idx < list.length && idx >= 0 ? idx : list.length; + return _concat(_concat(_slice(list, 0, idx), elts), _slice(list, idx)); + }); + + /** + * See if an object (`val`) is an instance of the supplied constructor. + * This function will check up the inheritance chain, if any. + * + * @func + * @memberOf R + * @category Type + * @sig (* -> {*}) -> a -> Boolean + * @param {Object} ctor A constructor + * @param {*} val The value to test + * @return {Boolean} + * @example + * + * R.is(Object, {}); //=> true + * R.is(Number, 1); //=> true + * R.is(Object, 1); //=> false + * R.is(String, 's'); //=> true + * R.is(String, new String('')); //=> true + * R.is(Object, new String('')); //=> true + * R.is(Object, 's'); //=> false + * R.is(Number, {}); //=> false + */ + var is = _curry2(function is(Ctor, val) { + return val != null && val.constructor === Ctor || val instanceof Ctor; + }); + + /** + * Tests whether or not an object is similar to an array. + * + * @func + * @memberOf R + * @category Type + * @category List + * @sig * -> Boolean + * @param {*} x The object to test. + * @return {Boolean} `true` if `x` has a numeric length property and extreme indices defined; `false` otherwise. + * @example + * + * R.isArrayLike([]); //=> true + * R.isArrayLike(true); //=> false + * R.isArrayLike({}); //=> false + * R.isArrayLike({length: 10}); //=> false + * R.isArrayLike({0: 'zero', 9: 'nine', length: 10}); //=> true + */ + var isArrayLike = _curry1(function isArrayLike(x) { + if (_isArray(x)) { + return true; + } + if (!x) { + return false; + } + if (typeof x !== 'object') { + return false; + } + if (x instanceof String) { + return false; + } + if (x.nodeType === 1) { + return !!x.length; + } + if (x.length === 0) { + return true; + } + if (x.length > 0) { + return x.hasOwnProperty(0) && x.hasOwnProperty(x.length - 1); + } + return false; + }); + + /** + * Reports whether the list has zero elements. + * + * @func + * @memberOf R + * @category Logic + * @sig [a] -> Boolean + * @param {Array} list + * @return {Boolean} + * @example + * + * R.isEmpty([1, 2, 3]); //=> false + * R.isEmpty([]); //=> true + * R.isEmpty(''); //=> true + * R.isEmpty(null); //=> false + * R.isEmpty(R.keys({})); //=> true + * R.isEmpty({}); //=> false ({} does not have a length property) + * R.isEmpty({length: 0}); //=> true + */ + var isEmpty = _curry1(function isEmpty(list) { + return Object(list).length === 0; + }); + + /** + * Checks if the input value is `null` or `undefined`. + * + * @func + * @memberOf R + * @category Type + * @sig * -> Boolean + * @param {*} x The value to test. + * @return {Boolean} `true` if `x` is `undefined` or `null`, otherwise `false`. + * @example + * + * R.isNil(null); //=> true + * R.isNil(undefined); //=> true + * R.isNil(0); //=> false + * R.isNil([]); //=> false + */ + var isNil = _curry1(function isNil(x) { + return x == null; + }); + + /** + * Returns a list containing the names of all the enumerable own + * properties of the supplied object. + * Note that the order of the output array is not guaranteed to be + * consistent across different JS platforms. + * + * @func + * @memberOf R + * @category Object + * @sig {k: v} -> [k] + * @param {Object} obj The object to extract properties from + * @return {Array} An array of the object's own properties. + * @example + * + * R.keys({a: 1, b: 2, c: 3}); //=> ['a', 'b', 'c'] + */ + // cover IE < 9 keys issues + var keys = function () { + // cover IE < 9 keys issues + var hasEnumBug = !{ toString: null }.propertyIsEnumerable('toString'); + var nonEnumerableProps = [ + 'constructor', + 'valueOf', + 'isPrototypeOf', + 'toString', + 'propertyIsEnumerable', + 'hasOwnProperty', + 'toLocaleString' + ]; + var contains = function contains(list, item) { + var idx = 0; + while (idx < list.length) { + if (list[idx] === item) { + return true; + } + idx += 1; + } + return false; + }; + return typeof Object.keys === 'function' ? _curry1(function keys(obj) { + return Object(obj) !== obj ? [] : Object.keys(obj); + }) : _curry1(function keys(obj) { + if (Object(obj) !== obj) { + return []; + } + var prop, ks = [], nIdx; + for (prop in obj) { + if (_has(prop, obj)) { + ks[ks.length] = prop; + } + } + if (hasEnumBug) { + nIdx = nonEnumerableProps.length - 1; + while (nIdx >= 0) { + prop = nonEnumerableProps[nIdx]; + if (_has(prop, obj) && !contains(ks, prop)) { + ks[ks.length] = prop; + } + nIdx -= 1; + } + } + return ks; + }); + }(); + + /** + * Returns a list containing the names of all the + * properties of the supplied object, including prototype properties. + * Note that the order of the output array is not guaranteed to be + * consistent across different JS platforms. + * + * @func + * @memberOf R + * @category Object + * @sig {k: v} -> [k] + * @param {Object} obj The object to extract properties from + * @return {Array} An array of the object's own and prototype properties. + * @example + * + * var F = function() { this.x = 'X'; }; + * F.prototype.y = 'Y'; + * var f = new F(); + * R.keysIn(f); //=> ['x', 'y'] + */ + var keysIn = _curry1(function keysIn(obj) { + var prop, ks = []; + for (prop in obj) { + ks[ks.length] = prop; + } + return ks; + }); + + /** + * Returns the number of elements in the array by returning `list.length`. + * + * @func + * @memberOf R + * @category List + * @sig [a] -> Number + * @param {Array} list The array to inspect. + * @return {Number} The length of the array. + * @example + * + * R.length([]); //=> 0 + * R.length([1, 2, 3]); //=> 3 + */ + var length = _curry1(function length(list) { + return list != null && is(Number, list.length) ? list.length : NaN; + }); + + /** + * Returns `true` if the first argument is less than the second; + * `false` otherwise. + * + * @func + * @memberOf R + * @category Relation + * @sig Ord a => a -> a -> Boolean + * @param {*} a + * @param {*} b + * @return {Boolean} + * @see R.gt + * @example + * + * R.lt(2, 1); //=> false + * R.lt(2, 2); //=> false + * R.lt(2, 3); //=> true + * R.lt('a', 'z'); //=> true + * R.lt('z', 'a'); //=> false + */ + var lt = _curry2(function lt(a, b) { + return a < b; + }); + + /** + * Returns `true` if the first argument is less than or equal to the second; + * `false` otherwise. + * + * @func + * @memberOf R + * @category Relation + * @sig Ord a => a -> a -> Boolean + * @param {Number} a + * @param {Number} b + * @return {Boolean} + * @see R.gte + * @example + * + * R.lte(2, 1); //=> false + * R.lte(2, 2); //=> true + * R.lte(2, 3); //=> true + * R.lte('a', 'z'); //=> true + * R.lte('z', 'a'); //=> false + */ + var lte = _curry2(function lte(a, b) { + return a <= b; + }); + + /** + * The mapAccum function behaves like a combination of map and reduce; it applies a + * function to each element of a list, passing an accumulating parameter from left to + * right, and returning a final value of this accumulator together with the new list. + * + * The iterator function receives two arguments, *acc* and *value*, and should return + * a tuple *[acc, value]*. + * + * @func + * @memberOf R + * @category List + * @sig (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y]) + * @param {Function} fn The function to be called on every element of the input `list`. + * @param {*} acc The accumulator value. + * @param {Array} list The list to iterate over. + * @return {*} The final, accumulated value. + * @example + * + * var digits = ['1', '2', '3', '4']; + * var append = function(a, b) { + * return [a + b, a + b]; + * } + * + * R.mapAccum(append, 0, digits); //=> ['01234', ['01', '012', '0123', '01234']] + */ + var mapAccum = _curry3(function mapAccum(fn, acc, list) { + var idx = 0, len = list.length, result = [], tuple = [acc]; + while (idx < len) { + tuple = fn(tuple[0], list[idx]); + result[idx] = tuple[1]; + idx += 1; + } + return [ + tuple[0], + result + ]; + }); + + /** + * The mapAccumRight function behaves like a combination of map and reduce; it applies a + * function to each element of a list, passing an accumulating parameter from right + * to left, and returning a final value of this accumulator together with the new list. + * + * Similar to `mapAccum`, except moves through the input list from the right to the + * left. + * + * The iterator function receives two arguments, *acc* and *value*, and should return + * a tuple *[acc, value]*. + * + * @func + * @memberOf R + * @category List + * @sig (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y]) + * @param {Function} fn The function to be called on every element of the input `list`. + * @param {*} acc The accumulator value. + * @param {Array} list The list to iterate over. + * @return {*} The final, accumulated value. + * @example + * + * var digits = ['1', '2', '3', '4']; + * var append = function(a, b) { + * return [a + b, a + b]; + * } + * + * R.mapAccumRight(append, 0, digits); //=> ['04321', ['04321', '0432', '043', '04']] + */ + var mapAccumRight = _curry3(function mapAccumRight(fn, acc, list) { + var idx = list.length - 1, result = [], tuple = [acc]; + while (idx >= 0) { + tuple = fn(tuple[0], list[idx]); + result[idx] = tuple[1]; + idx -= 1; + } + return [ + tuple[0], + result + ]; + }); + + /** + * Tests a regular expression against a String. Note that this function + * will return an empty array when there are no matches. This differs + * from [`String.prototype.match`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match) + * which returns `null` when there are no matches. + * + * @func + * @memberOf R + * @see R.test + * @category String + * @sig RegExp -> String -> [String | Undefined] + * @param {RegExp} rx A regular expression. + * @param {String} str The string to match against + * @return {Array} The list of matches or empty array. + * @example + * + * R.match(/([a-z]a)/g, 'bananas'); //=> ['ba', 'na', 'na'] + * R.match(/a/, 'b'); //=> [] + * R.match(/a/, null); //=> TypeError: null does not have a method named "match" + */ + var match = _curry2(function match(rx, str) { + return str.match(rx) || []; + }); + + /** + * mathMod behaves like the modulo operator should mathematically, unlike the `%` + * operator (and by extension, R.modulo). So while "-17 % 5" is -2, + * mathMod(-17, 5) is 3. mathMod requires Integer arguments, and returns NaN + * when the modulus is zero or negative. + * + * @func + * @memberOf R + * @category Math + * @sig Number -> Number -> Number + * @param {Number} m The dividend. + * @param {Number} p the modulus. + * @return {Number} The result of `b mod a`. + * @example + * + * R.mathMod(-17, 5); //=> 3 + * R.mathMod(17, 5); //=> 2 + * R.mathMod(17, -5); //=> NaN + * R.mathMod(17, 0); //=> NaN + * R.mathMod(17.2, 5); //=> NaN + * R.mathMod(17, 5.3); //=> NaN + * + * var clock = R.mathMod(R.__, 12); + * clock(15); //=> 3 + * clock(24); //=> 0 + * + * var seventeenMod = R.mathMod(17); + * seventeenMod(3); //=> 2 + * seventeenMod(4); //=> 1 + * seventeenMod(10); //=> 7 + */ + var mathMod = _curry2(function mathMod(m, p) { + if (!_isInteger(m)) { + return NaN; + } + if (!_isInteger(p) || p < 1) { + return NaN; + } + return (m % p + p) % p; + }); + + /** + * Returns the larger of its two arguments. + * + * @func + * @memberOf R + * @category Relation + * @sig Ord a => a -> a -> a + * @param {*} a + * @param {*} b + * @return {*} + * @see R.maxBy, R.min + * @example + * + * R.max(789, 123); //=> 789 + * R.max('a', 'b'); //=> 'b' + */ + var max = _curry2(function max(a, b) { + return b > a ? b : a; + }); + + /** + * Takes a function and two values, and returns whichever value produces + * the larger result when passed to the provided function. + * + * @func + * @memberOf R + * @category Relation + * @sig Ord b => (a -> b) -> a -> a -> a + * @param {Function} f + * @param {*} a + * @param {*} b + * @return {*} + * @see R.max, R.minBy + * @example + * + * R.maxBy(function(n) { return n * n; }, -3, 2); //=> -3 + */ + var maxBy = _curry3(function maxBy(f, a, b) { + return f(b) > f(a) ? b : a; + }); + + /** + * Create a new object with the own properties of `a` + * merged with the own properties of object `b`. + * + * @func + * @memberOf R + * @category Object + * @sig {k: v} -> {k: v} -> {k: v} + * @param {Object} a + * @param {Object} b + * @return {Object} + * @example + * + * R.merge({ 'name': 'fred', 'age': 10 }, { 'age': 40 }); + * //=> { 'name': 'fred', 'age': 40 } + * + * var resetToDefault = R.merge(R.__, {x: 0}); + * resetToDefault({x: 5, y: 2}); //=> {x: 0, y: 2} + */ + var merge = _curry2(function merge(a, b) { + var result = {}; + var ks = keys(a); + var idx = 0; + while (idx < ks.length) { + result[ks[idx]] = a[ks[idx]]; + idx += 1; + } + ks = keys(b); + idx = 0; + while (idx < ks.length) { + result[ks[idx]] = b[ks[idx]]; + idx += 1; + } + return result; + }); + + /** + * Returns the smaller of its two arguments. + * + * @func + * @memberOf R + * @category Relation + * @sig Ord a => a -> a -> a + * @param {*} a + * @param {*} b + * @return {*} + * @see R.minBy, R.max + * @example + * + * R.min(789, 123); //=> 123 + * R.min('a', 'b'); //=> 'a' + */ + var min = _curry2(function min(a, b) { + return b < a ? b : a; + }); + + /** + * Takes a function and two values, and returns whichever value produces + * the smaller result when passed to the provided function. + * + * @func + * @memberOf R + * @category Relation + * @sig Ord b => (a -> b) -> a -> a -> a + * @param {Function} f + * @param {*} a + * @param {*} b + * @return {*} + * @see R.min, R.maxBy + * @example + * + * R.minBy(function(n) { return n * n; }, -3, 2); //=> 2 + */ + var minBy = _curry3(function minBy(f, a, b) { + return f(b) < f(a) ? b : a; + }); + + /** + * Divides the second parameter by the first and returns the remainder. + * Note that this functions preserves the JavaScript-style behavior for + * modulo. For mathematical modulo see `mathMod` + * + * @func + * @memberOf R + * @category Math + * @sig Number -> Number -> Number + * @param {Number} a The value to the divide. + * @param {Number} b The pseudo-modulus + * @return {Number} The result of `b % a`. + * @see R.mathMod + * @example + * + * R.modulo(17, 3); //=> 2 + * // JS behavior: + * R.modulo(-17, 3); //=> -2 + * R.modulo(17, -3); //=> 2 + * + * var isOdd = R.modulo(R.__, 2); + * isOdd(42); //=> 0 + * isOdd(21); //=> 1 + */ + var modulo = _curry2(function modulo(a, b) { + return a % b; + }); + + /** + * Multiplies two numbers. Equivalent to `a * b` but curried. + * + * @func + * @memberOf R + * @category Math + * @sig Number -> Number -> Number + * @param {Number} a The first value. + * @param {Number} b The second value. + * @return {Number} The result of `a * b`. + * @see R.divide + * @example + * + * var double = R.multiply(2); + * var triple = R.multiply(3); + * double(3); //=> 6 + * triple(4); //=> 12 + * R.multiply(2, 5); //=> 10 + */ + var multiply = _curry2(function multiply(a, b) { + return a * b; + }); + + /** + * Wraps a function of any arity (including nullary) in a function that accepts exactly `n` + * parameters. Any extraneous parameters will not be passed to the supplied function. + * + * @func + * @memberOf R + * @category Function + * @sig Number -> (* -> a) -> (* -> a) + * @param {Number} n The desired arity of the new function. + * @param {Function} fn The function to wrap. + * @return {Function} A new function wrapping `fn`. The new function is guaranteed to be of + * arity `n`. + * @example + * + * var takesTwoArgs = function(a, b) { + * return [a, b]; + * }; + * takesTwoArgs.length; //=> 2 + * takesTwoArgs(1, 2); //=> [1, 2] + * + * var takesOneArg = R.nAry(1, takesTwoArgs); + * takesOneArg.length; //=> 1 + * // Only `n` arguments are passed to the wrapped function + * takesOneArg(1, 2); //=> [1, undefined] + */ + var nAry = _curry2(function nAry(n, fn) { + switch (n) { + case 0: + return function () { + return fn.call(this); + }; + case 1: + return function (a0) { + return fn.call(this, a0); + }; + case 2: + return function (a0, a1) { + return fn.call(this, a0, a1); + }; + case 3: + return function (a0, a1, a2) { + return fn.call(this, a0, a1, a2); + }; + case 4: + return function (a0, a1, a2, a3) { + return fn.call(this, a0, a1, a2, a3); + }; + case 5: + return function (a0, a1, a2, a3, a4) { + return fn.call(this, a0, a1, a2, a3, a4); + }; + case 6: + return function (a0, a1, a2, a3, a4, a5) { + return fn.call(this, a0, a1, a2, a3, a4, a5); + }; + case 7: + return function (a0, a1, a2, a3, a4, a5, a6) { + return fn.call(this, a0, a1, a2, a3, a4, a5, a6); + }; + case 8: + return function (a0, a1, a2, a3, a4, a5, a6, a7) { + return fn.call(this, a0, a1, a2, a3, a4, a5, a6, a7); + }; + case 9: + return function (a0, a1, a2, a3, a4, a5, a6, a7, a8) { + return fn.call(this, a0, a1, a2, a3, a4, a5, a6, a7, a8); + }; + case 10: + return function (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) { + return fn.call(this, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); + }; + default: + throw new Error('First argument to nAry must be a non-negative integer no greater than ten'); + } + }); + + /** + * Negates its argument. + * + * @func + * @memberOf R + * @category Math + * @sig Number -> Number + * @param {Number} n + * @return {Number} + * @example + * + * R.negate(42); //=> -42 + */ + var negate = _curry1(function negate(n) { + return -n; + }); + + /** + * A function that returns the `!` of its argument. It will return `true` when + * passed false-y value, and `false` when passed a truth-y one. + * + * @func + * @memberOf R + * @category Logic + * @sig * -> Boolean + * @param {*} a any value + * @return {Boolean} the logical inverse of passed argument. + * @see R.complement + * @example + * + * R.not(true); //=> false + * R.not(false); //=> true + * R.not(0); => true + * R.not(1); => false + */ + var not = _curry1(function not(a) { + return !a; + }); + + /** + * Returns the nth element of the given list or string. + * If n is negative the element at index length + n is returned. + * + * @func + * @memberOf R + * @category List + * @sig Number -> [a] -> a | Undefined + * @sig Number -> String -> String + * @param {Number} offset + * @param {*} list + * @return {*} + * @example + * + * var list = ['foo', 'bar', 'baz', 'quux']; + * R.nth(1, list); //=> 'bar' + * R.nth(-1, list); //=> 'quux' + * R.nth(-99, list); //=> undefined + * + * R.nth('abc', 2); //=> 'c' + * R.nth('abc', 3); //=> '' + */ + var nth = _curry2(function nth(offset, list) { + var idx = offset < 0 ? list.length + offset : offset; + return _isString(list) ? list.charAt(idx) : list[idx]; + }); + + /** + * Returns a function which returns its nth argument. + * + * @func + * @memberOf R + * @category Function + * @sig Number -> *... -> * + * @param {Number} n + * @return {Function} + * @example + * + * R.nthArg(1)('a', 'b', 'c'); //=> 'b' + * R.nthArg(-1)('a', 'b', 'c'); //=> 'c' + */ + var nthArg = _curry1(function nthArg(n) { + return function () { + return nth(n, arguments); + }; + }); + + /** + * Returns the nth character of the given string. + * + * @func + * @memberOf R + * @category String + * @sig Number -> String -> String + * @param {Number} n + * @param {String} str + * @return {String} + * @deprecated since v0.16.0 + * @example + * + * R.nthChar(2, 'Ramda'); //=> 'm' + * R.nthChar(-2, 'Ramda'); //=> 'd' + */ + var nthChar = _curry2(function nthChar(n, str) { + return str.charAt(n < 0 ? str.length + n : n); + }); + + /** + * Returns the character code of the nth character of the given string. + * + * @func + * @memberOf R + * @category String + * @sig Number -> String -> Number + * @param {Number} n + * @param {String} str + * @return {Number} + * @deprecated since v0.16.0 + * @example + * + * R.nthCharCode(2, 'Ramda'); //=> 'm'.charCodeAt(0) + * R.nthCharCode(-2, 'Ramda'); //=> 'd'.charCodeAt(0) + */ + var nthCharCode = _curry2(function nthCharCode(n, str) { + return str.charCodeAt(n < 0 ? str.length + n : n); + }); + + /** + * Returns a singleton array containing the value provided. + * + * Note this `of` is different from the ES6 `of`; See + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/of + * + * @func + * @memberOf R + * @category Function + * @sig a -> [a] + * @param {*} x any value + * @return {Array} An array wrapping `x`. + * @example + * + * R.of(null); //=> [null] + * R.of([42]); //=> [[42]] + */ + var of = _curry1(function of(x) { + return [x]; + }); + + /** + * Accepts a function `fn` and returns a function that guards invocation of `fn` such that + * `fn` can only ever be called once, no matter how many times the returned function is + * invoked. + * + * @func + * @memberOf R + * @category Function + * @sig (a... -> b) -> (a... -> b) + * @param {Function} fn The function to wrap in a call-only-once wrapper. + * @return {Function} The wrapped function. + * @example + * + * var addOneOnce = R.once(function(x){ return x + 1; }); + * addOneOnce(10); //=> 11 + * addOneOnce(addOneOnce(50)); //=> 11 + */ + var once = _curry1(function once(fn) { + var called = false, result; + return function () { + if (called) { + return result; + } + called = true; + result = fn.apply(this, arguments); + return result; + }; + }); + + /** + * Returns the result of "setting" the portion of the given data structure + * focused by the given lens to the given value. + * + * @func + * @memberOf R + * @category Object + * @typedef Lens s a = Functor f => (a -> f a) -> s -> f s + * @sig Lens s a -> (a -> a) -> s -> s + * @param {Lens} lens + * @param {*} v + * @param {*} x + * @return {*} + * @see R.prop, R.lensIndex, R.lensProp + * @example + * + * var headLens = R.lensIndex(0); + * + * R.over(headLens, R.toUpper, ['foo', 'bar', 'baz']); //=> ['FOO', 'bar', 'baz'] + */ + var over = function () { + var Identity = function (x) { + return { + value: x, + map: function (f) { + return Identity(f(x)); + } + }; + }; + return _curry3(function over(lens, f, x) { + return lens(function (y) { + return Identity(f(y)); + })(x).value; + }); + }(); + + /** + * Retrieve the value at a given path. + * + * @func + * @memberOf R + * @category Object + * @sig [String] -> {k: v} -> v | Undefined + * @param {Array} path The path to use. + * @return {*} The data at `path`. + * @example + * + * R.path(['a', 'b'], {a: {b: 2}}); //=> 2 + * R.path(['a', 'b'], {c: {b: 2}}); //=> undefined + */ + var path = _curry2(function path(paths, obj) { + if (obj == null) { + return; + } else { + var val = obj; + for (var idx = 0, len = paths.length; idx < len && val != null; idx += 1) { + val = val[paths[idx]]; + } + return val; + } + }); + + /** + * Returns a partial copy of an object containing only the keys specified. If the key does not exist, the + * property is ignored. + * + * @func + * @memberOf R + * @category Object + * @sig [k] -> {k: v} -> {k: v} + * @param {Array} names an array of String property names to copy onto a new object + * @param {Object} obj The object to copy from + * @return {Object} A new object with only properties from `names` on it. + * @see R.omit + * @example + * + * R.pick(['a', 'd'], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1, d: 4} + * R.pick(['a', 'e', 'f'], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1} + */ + var pick = _curry2(function pick(names, obj) { + var result = {}; + var idx = 0; + while (idx < names.length) { + if (names[idx] in obj) { + result[names[idx]] = obj[names[idx]]; + } + idx += 1; + } + return result; + }); + + /** + * Similar to `pick` except that this one includes a `key: undefined` pair for properties that don't exist. + * + * @func + * @memberOf R + * @category Object + * @sig [k] -> {k: v} -> {k: v} + * @param {Array} names an array of String property names to copy onto a new object + * @param {Object} obj The object to copy from + * @return {Object} A new object with only properties from `names` on it. + * @see R.pick + * @example + * + * R.pickAll(['a', 'd'], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1, d: 4} + * R.pickAll(['a', 'e', 'f'], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1, e: undefined, f: undefined} + */ + var pickAll = _curry2(function pickAll(names, obj) { + var result = {}; + var idx = 0; + var len = names.length; + while (idx < len) { + var name = names[idx]; + result[name] = obj[name]; + idx += 1; + } + return result; + }); + + /** + * Returns a partial copy of an object containing only the keys that + * satisfy the supplied predicate. + * + * @func + * @memberOf R + * @category Object + * @sig (v, k -> Boolean) -> {k: v} -> {k: v} + * @param {Function} pred A predicate to determine whether or not a key + * should be included on the output object. + * @param {Object} obj The object to copy from + * @return {Object} A new object with only properties that satisfy `pred` + * on it. + * @see R.pick + * @example + * + * var isUpperCase = function(val, key) { return key.toUpperCase() === key; } + * R.pickBy(isUpperCase, {a: 1, b: 2, A: 3, B: 4}); //=> {A: 3, B: 4} + */ + var pickBy = _curry2(function pickBy(test, obj) { + var result = {}; + for (var prop in obj) { + if (test(obj[prop], prop, obj)) { + result[prop] = obj[prop]; + } + } + return result; + }); + + /** + * Returns a new list with the given element at the front, followed by the contents of the + * list. + * + * @func + * @memberOf R + * @category List + * @sig a -> [a] -> [a] + * @param {*} el The item to add to the head of the output list. + * @param {Array} list The array to add to the tail of the output list. + * @return {Array} A new array. + * @see R.append + * @example + * + * R.prepend('fee', ['fi', 'fo', 'fum']); //=> ['fee', 'fi', 'fo', 'fum'] + */ + var prepend = _curry2(function prepend(el, list) { + return _concat([el], list); + }); + + /** + * Returns a function that when supplied an object returns the indicated property of that object, if it exists. + * + * @func + * @memberOf R + * @category Object + * @sig s -> {s: a} -> a | Undefined + * @param {String} p The property name + * @param {Object} obj The object to query + * @return {*} The value at `obj.p`. + * @example + * + * R.prop('x', {x: 100}); //=> 100 + * R.prop('x', {}); //=> undefined + */ + var prop = _curry2(function prop(p, obj) { + return obj[p]; + }); + + /** + * If the given, non-null object has an own property with the specified name, + * returns the value of that property. + * Otherwise returns the provided default value. + * + * @func + * @memberOf R + * @category Object + * @sig a -> String -> Object -> a + * @param {*} val The default value. + * @param {String} p The name of the property to return. + * @param {Object} obj The object to query. + * @return {*} The value of given property of the supplied object or the default value. + * @example + * + * var alice = { + * name: 'ALICE', + * age: 101 + * }; + * var favorite = R.prop('favoriteLibrary'); + * var favoriteWithDefault = R.propOr('Ramda', 'favoriteLibrary'); + * + * favorite(alice); //=> undefined + * favoriteWithDefault(alice); //=> 'Ramda' + */ + var propOr = _curry3(function propOr(val, p, obj) { + return obj != null && _has(p, obj) ? obj[p] : val; + }); + + /** + * Returns `true` if the specified object property satisfies the given + * predicate; `false` otherwise. + * + * @func + * @memberOf R + * @category Logic + * @sig (a -> Boolean) -> String -> {String: a} -> Boolean + * @param {Function} pred + * @param {String} name + * @param {*} obj + * @return {Boolean} + * @see R.propEq + * @see R.propIs + * @example + * + * R.propSatisfies(x => x > 0, 'x', {x: 1, y: 2}); //=> true + */ + var propSatisfies = _curry3(function propSatisfies(pred, name, obj) { + return pred(obj[name]); + }); + + /** + * Acts as multiple `prop`: array of keys in, array of values out. Preserves order. + * + * @func + * @memberOf R + * @category Object + * @sig [k] -> {k: v} -> [v] + * @param {Array} ps The property names to fetch + * @param {Object} obj The object to query + * @return {Array} The corresponding values or partially applied function. + * @example + * + * R.props(['x', 'y'], {x: 1, y: 2}); //=> [1, 2] + * R.props(['c', 'a', 'b'], {b: 2, a: 1}); //=> [undefined, 1, 2] + * + * var fullName = R.compose(R.join(' '), R.props(['first', 'last'])); + * fullName({last: 'Bullet-Tooth', age: 33, first: 'Tony'}); //=> 'Tony Bullet-Tooth' + */ + var props = _curry2(function props(ps, obj) { + var len = ps.length; + var out = []; + var idx = 0; + while (idx < len) { + out[idx] = obj[ps[idx]]; + idx += 1; + } + return out; + }); + + /** + * Returns a list of numbers from `from` (inclusive) to `to` + * (exclusive). + * + * @func + * @memberOf R + * @category List + * @sig Number -> Number -> [Number] + * @param {Number} from The first number in the list. + * @param {Number} to One more than the last number in the list. + * @return {Array} The list of numbers in tthe set `[a, b)`. + * @example + * + * R.range(1, 5); //=> [1, 2, 3, 4] + * R.range(50, 53); //=> [50, 51, 52] + */ + var range = _curry2(function range(from, to) { + if (!(_isNumber(from) && _isNumber(to))) { + throw new TypeError('Both arguments to range must be numbers'); + } + var result = []; + var n = from; + while (n < to) { + result.push(n); + n += 1; + } + return result; + }); + + /** + * Returns a single item by iterating through the list, successively calling the iterator + * function and passing it an accumulator value and the current value from the array, and + * then passing the result to the next call. + * + * Similar to `reduce`, except moves through the input list from the right to the left. + * + * The iterator function receives two values: *(acc, value)* + * + * Note: `R.reduceRight` does not skip deleted or unassigned indices (sparse arrays), unlike + * the native `Array.prototype.reduce` method. For more details on this behavior, see: + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduceRight#Description + * + * @func + * @memberOf R + * @category List + * @sig (a,b -> a) -> a -> [b] -> a + * @param {Function} fn The iterator function. Receives two values, the accumulator and the + * current element from the array. + * @param {*} acc The accumulator value. + * @param {Array} list The list to iterate over. + * @return {*} The final, accumulated value. + * @example + * + * var pairs = [ ['a', 1], ['b', 2], ['c', 3] ]; + * var flattenPairs = function(acc, pair) { + * return acc.concat(pair); + * }; + * + * R.reduceRight(flattenPairs, [], pairs); //=> [ 'c', 3, 'b', 2, 'a', 1 ] + */ + var reduceRight = _curry3(function reduceRight(fn, acc, list) { + var idx = list.length - 1; + while (idx >= 0) { + acc = fn(acc, list[idx]); + idx -= 1; + } + return acc; + }); + + /** + * Returns a value wrapped to indicate that it is the final value of the + * reduce and transduce functions. The returned value + * should be considered a black box: the internal structure is not + * guaranteed to be stable. + * + * Note: this optimization is unavailable to functions not explicitly listed + * above. For instance, it is not currently supported by reduceIndexed, + * reduceRight, or reduceRightIndexed. + * + * @func + * @memberOf R + * @category List + * @see R.reduce, R.transduce + * @sig a -> * + * @param {*} x The final value of the reduce. + * @return {*} The wrapped value. + * @example + * + * R.reduce( + * R.pipe(R.add, R.ifElse(R.lte(10), R.reduced, R.identity)), + * 0, + * [1, 2, 3, 4, 5]) // 10 + */ + var reduced = _curry1(_reduced); + + /** + * Removes the sub-list of `list` starting at index `start` and containing + * `count` elements. _Note that this is not destructive_: it returns a + * copy of the list with the changes. + * No lists have been harmed in the application of this function. + * + * @func + * @memberOf R + * @category List + * @sig Number -> Number -> [a] -> [a] + * @param {Number} start The position to start removing elements + * @param {Number} count The number of elements to remove + * @param {Array} list The list to remove from + * @return {Array} A new Array with `count` elements from `start` removed. + * @example + * + * R.remove(2, 3, [1,2,3,4,5,6,7,8]); //=> [1,2,6,7,8] + */ + var remove = _curry3(function remove(start, count, list) { + return _concat(_slice(list, 0, Math.min(start, list.length)), _slice(list, Math.min(list.length, start + count))); + }); + + /** + * Replace a substring or regex match in a string with a replacement. + * + * @func + * @memberOf R + * @category String + * @sig RegExp|String -> String -> String -> String + * @param {RegExp|String} pattern A regular expression or a substring to match. + * @param {String} replacement The string to replace the matches with. + * @param {String} str The String to do the search and replacement in. + * @return {String} The result. + * @example + * + * R.replace('foo', 'bar', 'foo foo foo'); //=> 'bar foo foo' + * R.replace(/foo/, 'bar', 'foo foo foo'); //=> 'bar foo foo' + * + * // Use the "g" (global) flag to replace all occurrences: + * R.replace(/foo/g, 'bar', 'foo foo foo'); //=> 'bar bar bar' + */ + var replace = _curry3(function replace(regex, replacement, str) { + return str.replace(regex, replacement); + }); + + /** + * Returns a new list with the same elements as the original list, just + * in the reverse order. + * + * @func + * @memberOf R + * @category List + * @sig [a] -> [a] + * @param {Array} list The list to reverse. + * @return {Array} A copy of the list in reverse order. + * @example + * + * R.reverse([1, 2, 3]); //=> [3, 2, 1] + * R.reverse([1, 2]); //=> [2, 1] + * R.reverse([1]); //=> [1] + * R.reverse([]); //=> [] + */ + var reverse = _curry1(function reverse(list) { + return _slice(list).reverse(); + }); + + /** + * Scan is similar to reduce, but returns a list of successively reduced values from the left + * + * @func + * @memberOf R + * @category List + * @sig (a,b -> a) -> a -> [b] -> [a] + * @param {Function} fn The iterator function. Receives two values, the accumulator and the + * current element from the array + * @param {*} acc The accumulator value. + * @param {Array} list The list to iterate over. + * @return {Array} A list of all intermediately reduced values. + * @example + * + * var numbers = [1, 2, 3, 4]; + * var factorials = R.scan(R.multiply, 1, numbers); //=> [1, 1, 2, 6, 24] + */ + var scan = _curry3(function scan(fn, acc, list) { + var idx = 0, len = list.length, result = [acc]; + while (idx < len) { + acc = fn(acc, list[idx]); + result[idx + 1] = acc; + idx += 1; + } + return result; + }); + + /** + * Returns the result of "setting" the portion of the given data structure + * focused by the given lens to the given value. + * + * @func + * @memberOf R + * @category Object + * @typedef Lens s a = Functor f => (a -> f a) -> s -> f s + * @sig Lens s a -> a -> s -> s + * @param {Lens} lens + * @param {*} v + * @param {*} x + * @return {*} + * @see R.prop, R.lensIndex, R.lensProp + * @example + * + * var xLens = R.lensProp('x'); + * + * R.set(xLens, 4, {x: 1, y: 2}); //=> {x: 4, y: 2} + * R.set(xLens, 8, {x: 1, y: 2}); //=> {x: 8, y: 2} + */ + var set = _curry3(function set(lens, v, x) { + return over(lens, always(v), x); + }); + + /** + * Returns a copy of the list, sorted according to the comparator function, which should accept two values at a + * time and return a negative number if the first value is smaller, a positive number if it's larger, and zero + * if they are equal. Please note that this is a **copy** of the list. It does not modify the original. + * + * @func + * @memberOf R + * @category List + * @sig (a,a -> Number) -> [a] -> [a] + * @param {Function} comparator A sorting function :: a -> b -> Int + * @param {Array} list The list to sort + * @return {Array} a new array with its elements sorted by the comparator function. + * @example + * + * var diff = function(a, b) { return a - b; }; + * R.sort(diff, [4,2,7,5]); //=> [2, 4, 5, 7] + */ + var sort = _curry2(function sort(comparator, list) { + return _slice(list).sort(comparator); + }); + + /** + * Sorts the list according to the supplied function. + * + * @func + * @memberOf R + * @category Relation + * @sig Ord b => (a -> b) -> [a] -> [a] + * @param {Function} fn + * @param {Array} list The list to sort. + * @return {Array} A new list sorted by the keys generated by `fn`. + * @example + * + * var sortByFirstItem = R.sortBy(prop(0)); + * var sortByNameCaseInsensitive = R.sortBy(R.compose(R.toLower, R.prop('name'))); + * var pairs = [[-1, 1], [-2, 2], [-3, 3]]; + * sortByFirstItem(pairs); //=> [[-3, 3], [-2, 2], [-1, 1]] + * var alice = { + * name: 'ALICE', + * age: 101 + * }; + * var bob = { + * name: 'Bob', + * age: -10 + * }; + * var clara = { + * name: 'clara', + * age: 314.159 + * }; + * var people = [clara, bob, alice]; + * sortByNameCaseInsensitive(people); //=> [alice, bob, clara] + */ + var sortBy = _curry2(function sortBy(fn, list) { + return _slice(list).sort(function (a, b) { + var aa = fn(a); + var bb = fn(b); + return aa < bb ? -1 : aa > bb ? 1 : 0; + }); + }); + + /** + * Subtracts two numbers. Equivalent to `a - b` but curried. + * + * @func + * @memberOf R + * @category Math + * @sig Number -> Number -> Number + * @param {Number} a The first value. + * @param {Number} b The second value. + * @return {Number} The result of `a - b`. + * @see R.add + * @example + * + * R.subtract(10, 8); //=> 2 + * + * var minus5 = R.subtract(R.__, 5); + * minus5(17); //=> 12 + * + * var complementaryAngle = R.subtract(90); + * complementaryAngle(30); //=> 60 + * complementaryAngle(72); //=> 18 + */ + var subtract = _curry2(function subtract(a, b) { + return a - b; + }); + + /** + * Returns a new list containing the last `n` elements of a given list, passing each value + * to the supplied predicate function, and terminating when the predicate function returns + * `false`. Excludes the element that caused the predicate function to fail. The predicate + * function is passed one argument: *(value)*. + * + * @func + * @memberOf R + * @category List + * @sig (a -> Boolean) -> [a] -> [a] + * @param {Function} fn The function called per iteration. + * @param {Array} list The collection to iterate over. + * @return {Array} A new array. + * @see R.dropLastWhile + * @example + * + * var isNotOne = function(x) { + * return !(x === 1); + * }; + * + * R.takeLastWhile(isNotOne, [1, 2, 3, 4]); //=> [2, 3, 4] + */ + var takeLastWhile = _curry2(function takeLastWhile(fn, list) { + var idx = list.length - 1; + while (idx >= 0 && fn(list[idx])) { + idx -= 1; + } + return _slice(list, idx + 1, Infinity); + }); + + /** + * Runs the given function with the supplied object, then returns the object. + * + * @func + * @memberOf R + * @category Function + * @sig (a -> *) -> a -> a + * @param {Function} fn The function to call with `x`. The return value of `fn` will be thrown away. + * @param {*} x + * @return {*} `x`. + * @example + * + * var sayX = function(x) { console.log('x is ' + x); }; + * R.tap(sayX, 100); //=> 100 + * //-> 'x is 100' + */ + var tap = _curry2(function tap(fn, x) { + fn(x); + return x; + }); + + /** + * Determines whether a given string matches a given regular expression. + * + * @func + * @memberOf R + * @see R.match + * @category String + * @sig RegExp -> String -> Boolean + * @param {RegExp} pattern + * @param {String} str + * @return {Boolean} + * @example + * + * R.test(/^x/, 'xyz'); //=> true + * R.test(/^y/, 'xyz'); //=> false + */ + var test = _curry2(function test(pattern, str) { + return _cloneRegExp(pattern).test(str); + }); + + /** + * Calls an input function `n` times, returning an array containing the results of those + * function calls. + * + * `fn` is passed one argument: The current value of `n`, which begins at `0` and is + * gradually incremented to `n - 1`. + * + * @func + * @memberOf R + * @category List + * @sig (i -> a) -> i -> [a] + * @param {Function} fn The function to invoke. Passed one argument, the current value of `n`. + * @param {Number} n A value between `0` and `n - 1`. Increments after each function call. + * @return {Array} An array containing the return values of all calls to `fn`. + * @example + * + * R.times(R.identity, 5); //=> [0, 1, 2, 3, 4] + */ + var times = _curry2(function times(fn, n) { + var len = Number(n); + var list = new Array(len); + var idx = 0; + while (idx < len) { + list[idx] = fn(idx); + idx += 1; + } + return list; + }); + + /** + * Converts an object into an array of key, value arrays. + * Only the object's own properties are used. + * Note that the order of the output array is not guaranteed to be + * consistent across different JS platforms. + * + * @func + * @memberOf R + * @category Object + * @sig {String: *} -> [[String,*]] + * @param {Object} obj The object to extract from + * @return {Array} An array of key, value arrays from the object's own properties. + * @see R.fromPairs + * @example + * + * R.toPairs({a: 1, b: 2, c: 3}); //=> [['a', 1], ['b', 2], ['c', 3]] + */ + var toPairs = _curry1(function toPairs(obj) { + var pairs = []; + for (var prop in obj) { + if (_has(prop, obj)) { + pairs[pairs.length] = [ + prop, + obj[prop] + ]; + } + } + return pairs; + }); + + /** + * Converts an object into an array of key, value arrays. + * The object's own properties and prototype properties are used. + * Note that the order of the output array is not guaranteed to be + * consistent across different JS platforms. + * + * @func + * @memberOf R + * @category Object + * @sig {String: *} -> [[String,*]] + * @param {Object} obj The object to extract from + * @return {Array} An array of key, value arrays from the object's own + * and prototype properties. + * @example + * + * var F = function() { this.x = 'X'; }; + * F.prototype.y = 'Y'; + * var f = new F(); + * R.toPairsIn(f); //=> [['x','X'], ['y','Y']] + */ + var toPairsIn = _curry1(function toPairsIn(obj) { + var pairs = []; + for (var prop in obj) { + pairs[pairs.length] = [ + prop, + obj[prop] + ]; + } + return pairs; + }); + + /** + * Removes (strips) whitespace from both ends of the string. + * + * @func + * @memberOf R + * @category String + * @sig String -> String + * @param {String} str The string to trim. + * @return {String} Trimmed version of `str`. + * @example + * + * R.trim(' xyz '); //=> 'xyz' + * R.map(R.trim, R.split(',', 'x, y, z')); //=> ['x', 'y', 'z'] + */ + var trim = function () { + var ws = '\t\n\x0B\f\r \xA0\u1680\u180E\u2000\u2001\u2002\u2003' + '\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028' + '\u2029\uFEFF'; + var zeroWidth = '\u200B'; + var hasProtoTrim = typeof String.prototype.trim === 'function'; + if (!hasProtoTrim || (ws.trim() || !zeroWidth.trim())) { + return _curry1(function trim(str) { + var beginRx = new RegExp('^[' + ws + '][' + ws + ']*'); + var endRx = new RegExp('[' + ws + '][' + ws + ']*$'); + return str.replace(beginRx, '').replace(endRx, ''); + }); + } else { + return _curry1(function trim(str) { + return str.trim(); + }); + } + }(); + + /** + * Gives a single-word string description of the (native) type of a value, returning such + * answers as 'Object', 'Number', 'Array', or 'Null'. Does not attempt to distinguish user + * Object types any further, reporting them all as 'Object'. + * + * @func + * @memberOf R + * @category Type + * @sig (* -> {*}) -> String + * @param {*} val The value to test + * @return {String} + * @example + * + * R.type({}); //=> "Object" + * R.type(1); //=> "Number" + * R.type(false); //=> "Boolean" + * R.type('s'); //=> "String" + * R.type(null); //=> "Null" + * R.type([]); //=> "Array" + * R.type(/[A-z]/); //=> "RegExp" + */ + var type = _curry1(function type(val) { + return val === null ? 'Null' : val === undefined ? 'Undefined' : Object.prototype.toString.call(val).slice(8, -1); + }); + + /** + * Takes a function `fn`, which takes a single array argument, and returns + * a function which: + * + * - takes any number of positional arguments; + * - passes these arguments to `fn` as an array; and + * - returns the result. + * + * In other words, R.unapply derives a variadic function from a function + * which takes an array. R.unapply is the inverse of R.apply. + * + * @func + * @memberOf R + * @category Function + * @sig ([*...] -> a) -> (*... -> a) + * @param {Function} fn + * @return {Function} + * @see R.apply + * @example + * + * R.unapply(JSON.stringify)(1, 2, 3); //=> '[1,2,3]' + */ + var unapply = _curry1(function unapply(fn) { + return function () { + return fn(_slice(arguments)); + }; + }); + + /** + * Wraps a function of any arity (including nullary) in a function that accepts exactly 1 + * parameter. Any extraneous parameters will not be passed to the supplied function. + * + * @func + * @memberOf R + * @category Function + * @sig (* -> b) -> (a -> b) + * @param {Function} fn The function to wrap. + * @return {Function} A new function wrapping `fn`. The new function is guaranteed to be of + * arity 1. + * @example + * + * var takesTwoArgs = function(a, b) { + * return [a, b]; + * }; + * takesTwoArgs.length; //=> 2 + * takesTwoArgs(1, 2); //=> [1, 2] + * + * var takesOneArg = R.unary(takesTwoArgs); + * takesOneArg.length; //=> 1 + * // Only 1 argument is passed to the wrapped function + * takesOneArg(1, 2); //=> [1, undefined] + */ + var unary = _curry1(function unary(fn) { + return nAry(1, fn); + }); + + /** + * Returns a function of arity `n` from a (manually) curried function. + * + * @func + * @memberOf R + * @category Function + * @sig Number -> (a -> b) -> (a -> c) + * @param {Number} length The arity for the returned function. + * @param {Function} fn The function to uncurry. + * @return {Function} A new function. + * @see R.curry + * @example + * + * var addFour = function(a) { + * return function(b) { + * return function(c) { + * return function(d) { + * return a + b + c + d; + * }; + * }; + * }; + * }; + * + * var uncurriedAddFour = R.uncurryN(4, addFour); + * curriedAddFour(1, 2, 3, 4); //=> 10 + */ + var uncurryN = _curry2(function uncurryN(depth, fn) { + return curryN(depth, function () { + var currentDepth = 1; + var value = fn; + var idx = 0; + var endIdx; + while (currentDepth <= depth && typeof value === 'function') { + endIdx = currentDepth === depth ? arguments.length : idx + value.length; + value = value.apply(this, _slice(arguments, idx, endIdx)); + currentDepth += 1; + idx = endIdx; + } + return value; + }); + }); + + /** + * Builds a list from a seed value. Accepts an iterator function, which returns either false + * to stop iteration or an array of length 2 containing the value to add to the resulting + * list and the seed to be used in the next call to the iterator function. + * + * The iterator function receives one argument: *(seed)*. + * + * @func + * @memberOf R + * @category List + * @sig (a -> [b]) -> * -> [b] + * @param {Function} fn The iterator function. receives one argument, `seed`, and returns + * either false to quit iteration or an array of length two to proceed. The element + * at index 0 of this array will be added to the resulting array, and the element + * at index 1 will be passed to the next call to `fn`. + * @param {*} seed The seed value. + * @return {Array} The final list. + * @example + * + * var f = function(n) { return n > 50 ? false : [-n, n + 10] }; + * R.unfold(f, 10); //=> [-10, -20, -30, -40, -50] + */ + var unfold = _curry2(function unfold(fn, seed) { + var pair = fn(seed); + var result = []; + while (pair && pair.length) { + result[result.length] = pair[0]; + pair = fn(pair[1]); + } + return result; + }); + + /** + * Returns a new list containing only one copy of each element in the original list, based + * upon the value returned by applying the supplied predicate to two list elements. Prefers + * the first item if two items compare equal based on the predicate. + * + * @func + * @memberOf R + * @category List + * @sig (a, a -> Boolean) -> [a] -> [a] + * @param {Function} pred A predicate used to test whether two items are equal. + * @param {Array} list The array to consider. + * @return {Array} The list of unique items. + * @example + * + * var strEq = function(a, b) { return String(a) === String(b); }; + * R.uniqWith(strEq)([1, '1', 2, 1]); //=> [1, 2] + * R.uniqWith(strEq)([{}, {}]); //=> [{}] + * R.uniqWith(strEq)([1, '1', 1]); //=> [1] + * R.uniqWith(strEq)(['1', 1, 1]); //=> ['1'] + */ + var uniqWith = _curry2(function uniqWith(pred, list) { + var idx = 0, len = list.length; + var result = [], item; + while (idx < len) { + item = list[idx]; + if (!_containsWith(pred, item, result)) { + result[result.length] = item; + } + idx += 1; + } + return result; + }); + + /** + * Returns a new copy of the array with the element at the + * provided index replaced with the given value. + * @see R.adjust + * + * @func + * @memberOf R + * @category List + * @sig Number -> a -> [a] -> [a] + * @param {Number} idx The index to update. + * @param {*} x The value to exist at the given index of the returned array. + * @param {Array|Arguments} list The source array-like object to be updated. + * @return {Array} A copy of `list` with the value at index `idx` replaced with `x`. + * @example + * + * R.update(1, 11, [0, 1, 2]); //=> [0, 11, 2] + * R.update(1)(11)([0, 1, 2]); //=> [0, 11, 2] + */ + var update = _curry3(function update(idx, x, list) { + return adjust(always(x), idx, list); + }); + + /** + * Returns a list of all the enumerable own properties of the supplied object. + * Note that the order of the output array is not guaranteed across + * different JS platforms. + * + * @func + * @memberOf R + * @category Object + * @sig {k: v} -> [v] + * @param {Object} obj The object to extract values from + * @return {Array} An array of the values of the object's own properties. + * @example + * + * R.values({a: 1, b: 2, c: 3}); //=> [1, 2, 3] + */ + var values = _curry1(function values(obj) { + var props = keys(obj); + var len = props.length; + var vals = []; + var idx = 0; + while (idx < len) { + vals[idx] = obj[props[idx]]; + idx += 1; + } + return vals; + }); + + /** + * Returns a list of all the properties, including prototype properties, + * of the supplied object. + * Note that the order of the output array is not guaranteed to be + * consistent across different JS platforms. + * + * @func + * @memberOf R + * @category Object + * @sig {k: v} -> [v] + * @param {Object} obj The object to extract values from + * @return {Array} An array of the values of the object's own and prototype properties. + * @example + * + * var F = function() { this.x = 'X'; }; + * F.prototype.y = 'Y'; + * var f = new F(); + * R.valuesIn(f); //=> ['X', 'Y'] + */ + var valuesIn = _curry1(function valuesIn(obj) { + var prop, vs = []; + for (prop in obj) { + vs[vs.length] = obj[prop]; + } + return vs; + }); + + /** + * Returns a "view" of the given data structure, determined by the given lens. + * The lens's focus determines which portion of the data structure is visible. + * + * @func + * @memberOf R + * @category Object + * @typedef Lens s a = Functor f => (a -> f a) -> s -> f s + * @sig Lens s a -> s -> a + * @param {Lens} lens + * @param {*} x + * @return {*} + * @see R.prop, R.lensIndex, R.lensProp + * @example + * + * var xLens = R.lensProp('x'); + * + * R.view(xLens, {x: 1, y: 2}); //=> 1 + * R.view(xLens, {x: 4, y: 2}); //=> 4 + */ + var view = function () { + var Const = function (x) { + return { + value: x, + map: function () { + return this; + } + }; + }; + return _curry2(function view(lens, x) { + return lens(Const)(x).value; + }); + }(); + + /** + * Takes a spec object and a test object; returns true if the test satisfies + * the spec. Each of the spec's own properties must be a predicate function. + * Each predicate is applied to the value of the corresponding property of + * the test object. `where` returns true if all the predicates return true, + * false otherwise. + * + * `where` is well suited to declaratively expressing constraints for other + * functions such as `filter` and `find`. + * + * @func + * @memberOf R + * @category Object + * @sig {String: (* -> Boolean)} -> {String: *} -> Boolean + * @param {Object} spec + * @param {Object} testObj + * @return {Boolean} + * @example + * + * // pred :: Object -> Boolean + * var pred = R.where({ + * a: R.equals('foo'), + * b: R.complement(R.equals('bar')), + * x: R.gt(_, 10), + * y: R.lt(_, 20) + * }); + * + * pred({a: 'foo', b: 'xxx', x: 11, y: 19}); //=> true + * pred({a: 'xxx', b: 'xxx', x: 11, y: 19}); //=> false + * pred({a: 'foo', b: 'bar', x: 11, y: 19}); //=> false + * pred({a: 'foo', b: 'xxx', x: 10, y: 19}); //=> false + * pred({a: 'foo', b: 'xxx', x: 11, y: 20}); //=> false + */ + var where = _curry2(function where(spec, testObj) { + for (var prop in spec) { + if (_has(prop, spec) && !spec[prop](testObj[prop])) { + return false; + } + } + return true; + }); + + /** + * Wrap a function inside another to allow you to make adjustments to the parameters, or do + * other processing either before the internal function is called or with its results. + * + * @func + * @memberOf R + * @category Function + * @sig (a... -> b) -> ((a... -> b) -> a... -> c) -> (a... -> c) + * @param {Function} fn The function to wrap. + * @param {Function} wrapper The wrapper function. + * @return {Function} The wrapped function. + * @example + * + * var greet = function(name) {return 'Hello ' + name;}; + * + * var shoutedGreet = R.wrap(greet, function(gr, name) { + * return gr(name).toUpperCase(); + * }); + * shoutedGreet("Kathy"); //=> "HELLO KATHY" + * + * var shortenedGreet = R.wrap(greet, function(gr, name) { + * return gr(name.substring(0, 3)); + * }); + * shortenedGreet("Robert"); //=> "Hello Rob" + */ + var wrap = _curry2(function wrap(fn, wrapper) { + return curryN(fn.length, function () { + return wrapper.apply(this, _concat([fn], arguments)); + }); + }); + + /** + * Creates a new list out of the two supplied by creating each possible + * pair from the lists. + * + * @func + * @memberOf R + * @category List + * @sig [a] -> [b] -> [[a,b]] + * @param {Array} as The first list. + * @param {Array} bs The second list. + * @return {Array} The list made by combining each possible pair from + * `as` and `bs` into pairs (`[a, b]`). + * @example + * + * R.xprod([1, 2], ['a', 'b']); //=> [[1, 'a'], [1, 'b'], [2, 'a'], [2, 'b']] + */ + // = xprodWith(prepend); (takes about 3 times as long...) + var xprod = _curry2(function xprod(a, b) { + // = xprodWith(prepend); (takes about 3 times as long...) + var idx = 0; + var ilen = a.length; + var j; + var jlen = b.length; + var result = []; + while (idx < ilen) { + j = 0; + while (j < jlen) { + result[result.length] = [ + a[idx], + b[j] + ]; + j += 1; + } + idx += 1; + } + return result; + }); + + /** + * Creates a new list out of the two supplied by pairing up + * equally-positioned items from both lists. The returned list is + * truncated to the length of the shorter of the two input lists. + * Note: `zip` is equivalent to `zipWith(function(a, b) { return [a, b] })`. + * + * @func + * @memberOf R + * @category List + * @sig [a] -> [b] -> [[a,b]] + * @param {Array} list1 The first array to consider. + * @param {Array} list2 The second array to consider. + * @return {Array} The list made by pairing up same-indexed elements of `list1` and `list2`. + * @example + * + * R.zip([1, 2, 3], ['a', 'b', 'c']); //=> [[1, 'a'], [2, 'b'], [3, 'c']] + */ + var zip = _curry2(function zip(a, b) { + var rv = []; + var idx = 0; + var len = Math.min(a.length, b.length); + while (idx < len) { + rv[idx] = [ + a[idx], + b[idx] + ]; + idx += 1; + } + return rv; + }); + + /** + * Creates a new object out of a list of keys and a list of values. + * + * @func + * @memberOf R + * @category List + * @sig [String] -> [*] -> {String: *} + * @param {Array} keys The array that will be properties on the output object. + * @param {Array} values The list of values on the output object. + * @return {Object} The object made by pairing up same-indexed elements of `keys` and `values`. + * @example + * + * R.zipObj(['a', 'b', 'c'], [1, 2, 3]); //=> {a: 1, b: 2, c: 3} + */ + var zipObj = _curry2(function zipObj(keys, values) { + var idx = 0, len = keys.length, out = {}; + while (idx < len) { + out[keys[idx]] = values[idx]; + idx += 1; + } + return out; + }); + + /** + * Creates a new list out of the two supplied by applying the function to + * each equally-positioned pair in the lists. The returned list is + * truncated to the length of the shorter of the two input lists. + * + * @function + * @memberOf R + * @category List + * @sig (a,b -> c) -> [a] -> [b] -> [c] + * @param {Function} fn The function used to combine the two elements into one value. + * @param {Array} list1 The first array to consider. + * @param {Array} list2 The second array to consider. + * @return {Array} The list made by combining same-indexed elements of `list1` and `list2` + * using `fn`. + * @example + * + * var f = function(x, y) { + * // ... + * }; + * R.zipWith(f, [1, 2, 3], ['a', 'b', 'c']); + * //=> [f(1, 'a'), f(2, 'b'), f(3, 'c')] + */ + var zipWith = _curry3(function zipWith(fn, a, b) { + var rv = [], idx = 0, len = Math.min(a.length, b.length); + while (idx < len) { + rv[idx] = fn(a[idx], b[idx]); + idx += 1; + } + return rv; + }); + + /** + * A function that always returns `false`. Any passed in parameters are ignored. + * + * @func + * @memberOf R + * @category Function + * @sig * -> false + * @return {Boolean} false + * @see R.always, R.T + * @example + * + * R.F(); //=> false + */ + var F = always(false); + + /** + * A function that always returns `true`. Any passed in parameters are ignored. + * + * @func + * @memberOf R + * @category Function + * @sig * -> true + * @return {Boolean} `true`. + * @see R.always, R.F + * @example + * + * R.T(); //=> true + */ + var T = always(true); + + /** + * Similar to hasMethod, this checks whether a function has a [methodname] + * function. If it isn't an array it will execute that function otherwise it will + * default to the ramda implementation. + * + * @private + * @param {Function} fn ramda implemtation + * @param {String} methodname property to check for a custom implementation + * @return {Object} Whatever the return value of the method is. + */ + var _checkForMethod = function _checkForMethod(methodname, fn) { + return function () { + var length = arguments.length; + if (length === 0) { + return fn(); + } + var obj = arguments[length - 1]; + return _isArray(obj) || typeof obj[methodname] !== 'function' ? fn.apply(this, arguments) : obj[methodname].apply(obj, _slice(arguments, 0, length - 1)); + }; + }; + + /** + * Copies an object. + * + * @private + * @param {*} value The value to be copied + * @param {Array} refFrom Array containing the source references + * @param {Array} refTo Array containing the copied source references + * @return {*} The copied value. + */ + var _clone = function _clone(value, refFrom, refTo) { + var copy = function copy(copiedValue) { + var len = refFrom.length; + var idx = 0; + while (idx < len) { + if (value === refFrom[idx]) { + return refTo[idx]; + } + idx += 1; + } + refFrom[idx + 1] = value; + refTo[idx + 1] = copiedValue; + for (var key in value) { + copiedValue[key] = _clone(value[key], refFrom, refTo); + } + return copiedValue; + }; + switch (type(value)) { + case 'Object': + return copy({}); + case 'Array': + return copy([]); + case 'Date': + return new Date(value); + case 'RegExp': + return _cloneRegExp(value); + default: + return value; + } + }; + + var _createPartialApplicator = function _createPartialApplicator(concat) { + return function (fn) { + var args = _slice(arguments, 1); + return _arity(Math.max(0, fn.length - args.length), function () { + return fn.apply(this, concat(args, arguments)); + }); + }; + }; + + /** + * Returns a function that dispatches with different strategies based on the + * object in list position (last argument). If it is an array, executes [fn]. + * Otherwise, if it has a function with [methodname], it will execute that + * function (functor case). Otherwise, if it is a transformer, uses transducer + * [xf] to return a new transformer (transducer case). Otherwise, it will + * default to executing [fn]. + * + * @private + * @param {String} methodname property to check for a custom implementation + * @param {Function} xf transducer to initialize if object is transformer + * @param {Function} fn default ramda implementation + * @return {Function} A function that dispatches on object in list position + */ + var _dispatchable = function _dispatchable(methodname, xf, fn) { + return function () { + var length = arguments.length; + if (length === 0) { + return fn(); + } + var obj = arguments[length - 1]; + if (!_isArray(obj)) { + var args = _slice(arguments, 0, length - 1); + if (typeof obj[methodname] === 'function') { + return obj[methodname].apply(obj, args); + } + if (_isTransformer(obj)) { + var transducer = xf.apply(null, args); + return transducer(obj); + } + } + return fn.apply(this, arguments); + }; + }; + + // The algorithm used to handle cyclic structures is + // inspired by underscore's isEqual + // RegExp equality algorithm: http://stackoverflow.com/a/10776635 + var _equals = function _equals(a, b, stackA, stackB) { + var typeA = type(a); + if (typeA !== type(b)) { + return false; + } + if (typeA === 'Boolean' || typeA === 'Number' || typeA === 'String') { + return typeof a === 'object' ? typeof b === 'object' && identical(a.valueOf(), b.valueOf()) : identical(a, b); + } + if (identical(a, b)) { + return true; + } + if (typeA === 'RegExp') { + // RegExp equality algorithm: http://stackoverflow.com/a/10776635 + return a.source === b.source && a.global === b.global && a.ignoreCase === b.ignoreCase && a.multiline === b.multiline && a.sticky === b.sticky && a.unicode === b.unicode; + } + if (Object(a) === a) { + if (typeA === 'Date' && a.getTime() !== b.getTime()) { + return false; + } + var keysA = keys(a); + if (keysA.length !== keys(b).length) { + return false; + } + var idx = stackA.length - 1; + while (idx >= 0) { + if (stackA[idx] === a) { + return stackB[idx] === b; + } + idx -= 1; + } + stackA[stackA.length] = a; + stackB[stackB.length] = b; + idx = keysA.length - 1; + while (idx >= 0) { + var key = keysA[idx]; + if (!_has(key, b) || !_equals(b[key], a[key], stackA, stackB)) { + return false; + } + idx -= 1; + } + stackA.pop(); + stackB.pop(); + return true; + } + return false; + }; + + /** + * Private function that determines whether or not a provided object has a given method. + * Does not ignore methods stored on the object's prototype chain. Used for dynamically + * dispatching Ramda methods to non-Array objects. + * + * @private + * @param {String} methodName The name of the method to check for. + * @param {Object} obj The object to test. + * @return {Boolean} `true` has a given method, `false` otherwise. + * @example + * + * var person = { name: 'John' }; + * person.shout = function() { alert(this.name); }; + * + * _hasMethod('shout', person); //=> true + * _hasMethod('foo', person); //=> false + */ + var _hasMethod = function _hasMethod(methodName, obj) { + return obj != null && !_isArray(obj) && typeof obj[methodName] === 'function'; + }; + + /** + * `_makeFlat` is a helper function that returns a one-level or fully recursive function + * based on the flag passed in. + * + * @private + */ + var _makeFlat = function _makeFlat(recursive) { + return function flatt(list) { + var value, result = [], idx = 0, j, ilen = list.length, jlen; + while (idx < ilen) { + if (isArrayLike(list[idx])) { + value = recursive ? flatt(list[idx]) : list[idx]; + j = 0; + jlen = value.length; + while (j < jlen) { + result[result.length] = value[j]; + j += 1; + } + } else { + result[result.length] = list[idx]; + } + idx += 1; + } + return result; + }; + }; + + var _reduce = function () { + function _arrayReduce(xf, acc, list) { + var idx = 0, len = list.length; + while (idx < len) { + acc = xf['@@transducer/step'](acc, list[idx]); + if (acc && acc['@@transducer/reduced']) { + acc = acc['@@transducer/value']; + break; + } + idx += 1; + } + return xf['@@transducer/result'](acc); + } + function _iterableReduce(xf, acc, iter) { + var step = iter.next(); + while (!step.done) { + acc = xf['@@transducer/step'](acc, step.value); + if (acc && acc['@@transducer/reduced']) { + acc = acc['@@transducer/value']; + break; + } + step = iter.next(); + } + return xf['@@transducer/result'](acc); + } + function _methodReduce(xf, acc, obj) { + return xf['@@transducer/result'](obj.reduce(bind(xf['@@transducer/step'], xf), acc)); + } + var symIterator = typeof Symbol !== 'undefined' ? Symbol.iterator : '@@iterator'; + return function _reduce(fn, acc, list) { + if (typeof fn === 'function') { + fn = _xwrap(fn); + } + if (isArrayLike(list)) { + return _arrayReduce(fn, acc, list); + } + if (typeof list.reduce === 'function') { + return _methodReduce(fn, acc, list); + } + if (list[symIterator] != null) { + return _iterableReduce(fn, acc, list[symIterator]()); + } + if (typeof list.next === 'function') { + return _iterableReduce(fn, acc, list); + } + throw new TypeError('reduce: list must be array or iterable'); + }; + }(); + + var _stepCat = function () { + var _stepCatArray = { + '@@transducer/init': Array, + '@@transducer/step': function (xs, x) { + return _concat(xs, [x]); + }, + '@@transducer/result': _identity + }; + var _stepCatString = { + '@@transducer/init': String, + '@@transducer/step': function (a, b) { + return a + b; + }, + '@@transducer/result': _identity + }; + var _stepCatObject = { + '@@transducer/init': Object, + '@@transducer/step': function (result, input) { + return merge(result, isArrayLike(input) ? createMapEntry(input[0], input[1]) : input); + }, + '@@transducer/result': _identity + }; + return function _stepCat(obj) { + if (_isTransformer(obj)) { + return obj; + } + if (isArrayLike(obj)) { + return _stepCatArray; + } + if (typeof obj === 'string') { + return _stepCatString; + } + if (typeof obj === 'object') { + return _stepCatObject; + } + throw new Error('Cannot create transformer for ' + obj); + }; + }(); + + var _xall = function () { + function XAll(f, xf) { + this.xf = xf; + this.f = f; + this.all = true; + } + XAll.prototype['@@transducer/init'] = _xfBase.init; + XAll.prototype['@@transducer/result'] = function (result) { + if (this.all) { + result = this.xf['@@transducer/step'](result, true); + } + return this.xf['@@transducer/result'](result); + }; + XAll.prototype['@@transducer/step'] = function (result, input) { + if (!this.f(input)) { + this.all = false; + result = _reduced(this.xf['@@transducer/step'](result, false)); + } + return result; + }; + return _curry2(function _xall(f, xf) { + return new XAll(f, xf); + }); + }(); + + var _xany = function () { + function XAny(f, xf) { + this.xf = xf; + this.f = f; + this.any = false; + } + XAny.prototype['@@transducer/init'] = _xfBase.init; + XAny.prototype['@@transducer/result'] = function (result) { + if (!this.any) { + result = this.xf['@@transducer/step'](result, false); + } + return this.xf['@@transducer/result'](result); + }; + XAny.prototype['@@transducer/step'] = function (result, input) { + if (this.f(input)) { + this.any = true; + result = _reduced(this.xf['@@transducer/step'](result, true)); + } + return result; + }; + return _curry2(function _xany(f, xf) { + return new XAny(f, xf); + }); + }(); + + var _xdrop = function () { + function XDrop(n, xf) { + this.xf = xf; + this.n = n; + } + XDrop.prototype['@@transducer/init'] = _xfBase.init; + XDrop.prototype['@@transducer/result'] = _xfBase.result; + XDrop.prototype['@@transducer/step'] = function (result, input) { + if (this.n > 0) { + this.n -= 1; + return result; + } + return this.xf['@@transducer/step'](result, input); + }; + return _curry2(function _xdrop(n, xf) { + return new XDrop(n, xf); + }); + }(); + + var _xdropWhile = function () { + function XDropWhile(f, xf) { + this.xf = xf; + this.f = f; + } + XDropWhile.prototype['@@transducer/init'] = _xfBase.init; + XDropWhile.prototype['@@transducer/result'] = _xfBase.result; + XDropWhile.prototype['@@transducer/step'] = function (result, input) { + if (this.f) { + if (this.f(input)) { + return result; + } + this.f = null; + } + return this.xf['@@transducer/step'](result, input); + }; + return _curry2(function _xdropWhile(f, xf) { + return new XDropWhile(f, xf); + }); + }(); + + var _xgroupBy = function () { + function XGroupBy(f, xf) { + this.xf = xf; + this.f = f; + this.inputs = {}; + } + XGroupBy.prototype['@@transducer/init'] = _xfBase.init; + XGroupBy.prototype['@@transducer/result'] = function (result) { + var key; + for (key in this.inputs) { + if (_has(key, this.inputs)) { + result = this.xf['@@transducer/step'](result, this.inputs[key]); + if (result['@@transducer/reduced']) { + result = result['@@transducer/value']; + break; + } + } + } + return this.xf['@@transducer/result'](result); + }; + XGroupBy.prototype['@@transducer/step'] = function (result, input) { + var key = this.f(input); + this.inputs[key] = this.inputs[key] || [ + key, + [] + ]; + this.inputs[key][1] = append(input, this.inputs[key][1]); + return result; + }; + return _curry2(function _xgroupBy(f, xf) { + return new XGroupBy(f, xf); + }); + }(); + + /** + * Creates a new list iteration function from an existing one by adding two new parameters + * to its callback function: the current index, and the entire list. + * + * This would turn, for instance, Ramda's simple `map` function into one that more closely + * resembles `Array.prototype.map`. Note that this will only work for functions in which + * the iteration callback function is the first parameter, and where the list is the last + * parameter. (This latter might be unimportant if the list parameter is not used.) + * + * @func + * @memberOf R + * @category Function + * @category List + * @sig ((a ... -> b) ... -> [a] -> *) -> (a ..., Int, [a] -> b) ... -> [a] -> *) + * @param {Function} fn A list iteration function that does not pass index or list to its callback + * @return {Function} An altered list iteration function that passes (item, index, list) to its callback + * @example + * + * var mapIndexed = R.addIndex(R.map); + * mapIndexed(function(val, idx) {return idx + '-' + val;}, ['f', 'o', 'o', 'b', 'a', 'r']); + * //=> ['0-f', '1-o', '2-o', '3-b', '4-a', '5-r'] + */ + var addIndex = _curry1(function addIndex(fn) { + return curryN(fn.length, function () { + var idx = 0; + var origFn = arguments[0]; + var list = arguments[arguments.length - 1]; + var args = _slice(arguments); + args[0] = function () { + var result = origFn.apply(this, _concat(arguments, [ + idx, + list + ])); + idx += 1; + return result; + }; + return fn.apply(this, args); + }); + }); + + /** + * Returns `true` if all elements of the list match the predicate, `false` if there are any + * that don't. + * + * Acts as a transducer if a transformer is given in list position. + * @see R.transduce + * + * @func + * @memberOf R + * @category List + * @sig (a -> Boolean) -> [a] -> Boolean + * @param {Function} fn The predicate function. + * @param {Array} list The array to consider. + * @return {Boolean} `true` if the predicate is satisfied by every element, `false` + * otherwise. + * @see R.any, R.none + * @example + * + * var lessThan2 = R.flip(R.lt)(2); + * var lessThan3 = R.flip(R.lt)(3); + * R.all(lessThan2)([1, 2]); //=> false + * R.all(lessThan3)([1, 2]); //=> true + */ + var all = _curry2(_dispatchable('all', _xall, function all(fn, list) { + var idx = 0; + while (idx < list.length) { + if (!fn(list[idx])) { + return false; + } + idx += 1; + } + return true; + })); + + /** + * A function that returns the first argument if it's falsy otherwise the second + * argument. Note that this is NOT short-circuited, meaning that if expressions + * are passed they are both evaluated. + * + * Dispatches to the `and` method of the first argument if applicable. + * + * @func + * @memberOf R + * @category Logic + * @sig * -> * -> * + * @param {*} a any value + * @param {*} b any other value + * @return {*} the first argument if falsy otherwise the second argument. + * @see R.both + * @example + * + * R.and(false, true); //=> false + * R.and(0, []); //=> 0 + * R.and(null, ''); => null + */ + var and = _curry2(function and(a, b) { + return _hasMethod('and', a) ? a.and(b) : a && b; + }); + + /** + * Returns `true` if at least one of elements of the list match the predicate, `false` + * otherwise. + * + * Acts as a transducer if a transformer is given in list position. + * @see R.transduce + * + * @func + * @memberOf R + * @category List + * @sig (a -> Boolean) -> [a] -> Boolean + * @param {Function} fn The predicate function. + * @param {Array} list The array to consider. + * @return {Boolean} `true` if the predicate is satisfied by at least one element, `false` + * otherwise. + * @see R.all, R.none + * @example + * + * var lessThan0 = R.flip(R.lt)(0); + * var lessThan2 = R.flip(R.lt)(2); + * R.any(lessThan0)([1, 2]); //=> false + * R.any(lessThan2)([1, 2]); //=> true + */ + var any = _curry2(_dispatchable('any', _xany, function any(fn, list) { + var idx = 0; + while (idx < list.length) { + if (fn(list[idx])) { + return true; + } + idx += 1; + } + return false; + })); + + /** + * Wraps a function of any arity (including nullary) in a function that accepts exactly 2 + * parameters. Any extraneous parameters will not be passed to the supplied function. + * + * @func + * @memberOf R + * @category Function + * @sig (* -> c) -> (a, b -> c) + * @param {Function} fn The function to wrap. + * @return {Function} A new function wrapping `fn`. The new function is guaranteed to be of + * arity 2. + * @example + * + * var takesThreeArgs = function(a, b, c) { + * return [a, b, c]; + * }; + * takesThreeArgs.length; //=> 3 + * takesThreeArgs(1, 2, 3); //=> [1, 2, 3] + * + * var takesTwoArgs = R.binary(takesThreeArgs); + * takesTwoArgs.length; //=> 2 + * // Only 2 arguments are passed to the wrapped function + * takesTwoArgs(1, 2, 3); //=> [1, 2, undefined] + */ + var binary = _curry1(function binary(fn) { + return nAry(2, fn); + }); + + /** + * Creates a deep copy of the value which may contain (nested) `Array`s and + * `Object`s, `Number`s, `String`s, `Boolean`s and `Date`s. `Function`s are + * not copied, but assigned by their reference. + * + * @func + * @memberOf R + * @category Object + * @sig {*} -> {*} + * @param {*} value The object or array to clone + * @return {*} A new object or array. + * @example + * + * var objects = [{}, {}, {}]; + * var objectsClone = R.clone(objects); + * objects[0] === objectsClone[0]; //=> false + */ + var clone = _curry1(function clone(value) { + return _clone(value, [], []); + }); + + /** + * Returns a new list consisting of the elements of the first list followed by the elements + * of the second. + * + * @func + * @memberOf R + * @category List + * @sig [a] -> [a] -> [a] + * @param {Array} list1 The first list to merge. + * @param {Array} list2 The second set to merge. + * @return {Array} A new array consisting of the contents of `list1` followed by the + * contents of `list2`. If, instead of an Array for `list1`, you pass an + * object with a `concat` method on it, `concat` will call `list1.concat` + * and pass it the value of `list2`. + * + * @example + * + * R.concat([], []); //=> [] + * R.concat([4, 5, 6], [1, 2, 3]); //=> [4, 5, 6, 1, 2, 3] + * R.concat('ABC', 'DEF'); // 'ABCDEF' + */ + var concat = _curry2(function concat(set1, set2) { + if (_isArray(set2)) { + return _concat(set1, set2); + } else if (_hasMethod('concat', set1)) { + return set1.concat(set2); + } else { + throw new TypeError('can\'t concat ' + typeof set1); + } + }); + + /** + * Returns a curried equivalent of the provided function. The curried + * function has two unusual capabilities. First, its arguments needn't + * be provided one at a time. If `f` is a ternary function and `g` is + * `R.curry(f)`, the following are equivalent: + * + * - `g(1)(2)(3)` + * - `g(1)(2, 3)` + * - `g(1, 2)(3)` + * - `g(1, 2, 3)` + * + * Secondly, the special placeholder value `R.__` may be used to specify + * "gaps", allowing partial application of any combination of arguments, + * regardless of their positions. If `g` is as above and `_` is `R.__`, + * the following are equivalent: + * + * - `g(1, 2, 3)` + * - `g(_, 2, 3)(1)` + * - `g(_, _, 3)(1)(2)` + * - `g(_, _, 3)(1, 2)` + * - `g(_, 2)(1)(3)` + * - `g(_, 2)(1, 3)` + * - `g(_, 2)(_, 3)(1)` + * + * @func + * @memberOf R + * @category Function + * @sig (* -> a) -> (* -> a) + * @param {Function} fn The function to curry. + * @return {Function} A new, curried function. + * @see R.curryN + * @example + * + * var addFourNumbers = function(a, b, c, d) { + * return a + b + c + d; + * }; + * + * var curriedAddFourNumbers = R.curry(addFourNumbers); + * var f = curriedAddFourNumbers(1, 2); + * var g = f(3); + * g(4); //=> 10 + */ + var curry = _curry1(function curry(fn) { + return curryN(fn.length, fn); + }); + + /** + * Returns a new list containing the last `n` elements of a given list, passing each value + * to the supplied predicate function, skipping elements while the predicate function returns + * `true`. The predicate function is passed one argument: *(value)*. + * + * Acts as a transducer if a transformer is given in list position. + * @see R.transduce + * + * @func + * @memberOf R + * @category List + * @sig (a -> Boolean) -> [a] -> [a] + * @param {Function} fn The function called per iteration. + * @param {Array} list The collection to iterate over. + * @return {Array} A new array. + * @see R.takeWhile + * @example + * + * var lteTwo = function(x) { + * return x <= 2; + * }; + * + * R.dropWhile(lteTwo, [1, 2, 3, 4, 3, 2, 1]); //=> [3, 4, 3, 2, 1] + */ + var dropWhile = _curry2(_dispatchable('dropWhile', _xdropWhile, function dropWhile(pred, list) { + var idx = 0, len = list.length; + while (idx < len && pred(list[idx])) { + idx += 1; + } + return _slice(list, idx); + })); + + /** + * Returns `true` if its arguments are equivalent, `false` otherwise. + * Dispatches to an `equals` method if present. Handles cyclical data + * structures. + * + * @func + * @memberOf R + * @category Relation + * @sig a -> b -> Boolean + * @param {*} a + * @param {*} b + * @return {Boolean} + * @example + * + * R.equals(1, 1); //=> true + * R.equals(1, '1'); //=> false + * R.equals([1, 2, 3], [1, 2, 3]); //=> true + * + * var a = {}; a.v = a; + * var b = {}; b.v = b; + * R.equals(a, b); //=> true + */ + var equals = _curry2(function equals(a, b) { + return _hasMethod('equals', a) ? a.equals(b) : _hasMethod('equals', b) ? b.equals(a) : _equals(a, b, [], []); + }); + + /** + * Returns a new list containing only those items that match a given predicate function. + * The predicate function is passed one argument: *(value)*. + * + * Note that `R.filter` does not skip deleted or unassigned indices, unlike the native + * `Array.prototype.filter` method. For more details on this behavior, see: + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter#Description + * + * Acts as a transducer if a transformer is given in list position. + * @see R.transduce + * + * @func + * @memberOf R + * @category List + * @sig (a -> Boolean) -> [a] -> [a] + * @param {Function} fn The function called per iteration. + * @param {Array} list The collection to iterate over. + * @return {Array} The new filtered array. + * @see R.reject + * @example + * + * var isEven = function(n) { + * return n % 2 === 0; + * }; + * R.filter(isEven, [1, 2, 3, 4]); //=> [2, 4] + */ + var filter = _curry2(_dispatchable('filter', _xfilter, _filter)); + + /** + * Returns the first element of the list which matches the predicate, or `undefined` if no + * element matches. + * + * Acts as a transducer if a transformer is given in list position. + * @see R.transduce + * + * @func + * @memberOf R + * @category List + * @sig (a -> Boolean) -> [a] -> a | undefined + * @param {Function} fn The predicate function used to determine if the element is the + * desired one. + * @param {Array} list The array to consider. + * @return {Object} The element found, or `undefined`. + * @example + * + * var xs = [{a: 1}, {a: 2}, {a: 3}]; + * R.find(R.propEq('a', 2))(xs); //=> {a: 2} + * R.find(R.propEq('a', 4))(xs); //=> undefined + */ + var find = _curry2(_dispatchable('find', _xfind, function find(fn, list) { + var idx = 0; + var len = list.length; + while (idx < len) { + if (fn(list[idx])) { + return list[idx]; + } + idx += 1; + } + })); + + /** + * Returns the index of the first element of the list which matches the predicate, or `-1` + * if no element matches. + * + * Acts as a transducer if a transformer is given in list position. + * @see R.transduce + * + * @func + * @memberOf R + * @category List + * @sig (a -> Boolean) -> [a] -> Number + * @param {Function} fn The predicate function used to determine if the element is the + * desired one. + * @param {Array} list The array to consider. + * @return {Number} The index of the element found, or `-1`. + * @example + * + * var xs = [{a: 1}, {a: 2}, {a: 3}]; + * R.findIndex(R.propEq('a', 2))(xs); //=> 1 + * R.findIndex(R.propEq('a', 4))(xs); //=> -1 + */ + var findIndex = _curry2(_dispatchable('findIndex', _xfindIndex, function findIndex(fn, list) { + var idx = 0; + var len = list.length; + while (idx < len) { + if (fn(list[idx])) { + return idx; + } + idx += 1; + } + return -1; + })); + + /** + * Returns the last element of the list which matches the predicate, or `undefined` if no + * element matches. + * + * Acts as a transducer if a transformer is given in list position. + * @see R.transduce + * + * @func + * @memberOf R + * @category List + * @sig (a -> Boolean) -> [a] -> a | undefined + * @param {Function} fn The predicate function used to determine if the element is the + * desired one. + * @param {Array} list The array to consider. + * @return {Object} The element found, or `undefined`. + * @example + * + * var xs = [{a: 1, b: 0}, {a:1, b: 1}]; + * R.findLast(R.propEq('a', 1))(xs); //=> {a: 1, b: 1} + * R.findLast(R.propEq('a', 4))(xs); //=> undefined + */ + var findLast = _curry2(_dispatchable('findLast', _xfindLast, function findLast(fn, list) { + var idx = list.length - 1; + while (idx >= 0) { + if (fn(list[idx])) { + return list[idx]; + } + idx -= 1; + } + })); + + /** + * Returns the index of the last element of the list which matches the predicate, or + * `-1` if no element matches. + * + * Acts as a transducer if a transformer is given in list position. + * @see R.transduce + * + * @func + * @memberOf R + * @category List + * @sig (a -> Boolean) -> [a] -> Number + * @param {Function} fn The predicate function used to determine if the element is the + * desired one. + * @param {Array} list The array to consider. + * @return {Number} The index of the element found, or `-1`. + * @example + * + * var xs = [{a: 1, b: 0}, {a:1, b: 1}]; + * R.findLastIndex(R.propEq('a', 1))(xs); //=> 1 + * R.findLastIndex(R.propEq('a', 4))(xs); //=> -1 + */ + var findLastIndex = _curry2(_dispatchable('findLastIndex', _xfindLastIndex, function findLastIndex(fn, list) { + var idx = list.length - 1; + while (idx >= 0) { + if (fn(list[idx])) { + return idx; + } + idx -= 1; + } + return -1; + })); + + /** + * Returns a new list by pulling every item out of it (and all its sub-arrays) and putting + * them in a new array, depth-first. + * + * @func + * @memberOf R + * @category List + * @sig [a] -> [b] + * @param {Array} list The array to consider. + * @return {Array} The flattened list. + * @see R.unnest + * @example + * + * R.flatten([1, 2, [3, 4], 5, [6, [7, 8, [9, [10, 11], 12]]]]); + * //=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] + */ + var flatten = _curry1(_makeFlat(true)); + + /** + * Returns a new function much like the supplied one, except that the first two arguments' + * order is reversed. + * + * @func + * @memberOf R + * @category Function + * @sig (a -> b -> c -> ... -> z) -> (b -> a -> c -> ... -> z) + * @param {Function} fn The function to invoke with its first two parameters reversed. + * @return {*} The result of invoking `fn` with its first two parameters' order reversed. + * @example + * + * var mergeThree = function(a, b, c) { + * return ([]).concat(a, b, c); + * }; + * + * mergeThree(1, 2, 3); //=> [1, 2, 3] + * + * R.flip(mergeThree)(1, 2, 3); //=> [2, 1, 3] + */ + var flip = _curry1(function flip(fn) { + return curry(function (a, b) { + var args = _slice(arguments); + args[0] = b; + args[1] = a; + return fn.apply(this, args); + }); + }); + + /** + * Iterate over an input `list`, calling a provided function `fn` for each element in the + * list. + * + * `fn` receives one argument: *(value)*. + * + * Note: `R.forEach` does not skip deleted or unassigned indices (sparse arrays), unlike + * the native `Array.prototype.forEach` method. For more details on this behavior, see: + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#Description + * + * Also note that, unlike `Array.prototype.forEach`, Ramda's `forEach` returns the original + * array. In some libraries this function is named `each`. + * + * @func + * @memberOf R + * @category List + * @sig (a -> *) -> [a] -> [a] + * @param {Function} fn The function to invoke. Receives one argument, `value`. + * @param {Array} list The list to iterate over. + * @return {Array} The original list. + * @example + * + * var printXPlusFive = function(x) { console.log(x + 5); }; + * R.forEach(printXPlusFive, [1, 2, 3]); //=> [1, 2, 3] + * //-> 6 + * //-> 7 + * //-> 8 + */ + var forEach = _curry2(_checkForMethod('forEach', function forEach(fn, list) { + var len = list.length; + var idx = 0; + while (idx < len) { + fn(list[idx]); + idx += 1; + } + return list; + })); + + /** + * Returns a list of function names of object's own functions + * + * @func + * @memberOf R + * @category Object + * @sig {*} -> [String] + * @param {Object} obj The objects with functions in it + * @return {Array} A list of the object's own properties that map to functions. + * @example + * + * R.functions(R); // returns list of ramda's own function names + * + * var F = function() { this.x = function(){}; this.y = 1; } + * F.prototype.z = function() {}; + * F.prototype.a = 100; + * R.functions(new F()); //=> ["x"] + */ + var functions = _curry1(_functionsWith(keys)); + + /** + * Returns a list of function names of object's own and prototype functions + * + * @func + * @memberOf R + * @category Object + * @sig {*} -> [String] + * @param {Object} obj The objects with functions in it + * @return {Array} A list of the object's own properties and prototype + * properties that map to functions. + * @example + * + * R.functionsIn(R); // returns list of ramda's own and prototype function names + * + * var F = function() { this.x = function(){}; this.y = 1; } + * F.prototype.z = function() {}; + * F.prototype.a = 100; + * R.functionsIn(new F()); //=> ["x", "z"] + */ + var functionsIn = _curry1(_functionsWith(keysIn)); + + /** + * Splits a list into sub-lists stored in an object, based on the result of calling a String-returning function + * on each element, and grouping the results according to values returned. + * + * Acts as a transducer if a transformer is given in list position. + * @see R.transduce + * + * @func + * @memberOf R + * @category List + * @sig (a -> String) -> [a] -> {String: [a]} + * @param {Function} fn Function :: a -> String + * @param {Array} list The array to group + * @return {Object} An object with the output of `fn` for keys, mapped to arrays of elements + * that produced that key when passed to `fn`. + * @example + * + * var byGrade = R.groupBy(function(student) { + * var score = student.score; + * return score < 65 ? 'F' : + * score < 70 ? 'D' : + * score < 80 ? 'C' : + * score < 90 ? 'B' : 'A'; + * }); + * var students = [{name: 'Abby', score: 84}, + * {name: 'Eddy', score: 58}, + * // ... + * {name: 'Jack', score: 69}]; + * byGrade(students); + * // { + * // 'A': [{name: 'Dianne', score: 99}], + * // 'B': [{name: 'Abby', score: 84}] + * // // ..., + * // 'F': [{name: 'Eddy', score: 58}] + * // } + */ + var groupBy = _curry2(_dispatchable('groupBy', _xgroupBy, function groupBy(fn, list) { + return _reduce(function (acc, elt) { + var key = fn(elt); + acc[key] = append(elt, acc[key] || (acc[key] = [])); + return acc; + }, {}, list); + })); + + /** + * Returns the first element of the given list or string. In some libraries + * this function is named `first`. + * + * @func + * @memberOf R + * @category List + * @see R.tail, R.init, R.last + * @sig [a] -> a | Undefined + * @sig String -> String + * @param {*} list + * @return {*} + * @example + * + * R.head(['fi', 'fo', 'fum']); //=> 'fi' + * R.head([]); //=> undefined + * + * R.head('abc'); //=> 'a' + * R.head(''); //=> '' + */ + var head = nth(0); + + /** + * Combines two lists into a set (i.e. no duplicates) composed of those + * elements common to both lists. Duplication is determined according + * to the value returned by applying the supplied predicate to two list + * elements. + * + * @func + * @memberOf R + * @category Relation + * @sig (a,a -> Boolean) -> [a] -> [a] -> [a] + * @param {Function} pred A predicate function that determines whether + * the two supplied elements are equal. + * @param {Array} list1 One list of items to compare + * @param {Array} list2 A second list of items to compare + * @see R.intersection + * @return {Array} A new list containing those elements common to both lists. + * @example + * + * var buffaloSpringfield = [ + * {id: 824, name: 'Richie Furay'}, + * {id: 956, name: 'Dewey Martin'}, + * {id: 313, name: 'Bruce Palmer'}, + * {id: 456, name: 'Stephen Stills'}, + * {id: 177, name: 'Neil Young'} + * ]; + * var csny = [ + * {id: 204, name: 'David Crosby'}, + * {id: 456, name: 'Stephen Stills'}, + * {id: 539, name: 'Graham Nash'}, + * {id: 177, name: 'Neil Young'} + * ]; + * + * var sameId = function(o1, o2) {return o1.id === o2.id;}; + * + * R.intersectionWith(sameId, buffaloSpringfield, csny); + * //=> [{id: 456, name: 'Stephen Stills'}, {id: 177, name: 'Neil Young'}] + */ + var intersectionWith = _curry3(function intersectionWith(pred, list1, list2) { + var results = [], idx = 0; + while (idx < list1.length) { + if (_containsWith(pred, list1[idx], list2)) { + results[results.length] = list1[idx]; + } + idx += 1; + } + return uniqWith(pred, results); + }); + + /** + * Creates a new list with the separator interposed between elements. + * + * @func + * @memberOf R + * @category List + * @sig a -> [a] -> [a] + * @param {*} separator The element to add to the list. + * @param {Array} list The list to be interposed. + * @return {Array} The new list. + * @example + * + * R.intersperse('n', ['ba', 'a', 'a']); //=> ['ba', 'n', 'a', 'n', 'a'] + */ + var intersperse = _curry2(_checkForMethod('intersperse', function intersperse(separator, list) { + var out = []; + var idx = 0; + var length = list.length; + while (idx < length) { + if (idx === length - 1) { + out.push(list[idx]); + } else { + out.push(list[idx], separator); + } + idx += 1; + } + return out; + })); + + /** + * Transforms the items of the list with the transducer and appends the transformed items to + * the accumulator using an appropriate iterator function based on the accumulator type. + * + * The accumulator can be an array, string, object or a transformer. Iterated items will + * be appended to arrays and concatenated to strings. Objects will be merged directly or 2-item + * arrays will be merged as key, value pairs. + * + * The accumulator can also be a transformer object that provides a 2-arity reducing iterator + * function, step, 0-arity initial value function, init, and 1-arity result extraction function + * result. The step function is used as the iterator function in reduce. The result function is + * used to convert the final accumulator into the return type and in most cases is R.identity. + * The init function is used to provide the initial accumulator. + * + * The iteration is performed with R.reduce after initializing the transducer. + * + * @func + * @memberOf R + * @category List + * @sig a -> (b -> b) -> [c] -> a + * @param {*} acc The initial accumulator value. + * @param {Function} xf The transducer function. Receives a transformer and returns a transformer. + * @param {Array} list The list to iterate over. + * @return {*} The final, accumulated value. + * @example + * + * var numbers = [1, 2, 3, 4]; + * var transducer = R.compose(R.map(R.add(1)), R.take(2)); + * + * R.into([], transducer, numbers); //=> [2, 3] + * + * var intoArray = R.into([]); + * intoArray(transducer, numbers); //=> [2, 3] + */ + var into = _curry3(function into(acc, xf, list) { + return _isTransformer(acc) ? _reduce(xf(acc), acc['@@transducer/init'](), list) : _reduce(xf(_stepCat(acc)), acc, list); + }); + + /** + * Same as R.invertObj, however this accounts for objects + * with duplicate values by putting the values into an + * array. + * + * @func + * @memberOf R + * @category Object + * @sig {s: x} -> {x: [ s, ... ]} + * @param {Object} obj The object or array to invert + * @return {Object} out A new object with keys + * in an array. + * @example + * + * var raceResultsByFirstName = { + * first: 'alice', + * second: 'jake', + * third: 'alice', + * }; + * R.invert(raceResultsByFirstName); + * //=> { 'alice': ['first', 'third'], 'jake':['second'] } + */ + var invert = _curry1(function invert(obj) { + var props = keys(obj); + var len = props.length; + var idx = 0; + var out = {}; + while (idx < len) { + var key = props[idx]; + var val = obj[key]; + var list = _has(val, out) ? out[val] : out[val] = []; + list[list.length] = key; + idx += 1; + } + return out; + }); + + /** + * Returns a new object with the keys of the given object + * as values, and the values of the given object as keys. + * + * @func + * @memberOf R + * @category Object + * @sig {s: x} -> {x: s} + * @param {Object} obj The object or array to invert + * @return {Object} out A new object + * @example + * + * var raceResults = { + * first: 'alice', + * second: 'jake' + * }; + * R.invertObj(raceResults); + * //=> { 'alice': 'first', 'jake':'second' } + * + * // Alternatively: + * var raceResults = ['alice', 'jake']; + * R.invertObj(raceResults); + * //=> { 'alice': '0', 'jake':'1' } + */ + var invertObj = _curry1(function invertObj(obj) { + var props = keys(obj); + var len = props.length; + var idx = 0; + var out = {}; + while (idx < len) { + var key = props[idx]; + out[obj[key]] = key; + idx += 1; + } + return out; + }); + + /** + * Returns the last element of the given list or string. + * + * @func + * @memberOf R + * @category List + * @see R.init, R.head, R.tail + * @sig [a] -> a | Undefined + * @sig String -> String + * @param {*} list + * @return {*} + * @example + * + * R.last(['fi', 'fo', 'fum']); //=> 'fum' + * R.last([]); //=> undefined + * + * R.last('abc'); //=> 'c' + * R.last(''); //=> '' + */ + var last = nth(-1); + + /** + * Returns the position of the last occurrence of an item in + * an array, or -1 if the item is not included in the array. + * `R.equals` is used to determine equality. + * + * @func + * @memberOf R + * @category List + * @sig a -> [a] -> Number + * @param {*} target The item to find. + * @param {Array} xs The array to search in. + * @return {Number} the index of the target, or -1 if the target is not found. + * @see R.indexOf + * @example + * + * R.lastIndexOf(3, [-1,3,3,0,1,2,3,4]); //=> 6 + * R.lastIndexOf(10, [1,2,3,4]); //=> -1 + */ + var lastIndexOf = _curry2(function lastIndexOf(target, xs) { + if (_hasMethod('lastIndexOf', xs)) { + return xs.lastIndexOf(target); + } else { + var idx = xs.length - 1; + while (idx >= 0) { + if (equals(xs[idx], target)) { + return idx; + } + idx -= 1; + } + return -1; + } + }); + + /** + * Returns a new list, constructed by applying the supplied function to every element of the + * supplied list. + * + * Note: `R.map` does not skip deleted or unassigned indices (sparse arrays), unlike the + * native `Array.prototype.map` method. For more details on this behavior, see: + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map#Description + * + * Acts as a transducer if a transformer is given in list position. + * @see R.transduce + * + * @func + * @memberOf R + * @category List + * @sig (a -> b) -> [a] -> [b] + * @param {Function} fn The function to be called on every element of the input `list`. + * @param {Array} list The list to be iterated over. + * @return {Array} The new list. + * @example + * + * var double = function(x) { + * return x * 2; + * }; + * + * R.map(double, [1, 2, 3]); //=> [2, 4, 6] + */ + var map = _curry2(_dispatchable('map', _xmap, _map)); + + /** + * Map, but for objects. Creates an object with the same keys as `obj` and values + * generated by running each property of `obj` through `fn`. `fn` is passed one argument: + * *(value)*. + * + * @func + * @memberOf R + * @category Object + * @sig (v -> v) -> {k: v} -> {k: v} + * @param {Function} fn A function called for each property in `obj`. Its return value will + * become a new property on the return object. + * @param {Object} obj The object to iterate over. + * @return {Object} A new object with the same keys as `obj` and values that are the result + * of running each property through `fn`. + * @example + * + * var values = { x: 1, y: 2, z: 3 }; + * var double = function(num) { + * return num * 2; + * }; + * + * R.mapObj(double, values); //=> { x: 2, y: 4, z: 6 } + */ + var mapObj = _curry2(function mapObj(fn, obj) { + return _reduce(function (acc, key) { + acc[key] = fn(obj[key]); + return acc; + }, {}, keys(obj)); + }); + + /** + * Like `mapObj`, but but passes additional arguments to the predicate function. The + * predicate function is passed three arguments: *(value, key, obj)*. + * + * @func + * @memberOf R + * @category Object + * @sig (v, k, {k: v} -> v) -> {k: v} -> {k: v} + * @param {Function} fn A function called for each property in `obj`. Its return value will + * become a new property on the return object. + * @param {Object} obj The object to iterate over. + * @return {Object} A new object with the same keys as `obj` and values that are the result + * of running each property through `fn`. + * @example + * + * var values = { x: 1, y: 2, z: 3 }; + * var prependKeyAndDouble = function(num, key, obj) { + * return key + (num * 2); + * }; + * + * R.mapObjIndexed(prependKeyAndDouble, values); //=> { x: 'x2', y: 'y4', z: 'z6' } + */ + var mapObjIndexed = _curry2(function mapObjIndexed(fn, obj) { + return _reduce(function (acc, key) { + acc[key] = fn(obj[key], key, obj); + return acc; + }, {}, keys(obj)); + }); + + /** + * Returns `true` if no elements of the list match the predicate, + * `false` otherwise. + * + * @func + * @memberOf R + * @category List + * @sig (a -> Boolean) -> [a] -> Boolean + * @param {Function} fn The predicate function. + * @param {Array} list The array to consider. + * @return {Boolean} `true` if the predicate is not satisfied by every element, `false` otherwise. + * @see R.all, R.any + * @example + * + * R.none(R.isNaN, [1, 2, 3]); //=> true + * R.none(R.isNaN, [1, 2, 3, NaN]); //=> false + */ + var none = _curry2(_complement(_dispatchable('any', _xany, any))); + + /** + * A function that returns the first truthy of two arguments otherwise the + * last argument. Note that this is NOT short-circuited, meaning that if + * expressions are passed they are both evaluated. + * + * Dispatches to the `or` method of the first argument if applicable. + * + * @func + * @memberOf R + * @category Logic + * @sig * -> * -> * + * @param {*} a any value + * @param {*} b any other value + * @return {*} the first truthy argument, otherwise the last argument. + * @see R.either + * @example + * + * R.or(false, true); //=> true + * R.or(0, []); //=> [] + * R.or(null, ''); => '' + */ + var or = _curry2(function or(a, b) { + return _hasMethod('or', a) ? a.or(b) : a || b; + }); + + /** + * Accepts as its arguments a function and any number of values and returns a function that, + * when invoked, calls the original function with all of the values prepended to the + * original function's arguments list. In some libraries this function is named `applyLeft`. + * + * @func + * @memberOf R + * @category Function + * @sig (a -> b -> ... -> i -> j -> ... -> m -> n) -> a -> b-> ... -> i -> (j -> ... -> m -> n) + * @param {Function} fn The function to invoke. + * @param {...*} [args] Arguments to prepend to `fn` when the returned function is invoked. + * @return {Function} A new function wrapping `fn`. When invoked, it will call `fn` + * with `args` prepended to `fn`'s arguments list. + * @example + * + * var multiply = function(a, b) { return a * b; }; + * var double = R.partial(multiply, 2); + * double(2); //=> 4 + * + * var greet = function(salutation, title, firstName, lastName) { + * return salutation + ', ' + title + ' ' + firstName + ' ' + lastName + '!'; + * }; + * var sayHello = R.partial(greet, 'Hello'); + * var sayHelloToMs = R.partial(sayHello, 'Ms.'); + * sayHelloToMs('Jane', 'Jones'); //=> 'Hello, Ms. Jane Jones!' + */ + var partial = curry(_createPartialApplicator(_concat)); + + /** + * Accepts as its arguments a function and any number of values and returns a function that, + * when invoked, calls the original function with all of the values appended to the original + * function's arguments list. + * + * Note that `partialRight` is the opposite of `partial`: `partialRight` fills `fn`'s arguments + * from the right to the left. In some libraries this function is named `applyRight`. + * + * @func + * @memberOf R + * @category Function + * @sig (a -> b-> ... -> i -> j -> ... -> m -> n) -> j -> ... -> m -> n -> (a -> b-> ... -> i) + * @param {Function} fn The function to invoke. + * @param {...*} [args] Arguments to append to `fn` when the returned function is invoked. + * @return {Function} A new function wrapping `fn`. When invoked, it will call `fn` with + * `args` appended to `fn`'s arguments list. + * @example + * + * var greet = function(salutation, title, firstName, lastName) { + * return salutation + ', ' + title + ' ' + firstName + ' ' + lastName + '!'; + * }; + * var greetMsJaneJones = R.partialRight(greet, 'Ms.', 'Jane', 'Jones'); + * + * greetMsJaneJones('Hello'); //=> 'Hello, Ms. Jane Jones!' + */ + var partialRight = curry(_createPartialApplicator(flip(_concat))); + + /** + * Takes a predicate and a list and returns the pair of lists of + * elements which do and do not satisfy the predicate, respectively. + * + * @func + * @memberOf R + * @category List + * @sig (a -> Boolean) -> [a] -> [[a],[a]] + * @param {Function} pred A predicate to determine which array the element belongs to. + * @param {Array} list The array to partition. + * @return {Array} A nested array, containing first an array of elements that satisfied the predicate, + * and second an array of elements that did not satisfy. + * @example + * + * R.partition(R.contains('s'), ['sss', 'ttt', 'foo', 'bars']); + * //=> [ [ 'sss', 'bars' ], [ 'ttt', 'foo' ] ] + */ + var partition = _curry2(function partition(pred, list) { + return _reduce(function (acc, elt) { + var xs = acc[pred(elt) ? 0 : 1]; + xs[xs.length] = elt; + return acc; + }, [ + [], + [] + ], list); + }); + + /** + * Determines whether a nested path on an object has a specific value, + * in `R.equals` terms. Most likely used to filter a list. + * + * @func + * @memberOf R + * @category Relation + * @sig [String] -> * -> {String: *} -> Boolean + * @param {Array} path The path of the nested property to use + * @param {*} val The value to compare the nested property with + * @param {Object} obj The object to check the nested property in + * @return {Boolean} `true` if the value equals the nested object property, + * `false` otherwise. + * @example + * + * var user1 = { address: { zipCode: 90210 } }; + * var user2 = { address: { zipCode: 55555 } }; + * var user3 = { name: 'Bob' }; + * var users = [ user1, user2, user3 ]; + * var isFamous = R.pathEq(['address', 'zipCode'], 90210); + * R.filter(isFamous, users); //=> [ user1 ] + */ + var pathEq = _curry3(function pathEq(_path, val, obj) { + return equals(path(_path, obj), val); + }); + + /** + * Returns a new list by plucking the same named property off all objects in the list supplied. + * + * @func + * @memberOf R + * @category List + * @sig k -> [{k: v}] -> [v] + * @param {Number|String} key The key name to pluck off of each object. + * @param {Array} list The array to consider. + * @return {Array} The list of values for the given key. + * @example + * + * R.pluck('a')([{a: 1}, {a: 2}]); //=> [1, 2] + * R.pluck(0)([[1, 2], [3, 4]]); //=> [1, 3] + */ + var pluck = _curry2(function pluck(p, list) { + return map(prop(p), list); + }); + + /** + * Returns `true` if the specified object property is equal, in `R.equals` + * terms, to the given value; `false` otherwise. + * + * @func + * @memberOf R + * @category Relation + * @sig String -> a -> Object -> Boolean + * @param {String} name + * @param {*} val + * @param {*} obj + * @return {Boolean} + * @see R.equals, R.propSatisfies + * @example + * + * var abby = {name: 'Abby', age: 7, hair: 'blond'}; + * var fred = {name: 'Fred', age: 12, hair: 'brown'}; + * var rusty = {name: 'Rusty', age: 10, hair: 'brown'}; + * var alois = {name: 'Alois', age: 15, disposition: 'surly'}; + * var kids = [abby, fred, rusty, alois]; + * var hasBrownHair = R.propEq('hair', 'brown'); + * R.filter(hasBrownHair, kids); //=> [fred, rusty] + */ + var propEq = _curry3(function propEq(name, val, obj) { + return propSatisfies(equals(val), name, obj); + }); + + /** + * Returns `true` if the specified object property is of the given type; + * `false` otherwise. + * + * @func + * @memberOf R + * @category Type + * @sig Type -> String -> Object -> Boolean + * @param {Function} type + * @param {String} name + * @param {*} obj + * @return {Boolean} + * @see R.is + * @see R.propSatisfies + * @example + * + * R.propIs(Number, 'x', {x: 1, y: 2}); //=> true + * R.propIs(Number, 'x', {x: 'foo'}); //=> false + * R.propIs(Number, 'x', {}); //=> false + */ + var propIs = _curry3(function propIs(type, name, obj) { + return propSatisfies(is(type), name, obj); + }); + + /** + * Returns a single item by iterating through the list, successively calling the iterator + * function and passing it an accumulator value and the current value from the array, and + * then passing the result to the next call. + * + * The iterator function receives two values: *(acc, value)*. It may use `R.reduced` to + * shortcut the iteration. + * + * Note: `R.reduce` does not skip deleted or unassigned indices (sparse arrays), unlike + * the native `Array.prototype.reduce` method. For more details on this behavior, see: + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce#Description + * @see R.reduced + * + * @func + * @memberOf R + * @category List + * @sig (a,b -> a) -> a -> [b] -> a + * @param {Function} fn The iterator function. Receives two values, the accumulator and the + * current element from the array. + * @param {*} acc The accumulator value. + * @param {Array} list The list to iterate over. + * @return {*} The final, accumulated value. + * @example + * + * var numbers = [1, 2, 3]; + * var add = function(a, b) { + * return a + b; + * }; + * + * R.reduce(add, 10, numbers); //=> 16 + */ + var reduce = _curry3(_reduce); + + /** + * Similar to `filter`, except that it keeps only values for which the given predicate + * function returns falsy. The predicate function is passed one argument: *(value)*. + * + * Acts as a transducer if a transformer is given in list position. + * @see R.transduce + * + * @func + * @memberOf R + * @category List + * @sig (a -> Boolean) -> [a] -> [a] + * @param {Function} fn The function called per iteration. + * @param {Array} list The collection to iterate over. + * @return {Array} The new filtered array. + * @see R.filter + * @example + * + * var isOdd = function(n) { + * return n % 2 === 1; + * }; + * R.reject(isOdd, [1, 2, 3, 4]); //=> [2, 4] + */ + var reject = _curry2(function reject(fn, list) { + return filter(_complement(fn), list); + }); + + /** + * Returns a fixed list of size `n` containing a specified identical value. + * + * @func + * @memberOf R + * @category List + * @sig a -> n -> [a] + * @param {*} value The value to repeat. + * @param {Number} n The desired size of the output list. + * @return {Array} A new array containing `n` `value`s. + * @example + * + * R.repeat('hi', 5); //=> ['hi', 'hi', 'hi', 'hi', 'hi'] + * + * var obj = {}; + * var repeatedObjs = R.repeat(obj, 5); //=> [{}, {}, {}, {}, {}] + * repeatedObjs[0] === repeatedObjs[1]; //=> true + */ + var repeat = _curry2(function repeat(value, n) { + return times(always(value), n); + }); + + /** + * Returns the elements of the given list or string (or object with a `slice` + * method) from `fromIndex` (inclusive) to `toIndex` (exclusive). + * + * @func + * @memberOf R + * @category List + * @sig Number -> Number -> [a] -> [a] + * @sig Number -> Number -> String -> String + * @param {Number} fromIndex The start index (inclusive). + * @param {Number} toIndex The end index (exclusive). + * @param {*} list + * @return {*} + * @example + * + * R.slice(1, 3, ['a', 'b', 'c', 'd']); //=> ['b', 'c'] + * R.slice(1, Infinity, ['a', 'b', 'c', 'd']); //=> ['b', 'c', 'd'] + * R.slice(0, -1, ['a', 'b', 'c', 'd']); //=> ['a', 'b', 'c'] + * R.slice(-3, -1, ['a', 'b', 'c', 'd']); //=> ['b', 'c'] + * R.slice(0, 3, 'ramda'); //=> 'ram' + */ + var slice = _curry3(_checkForMethod('slice', function slice(fromIndex, toIndex, list) { + return Array.prototype.slice.call(list, fromIndex, toIndex); + })); + + /** + * Splits a collection into slices of the specified length. + * + * @func + * @memberOf R + * @category List + * @sig Number -> [a] -> [[a]] + * @sig Number -> String -> [String] + * @param {Number} n + * @param {Array} list + * @return {Array} + * @example + * + * R.splitEvery(3, [1, 2, 3, 4, 5, 6, 7]); //=> [[1, 2, 3], [4, 5, 6], [7]] + * R.splitEvery(3, 'foobarbaz'); //=> ['foo', 'bar', 'baz'] + */ + var splitEvery = _curry2(function splitEvery(n, list) { + if (n <= 0) { + throw new Error('First argument to splitEvery must be a positive integer'); + } + var result = []; + var idx = 0; + while (idx < list.length) { + result.push(slice(idx, idx += n, list)); + } + return result; + }); + + /** + * Adds together all the elements of a list. + * + * @func + * @memberOf R + * @category Math + * @sig [Number] -> Number + * @param {Array} list An array of numbers + * @return {Number} The sum of all the numbers in the list. + * @see R.reduce + * @example + * + * R.sum([2,4,6,8,100,1]); //=> 121 + */ + var sum = reduce(add, 0); + + /** + * Returns all but the first element of the given list or string (or object + * with a `tail` method). + * + * @func + * @memberOf R + * @category List + * @see R.head, R.init, R.last + * @sig [a] -> [a] + * @sig String -> String + * @param {*} list + * @return {*} + * @example + * + * R.tail([1, 2, 3]); //=> [2, 3] + * R.tail([1, 2]); //=> [2] + * R.tail([1]); //=> [] + * R.tail([]); //=> [] + * + * R.tail('abc'); //=> 'bc' + * R.tail('ab'); //=> 'b' + * R.tail('a'); //=> '' + * R.tail(''); //=> '' + */ + var tail = _checkForMethod('tail', slice(1, Infinity)); + + /** + * Returns the first `n` elements of the given list, string, or + * transducer/transformer (or object with a `take` method). + * + * @func + * @memberOf R + * @category List + * @sig Number -> [a] -> [a] + * @sig Number -> String -> String + * @param {Number} n + * @param {*} list + * @return {*} + * @see R.drop + * @example + * + * R.take(1, ['foo', 'bar', 'baz']); //=> ['foo'] + * R.take(2, ['foo', 'bar', 'baz']); //=> ['foo', 'bar'] + * R.take(3, ['foo', 'bar', 'baz']); //=> ['foo', 'bar', 'baz'] + * R.take(4, ['foo', 'bar', 'baz']); //=> ['foo', 'bar', 'baz'] + * R.take(3, 'ramda'); //=> 'ram' + * + * var personnel = [ + * 'Dave Brubeck', + * 'Paul Desmond', + * 'Eugene Wright', + * 'Joe Morello', + * 'Gerry Mulligan', + * 'Bob Bates', + * 'Joe Dodge', + * 'Ron Crotty' + * ]; + * + * var takeFive = R.take(5); + * takeFive(personnel); + * //=> ['Dave Brubeck', 'Paul Desmond', 'Eugene Wright', 'Joe Morello', 'Gerry Mulligan'] + */ + var take = _curry2(_dispatchable('take', _xtake, function take(n, xs) { + return slice(0, n < 0 ? Infinity : n, xs); + })); + + /** + * Returns a new list containing the first `n` elements of a given list, passing each value + * to the supplied predicate function, and terminating when the predicate function returns + * `false`. Excludes the element that caused the predicate function to fail. The predicate + * function is passed one argument: *(value)*. + * + * Acts as a transducer if a transformer is given in list position. + * @see R.transduce + * + * @func + * @memberOf R + * @category List + * @sig (a -> Boolean) -> [a] -> [a] + * @param {Function} fn The function called per iteration. + * @param {Array} list The collection to iterate over. + * @return {Array} A new array. + * @see R.dropWhile + * @example + * + * var isNotFour = function(x) { + * return !(x === 4); + * }; + * + * R.takeWhile(isNotFour, [1, 2, 3, 4]); //=> [1, 2, 3] + */ + var takeWhile = _curry2(_dispatchable('takeWhile', _xtakeWhile, function takeWhile(fn, list) { + var idx = 0, len = list.length; + while (idx < len && fn(list[idx])) { + idx += 1; + } + return _slice(list, 0, idx); + })); + + /** + * Initializes a transducer using supplied iterator function. Returns a single item by + * iterating through the list, successively calling the transformed iterator function and + * passing it an accumulator value and the current value from the array, and then passing + * the result to the next call. + * + * The iterator function receives two values: *(acc, value)*. It will be wrapped as a + * transformer to initialize the transducer. A transformer can be passed directly in place + * of an iterator function. In both cases, iteration may be stopped early with the + * `R.reduced` function. + * + * A transducer is a function that accepts a transformer and returns a transformer and can + * be composed directly. + * + * A transformer is an an object that provides a 2-arity reducing iterator function, step, + * 0-arity initial value function, init, and 1-arity result extraction function, result. + * The step function is used as the iterator function in reduce. The result function is used + * to convert the final accumulator into the return type and in most cases is R.identity. + * The init function can be used to provide an initial accumulator, but is ignored by transduce. + * + * The iteration is performed with R.reduce after initializing the transducer. + * + * @func + * @memberOf R + * @category List + * @see R.reduce, R.reduced, R.into + * @sig (c -> c) -> (a,b -> a) -> a -> [b] -> a + * @param {Function} xf The transducer function. Receives a transformer and returns a transformer. + * @param {Function} fn The iterator function. Receives two values, the accumulator and the + * current element from the array. Wrapped as transformer, if necessary, and used to + * initialize the transducer + * @param {*} acc The initial accumulator value. + * @param {Array} list The list to iterate over. + * @return {*} The final, accumulated value. + * @example + * + * var numbers = [1, 2, 3, 4]; + * var transducer = R.compose(R.map(R.add(1)), R.take(2)); + * + * R.transduce(transducer, R.flip(R.append), [], numbers); //=> [2, 3] + */ + var transduce = curryN(4, function transduce(xf, fn, acc, list) { + return _reduce(xf(typeof fn === 'function' ? _xwrap(fn) : fn), acc, list); + }); + + /** + * Combines two lists into a set (i.e. no duplicates) composed of the elements of each list. Duplication is + * determined according to the value returned by applying the supplied predicate to two list elements. + * + * @func + * @memberOf R + * @category Relation + * @sig (a,a -> Boolean) -> [a] -> [a] -> [a] + * @param {Function} pred A predicate used to test whether two items are equal. + * @param {Array} list1 The first list. + * @param {Array} list2 The second list. + * @return {Array} The first and second lists concatenated, with + * duplicates removed. + * @see R.union + * @example + * + * function cmp(x, y) { return x.a === y.a; } + * var l1 = [{a: 1}, {a: 2}]; + * var l2 = [{a: 1}, {a: 4}]; + * R.unionWith(cmp, l1, l2); //=> [{a: 1}, {a: 2}, {a: 4}] + */ + var unionWith = _curry3(function unionWith(pred, list1, list2) { + return uniqWith(pred, _concat(list1, list2)); + }); + + /** + * Returns a new list containing only one copy of each element in the original list. + * `R.equals` is used to determine equality. + * + * @func + * @memberOf R + * @category List + * @sig [a] -> [a] + * @param {Array} list The array to consider. + * @return {Array} The list of unique items. + * @example + * + * R.uniq([1, 1, 2, 1]); //=> [1, 2] + * R.uniq([1, '1']); //=> [1, '1'] + * R.uniq([[42], [42]]); //=> [[42]] + */ + var uniq = uniqWith(equals); + + /** + * Returns a new list by pulling every item at the first level of nesting out, and putting + * them in a new array. + * + * @func + * @memberOf R + * @category List + * @sig [a] -> [b] + * @param {Array} list The array to consider. + * @return {Array} The flattened list. + * @see R.flatten + * @example + * + * R.unnest([1, [2], [[3]]]); //=> [1, 2, [3]] + * R.unnest([[1, 2], [3, 4], [5, 6]]); //=> [1, 2, 3, 4, 5, 6] + */ + var unnest = _curry1(_makeFlat(false)); + + /** + * Accepts a function `fn` and any number of transformer functions and returns a new + * function. When the new function is invoked, it calls the function `fn` with parameters + * consisting of the result of calling each supplied handler on successive arguments to the + * new function. + * + * If more arguments are passed to the returned function than transformer functions, those + * arguments are passed directly to `fn` as additional parameters. If you expect additional + * arguments that don't need to be transformed, although you can ignore them, it's best to + * pass an identity function so that the new function reports the correct arity. + * + * @func + * @memberOf R + * @category Function + * @sig (x1 -> x2 -> ... -> z) -> ((a -> x1), (b -> x2), ...) -> (a -> b -> ... -> z) + * @param {Function} fn The function to wrap. + * @param {...Function} transformers A variable number of transformer functions + * @return {Function} The wrapped function. + * @example + * + * var double = function(y) { return y * 2; }; + * var square = function(x) { return x * x; }; + * var add = function(a, b) { return a + b; }; + * // Adds any number of arguments together + * var addAll = function() { + * return R.reduce(add, 0, arguments); + * }; + * + * // Basic example + * var addDoubleAndSquare = R.useWith(addAll, double, square); + * + * //≅ addAll(double(10), square(5)); + * addDoubleAndSquare(10, 5); //=> 45 + * + * // Example of passing more arguments than transformers + * //≅ addAll(double(10), square(5), 100); + * addDoubleAndSquare(10, 5, 100); //=> 145 + * + * // If there are extra _expected_ arguments that don't need to be transformed, although + * // you can ignore them, it might be best to pass in the identity function so that the new + * // function correctly reports arity. + * var addDoubleAndSquareWithExtraParams = R.useWith(addAll, double, square, R.identity); + * // addDoubleAndSquareWithExtraParams.length //=> 3 + * //≅ addAll(double(10), square(5), R.identity(100)); + * addDoubleAndSquare(10, 5, 100); //=> 145 + */ + /*, transformers */ + var useWith = curry(function useWith(fn) { + var transformers = _slice(arguments, 1); + var tlen = transformers.length; + return curry(_arity(tlen, function () { + var args = [], idx = 0; + while (idx < tlen) { + args[idx] = transformers[idx](arguments[idx]); + idx += 1; + } + return fn.apply(this, args.concat(_slice(arguments, tlen))); + })); + }); + + /** + * Takes a spec object and a test object; returns true if the test satisfies + * the spec, false otherwise. An object satisfies the spec if, for each of the + * spec's own properties, accessing that property of the object gives the same + * value (in `R.equals` terms) as accessing that property of the spec. + * + * `whereEq` is a specialization of [`where`](#where). + * + * @func + * @memberOf R + * @category Object + * @sig {String: *} -> {String: *} -> Boolean + * @param {Object} spec + * @param {Object} testObj + * @return {Boolean} + * @see R.where + * @example + * + * // pred :: Object -> Boolean + * var pred = R.whereEq({a: 1, b: 2}); + * + * pred({a: 1}); //=> false + * pred({a: 1, b: 2}); //=> true + * pred({a: 1, b: 2, c: 3}); //=> true + * pred({a: 1, b: 1}); //=> false + */ + var whereEq = _curry2(function whereEq(spec, testObj) { + return where(mapObj(equals, spec), testObj); + }); + + var _flatCat = function () { + var preservingReduced = function (xf) { + return { + '@@transducer/init': _xfBase.init, + '@@transducer/result': function (result) { + return xf['@@transducer/result'](result); + }, + '@@transducer/step': function (result, input) { + var ret = xf['@@transducer/step'](result, input); + return ret['@@transducer/reduced'] ? _forceReduced(ret) : ret; + } + }; + }; + return function _xcat(xf) { + var rxf = preservingReduced(xf); + return { + '@@transducer/init': _xfBase.init, + '@@transducer/result': function (result) { + return rxf['@@transducer/result'](result); + }, + '@@transducer/step': function (result, input) { + return !isArrayLike(input) ? _reduce(rxf, result, [input]) : _reduce(rxf, result, input); + } + }; + }; + }(); + + var _indexOf = function _indexOf(list, item, from) { + var idx = from; + while (idx < list.length) { + if (equals(list[idx], item)) { + return idx; + } + idx += 1; + } + return -1; + }; + + /** + * Create a predicate wrapper which will call a pick function (all/any) for each predicate + * + * @private + * @see R.all + * @see R.any + */ + // Call function immediately if given arguments + // Return a function which will call the predicates with the provided arguments + var _predicateWrap = function _predicateWrap(predPicker) { + return function (preds) { + var predIterator = function () { + var args = arguments; + return predPicker(function (predicate) { + return predicate.apply(null, args); + }, preds); + }; + return arguments.length > 1 ? // Call function immediately if given arguments + predIterator.apply(null, _slice(arguments, 1)) : // Return a function which will call the predicates with the provided arguments + _arity(Math.max.apply(Math, pluck('length', preds)), predIterator); + }; + }; + + var _xchain = _curry2(function _xchain(f, xf) { + return map(f, _flatCat(xf)); + }); + + /** + * Given a list of predicates, returns a new predicate that will be true exactly when all of them are. + * + * @func + * @memberOf R + * @category Logic + * @sig [(*... -> Boolean)] -> (*... -> Boolean) + * @param {Array} list An array of predicate functions + * @param {*} optional Any arguments to pass into the predicates + * @return {Function} a function that applies its arguments to each of + * the predicates, returning `true` if all are satisfied. + * @see R.anyPass + * @example + * + * var gt10 = function(x) { return x > 10; }; + * var even = function(x) { return x % 2 === 0}; + * var f = R.allPass([gt10, even]); + * f(11); //=> false + * f(12); //=> true + */ + var allPass = _curry1(_predicateWrap(all)); + + /** + * Given a list of predicates returns a new predicate that will be true exactly when any one of them is. + * + * @func + * @memberOf R + * @category Logic + * @sig [(*... -> Boolean)] -> (*... -> Boolean) + * @param {Array} list An array of predicate functions + * @param {*} optional Any arguments to pass into the predicates + * @return {Function} A function that applies its arguments to each of the predicates, returning + * `true` if all are satisfied. + * @see R.allPass + * @example + * + * var gt10 = function(x) { return x > 10; }; + * var even = function(x) { return x % 2 === 0}; + * var f = R.anyPass([gt10, even]); + * f(11); //=> true + * f(8); //=> true + * f(9); //=> false + */ + var anyPass = _curry1(_predicateWrap(any)); + + /** + * ap applies a list of functions to a list of values. + * + * @func + * @memberOf R + * @category Function + * @sig [f] -> [a] -> [f a] + * @param {Array} fns An array of functions + * @param {Array} vs An array of values + * @return {Array} An array of results of applying each of `fns` to all of `vs` in turn. + * @example + * + * R.ap([R.multiply(2), R.add(3)], [1,2,3]); //=> [2, 4, 6, 4, 5, 6] + */ + var ap = _curry2(function ap(fns, vs) { + return _hasMethod('ap', fns) ? fns.ap(vs) : _reduce(function (acc, fn) { + return _concat(acc, map(fn, vs)); + }, [], fns); + }); + + /** + * Returns the result of calling its first argument with the remaining + * arguments. This is occasionally useful as a converging function for + * `R.converge`: the left branch can produce a function while the right + * branch produces a value to be passed to that function as an argument. + * + * @func + * @memberOf R + * @category Function + * @sig (*... -> a),*... -> a + * @param {Function} fn The function to apply to the remaining arguments. + * @param {...*} args Any number of positional arguments. + * @return {*} + * @see R.apply + * @example + * + * var indentN = R.pipe(R.times(R.always(' ')), + * R.join(''), + * R.replace(/^(?!$)/gm)); + * + * var format = R.converge(R.call, + * R.pipe(R.prop('indent'), indentN), + * R.prop('value')); + * + * format({indent: 2, value: 'foo\nbar\nbaz\n'}); //=> ' foo\n bar\n baz\n' + */ + var call = curry(function call(fn) { + return fn.apply(this, _slice(arguments, 1)); + }); + + /** + * `chain` maps a function over a list and concatenates the results. + * This implementation is compatible with the + * Fantasy-land Chain spec, and will work with types that implement that spec. + * `chain` is also known as `flatMap` in some libraries + * + * @func + * @memberOf R + * @category List + * @sig (a -> [b]) -> [a] -> [b] + * @param {Function} fn + * @param {Array} list + * @return {Array} + * @example + * + * var duplicate = function(n) { + * return [n, n]; + * }; + * R.chain(duplicate, [1, 2, 3]); //=> [1, 1, 2, 2, 3, 3] + */ + var chain = _curry2(_dispatchable('chain', _xchain, function chain(fn, list) { + return unnest(map(fn, list)); + })); + + /** + * Turns a list of Functors into a Functor of a list, applying + * a mapping function to the elements of the list along the way. + * + * @func + * @memberOf R + * @category List + * @see R.commute + * @sig Functor f => (f a -> f b) -> (x -> f x) -> [f a] -> f [b] + * @param {Function} fn The transformation function + * @param {Function} of A function that returns the data type to return + * @param {Array} list An array of functors of the same type + * @return {*} + * @example + * + * R.commuteMap(R.map(R.add(10)), R.of, [[1], [2, 3]]); //=> [[11, 12], [11, 13]] + * R.commuteMap(R.map(R.add(10)), R.of, [[1, 2], [3]]); //=> [[11, 13], [12, 13]] + * R.commuteMap(R.map(R.add(10)), R.of, [[1], [2], [3]]); //=> [[11, 12, 13]] + * R.commuteMap(R.map(R.add(10)), Maybe.of, [Just(1), Just(2), Just(3)]); //=> Just([11, 12, 13]) + * R.commuteMap(R.map(R.add(10)), Maybe.of, [Just(1), Just(2), Nothing()]); //=> Nothing() + */ + var commuteMap = _curry3(function commuteMap(fn, of, list) { + function consF(acc, ftor) { + return ap(map(append, fn(ftor)), acc); + } + return _reduce(consF, of([]), list); + }); + + /** + * Wraps a constructor function inside a curried function that can be called with the same + * arguments and returns the same type. The arity of the function returned is specified + * to allow using variadic constructor functions. + * + * @func + * @memberOf R + * @category Function + * @sig Number -> (* -> {*}) -> (* -> {*}) + * @param {Number} n The arity of the constructor function. + * @param {Function} Fn The constructor function to wrap. + * @return {Function} A wrapped, curried constructor function. + * @example + * + * // Variadic constructor function + * var Widget = function() { + * this.children = Array.prototype.slice.call(arguments); + * // ... + * }; + * Widget.prototype = { + * // ... + * }; + * var allConfigs = [ + * // ... + * ]; + * R.map(R.constructN(1, Widget), allConfigs); // a list of Widgets + */ + var constructN = _curry2(function constructN(n, Fn) { + if (n > 10) { + throw new Error('Constructor with greater than ten arguments'); + } + if (n === 0) { + return function () { + return new Fn(); + }; + } + return curry(nAry(n, function ($0, $1, $2, $3, $4, $5, $6, $7, $8, $9) { + switch (arguments.length) { + case 1: + return new Fn($0); + case 2: + return new Fn($0, $1); + case 3: + return new Fn($0, $1, $2); + case 4: + return new Fn($0, $1, $2, $3); + case 5: + return new Fn($0, $1, $2, $3, $4); + case 6: + return new Fn($0, $1, $2, $3, $4, $5); + case 7: + return new Fn($0, $1, $2, $3, $4, $5, $6); + case 8: + return new Fn($0, $1, $2, $3, $4, $5, $6, $7); + case 9: + return new Fn($0, $1, $2, $3, $4, $5, $6, $7, $8); + case 10: + return new Fn($0, $1, $2, $3, $4, $5, $6, $7, $8, $9); + } + })); + }); + + /** + * Accepts at least three functions and returns a new function. When invoked, this new + * function will invoke the first function, `after`, passing as its arguments the + * results of invoking the subsequent functions with whatever arguments are passed to + * the new function. + * + * @func + * @memberOf R + * @category Function + * @sig (x1 -> x2 -> ... -> z) -> ((a -> b -> ... -> x1), (a -> b -> ... -> x2), ...) -> (a -> b -> ... -> z) + * @param {Function} after A function. `after` will be invoked with the return values of + * `fn1` and `fn2` as its arguments. + * @param {...Function} functions A variable number of functions. + * @return {Function} A new function. + * @example + * + * var add = function(a, b) { return a + b; }; + * var multiply = function(a, b) { return a * b; }; + * var subtract = function(a, b) { return a - b; }; + * + * //≅ multiply( add(1, 2), subtract(1, 2) ); + * R.converge(multiply, add, subtract)(1, 2); //=> -3 + * + * var add3 = function(a, b, c) { return a + b + c; }; + * R.converge(add3, multiply, add, subtract)(1, 2); //=> 4 + */ + var converge = curryN(3, function converge(after) { + var fns = _slice(arguments, 1); + return curryN(Math.max.apply(Math, pluck('length', fns)), function () { + var args = arguments; + var context = this; + return after.apply(context, _map(function (fn) { + return fn.apply(context, args); + }, fns)); + }); + }); + + /** + * Returns all but the first `n` elements of the given list, string, or + * transducer/transformer (or object with a `drop` method). + * + * @func + * @memberOf R + * @category List + * @see R.transduce + * @sig Number -> [a] -> [a] + * @sig Number -> String -> String + * @param {Number} n + * @param {*} list + * @return {*} + * @see R.take + * @example + * + * R.drop(1, ['foo', 'bar', 'baz']); //=> ['bar', 'baz'] + * R.drop(2, ['foo', 'bar', 'baz']); //=> ['baz'] + * R.drop(3, ['foo', 'bar', 'baz']); //=> [] + * R.drop(4, ['foo', 'bar', 'baz']); //=> [] + * R.drop(3, 'ramda'); //=> 'da' + */ + var drop = _curry2(_dispatchable('drop', _xdrop, function drop(n, xs) { + return slice(Math.max(0, n), Infinity, xs); + })); + + /** + * Returns a list containing all but the last `n` elements of the given `list`. + * + * @func + * @memberOf R + * @category List + * @sig Number -> [a] -> [a] + * @sig Number -> String -> String + * @param {Number} n The number of elements of `xs` to skip. + * @param {Array} xs The collection to consider. + * @return {Array} + * @see R.takeLast + * @example + * + * R.dropLast(1, ['foo', 'bar', 'baz']); //=> ['foo', 'bar'] + * R.dropLast(2, ['foo', 'bar', 'baz']); //=> ['foo'] + * R.dropLast(3, ['foo', 'bar', 'baz']); //=> [] + * R.dropLast(4, ['foo', 'bar', 'baz']); //=> [] + * R.dropLast(3, 'ramda'); //=> 'ra' + */ + var dropLast = _curry2(function dropLast(n, xs) { + return take(n < xs.length ? xs.length - n : 0, xs); + }); + + /** + * Returns a new list without any consecutively repeating elements. Equality is + * determined by applying the supplied predicate two consecutive elements. + * The first element in a series of equal element is the one being preserved. + * + * Acts as a transducer if a transformer is given in list position. + * @see R.transduce + * + * @func + * @memberOf R + * @category List + * @sig (a, a -> Boolean) -> [a] -> [a] + * @param {Function} pred A predicate used to test whether two items are equal. + * @param {Array} list The array to consider. + * @return {Array} `list` without repeating elements. + * @example + * + * function lengthEq(x, y) { return Math.abs(x) === Math.abs(y); }; + * var l = [1, -1, 1, 3, 4, -4, -4, -5, 5, 3, 3]; + * R.dropRepeatsWith(lengthEq, l); //=> [1, 3, 4, -5, 3] + */ + var dropRepeatsWith = _curry2(_dispatchable('dropRepeatsWith', _xdropRepeatsWith, function dropRepeatsWith(pred, list) { + var result = []; + var idx = 1; + var len = list.length; + if (len !== 0) { + result[0] = list[0]; + while (idx < len) { + if (!pred(last(result), list[idx])) { + result[result.length] = list[idx]; + } + idx += 1; + } + } + return result; + })); + + /** + * Reports whether two objects have the same value, in `R.equals` terms, + * for the specified property. Useful as a curried predicate. + * + * @func + * @memberOf R + * @category Object + * @sig k -> {k: v} -> {k: v} -> Boolean + * @param {String} prop The name of the property to compare + * @param {Object} obj1 + * @param {Object} obj2 + * @return {Boolean} + * + * @example + * + * var o1 = { a: 1, b: 2, c: 3, d: 4 }; + * var o2 = { a: 10, b: 20, c: 3, d: 40 }; + * R.eqProps('a', o1, o2); //=> false + * R.eqProps('c', o1, o2); //=> true + */ + var eqProps = _curry3(function eqProps(prop, obj1, obj2) { + return equals(obj1[prop], obj2[prop]); + }); + + /** + * Returns the position of the first occurrence of an item in an array, + * or -1 if the item is not included in the array. `R.equals` is used to + * determine equality. + * + * @func + * @memberOf R + * @category List + * @sig a -> [a] -> Number + * @param {*} target The item to find. + * @param {Array} xs The array to search in. + * @return {Number} the index of the target, or -1 if the target is not found. + * @see R.lastIndexOf + * @example + * + * R.indexOf(3, [1,2,3,4]); //=> 2 + * R.indexOf(10, [1,2,3,4]); //=> -1 + */ + var indexOf = _curry2(function indexOf(target, xs) { + return _hasMethod('indexOf', xs) ? xs.indexOf(target) : _indexOf(xs, target, 0); + }); + + /** + * Returns all but the last element of the given list or string. + * + * @func + * @memberOf R + * @category List + * @see R.last, R.head, R.tail + * @sig [a] -> [a] + * @sig String -> String + * @param {*} list + * @return {*} + * @example + * + * R.init([1, 2, 3]); //=> [1, 2] + * R.init([1, 2]); //=> [1] + * R.init([1]); //=> [] + * R.init([]); //=> [] + * + * R.init('abc'); //=> 'ab' + * R.init('ab'); //=> 'a' + * R.init('a'); //=> '' + * R.init(''); //=> '' + */ + var init = slice(0, -1); + + /** + * Returns `true` if all elements are unique, in `R.equals` terms, + * otherwise `false`. + * + * @func + * @memberOf R + * @category List + * @sig [a] -> Boolean + * @param {Array} list The array to consider. + * @return {Boolean} `true` if all elements are unique, else `false`. + * @example + * + * R.isSet(['1', 1]); //=> true + * R.isSet([1, 1]); //=> false + * R.isSet([[42], [42]]); //=> false + */ + var isSet = _curry1(function isSet(list) { + var len = list.length; + var idx = 0; + while (idx < len) { + if (_indexOf(list, list[idx], idx + 1) >= 0) { + return false; + } + idx += 1; + } + return true; + }); + + /** + * Returns a lens for the given getter and setter functions. The getter "gets" + * the value of the focus; the setter "sets" the value of the focus. The setter + * should not mutate the data structure. + * + * @func + * @memberOf R + * @category Object + * @typedef Lens s a = Functor f => (a -> f a) -> s -> f s + * @sig (s -> a) -> ((a, s) -> s) -> Lens s a + * @param {Function} getter + * @param {Function} setter + * @return {Lens} + * @see R.view, R.set, R.over, R.lensIndex, R.lensProp + * @example + * + * var xLens = R.lens(R.prop('x'), R.assoc('x')); + * + * R.view(xLens, {x: 1, y: 2}); //=> 1 + * R.set(xLens, 4, {x: 1, y: 2}); //=> {x: 4, y: 2} + * R.over(xLens, R.negate, {x: 1, y: 2}); //=> {x: -1, y: 2} + */ + var lens = _curry2(function lens(getter, setter) { + return function (f) { + return function (s) { + return map(function (v) { + return setter(v, s); + }, f(getter(s))); + }; + }; + }); + + /** + * Returns a lens whose focus is the specified index. + * + * @func + * @memberOf R + * @category Object + * @typedef Lens s a = Functor f => (a -> f a) -> s -> f s + * @sig Number -> Lens s a + * @param {Number} n + * @return {Lens} + * @see R.view, R.set, R.over + * @example + * + * var headLens = R.lensIndex(0); + * + * R.view(headLens, ['a', 'b', 'c']); //=> 'a' + * R.set(headLens, 'x', ['a', 'b', 'c']); //=> ['x', 'b', 'c'] + * R.over(headLens, R.toUpper, ['a', 'b', 'c']); //=> ['A', 'b', 'c'] + */ + var lensIndex = _curry1(function lensIndex(n) { + return lens(nth(n), update(n)); + }); + + /** + * Returns a lens whose focus is the specified property. + * + * @func + * @memberOf R + * @category Object + * @typedef Lens s a = Functor f => (a -> f a) -> s -> f s + * @sig String -> Lens s a + * @param {String} k + * @return {Lens} + * @see R.view, R.set, R.over + * @example + * + * var xLens = R.lensProp('x'); + * + * R.view(xLens, {x: 1, y: 2}); //=> 1 + * R.set(xLens, 4, {x: 1, y: 2}); //=> {x: 4, y: 2} + * R.over(xLens, R.negate, {x: 1, y: 2}); //=> {x: -1, y: 2} + */ + var lensProp = _curry1(function lensProp(k) { + return lens(prop(k), assoc(k)); + }); + + /** + * "lifts" a function to be the specified arity, so that it may "map over" that many + * lists (or other Functors). + * + * @func + * @memberOf R + * @see R.lift + * @category Function + * @sig Number -> (*... -> *) -> ([*]... -> [*]) + * @param {Function} fn The function to lift into higher context + * @return {Function} The function `fn` applicable to mappable objects. + * @example + * + * var madd3 = R.liftN(3, R.curryN(3, function() { + * return R.reduce(R.add, 0, arguments); + * })); + * madd3([1,2,3], [1,2,3], [1]); //=> [3, 4, 5, 4, 5, 6, 5, 6, 7] + */ + var liftN = _curry2(function liftN(arity, fn) { + var lifted = curryN(arity, fn); + return curryN(arity, function () { + return _reduce(ap, map(lifted, arguments[0]), _slice(arguments, 1)); + }); + }); + + /** + * Returns the mean of the given list of numbers. + * + * @func + * @memberOf R + * @category Math + * @sig [Number] -> Number + * @param {Array} list + * @return {Number} + * @example + * + * R.mean([2, 7, 9]); //=> 6 + * R.mean([]); //=> NaN + */ + var mean = _curry1(function mean(list) { + return sum(list) / list.length; + }); + + /** + * Returns the median of the given list of numbers. + * + * @func + * @memberOf R + * @category Math + * @sig [Number] -> Number + * @param {Array} list + * @return {Number} + * @example + * + * R.median([2, 9, 7]); //=> 7 + * R.median([7, 2, 10, 9]); //=> 8 + * R.median([]); //=> NaN + */ + var median = _curry1(function median(list) { + var len = list.length; + if (len === 0) { + return NaN; + } + var width = 2 - len % 2; + var idx = (len - width) / 2; + return mean(_slice(list).sort(function (a, b) { + return a < b ? -1 : a > b ? 1 : 0; + }).slice(idx, idx + width)); + }); + + /** + * Merges a list of objects together into one object. + * + * @func + * @memberOf R + * @category List + * @sig [{k: v}] -> {k: v} + * @param {Array} list An array of objects + * @return {Object} A merged object. + * @see R.reduce + * @example + * + * R.mergeAll([{foo:1},{bar:2},{baz:3}]); //=> {foo:1,bar:2,baz:3} + * R.mergeAll([{foo:1},{foo:2},{bar:2}]); //=> {foo:2,bar:2} + */ + var mergeAll = _curry1(function mergeAll(list) { + return reduce(merge, {}, list); + }); + + /** + * Performs left-to-right function composition. The leftmost function may have + * any arity; the remaining functions must be unary. + * + * In some libraries this function is named `sequence`. + * + * @func + * @memberOf R + * @category Function + * @sig (((a, b, ..., n) -> o), (o -> p), ..., (x -> y), (y -> z)) -> (a -> b -> ... -> n -> z) + * @param {...Function} functions + * @return {Function} + * @see R.compose + * @example + * + * var f = R.pipe(Math.pow, R.negate, R.inc); + * + * f(3, 4); // -(3^4) + 1 + */ + var pipe = function pipe() { + if (arguments.length === 0) { + throw new Error('pipe requires at least one argument'); + } + return curryN(arguments[0].length, reduce(_pipe, arguments[0], tail(arguments))); + }; + + /** + * Performs left-to-right composition of one or more Promise-returning + * functions. The leftmost function may have any arity; the remaining + * functions must be unary. + * + * @func + * @memberOf R + * @category Function + * @sig ((a -> Promise b), (b -> Promise c), ..., (y -> Promise z)) -> (a -> Promise z) + * @param {...Function} functions + * @return {Function} + * @see R.composeP + * @example + * + * // followersForUser :: String -> Promise [User] + * var followersForUser = R.pipeP(db.getUserById, db.getFollowers); + */ + var pipeP = function pipeP() { + if (arguments.length === 0) { + throw new Error('pipeP requires at least one argument'); + } + return curryN(arguments[0].length, reduce(_pipeP, arguments[0], tail(arguments))); + }; + + /** + * Multiplies together all the elements of a list. + * + * @func + * @memberOf R + * @category Math + * @sig [Number] -> Number + * @param {Array} list An array of numbers + * @return {Number} The product of all the numbers in the list. + * @see R.reduce + * @example + * + * R.product([2,4,6,8,100,1]); //=> 38400 + */ + var product = reduce(multiply, 1); + + /** + * Reasonable analog to SQL `select` statement. + * + * @func + * @memberOf R + * @category Object + * @category Relation + * @sig [k] -> [{k: v}] -> [{k: v}] + * @param {Array} props The property names to project + * @param {Array} objs The objects to query + * @return {Array} An array of objects with just the `props` properties. + * @example + * + * var abby = {name: 'Abby', age: 7, hair: 'blond', grade: 2}; + * var fred = {name: 'Fred', age: 12, hair: 'brown', grade: 7}; + * var kids = [abby, fred]; + * R.project(['name', 'grade'], kids); //=> [{name: 'Abby', grade: 2}, {name: 'Fred', grade: 7}] + */ + // passing `identity` gives correct arity + var project = useWith(_map, pickAll, identity); + + /** + * Returns a new list containing the last `n` elements of the given list. + * If `n > list.length`, returns a list of `list.length` elements. + * + * @func + * @memberOf R + * @category List + * @sig Number -> [a] -> [a] + * @sig Number -> String -> String + * @param {Number} n The number of elements to return. + * @param {Array} xs The collection to consider. + * @return {Array} + * @see R.dropLast + * @example + * + * R.takeLast(1, ['foo', 'bar', 'baz']); //=> ['baz'] + * R.takeLast(2, ['foo', 'bar', 'baz']); //=> ['for', 'baz'] + * R.takeLast(3, ['foo', 'bar', 'baz']); //=> ['foo', 'bar', 'baz'] + * R.takeLast(4, ['foo', 'bar', 'baz']); //=> ['foo', 'bar', 'baz'] + * R.takeLast(3, 'ramda'); //=> 'mda' + */ + var takeLast = _curry2(function takeLast(n, xs) { + return drop(n >= 0 ? xs.length - n : 0, xs); + }); + + var _contains = function _contains(a, list) { + return _indexOf(list, a, 0) >= 0; + }; + + // mapPairs :: (Object, [String]) -> [String] + // Function, RegExp, user-defined types + var _toString = function _toString(x, seen) { + var recur = function recur(y) { + var xs = seen.concat([x]); + return _contains(y, xs) ? '' : _toString(y, xs); + }; + // mapPairs :: (Object, [String]) -> [String] + var mapPairs = function (obj, keys) { + return _map(function (k) { + return _quote(k) + ': ' + recur(obj[k]); + }, keys.slice().sort()); + }; + switch (Object.prototype.toString.call(x)) { + case '[object Arguments]': + return '(function() { return arguments; }(' + _map(recur, x).join(', ') + '))'; + case '[object Array]': + return '[' + _map(recur, x).concat(mapPairs(x, reject(test(/^\d+$/), keys(x)))).join(', ') + ']'; + case '[object Boolean]': + return typeof x === 'object' ? 'new Boolean(' + recur(x.valueOf()) + ')' : x.toString(); + case '[object Date]': + return 'new Date(' + _quote(_toISOString(x)) + ')'; + case '[object Null]': + return 'null'; + case '[object Number]': + return typeof x === 'object' ? 'new Number(' + recur(x.valueOf()) + ')' : 1 / x === -Infinity ? '-0' : x.toString(10); + case '[object String]': + return typeof x === 'object' ? 'new String(' + recur(x.valueOf()) + ')' : _quote(x); + case '[object Undefined]': + return 'undefined'; + default: + return typeof x.constructor === 'function' && x.constructor.name !== 'Object' && typeof x.toString === 'function' && x.toString() !== '[object Object]' ? x.toString() : // Function, RegExp, user-defined types + '{' + mapPairs(x, keys(x)).join(', ') + '}'; + } + }; + + /** + * Turns a list of Functors into a Functor of a list. + * + * @func + * @memberOf R + * @category List + * @see R.commuteMap + * @sig Functor f => (x -> f x) -> [f a] -> f [a] + * @param {Function} of A function that returns the data type to return + * @param {Array} list An array of functors of the same type + * @return {*} + * @example + * + * R.commute(R.of, [[1], [2, 3]]); //=> [[1, 2], [1, 3]] + * R.commute(R.of, [[1, 2], [3]]); //=> [[1, 3], [2, 3]] + * R.commute(R.of, [[1], [2], [3]]); //=> [[1, 2, 3]] + * R.commute(Maybe.of, [Just(1), Just(2), Just(3)]); //=> Just([1, 2, 3]) + * R.commute(Maybe.of, [Just(1), Just(2), Nothing()]); //=> Nothing() + */ + var commute = commuteMap(identity); + + /** + * Performs right-to-left function composition. The rightmost function may have + * any arity; the remaining functions must be unary. + * + * @func + * @memberOf R + * @category Function + * @sig ((y -> z), (x -> y), ..., (o -> p), ((a, b, ..., n) -> o)) -> (a -> b -> ... -> n -> z) + * @param {...Function} functions + * @return {Function} + * @see R.pipe + * @example + * + * var f = R.compose(R.inc, R.negate, Math.pow); + * + * f(3, 4); // -(3^4) + 1 + */ + var compose = function compose() { + if (arguments.length === 0) { + throw new Error('compose requires at least one argument'); + } + return pipe.apply(this, reverse(arguments)); + }; + + /** + * Returns the right-to-left Kleisli composition of the provided functions, + * each of which must return a value of a type supported by [`chain`](#chain). + * + * `R.composeK(h, g, f)` is equivalent to `R.compose(R.chain(h), R.chain(g), R.chain(f))`. + * + * @func + * @memberOf R + * @category Function + * @see R.pipeK + * @sig Chain m => ((y -> m z), (x -> m y), ..., (a -> m b)) -> (m a -> m z) + * @param {...Function} + * @return {Function} + * @example + * + * // parseJson :: String -> Maybe * + * // get :: String -> Object -> Maybe * + * + * // getStateCode :: Maybe String -> Maybe String + * var getStateCode = R.composeK( + * R.compose(Maybe.of, R.toUpper), + * get('state'), + * get('address'), + * get('user'), + * parseJson + * ); + * + * getStateCode(Maybe.of('{"user":{"address":{"state":"ny"}}}')); + * //=> Just('NY') + * getStateCode(Maybe.of('[Invalid JSON]')); + * //=> Nothing() + */ + var composeK = function composeK() { + return arguments.length === 0 ? identity : compose.apply(this, map(chain, arguments)); + }; + + /** + * Performs right-to-left composition of one or more Promise-returning + * functions. The rightmost function may have any arity; the remaining + * functions must be unary. + * + * @func + * @memberOf R + * @category Function + * @sig ((y -> Promise z), (x -> Promise y), ..., (a -> Promise b)) -> (a -> Promise z) + * @param {...Function} functions + * @return {Function} + * @see R.pipeP + * @example + * + * // followersForUser :: String -> Promise [User] + * var followersForUser = R.composeP(db.getFollowers, db.getUserById); + */ + var composeP = function composeP() { + if (arguments.length === 0) { + throw new Error('composeP requires at least one argument'); + } + return pipeP.apply(this, reverse(arguments)); + }; + + /** + * Wraps a constructor function inside a curried function that can be called with the same + * arguments and returns the same type. + * + * @func + * @memberOf R + * @category Function + * @sig (* -> {*}) -> (* -> {*}) + * @param {Function} Fn The constructor function to wrap. + * @return {Function} A wrapped, curried constructor function. + * @example + * + * // Constructor function + * var Widget = function(config) { + * // ... + * }; + * Widget.prototype = { + * // ... + * }; + * var allConfigs = [ + * // ... + * ]; + * R.map(R.construct(Widget), allConfigs); // a list of Widgets + */ + var construct = _curry1(function construct(Fn) { + return constructN(Fn.length, Fn); + }); + + /** + * Returns `true` if the specified value is equal, in `R.equals` terms, + * to at least one element of the given list; `false` otherwise. + * + * @func + * @memberOf R + * @category List + * @sig a -> [a] -> Boolean + * @param {Object} a The item to compare against. + * @param {Array} list The array to consider. + * @return {Boolean} `true` if the item is in the list, `false` otherwise. + * + * @example + * + * R.contains(3, [1, 2, 3]); //=> true + * R.contains(4, [1, 2, 3]); //=> false + * R.contains([42], [[42]]); //=> true + */ + var contains = _curry2(_contains); + + /** + * Finds the set (i.e. no duplicates) of all elements in the first list not contained in the second list. + * + * @func + * @memberOf R + * @category Relation + * @sig [a] -> [a] -> [a] + * @param {Array} list1 The first list. + * @param {Array} list2 The second list. + * @return {Array} The elements in `list1` that are not in `list2`. + * @see R.differenceWith + * @example + * + * R.difference([1,2,3,4], [7,6,5,4,3]); //=> [1,2] + * R.difference([7,6,5,4,3], [1,2,3,4]); //=> [7,6,5] + */ + var difference = _curry2(function difference(first, second) { + var out = []; + var idx = 0; + var firstLen = first.length; + while (idx < firstLen) { + if (!_contains(first[idx], second) && !_contains(first[idx], out)) { + out[out.length] = first[idx]; + } + idx += 1; + } + return out; + }); + + /** + * Returns a new list without any consecutively repeating elements. + * `R.equals` is used to determine equality. + * + * Acts as a transducer if a transformer is given in list position. + * @see R.transduce + * + * @func + * @memberOf R + * @category List + * @sig [a] -> [a] + * @param {Array} list The array to consider. + * @return {Array} `list` without repeating elements. + * @example + * + * R.dropRepeats([1, 1, 1, 2, 3, 4, 4, 2, 2]); //=> [1, 2, 3, 4, 2] + */ + var dropRepeats = _curry1(_dispatchable('dropRepeats', _xdropRepeatsWith(equals), dropRepeatsWith(equals))); + + /** + * Combines two lists into a set (i.e. no duplicates) composed of those elements common to both lists. + * + * @func + * @memberOf R + * @category Relation + * @sig [a] -> [a] -> [a] + * @param {Array} list1 The first list. + * @param {Array} list2 The second list. + * @see R.intersectionWith + * @return {Array} The list of elements found in both `list1` and `list2`. + * @example + * + * R.intersection([1,2,3,4], [7,6,5,4,3]); //=> [4, 3] + */ + var intersection = _curry2(function intersection(list1, list2) { + return uniq(_filter(flip(_contains)(list1), list2)); + }); + + /** + * "lifts" a function of arity > 1 so that it may "map over" an Array or + * other Functor. + * + * @func + * @memberOf R + * @see R.liftN + * @category Function + * @sig (*... -> *) -> ([*]... -> [*]) + * @param {Function} fn The function to lift into higher context + * @return {Function} The function `fn` applicable to mappable objects. + * @example + * + * var madd3 = R.lift(R.curry(function(a, b, c) { + * return a + b + c; + * })); + * madd3([1,2,3], [1,2,3], [1]); //=> [3, 4, 5, 4, 5, 6, 5, 6, 7] + * + * var madd5 = R.lift(R.curry(function(a, b, c, d, e) { + * return a + b + c + d + e; + * })); + * madd5([1,2], [3], [4, 5], [6], [7, 8]); //=> [21, 22, 22, 23, 22, 23, 23, 24] + */ + var lift = _curry1(function lift(fn) { + return liftN(fn.length, fn); + }); + + /** + * Returns a partial copy of an object omitting the keys specified. + * + * @func + * @memberOf R + * @category Object + * @sig [String] -> {String: *} -> {String: *} + * @param {Array} names an array of String property names to omit from the new object + * @param {Object} obj The object to copy from + * @return {Object} A new object with properties from `names` not on it. + * @see R.pick + * @example + * + * R.omit(['a', 'd'], {a: 1, b: 2, c: 3, d: 4}); //=> {b: 2, c: 3} + */ + var omit = _curry2(function omit(names, obj) { + var result = {}; + for (var prop in obj) { + if (!_contains(prop, names)) { + result[prop] = obj[prop]; + } + } + return result; + }); + + /** + * Returns the left-to-right Kleisli composition of the provided functions, + * each of which must return a value of a type supported by [`chain`](#chain). + * + * `R.pipeK(f, g, h)` is equivalent to `R.pipe(R.chain(f), R.chain(g), R.chain(h))`. + * + * @func + * @memberOf R + * @category Function + * @see R.composeK + * @sig Chain m => ((a -> m b), (b -> m c), ..., (y -> m z)) -> (m a -> m z) + * @param {...Function} + * @return {Function} + * @example + * + * // parseJson :: String -> Maybe * + * // get :: String -> Object -> Maybe * + * + * // getStateCode :: Maybe String -> Maybe String + * var getStateCode = R.pipeK( + * parseJson, + * get('user'), + * get('address'), + * get('state'), + * R.compose(Maybe.of, R.toUpper) + * ); + * + * getStateCode(Maybe.of('{"user":{"address":{"state":"ny"}}}')); + * //=> Just('NY') + * getStateCode(Maybe.of('[Invalid JSON]')); + * //=> Nothing() + */ + var pipeK = function pipeK() { + return composeK.apply(this, reverse(arguments)); + }; + + /** + * Returns the string representation of the given value. `eval`'ing the output + * should result in a value equivalent to the input value. Many of the built-in + * `toString` methods do not satisfy this requirement. + * + * If the given value is an `[object Object]` with a `toString` method other + * than `Object.prototype.toString`, this method is invoked with no arguments + * to produce the return value. This means user-defined constructor functions + * can provide a suitable `toString` method. For example: + * + * function Point(x, y) { + * this.x = x; + * this.y = y; + * } + * + * Point.prototype.toString = function() { + * return 'new Point(' + this.x + ', ' + this.y + ')'; + * }; + * + * R.toString(new Point(1, 2)); //=> 'new Point(1, 2)' + * + * @func + * @memberOf R + * @category String + * @sig * -> String + * @param {*} val + * @return {String} + * @example + * + * R.toString(42); //=> '42' + * R.toString('abc'); //=> '"abc"' + * R.toString([1, 2, 3]); //=> '[1, 2, 3]' + * R.toString({foo: 1, bar: 2, baz: 3}); //=> '{"bar": 2, "baz": 3, "foo": 1}' + * R.toString(new Date('2001-02-03T04:05:06Z')); //=> 'new Date("2001-02-03T04:05:06.000Z")' + */ + var toString = _curry1(function toString(val) { + return _toString(val, []); + }); + + /** + * Combines two lists into a set (i.e. no duplicates) composed of the + * elements of each list. + * + * @func + * @memberOf R + * @category Relation + * @sig [a] -> [a] -> [a] + * @param {Array} as The first list. + * @param {Array} bs The second list. + * @return {Array} The first and second lists concatenated, with + * duplicates removed. + * @example + * + * R.union([1, 2, 3], [2, 3, 4]); //=> [1, 2, 3, 4] + */ + var union = _curry2(compose(uniq, _concat)); + + /** + * Returns a new list containing only one copy of each element in the + * original list, based upon the value returned by applying the supplied + * function to each list element. Prefers the first item if the supplied + * function produces the same value on two items. `R.equals` is used for + * comparison. + * + * @func + * @memberOf R + * @category List + * @sig (a -> b) -> [a] -> [a] + * @param {Function} fn A function used to produce a value to use during comparisons. + * @param {Array} list The array to consider. + * @return {Array} The list of unique items. + * @example + * + * R.uniqBy(Math.abs, [-1, -5, 2, 10, 1, 2]); //=> [-1, -5, 2, 10] + */ + var uniqBy = _curry2(function uniqBy(fn, list) { + var idx = 0, applied = [], result = [], appliedItem, item; + while (idx < list.length) { + item = list[idx]; + appliedItem = fn(item); + if (!_contains(appliedItem, applied)) { + result.push(item); + applied.push(appliedItem); + } + idx += 1; + } + return result; + }); + + /** + * Turns a named method with a specified arity into a function + * that can be called directly supplied with arguments and a target object. + * + * The returned function is curried and accepts `arity + 1` parameters where + * the final parameter is the target object. + * + * @func + * @memberOf R + * @category Function + * @sig Number -> String -> (a -> b -> ... -> n -> Object -> *) + * @param {Number} arity Number of arguments the returned function should take + * before the target object. + * @param {Function} method Name of the method to call. + * @return {Function} A new curried function. + * @example + * + * var sliceFrom = R.invoker(1, 'slice'); + * sliceFrom(6, 'abcdefghijklm'); //=> 'ghijklm' + * var sliceFrom6 = R.invoker(2, 'slice')(6); + * sliceFrom6(8, 'abcdefghijklm'); //=> 'gh' + */ + var invoker = _curry2(function invoker(arity, method) { + return curryN(arity + 1, function () { + var target = arguments[arity]; + if (target != null && is(Function, target[method])) { + return target[method].apply(target, _slice(arguments, 0, arity)); + } + throw new TypeError(toString(target) + ' does not have a method named "' + method + '"'); + }); + }); + + /** + * Returns a string made by inserting the `separator` between each + * element and concatenating all the elements into a single string. + * + * @func + * @memberOf R + * @category List + * @sig String -> [a] -> String + * @param {Number|String} separator The string used to separate the elements. + * @param {Array} xs The elements to join into a string. + * @return {String} str The string made by concatenating `xs` with `separator`. + * @see R.split + * @example + * + * var spacer = R.join(' '); + * spacer(['a', 2, 3.4]); //=> 'a 2 3.4' + * R.join('|', [1, 2, 3]); //=> '1|2|3' + */ + var join = invoker(1, 'join'); + + /** + * Creates a new function that, when invoked, caches the result of calling `fn` for a given + * argument set and returns the result. Subsequent calls to the memoized `fn` with the same + * argument set will not result in an additional call to `fn`; instead, the cached result + * for that set of arguments will be returned. + * + * @func + * @memberOf R + * @category Function + * @sig (*... -> a) -> (*... -> a) + * @param {Function} fn The function to memoize. + * @return {Function} Memoized version of `fn`. + * @example + * + * var count = 0; + * var factorial = R.memoize(function(n) { + * count += 1; + * return R.product(R.range(1, n + 1)); + * }); + * factorial(5); //=> 120 + * factorial(5); //=> 120 + * factorial(5); //=> 120 + * count; //=> 1 + */ + var memoize = _curry1(function memoize(fn) { + var cache = {}; + return function () { + var key = toString(arguments); + if (!_has(key, cache)) { + cache[key] = fn.apply(this, arguments); + } + return cache[key]; + }; + }); + + /** + * Splits a string into an array of strings based on the given + * separator. + * + * @func + * @memberOf R + * @category String + * @sig String -> String -> [String] + * @param {String} sep The separator string. + * @param {String} str The string to separate into an array. + * @return {Array} The array of strings from `str` separated by `str`. + * @see R.join + * @example + * + * var pathComponents = R.split('/'); + * R.tail(pathComponents('/usr/local/bin/node')); //=> ['usr', 'local', 'bin', 'node'] + * + * R.split('.', 'a.b.c.xyz.d'); //=> ['a', 'b', 'c', 'xyz', 'd'] + */ + var split = invoker(1, 'split'); + + /** + * The lower case version of a string. + * + * @func + * @memberOf R + * @category String + * @sig String -> String + * @param {String} str The string to lower case. + * @return {String} The lower case version of `str`. + * @see R.toUpper + * @example + * + * R.toLower('XYZ'); //=> 'xyz' + */ + var toLower = invoker(0, 'toLowerCase'); + + /** + * The upper case version of a string. + * + * @func + * @memberOf R + * @category String + * @sig String -> String + * @param {String} str The string to upper case. + * @return {String} The upper case version of `str`. + * @see R.toLower + * @example + * + * R.toUpper('abc'); //=> 'ABC' + */ + var toUpper = invoker(0, 'toUpperCase'); + + var R = { + F: F, + T: T, + __: __, + add: add, + addIndex: addIndex, + adjust: adjust, + all: all, + allPass: allPass, + always: always, + and: and, + any: any, + anyPass: anyPass, + ap: ap, + aperture: aperture, + append: append, + apply: apply, + assoc: assoc, + assocPath: assocPath, + binary: binary, + bind: bind, + both: both, + call: call, + chain: chain, + clone: clone, + commute: commute, + commuteMap: commuteMap, + comparator: comparator, + complement: complement, + compose: compose, + composeK: composeK, + composeP: composeP, + concat: concat, + cond: cond, + construct: construct, + constructN: constructN, + contains: contains, + containsWith: containsWith, + converge: converge, + countBy: countBy, + createMapEntry: createMapEntry, + curry: curry, + curryN: curryN, + dec: dec, + defaultTo: defaultTo, + difference: difference, + differenceWith: differenceWith, + dissoc: dissoc, + dissocPath: dissocPath, + divide: divide, + drop: drop, + dropLast: dropLast, + dropLastWhile: dropLastWhile, + dropRepeats: dropRepeats, + dropRepeatsWith: dropRepeatsWith, + dropWhile: dropWhile, + either: either, + empty: empty, + eqProps: eqProps, + equals: equals, + evolve: evolve, + filter: filter, + find: find, + findIndex: findIndex, + findLast: findLast, + findLastIndex: findLastIndex, + flatten: flatten, + flip: flip, + forEach: forEach, + fromPairs: fromPairs, + functions: functions, + functionsIn: functionsIn, + groupBy: groupBy, + gt: gt, + gte: gte, + has: has, + hasIn: hasIn, + head: head, + identical: identical, + identity: identity, + ifElse: ifElse, + inc: inc, + indexOf: indexOf, + init: init, + insert: insert, + insertAll: insertAll, + intersection: intersection, + intersectionWith: intersectionWith, + intersperse: intersperse, + into: into, + invert: invert, + invertObj: invertObj, + invoker: invoker, + is: is, + isArrayLike: isArrayLike, + isEmpty: isEmpty, + isNil: isNil, + isSet: isSet, + join: join, + keys: keys, + keysIn: keysIn, + last: last, + lastIndexOf: lastIndexOf, + length: length, + lens: lens, + lensIndex: lensIndex, + lensProp: lensProp, + lift: lift, + liftN: liftN, + lt: lt, + lte: lte, + map: map, + mapAccum: mapAccum, + mapAccumRight: mapAccumRight, + mapObj: mapObj, + mapObjIndexed: mapObjIndexed, + match: match, + mathMod: mathMod, + max: max, + maxBy: maxBy, + mean: mean, + median: median, + memoize: memoize, + merge: merge, + mergeAll: mergeAll, + min: min, + minBy: minBy, + modulo: modulo, + multiply: multiply, + nAry: nAry, + negate: negate, + none: none, + not: not, + nth: nth, + nthArg: nthArg, + nthChar: nthChar, + nthCharCode: nthCharCode, + of: of, + omit: omit, + once: once, + or: or, + over: over, + partial: partial, + partialRight: partialRight, + partition: partition, + path: path, + pathEq: pathEq, + pick: pick, + pickAll: pickAll, + pickBy: pickBy, + pipe: pipe, + pipeK: pipeK, + pipeP: pipeP, + pluck: pluck, + prepend: prepend, + product: product, + project: project, + prop: prop, + propEq: propEq, + propIs: propIs, + propOr: propOr, + propSatisfies: propSatisfies, + props: props, + range: range, + reduce: reduce, + reduceRight: reduceRight, + reduced: reduced, + reject: reject, + remove: remove, + repeat: repeat, + replace: replace, + reverse: reverse, + scan: scan, + set: set, + slice: slice, + sort: sort, + sortBy: sortBy, + split: split, + splitEvery: splitEvery, + subtract: subtract, + sum: sum, + tail: tail, + take: take, + takeLast: takeLast, + takeLastWhile: takeLastWhile, + takeWhile: takeWhile, + tap: tap, + test: test, + times: times, + toLower: toLower, + toPairs: toPairs, + toPairsIn: toPairsIn, + toString: toString, + toUpper: toUpper, + transduce: transduce, + trim: trim, + type: type, + unapply: unapply, + unary: unary, + uncurryN: uncurryN, + unfold: unfold, + union: union, + unionWith: unionWith, + uniq: uniq, + uniqBy: uniqBy, + uniqWith: uniqWith, + unnest: unnest, + update: update, + useWith: useWith, + values: values, + valuesIn: valuesIn, + view: view, + where: where, + whereEq: whereEq, + wrap: wrap, + xprod: xprod, + zip: zip, + zipObj: zipObj, + zipWith: zipWith + }; + + /* TEST_ENTRY_POINT */ + + if (true) { + module.exports = R; + } else if (typeof define === 'function' && define.amd) { + define(function() { return R; }); + } else { + this.R = R; + } + + }.call(this)); + + +/***/ }), +/* 2 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + exports.default = functor; + + var _ramda = __webpack_require__(1); + + function functor(v) { + return (0, _ramda.is)(Function, v) ? v : function () { + return v; + }; + } + +/***/ }), +/* 3 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + + var _prependClass = __webpack_require__(4); + + var _prependClass2 = _interopRequireDefault(_prependClass); + + var _functor = __webpack_require__(2); + + var _functor2 = _interopRequireDefault(_functor); + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + + exports.default = { + prependClass: _prependClass2.default, + functor: _functor2.default + }; + +/***/ }), +/* 4 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + exports.default = prependClass; + + var _ramda = __webpack_require__(1); + + var _functor = __webpack_require__(2); + + var _functor2 = _interopRequireDefault(_functor); + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + + function prependClass(className) { + return (0, _ramda.mapObjIndexed)(function (value, key) { + if (key === 'class') { + var fn = (0, _functor2.default)(value); + + return function (d, i) { + var classNames = fn(d, i); + if (classNames !== className) { + return (0, _ramda.join)(' ', [className, classNames]); + } + return classNames; + }; + } + + return value; + }); + } + +/***/ }) +/******/ ]) +}); +; \ No newline at end of file diff --git a/packages/d3tooltip/dist/d3tooltip.min.js b/packages/d3tooltip/dist/d3tooltip.min.js new file mode 100644 index 00000000..ea7a676f --- /dev/null +++ b/packages/d3tooltip/dist/d3tooltip.min.js @@ -0,0 +1,2 @@ +!function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.d3tooltip=n():t.d3tooltip=n()}(this,function(){return function(t){function n(e){if(r[e])return r[e].exports;var u=r[e]={exports:{},id:e,loaded:!1};return t[e].call(u.exports,u,u.exports,n),u.loaded=!0,u.exports}var r={};return n.m=t,n.c=r,n.p="",n(0)}([function(t,n,r){"use strict";function e(t){return t&&t.__esModule?t:{default:t}}function u(t){function n(n){n.on({"mouseover.tip":function(n){var e=t.mouse(x),u=e[0],o=e[1],l=c||u+a.left,p=f||o-a.top;m.selectAll("div."+r).remove(),v=m.append("div").attr(s(r)(d)).style(i({position:"absolute","z-index":1001,left:l+"px",top:p+"px"},y)).html(function(){return g(n)})},"mousemove.tip":function(n){var r=t.mouse(x),e=r[0],u=r[1],i=c||e+a.left,o=f||u-a.top;v.style({left:i+"px",top:o+"px"}).html(function(){return g(n)})},"mouseout.tip":function(){return v.remove()}})}var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"tooltip",e=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},u=i({},p,e),c=u.left,f=u.top,a=u.offset,h=u.root,d={class:r},g=function(){return""},y={},v=void 0,m=h||t.select("body"),x=m.node();return n.attr=function(t){return(0,o.is)(Object,t)&&(d=i({},d,t)),this},n.style=function(t){return(0,o.is)(Object,t)&&(y=i({},y,t)),this},n.text=function(t){return g=l(t),this},n}n.__esModule=!0;var i=Object.assign||function(t){for(var n=1;n=arguments.length)?a=e[f]:(a=arguments[o],o+=1),i[f]=a,null!=a&&a["@@functional/placeholder"]===!0||(c-=1),f+=1}return c<=0?u.apply(this,i):r(c,t(n,i,u))}},l=function(t,n){for(var r=0,e=n.length,u=[];r=0&&"[object Array]"===Object.prototype.toString.call(t)},v=Number.isInteger||function(t){return t<<0===t},m=function(t){return"[object Number]"===Object.prototype.toString.call(t)},x=function(t){return"[object String]"===Object.prototype.toString.call(t)},w=function(t){return"function"==typeof t["@@transducer/step"]},b=function(t,n){for(var r=0,e=n.length,u=Array(e);r=r.length||n<-r.length)return r;var e=n<0?r.length:0,u=e+n,o=i(r);return o[u]=t(r[u]),o}),U=c(function(t){return function(){return t}}),D=f(function(t,n){for(var r=0,e=n.length-(t-1),u=new Array(e>=0?e:0);r=0&&t(n[r]);)r-=1;return M(n,0,r+1)}),at=f(function(t,n){return function(){return t.apply(this,arguments)||n.apply(this,arguments)}}),st=c(function(t){if(null!=t&&"function"==typeof t.empty)return t.empty();if(null!=t&&null!=typeof t.constructor&&"function"==typeof t.constructor.empty)return t.constructor.empty();switch(Object.prototype.toString.call(t)){case"[object Array]":return[];case"[object Object]":return{};case"[object String]":return""}}),lt=f(function t(n,r){var e,u,i,o={};for(u in r)e=n[u],i=typeof e,o[u]="function"===i?e(r[u]):"object"===i?t(n[u],r[u]):r[u];return o}),pt=c(function(t){for(var n=0,r=t.length,e={};nn}),dt=f(function(t,n){return t>=n}),gt=f(d),yt=f(function(t,n){return t in n}),vt=f(function(t,n){return t===n?0!==t||1/t===1/n:t!==t&&n!==n}),mt=c(g),xt=a(function(t,n,r){return nt(Math.max(t.length,n.length,r.length),function(){return t.apply(this,arguments)?n.apply(this,arguments):r.apply(this,arguments)})}),wt=R(1),bt=a(function(t,n,r){t=t=0?t:r.length;var e=M(r);return e.splice(t,0,n),e}),jt=a(function(t,n,r){return t=t=0?t:r.length,i(i(M(r,0,t),n),M(r,t))}),Ot=f(function(t,n){return null!=n&&n.constructor===t||n instanceof t}),St=c(function(t){return!!y(t)||!!t&&("object"==typeof t&&(!(t instanceof String)&&(1===t.nodeType?!!t.length:0===t.length||t.length>0&&(t.hasOwnProperty(0)&&t.hasOwnProperty(t.length-1)))))}),Et=c(function(t){return 0===Object(t).length}),Mt=c(function(t){return null==t}),At=function(){var t=!{toString:null}.propertyIsEnumerable("toString"),n=["constructor","valueOf","isPrototypeOf","toString","propertyIsEnumerable","hasOwnProperty","toLocaleString"],r=function(t,n){for(var r=0;r=0;)u=n[i],d(u,e)&&!r(o,u)&&(o[o.length]=u),i-=1;return o})}(),It=c(function(t){var n,r=[];for(n in t)r[r.length]=n;return r}),kt=c(function(t){return null!=t&&Ot(Number,t.length)?t.length:NaN}),Nt=f(function(t,n){return t=0;)i=t(i[0],r[e]),u[e]=i[1],e-=1;return[i[0],u]}),_t=f(function(t,n){return n.match(t)||[]}),qt=f(function(t,n){return v(t)?!v(n)||n<1?NaN:(t%n+n)%n:NaN}),Wt=f(function(t,n){return n>t?n:t}),Bt=a(function(t,n,r){return t(r)>t(n)?r:n}),Lt=f(function(t,n){for(var r={},e=At(t),u=0;u=0;)n=t(n,r[e]),e-=1;return n}),ln=c(E),pn=a(function(t,n,r){return i(M(r,0,Math.min(t,r.length)),M(r,Math.min(r.length,t+n)))}),hn=a(function(t,n,r){return r.replace(t,n)}),dn=c(function(t){return M(t).reverse()}),gn=a(function(t,n,r){for(var e=0,u=r.length,i=[n];eu?1:0})}),xn=f(function(t,n){return t-n}),wn=f(function(t,n){for(var r=n.length-1;r>=0&&t(n[r]);)r-=1;return M(n,r+1,1/0)}),bn=f(function(t,n){return t(n),n}),jn=f(function(t,n){return e(t).test(n)}),On=f(function(t,n){for(var r=Number(n),e=new Array(r),u=0;u=0;){if(e[c]===n)return u[c]===r;c-=1}for(e[e.length]=n,u[u.length]=r,c=o.length-1;c>=0;){var f=o[c];if(!d(f,r)||!t(r[f],n[f],e,u))return!1;c-=1}return e.pop(),u.pop(),!0}return!1},Zn=function(t,n){return null!=n&&!y(n)&&"function"==typeof n[t]},Gn=function(t){return function n(r){for(var e,u,i,o=[],c=0,f=r.length;c0?(this.n-=1,t):this.xf["@@transducer/step"](t,n)},f(function(n,r){return new t(n,r)})}(),er=function(){function t(t,n){this.xf=n,this.f=t}return t.prototype["@@transducer/init"]=k.init,t.prototype["@@transducer/result"]=k.result,t.prototype["@@transducer/step"]=function(t,n){if(this.f){if(this.f(n))return t;this.f=null}return this.xf["@@transducer/step"](t,n)},f(function(n,r){return new t(n,r)})}(),ur=function(){function t(t,n){this.xf=n,this.f=t,this.inputs={}}return t.prototype["@@transducer/init"]=k.init,t.prototype["@@transducer/result"]=function(t){var n;for(n in this.inputs)if(d(n,this.inputs)&&(t=this.xf["@@transducer/step"](t,this.inputs[n]),t["@@transducer/reduced"])){t=t["@@transducer/value"];break}return this.xf["@@transducer/result"](t)},t.prototype["@@transducer/step"]=function(t,n){var r=this.f(n);return this.inputs[r]=this.inputs[r]||[r,[]],this.inputs[r][1]=V(n,this.inputs[r][1]),t},f(function(n,r){return new t(n,r)})}(),ir=c(function(t){return nt(t.length,function(){var n=0,r=arguments[0],e=arguments[arguments.length-1],u=M(arguments);return u[0]=function(){var t=r.apply(this,i(arguments,[n,e]));return n+=1,t},t.apply(this,u)})}),or=f(Xn("all",tr,function(t,n){for(var r=0;r=0;){if(t(n[r]))return n[r];r-=1}})),xr=f(Xn("findLastIndex",_,function(t,n){for(var r=n.length-1;r>=0;){if(t(n[r]))return r;r-=1}return-1})),wr=c(Gn(!0)),br=c(function(t){return pr(function(n,r){var e=M(arguments);return e[0]=r,e[1]=n,t.apply(this,e)})}),jr=f(Kn("forEach",function(t,n){for(var r=n.length,e=0;e=0;){if(dr(n[r],t))return r;r-=1}return-1}),_r=f(Xn("map",q,b)),qr=f(function(t,n){return Jn(function(r,e){return r[e]=t(n[e]),r},{},At(n))}),Wr=f(function(t,n){return Jn(function(r,e){return r[e]=t(n[e],e,n),r},{},At(n))}),Br=f(u(Xn("any",nr,fr))),Lr=f(function(t,n){return Zn("or",t)?t.or(n):t||n}),Rr=pr(Hn(i)),Fr=pr(Hn(br(i))),Ur=f(function(t,n){return Jn(function(n,r){var e=n[t(r)?0:1];return e[e.length]=r,n},[[],[]],n)}),Dr=a(function(t,n,r){return dr(Qt(t,r),n)}),Vr=f(function(t,n){return _r(un(t),n)}),zr=a(function(t,n,r){return cn(dr(n),t,r)}),Kr=a(function(t,n,r){return cn(Ot(t),n,r)}),$r=a(Jn),Hr=f(function(t,n){return gr(u(t),n)}),Xr=f(function(t,n){return On(U(t),n)}),Yr=a(Kn("slice",function(t,n,r){return Array.prototype.slice.call(r,t,n)})),Zr=f(function(t,n){if(t<=0)throw new Error("First argument to splitEvery must be a positive integer");for(var r=[],e=0;e1?e.apply(null,M(arguments,1)):r(Math.max.apply(Math,Vr("length",n)),e)}},se=f(function(t,n){return _r(t,ce(n))}),le=c(ae(or)),pe=c(ae(fr)),he=f(function(t,n){return Zn("ap",t)?t.ap(n):Jn(function(t,r){return i(t,_r(r,n))},[],t)}),de=pr(function(t){return t.apply(this,M(arguments,1))}),ge=f(Xn("chain",se,function(t,n){return ue(_r(t,n))})),ye=a(function(t,n,r){function e(n,r){return he(_r(V,t(r)),n)}return Jn(e,n([]),r)}),ve=f(function(t,n){if(t>10)throw new Error("Constructor with greater than ten arguments");return 0===t?function(){return new n}:pr(Vt(t,function(t,r,e,u,i,o,c,f,a,s){switch(arguments.length){case 1:return new n(t);case 2:return new n(t,r);case 3:return new n(t,r,e);case 4:return new n(t,r,e,u);case 5:return new n(t,r,e,u,i);case 6:return new n(t,r,e,u,i,o);case 7:return new n(t,r,e,u,i,o,c);case 8:return new n(t,r,e,u,i,o,c,f);case 9:return new n(t,r,e,u,i,o,c,f,a);case 10:return new n(t,r,e,u,i,o,c,f,a,s)}}))}),me=nt(3,function(t){var n=M(arguments,1);return nt(Math.max.apply(Math,Vr("length",n)),function(){var r=arguments,e=this;return t.apply(e,b(function(t){return t.apply(e,r)},n))})}),xe=f(Xn("drop",rr,function(t,n){return Yr(Math.max(0,t),1/0,n)})),we=f(function(t,n){return Qr(t=0)return!1;r+=1}return!0}),Me=f(function(t,n){return function(r){return function(e){return _r(function(t){return n(t,e)},r(t(e)))}}}),Ae=c(function(t){return Me($t(t),Tn(t))}),Ie=c(function(t){return Me(un(t),K(t))}),ke=f(function(t,n){var r=nt(t,n);return nt(t,function(){return Jn(he,_r(r,arguments[0]),M(arguments,1))})}),Ne=c(function(t){return Gr(t)/t.length}),Ce=c(function(t){var n=t.length;if(0===n)return NaN;var r=2-n%2,e=(n-r)/2;return Ne(M(t).sort(function(t,n){return tn?1:0}).slice(e,e+r))}),Pe=c(function(t){return $r(Lt,{},t)}),Te=function(){if(0===arguments.length)throw new Error("pipe requires at least one argument"); +return nt(arguments[0].length,$r(j,arguments[0],Jr(arguments)))},_e=function(){if(0===arguments.length)throw new Error("pipeP requires at least one argument");return nt(arguments[0].length,$r(O,arguments[0],Jr(arguments)))},qe=$r(Dt,1),We=ie(b,nn,mt),Be=f(function(t,n){return xe(t>=0?n.length-t:0,n)}),Le=function(t,n){return fe(n,t,0)>=0},Re=function t(n,r){var e=function(e){var u=r.concat([n]);return Le(e,u)?"":t(e,u)},u=function(t,n){return b(function(n){return S(n)+": "+e(t[n])},n.slice().sort())};switch(Object.prototype.toString.call(n)){case"[object Arguments]":return"(function() { return arguments; }("+b(e,n).join(", ")+"))";case"[object Array]":return"["+b(e,n).concat(u(n,Hr(jn(/^\d+$/),At(n)))).join(", ")+"]";case"[object Boolean]":return"object"==typeof n?"new Boolean("+e(n.valueOf())+")":n.toString();case"[object Date]":return"new Date("+S(A(n))+")";case"[object Null]":return"null";case"[object Number]":return"object"==typeof n?"new Number("+e(n.valueOf())+")":1/n===-(1/0)?"-0":n.toString(10);case"[object String]":return"object"==typeof n?"new String("+e(n.valueOf())+")":S(n);case"[object Undefined]":return"undefined";default:return"function"==typeof n.constructor&&"Object"!==n.constructor.name&&"function"==typeof n.toString&&"[object Object]"!==n.toString()?n.toString():"{"+u(n,At(n)).join(", ")+"}"}},Fe=ye(mt),Ue=function(){if(0===arguments.length)throw new Error("compose requires at least one argument");return Te.apply(this,dn(arguments))},De=function(){return 0===arguments.length?mt:Ue.apply(this,_r(ge,arguments))},Ve=function(){if(0===arguments.length)throw new Error("composeP requires at least one argument");return _e.apply(this,dn(arguments))},ze=c(function(t){return ve(t.length,t)}),Ke=f(Le),$e=f(function(t,n){for(var r=[],e=0,u=t.length;e ''; + let styles = {}; + + let el; + const anchor = root || d3.select('body'); + const rootNode = anchor.node(); + + function tip(selection) { + selection.on({ + 'mouseover.tip': node => { + let [mouseX, mouseY] = d3.mouse(rootNode); + let [x, y] = [left || mouseX + offset.left, top || mouseY - offset.top]; + + anchor.selectAll(`div.${className}`).remove(); + + el = anchor.append('div') + .attr(prependClass(className)(attrs)) + .style({ + position: 'absolute', + 'z-index': 1001, + left: x + 'px', + top: y + 'px', + ...styles + }) + .html(() => text(node)); + }, + + 'mousemove.tip': node => { + let [mouseX, mouseY] = d3.mouse(rootNode); + let [x, y] = [left || mouseX + offset.left, top || mouseY - offset.top]; + + el + .style({ + left: x + 'px', + top: y + 'px' + }) + .html(() => text(node)); + }, + + 'mouseout.tip': () => el.remove() + }); + } + + tip.attr = function setAttr(d) { + if (is(Object, d)) { + attrs = {...attrs, ...d}; + } + return this; + }; + + tip.style = function setStyle(d) { + if (is(Object, d)) { + styles = {...styles, ...d}; + } + return this; + }; + + tip.text = function setText(d) { + text = functor(d); + return this; + }; + + return tip; +} diff --git a/packages/d3tooltip/src/utils/functor.js b/packages/d3tooltip/src/utils/functor.js new file mode 100644 index 00000000..007885d3 --- /dev/null +++ b/packages/d3tooltip/src/utils/functor.js @@ -0,0 +1,5 @@ +import { is } from 'ramda'; + +export default function functor(v) { + return is(Function, v) ? v : () => v; +} diff --git a/packages/d3tooltip/src/utils/index.js b/packages/d3tooltip/src/utils/index.js new file mode 100644 index 00000000..7893c5ca --- /dev/null +++ b/packages/d3tooltip/src/utils/index.js @@ -0,0 +1,7 @@ +import prependClass from './prependClass'; +import functor from './functor'; + +export default { + prependClass, + functor +}; diff --git a/packages/d3tooltip/src/utils/prependClass.js b/packages/d3tooltip/src/utils/prependClass.js new file mode 100644 index 00000000..2194f865 --- /dev/null +++ b/packages/d3tooltip/src/utils/prependClass.js @@ -0,0 +1,20 @@ +import { mapObjIndexed, join } from 'ramda'; +import functor from './functor'; + +export default function prependClass(className) { + return mapObjIndexed((value, key) => { + if (key === 'class') { + const fn = functor(value); + + return (d, i) => { + const classNames = fn(d, i); + if (classNames !== className) { + return join(' ', [className, classNames]); + } + return classNames; + }; + } + + return value; + }); +} diff --git a/packages/d3tooltip/webpack.config.base.js b/packages/d3tooltip/webpack.config.base.js new file mode 100644 index 00000000..9576681c --- /dev/null +++ b/packages/d3tooltip/webpack.config.base.js @@ -0,0 +1,16 @@ +'use strict'; + +module.exports = { + module: { + loaders: [ + { test: /\.js$/, loaders: ['babel-loader'], exclude: /node_modules/ } + ] + }, + output: { + library: 'd3tooltip', + libraryTarget: 'umd' + }, + resolve: { + extensions: ['', '.js'] + } +}; diff --git a/packages/d3tooltip/webpack.config.development.js b/packages/d3tooltip/webpack.config.development.js new file mode 100644 index 00000000..e509d7cd --- /dev/null +++ b/packages/d3tooltip/webpack.config.development.js @@ -0,0 +1,14 @@ +'use strict'; + +var webpack = require('webpack'); +var baseConfig = require('./webpack.config.base'); + +var config = Object.create(baseConfig); +config.plugins = [ + new webpack.optimize.OccurenceOrderPlugin(), + new webpack.DefinePlugin({ + 'process.env.NODE_ENV': JSON.stringify('development') + }) +]; + +module.exports = config; diff --git a/packages/d3tooltip/webpack.config.production.js b/packages/d3tooltip/webpack.config.production.js new file mode 100644 index 00000000..f4589cc0 --- /dev/null +++ b/packages/d3tooltip/webpack.config.production.js @@ -0,0 +1,20 @@ +'use strict'; + +var webpack = require('webpack'); +var baseConfig = require('./webpack.config.base'); + +var config = Object.create(baseConfig); +config.plugins = [ + new webpack.optimize.OccurenceOrderPlugin(), + new webpack.DefinePlugin({ + 'process.env.NODE_ENV': JSON.stringify('production') + }), + new webpack.optimize.UglifyJsPlugin({ + compressor: { + screw_ie8: true, + warnings: false + } + }) +]; + +module.exports = config; diff --git a/yarn.lock b/yarn.lock index 9a6a773e..bee9ff4b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -721,6 +721,11 @@ acorn-to-esprima@^1.0.5: resolved "https://registry.yarnpkg.com/acorn-to-esprima/-/acorn-to-esprima-1.0.7.tgz#9436259760098f9ead9b9da2242fab2f4850281b" integrity sha1-lDYll2AJj56tm52iJC+rL0hQKBs= +acorn-to-esprima@^2.0.4: + version "2.0.8" + resolved "https://registry.yarnpkg.com/acorn-to-esprima/-/acorn-to-esprima-2.0.8.tgz#003f0c642eb92132f417d3708f14ada82adf2eb1" + integrity sha1-AD8MZC65ITL0F9NwjxStqCrfLrE= + acorn-walk@^6.0.1: version "6.1.1" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.1.1.tgz#d363b66f5fac5f018ff9c3a1e7b6f8e310cc3913" @@ -1103,7 +1108,7 @@ axobject-query@^2.0.1: dependencies: ast-types-flow "0.0.7" -babel-cli@^6.10.1, babel-cli@^6.3.17: +babel-cli@^6.10.1, babel-cli@^6.3.15, babel-cli@^6.3.17: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.26.0.tgz#502ab54874d7db88ad00b887a06383ce03d002f1" integrity sha1-UCq1SHTX24itALiHoGODzgPQAvE= @@ -1186,7 +1191,7 @@ babel-core@^5.1.8, babel-core@^5.8.25, babel-core@^5.8.33: trim-right "^1.0.0" try-resolve "^1.0.0" -babel-core@^6.0.0, babel-core@^6.26.0, babel-core@^6.3.17: +babel-core@^6.0.0, babel-core@^6.1.20, babel-core@^6.26.0, babel-core@^6.3.17: version "6.26.3" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" integrity sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA== @@ -1241,6 +1246,18 @@ babel-eslint@^4.1.6: lodash.assign "^3.2.0" lodash.pick "^3.1.0" +babel-eslint@^5.0.0-beta4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-5.0.4.tgz#a6ba51ae582a1d4e25adfddbc2a61f8d5a9040b9" + integrity sha1-prpRrlgqHU4lrf3bwqYfjVqQQLk= + dependencies: + acorn-to-esprima "^2.0.4" + babel-traverse "^6.0.20" + babel-types "^6.0.19" + babylon "^6.0.18" + lodash.assign "^3.2.0" + lodash.pick "^3.1.0" + babel-generator@^6.18.0, babel-generator@^6.26.0: version "6.26.1" resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" @@ -2155,7 +2172,7 @@ babel-preset-react-app@^3.1.2: babel-preset-env "1.6.1" babel-preset-react "6.24.1" -babel-preset-react@6.24.1, babel-preset-react@^6.5.0: +babel-preset-react@6.24.1, babel-preset-react@^6.3.13, babel-preset-react@^6.5.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-preset-react/-/babel-preset-react-6.24.1.tgz#ba69dfaea45fc3ec639b6a4ecea6e17702c91380" integrity sha1-umnfrqRfw+xjm2pOzqbhdwLJE4A= @@ -2257,7 +2274,7 @@ babel-template@^6.16.0, babel-template@^6.24.1, babel-template@^6.26.0, babel-te babylon "^6.18.0" lodash "^4.17.4" -babel-traverse@^6.0.0, babel-traverse@^6.18.0, babel-traverse@^6.24.1, babel-traverse@^6.26.0: +babel-traverse@^6.0.0, babel-traverse@^6.0.20, babel-traverse@^6.18.0, babel-traverse@^6.24.1, babel-traverse@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" integrity sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4= @@ -2272,7 +2289,7 @@ babel-traverse@^6.0.0, babel-traverse@^6.18.0, babel-traverse@^6.24.1, babel-tra invariant "^2.2.2" lodash "^4.17.4" -babel-types@^6.0.0, babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: +babel-types@^6.0.0, babel-types@^6.0.19, babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc= @@ -2287,7 +2304,7 @@ babylon@^5.8.38: resolved "https://registry.yarnpkg.com/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd" integrity sha1-7JsSCxG/bM1Bc6GL8hfmC3mFn/0= -babylon@^6.18.0: +babylon@^6.0.18, babylon@^6.18.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== @@ -3862,6 +3879,11 @@ eslint-plugin-react@^2.3.0: resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-2.7.1.tgz#5d6f1bca507d1387b6593c230998af04f0b9aed6" integrity sha1-XW8bylB9E4e2WTwjCZivBPC5rtY= +eslint-plugin-react@^3.6.3: + version "3.16.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-3.16.1.tgz#262d96b77d7c4a42af809a73c0e527a58612293c" + integrity sha1-Ji2Wt318SkKvgJpzwOUnpYYSKTw= + eslint-scope@3.7.1: version "3.7.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" @@ -3943,6 +3965,34 @@ eslint@^0.23: user-home "^1.0.0" xml-escape "~1.0.0" +eslint@^0.24: + version "0.24.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-0.24.1.tgz#54a50809855b9655721c6f2ee57b351edce28101" + integrity sha1-VKUICYVbllVyHG8u5Xs1HtzigQE= + dependencies: + chalk "^1.0.0" + concat-stream "^1.4.6" + debug "^2.1.1" + doctrine "^0.6.2" + escape-string-regexp "^1.0.2" + escope "^3.1.0" + espree "^2.0.1" + estraverse "^4.1.0" + estraverse-fb "^1.3.1" + globals "^8.0.0" + inquirer "^0.8.2" + is-my-json-valid "^2.10.0" + js-yaml "^3.2.5" + minimatch "^2.0.1" + mkdirp "^0.5.0" + object-assign "^2.0.0" + optionator "^0.5.0" + path-is-absolute "^1.0.0" + strip-json-comments "~1.0.1" + text-table "~0.2.0" + user-home "^1.0.0" + xml-escape "~1.0.0" + eslint@^5.0.0: version "5.10.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.10.0.tgz#24adcbe92bf5eb1fc2d2f2b1eebe0c5e0713903a" @@ -7877,6 +7927,11 @@ railroad-diagrams@^1.0.0: resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e" integrity sha1-635iZ1SN3t+4mcG5Dlc3RVnN234= +ramda@^0.17.1: + version "0.17.1" + resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.17.1.tgz#4c198147d3ab54e8c15255f11730e2116f6e6073" + integrity sha1-TBmBR9OrVOjBUlXxFzDiEW9uYHM= + randexp@0.4.6: version "0.4.6" resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.4.6.tgz#e986ad5e5e31dae13ddd6f7b3019aa7c87f60ca3" @@ -9586,7 +9641,7 @@ webpack-core@~0.6.9: source-list-map "~0.1.7" source-map "~0.4.1" -webpack@^1.11.0: +webpack@^1.11.0, webpack@^1.9.6: version "1.15.0" resolved "https://registry.yarnpkg.com/webpack/-/webpack-1.15.0.tgz#4ff31f53db03339e55164a9d468ee0324968fe98" integrity sha1-T/MfU9sDM55VFkqdRo7gMklo/pg=