[
  {
    "path": ".babelrc",
    "content": "{\n  \"presets\": [\n    [\n      \"@babel/preset-env\",\n      {\n        \"loose\": true,\n        \"targets\": {\n          \"node\": \"8\"\n        }\n      }\n    ],\n    \"@babel/preset-flow\"\n  ],\n  \"plugins\": [\n    \"@babel/plugin-transform-flow-strip-types\",\n    \"@babel/plugin-syntax-dynamic-import\",\n    \"@babel/plugin-syntax-import-meta\",\n    \"@babel/plugin-proposal-class-properties\",\n    \"@babel/plugin-proposal-json-strings\",\n    [\n      \"@babel/plugin-proposal-decorators\",\n      {\n        \"legacy\": true\n      }\n    ],\n    \"@babel/plugin-proposal-function-sent\",\n    \"@babel/plugin-proposal-export-namespace-from\",\n    \"@babel/plugin-proposal-numeric-separator\",\n    \"@babel/plugin-proposal-throw-expressions\"\n  ]\n}\n"
  },
  {
    "path": ".flowconfig",
    "content": "[ignore]\ndist/.*\n\n[include]\n\n[libs]\n\n[options]\nesproposal.decorators=ignore\n"
  },
  {
    "path": ".gitignore",
    "content": ".idea\nnode_modules\ncoverage\ndist\nlib\nnpm-debug.log\n.DS_Store\n"
  },
  {
    "path": ".npmignore",
    "content": "src\ntest\nscripts\n"
  },
  {
    "path": ".travis.yml",
    "content": "sudo: false\nlanguage: node_js\nbefore_install:\n  - npm install -g npm@6.7.0\ncache:\n  directories:\n    - node_modules\nnotifications:\n  email: false\nnode_js:\n  - '8'\n  - '9'\n  - '10'\n  - '11'\n  - 'stable'\nscript:\n  - npm start validate\nafter_success:\n  - npx codecov\nbranches:\n  only:\n    - master"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2017 Erik Rasmussen\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# lru-memoize\n\n[![NPM Version](https://img.shields.io/npm/v/lru-memoize.svg?style=flat-square)](https://www.npmjs.com/package/lru-memoize) \n[![NPM Downloads](https://img.shields.io/npm/dm/lru-memoize.svg?style=flat-square)](https://www.npmjs.com/package/lru-memoize)\n[![Build Status](https://img.shields.io/travis/erikras/lru-memoize/master.svg?style=flat-square)](https://travis-ci.org/erikras/lru-memoize)\n\n`lru-memoize` is a utility to provide simple memoization for any pure javascript function, using an [LRU cache](https://en.wikipedia.org/wiki/Cache_algorithms) that prioritizes the most recently accessed values, and discards the \"least recently used\" (LRU) items when the size limit is reached. _If your function has side effects or relies on some external state to generate its result, it should not be memoized._\n\n## Installation\n\n```\nnpm install --save lru-memoize\n```\n\n## Usage\n\nLet's look at an example where we want to memoize a function that multiplies three numbers together, and we want to keep the last ten `arguments -> value` mappings in memory.\n\n### ES5\n\n```javascript\nvar memoize = require('lru-memoize');\n\nvar multiply = function(a, b, c) {\n  return a * b * c;\n}\n\nmultiply = memoize(10)(multiply);\n\nmodule.exports = multiply;\n```\n\n### ES6\n\n```javascript\nimport memoize from 'lru-memoize';\n\nlet multiply = (a, b, c) => a * b * c;\n\nmultiply = memoize(10)(multiply);\n\nexport default multiply;\n```\n\n## API\n\n#### `memoize(limit:Integer?, equals:Function?, deepObjects:Boolean?)`\n\nReturns `(Function) => Function`.\n\n###### -`limit` : Integer [optional]\n\n> The number of `arguments -> value` mappings to keep in memory. Defaults to `1`.\n\n###### -`equals` : Function [optional]\n\n> A function to compare two values for equality. Defaults to `===`.\n\n###### -`deepObjects` : Boolean [optional]\n\n> Whether or not to perform a deep equals on Object values. Defaults to `false`.\n\n"
  },
  {
    "path": "package-scripts.js",
    "content": "const npsUtils = require(\"nps-utils\");\n\nconst series = npsUtils.series;\nconst concurrent = npsUtils.concurrent;\nconst rimraf = npsUtils.rimraf;\nconst crossEnv = npsUtils.crossEnv;\n\nmodule.exports = {\n  scripts: {\n    test: {\n      default: crossEnv(\"NODE_ENV=test jest --coverage\"),\n      update: crossEnv(\"NODE_ENV=test jest --coverage --updateSnapshot\"),\n      watch: crossEnv(\"NODE_ENV=test jest --watch\"),\n      codeCov: crossEnv(\n        \"cat ./coverage/lcov.info | ./node_modules/codecov.io/bin/codecov.io.js\"\n      ),\n      size: {\n        description: \"check the size of the bundle\",\n        script: \"bundlesize\"\n      }\n    },\n    build: {\n      description: \"delete the dist directory and run all builds\",\n      default: series(\n        rimraf(\"dist\"),\n        concurrent.nps(\n          \"build.es\",\n          \"build.cjs\",\n          \"build.umd.main\",\n          \"build.umd.min\",\n          \"copyTypes\"\n        )\n      ),\n      es: {\n        description: \"run the build with rollup (uses rollup.config.js)\",\n        script: \"rollup --config --environment FORMAT:es\"\n      },\n      cjs: {\n        description: \"run rollup build with CommonJS format\",\n        script: \"rollup --config --environment FORMAT:cjs\"\n      },\n      umd: {\n        min: {\n          description: \"run the rollup build with sourcemaps\",\n          script: \"rollup --config --sourcemap --environment MINIFY,FORMAT:umd\"\n        },\n        main: {\n          description: \"builds the cjs and umd files\",\n          script: \"rollup --config --sourcemap --environment FORMAT:umd\"\n        }\n      },\n      andTest: series.nps(\"build\", \"test.size\")\n    },\n    docs: {\n      description: \"Generates table of contents in README\",\n      script: \"doctoc README.md\"\n    },\n    copyTypes: series(\n      npsUtils.copy(\"src/*.js.flow src/*.d.ts dist\"),\n      npsUtils.copy(\n        'dist/index.js.flow dist --rename=\"lru-memoize.cjs.js.flow\"'\n      ),\n      npsUtils.copy('dist/index.js.flow dist --rename=\"lru-memoize.es.js.flow\"')\n    ),\n    flow: {\n      description: \"flow check the entire project\",\n      script: \"flow check\"\n    },\n    validate: {\n      description:\n        \"This runs several scripts to make sure things look good before committing or on clean install\",\n      default: concurrent.nps(\"flow\", \"build.andTest\", \"test\")\n    }\n  },\n  options: {\n    silent: false\n  }\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"lru-memoize\",\n  \"version\": \"1.1.0\",\n  \"description\": \"A utility to provide lru memoization for any js function\",\n  \"main\": \"dist/lru-memoize.cjs.js\",\n  \"jsnext:main\": \"dist/lru-memoize.es.js\",\n  \"module\": \"dist/lru-memoize.es.js\",\n  \"typings\": \"dist/index.d.ts\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/erikras/lru-memoize\"\n  },\n  \"scripts\": {\n    \"start\": \"nps\",\n    \"test\": \"nps test\",\n    \"prepare\": \"lint-staged && npm start validate\"\n  },\n  \"keywords\": [\n    \"memoize\",\n    \"cache\",\n    \"caching\",\n    \"es7\",\n    \"decorator\"\n  ],\n  \"author\": \"Erik Rasmussen <rasmussenerik@gmail.com> (http://github.com/erikras)\",\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/erikras/lru-memoize/issues\"\n  },\n  \"homepage\": \"https://github.com/erikras/lru-memoize\",\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.0.0\",\n    \"@babel/core\": \"^7.0.0\",\n    \"@babel/plugin-proposal-class-properties\": \"^7.3.3\",\n    \"@babel/plugin-proposal-decorators\": \"^7.3.0\",\n    \"@babel/plugin-proposal-export-namespace-from\": \"^7.2.0\",\n    \"@babel/plugin-proposal-function-sent\": \"^7.2.0\",\n    \"@babel/plugin-proposal-json-strings\": \"^7.2.0\",\n    \"@babel/plugin-proposal-numeric-separator\": \"^7.2.0\",\n    \"@babel/plugin-proposal-throw-expressions\": \"^7.2.0\",\n    \"@babel/plugin-syntax-dynamic-import\": \"^7.2.0\",\n    \"@babel/plugin-syntax-import-meta\": \"^7.2.0\",\n    \"@babel/plugin-transform-flow-strip-types\": \"^7.2.3\",\n    \"@babel/plugin-transform-runtime\": \"^7.2.0\",\n    \"@babel/preset-env\": \"^7.0.0\",\n    \"@babel/preset-flow\": \"^7.0.0\",\n    \"@babel/register\": \"^7.0.0\",\n    \"babel-jest\": \"^24.1.0\",\n    \"babel-loader\": \"^8.0.5\",\n    \"bundlesize\": \"^0.17.1\",\n    \"flow-bin\": \"^0.93.0\",\n    \"glow\": \"^1.2.2\",\n    \"husky\": \"^1.3.1\",\n    \"jest\": \"^24.1.0\",\n    \"lint-staged\": \"^8.1.4\",\n    \"nps\": \"^5.9.3\",\n    \"nps-utils\": \"^1.7.0\",\n    \"nyc\": \"^13.2.0\",\n    \"prettier\": \"^1.16.4\",\n    \"rifraf\": \"^2.0.3\",\n    \"rimraf\": \"^2.6.1\",\n    \"rollup\": \"^1.2.2\",\n    \"rollup-plugin-babel\": \"^4.3.2\",\n    \"rollup-plugin-commonjs\": \"^9.2.0\",\n    \"rollup-plugin-flow\": \"^1.1.1\",\n    \"rollup-plugin-node-resolve\": \"^4.0.0\",\n    \"rollup-plugin-replace\": \"^2.1.0\",\n    \"rollup-plugin-uglify\": \"^6.0.2\"\n  },\n  \"lint-staged\": {\n    \"*.{js*,ts*,json,md,css}\": [\n      \"prettier --write\",\n      \"git add\"\n    ]\n  },\n  \"jest\": {\n    \"testEnvironment\": \"node\",\n    \"testPathIgnorePatterns\": [\n      \".*\\\\.ts\"\n    ]\n  },\n  \"bundlesize\": [\n    {\n      \"path\": \"dist/lru-memoize.umd.min.js\",\n      \"maxSize\": \"1kB\"\n    },\n    {\n      \"path\": \"dist/lru-memoize.es.js\",\n      \"maxSize\": \"2kB\"\n    },\n    {\n      \"path\": \"dist/lru-memoize.cjs.js\",\n      \"maxSize\": \"2kB\"\n    }\n  ],\n  \"husky\": {\n    \"hooks\": {\n      \"pre-commit\": \"lint-staged && npm start validate\"\n    }\n  }\n}\n"
  },
  {
    "path": "rollup.config.js",
    "content": "import resolve from \"rollup-plugin-node-resolve\";\nimport babel from \"rollup-plugin-babel\";\nimport flow from \"rollup-plugin-flow\";\nimport commonjs from \"rollup-plugin-commonjs\";\nimport { uglify } from \"rollup-plugin-uglify\";\nimport replace from \"rollup-plugin-replace\";\nimport pkg from \"./package.json\";\n\nconst makeExternalPredicate = externalArr => {\n  if (externalArr.length === 0) {\n    return () => false;\n  }\n  const pattern = new RegExp(`^(${externalArr.join(\"|\")})($|/)`);\n  return id => pattern.test(id);\n};\n\nconst minify = process.env.MINIFY;\nconst format = process.env.FORMAT;\nconst es = format === \"es\";\nconst umd = format === \"umd\";\nconst cjs = format === \"cjs\";\n\nlet output;\n\nif (es) {\n  output = { file: `dist/lru-memoize.es.js`, format: \"es\" };\n} else if (umd) {\n  if (minify) {\n    output = {\n      file: `dist/lru-memoize.umd.min.js`,\n      format: \"umd\"\n    };\n  } else {\n    output = { file: `dist/lru-memoize.umd.js`, format: \"umd\" };\n  }\n} else if (cjs) {\n  output = { file: `dist/lru-memoize.cjs.js`, format: \"cjs\" };\n} else if (format) {\n  throw new Error(`invalid format specified: \"${format}\".`);\n} else {\n  throw new Error(\"no format specified. --environment FORMAT:xxx\");\n}\n\nexport default {\n  input: \"src/index.js\",\n  output: Object.assign(\n    {\n      name: \"lru-memoize\",\n      exports: \"named\"\n    },\n    output\n  ),\n  external: makeExternalPredicate(\n    umd\n      ? Object.keys(pkg.peerDependencies || {})\n      : [\n          ...Object.keys(pkg.dependencies || {}),\n          ...Object.keys(pkg.peerDependencies || {})\n        ]\n  ),\n  plugins: [\n    resolve({ jsnext: true, main: true }),\n    flow(),\n    commonjs({ include: \"node_modules/**\" }),\n    babel({\n      exclude: \"node_modules/**\",\n      babelrc: false,\n      runtimeHelpers: true,\n      presets: [\n        [\n          \"@babel/preset-env\",\n          {\n            modules: false,\n            loose: true\n          }\n        ],\n        \"@babel/preset-flow\"\n      ],\n      plugins: [\n        [\"@babel/plugin-transform-runtime\", { useESModules: !cjs }],\n        \"@babel/plugin-transform-flow-strip-types\",\n        \"@babel/plugin-syntax-dynamic-import\",\n        \"@babel/plugin-syntax-import-meta\",\n        \"@babel/plugin-proposal-class-properties\",\n        \"@babel/plugin-proposal-json-strings\",\n        [\n          \"@babel/plugin-proposal-decorators\",\n          {\n            legacy: true\n          }\n        ],\n        \"@babel/plugin-proposal-function-sent\",\n        \"@babel/plugin-proposal-export-namespace-from\",\n        \"@babel/plugin-proposal-numeric-separator\",\n        \"@babel/plugin-proposal-throw-expressions\"\n      ]\n    }),\n    umd || es\n      ? replace({\n          \"process.env.NODE_ENV\": JSON.stringify(\n            minify ? \"production\" : \"development\"\n          )\n        })\n      : null,\n    minify ? uglify() : null\n  ].filter(Boolean)\n};\n"
  },
  {
    "path": "src/__tests__/deepEquals.spec.js",
    "content": "import expect from 'expect'\nimport deepEquals from '../deepEquals'\n\nconst tripleEquals = deepEquals((valueA, valueB) => valueA === valueB, true)\n\ndescribe('deepEquals', () => {\n  it('should return true if argument fields are equal', () => {\n    expect(tripleEquals(3, 3)).toBe(true)\n\n    expect(tripleEquals('dog', 'dog')).toBe(true)\n\n    expect(\n      tripleEquals({ a: 1, b: 2, c: undefined }, { a: 1, b: 2, c: undefined })\n    ).toBe(true)\n\n    expect(tripleEquals({ a: 1, b: 2, c: 3 }, { a: 1, b: 2, c: 3 })).toBe(true)\n\n    const obj = {}\n    expect(tripleEquals({ a: 1, b: 2, c: obj }, { a: 1, b: 2, c: obj })).toBe(\n      true\n    )\n\n    expect(tripleEquals(null, null)).toBe(true)\n  })\n\n  it('should return false if arguments are number and string', () => {\n    expect(tripleEquals(2, '2')).toBe(false)\n  })\n\n  it('should return false if arguments are string and number', () => {\n    expect(tripleEquals('2', 2)).toBe(false)\n  })\n\n  it('should return false if arguments are number and object', () => {\n    expect(tripleEquals(4, {})).toBe(false)\n  })\n\n  it('should return false if arguments are object and number', () => {\n    expect(tripleEquals({}, 4)).toBe(false)\n  })\n\n  it('should return false if arguments are number and array', () => {\n    expect(tripleEquals(4, [])).toBe(false)\n  })\n\n  it('should return false if arguments are array and number', () => {\n    expect(tripleEquals([], 4)).toBe(false)\n  })\n\n  it('should return false if arguments are string and object', () => {\n    expect(tripleEquals('cat', {})).toBe(false)\n  })\n\n  it('should return false if arguments are object and string', () => {\n    expect(tripleEquals({}, 'cat')).toBe(false)\n  })\n\n  it('should return false if arguments are string and array', () => {\n    expect(tripleEquals('cat', ['c', 'a', 't'])).toBe(false)\n  })\n\n  it('should return false if arguments are array and string', () => {\n    expect(tripleEquals(['c', 'a', 't'], 'cat')).toBe(false)\n  })\n\n  it('should return false if arguments are array and object', () => {\n    expect(tripleEquals([], {})).toBe(false)\n  })\n\n  it('should return false if arguments are object and array', () => {\n    expect(tripleEquals({}, [])).toBe(false)\n  })\n\n  it('should return false if arguments are object and null', () => {\n    expect(tripleEquals({ a: 1 }, null)).toBe(false)\n  })\n\n  it('should return false if arguments are null and object', () => {\n    expect(tripleEquals(null, { a: 1 })).toBe(false)\n  })\n\n  it('should return false if first argument has too many keys', () => {\n    expect(tripleEquals({ a: 1, b: 2, c: 3 }, { a: 1, b: 2 })).toBe(false)\n  })\n\n  it('should return false if second argument has too many keys', () => {\n    expect(tripleEquals({ a: 1, b: 2 }, { a: 1, b: 2, c: 3 })).toBe(false)\n  })\n\n  it('should return false if arguments have different keys', () => {\n    expect(\n      tripleEquals({ a: 1, b: 2, c: undefined }, { a: 1, bb: 2, c: undefined })\n    ).toBe(false)\n  })\n\n  it('should return false if first array argument has too many items', () => {\n    expect(tripleEquals([1, 2, 3, 4], [1, 2, 3])).toBe(false)\n  })\n\n  it('should return false if second array argument has too many items', () => {\n    expect(tripleEquals([1, 2, 3], [1, 2, 3, 4])).toBe(false)\n  })\n\n  it('should work with objects inside arrays', () => {\n    expect(tripleEquals(\n      [ { val: 4 }, { val: 2 }, { val: 3 } ],\n      [ { val: 1 }, { val: 2 }, { val: 3 } ]\n    )).toBe(false)\n  })\n})\n"
  },
  {
    "path": "src/__tests__/memoize.spec.js",
    "content": "import expect from 'expect'\nimport memoize from '../memoize'\n\ndescribe('memoize', () => {\n  describe('basic', () => {\n    it('single', () => {\n      let callCount = 0\n      let multiply = (x, y, z) => {\n        callCount += 1\n        return x * y * z\n      }\n      multiply = memoize()(multiply)\n\n      expect(multiply(1, 2, 3)).toBe(6)\n\n      expect(multiply(1, 2, 3)).toBe(6)\n\n      expect(callCount).toBe(1)\n\n      expect(multiply(4, 5, 6)).toBe(120)\n\n      expect(callCount).toBe(2)\n\n      expect(multiply(1, 2, 3)).toBe(6)\n\n      expect(callCount).toBe(3)\n    })\n\n    it('multiple', () => {\n      let callCount = 0\n      let multiply = (x, y, z) => {\n        callCount += 1\n        return x * y * z\n      }\n      multiply = memoize(2)(multiply)\n\n      expect(multiply(1, 2, 3)).toBe(6)\n\n      expect(multiply(1, 2, 3)).toBe(6)\n\n      expect(callCount).toBe(1)\n\n      expect(multiply(4, 5, 6)).toBe(120)\n\n      expect(callCount).toBe(2)\n\n      expect(multiply(1, 2, 3)).toBe(6)\n\n      expect(callCount).toBe(2)\n\n      expect(multiply(4, 5, 6)).toBe(120)\n\n      expect(callCount).toBe(2)\n    })\n  })\n\n  describe('shallow', () => {\n    it('array', () => {\n      let callCount = 0\n      let multiply = (x, y, z) => {\n        callCount += 1\n        return x.concat(y, z).reduce((t, n) => t * n)\n      }\n      multiply = memoize()(multiply)\n\n      const x = [1, 2, 3]\n      const y = [4, 5, 6]\n      const z = [7, 8, 9]\n\n      const x2 = [1, 2, 3]\n\n      expect(multiply(x, y, z)).toBe(362880)\n\n      expect(multiply(x2, y, z)).toBe(362880)\n\n      expect(callCount).toBe(2)\n    })\n\n    it('object', () => {\n      let callCount = 0\n      let multiply = (x, y, z) => {\n        callCount += 1\n        return x.val * y.val * z.val\n      }\n      multiply = memoize(2)(multiply)\n\n      const x = { val: 1 }\n      const y = { val: 2 }\n      const z = { val: 3 }\n\n      const x2 = { val: 1 }\n\n      expect(multiply(x, y, z)).toBe(6)\n\n      expect(multiply(x2, y, z)).toBe(6)\n\n      expect(callCount).toBe(2)\n    })\n  })\n\n  describe('deep', () => {\n    it('array', () => {\n      let callCount = 0\n      let multiply = (x, y, z) => {\n        callCount += 1\n        return x.concat(y, z).reduce((t, n) => t * n)\n      }\n      multiply = memoize(true)(multiply)\n\n      const x = [1, 2, 3]\n      const y = [4, 5, 6]\n      const z = [7, 8, 9]\n\n      const x2 = [1, 2, 3]\n      const x3 = [3, 2, 1]\n\n      expect(multiply(x, y, z)).toBe(362880)\n\n      expect(multiply(x2, y, z)).toBe(362880)\n\n      expect(callCount).toBe(1)\n\n      expect(multiply(x3, y, z)).toBe(362880)\n\n      expect(callCount).toBe(2)\n    })\n\n    it('object', () => {\n      let callCount = 0\n      let multiply = (x, y, z) => {\n        callCount += 1\n        return x.val * y.val * z.val\n      }\n      multiply = memoize(true)(multiply)\n\n      const x = { val: 1 }\n      const y = { val: 2 }\n      const z = { val: 3 }\n\n      const x2 = { val: 1 }\n      const x3 = { val: 4 }\n\n      expect(multiply(x, y, z)).toBe(6)\n\n      expect(multiply(x2, y, z)).toBe(6)\n\n      expect(callCount).toBe(1)\n\n      expect(multiply(x3, y, z)).toBe(24)\n\n      expect(callCount).toBe(2)\n    })\n\n    it('object nested', () => {\n      let callCount = 0\n      let multiply = (x, y, z) => {\n        callCount += 1\n        return x.inner.val * y.inner.val * z.inner.val\n      }\n      multiply = memoize(true)(multiply)\n\n      const x = { inner: { val: 1 } }\n      const y = { inner: { val: 2 } }\n      const z = { inner: { val: 3 } }\n\n      const x2 = { inner: { val: 1 } }\n      const x3 = { inner: { val: 4 } }\n\n      expect(multiply(x, y, z)).toBe(6)\n\n      expect(multiply(x2, y, z)).toBe(6)\n\n      expect(callCount).toBe(1)\n\n      expect(multiply(x3, y, z)).toBe(24)\n\n      expect(callCount).toBe(2)\n    })\n  })\n})\n"
  },
  {
    "path": "src/deepEquals.js",
    "content": "// @flow\nimport type { Equals } from \".\";\nconst hasOwn = (object, key) =>\n  Object.prototype.hasOwnProperty.call(object, key);\nexport default function deepEquals(equals: Equals, deepObjects: boolean) {\n  function deep(valueA: any, valueB: any) {\n    if (equals(valueA, valueB)) {\n      return true;\n    }\n\n    if (Array.isArray(valueA)) {\n      if (!Array.isArray(valueB) || valueA.length !== valueB.length) {\n        return false;\n      }\n\n      // Check deep equality of each value in A against the same indexed value in B\n      if (!valueA.every((value, index) => deep(value, valueB[index]))) {\n        return false;\n      }\n\n      // could not find unequal items\n      return true;\n    }\n\n    if (Array.isArray(valueB)) {\n      return false;\n    }\n\n    if (typeof valueA === \"object\") {\n      if (typeof valueB !== \"object\") {\n        return false;\n      }\n\n      const isANull = valueA === null;\n      const isBNull = valueB === null;\n      if (isANull || isBNull) {\n        return isANull === isBNull;\n      }\n\n      const aKeys = Object.keys(valueA);\n      const bKeys = Object.keys(valueB);\n\n      if (aKeys.length !== bKeys.length) {\n        return false;\n      }\n\n      // Should we compare with shallow equivalence or deep equivalence?\n      const equalityChecker = deepObjects ? deep : equals;\n\n      // Check if objects share same keys, and each of those keys are equal\n      if (\n        !aKeys.every(\n          aKey =>\n            hasOwn(valueA, aKey) &&\n            hasOwn(valueB, aKey) &&\n            equalityChecker(valueA[aKey], valueB[aKey])\n        )\n      ) {\n        return false;\n      }\n\n      // could not find unequal keys or values\n      return true;\n    }\n    return false;\n  }\n\n  return deep;\n}\n"
  },
  {
    "path": "src/index.d.ts",
    "content": "declare const memoize = (\n  limit?: number,\n  equals?: (a: any, b: any) => boolean,\n  deepObjects?: boolean\n) => <T extends Function>(func: T) => T;\nexport default memoize;\n"
  },
  {
    "path": "src/index.js",
    "content": "import memoize from './memoize'\n\nexport default memoize\n"
  },
  {
    "path": "src/index.js.flow",
    "content": "// @flow\nexport type Entry = {\n  key: any,\n  value: any\n};\ntype ConfigItem = number | Function | boolean | void;\nexport type Config = ConfigItem[];\nexport type Equals = (any, any) => boolean;\n\ndeclare export default function memoize(Config): Function => Function;\n"
  },
  {
    "path": "src/lruCache.js",
    "content": "// @flow\nimport type { Entry, Equals } from \".\";\n\nconst findIndex = (arr: any[], fn: any => any) => {\n  for (let i = 0; i < arr.length; i++) {\n    if (fn(arr[i])) {\n      return i;\n    }\n  }\n\n  return -1;\n};\n\nexport default function lruCache(limit: number, equals: Equals) {\n  const entries: Entry[] = [];\n\n  function get(key: any) {\n    const cacheIndex = findIndex(entries, entry => equals(key, entry.key));\n\n    // We found a cached entry\n    if (cacheIndex > -1) {\n      const entry = entries[cacheIndex];\n\n      // Cached entry not at top of cache, move it to the top\n      if (cacheIndex > 0) {\n        entries.splice(cacheIndex, 1);\n        entries.unshift(entry);\n      }\n\n      return entry.value;\n    }\n\n    // No entry found in cache, return null\n    return undefined;\n  }\n\n  function put(key: any, value: any) {\n    if (!get(key)) {\n      entries.unshift({ key, value });\n      if (entries.length > limit) {\n        entries.pop();\n      }\n    }\n  }\n\n  return { get, put };\n}\n"
  },
  {
    "path": "src/memoize.js",
    "content": "// @flow\nimport type { Config, Equals } from \".\";\nimport deepEquals from \"./deepEquals\";\nimport lruCache from \"./lruCache\";\nimport singletonCache from \"./singletonCache\";\n\nfunction createCache(limit: number, equals: Equals) {\n  return limit === 1 ? singletonCache(equals) : lruCache(limit, equals);\n}\n\nfunction createEqualsFn(basicEquals: Equals, deepObjects: boolean) {\n  // Choose strategy for basic or deep object equals\n  const equals = deepObjects\n    ? deepEquals(basicEquals, deepObjects)\n    : basicEquals;\n\n  return (valueA, valueB) => {\n    // The arguments are always the argument array-like objects\n\n    // Different lengths means they are not the same\n    if (valueA.length !== valueB.length) {\n      return false;\n    }\n\n    // Compare the values\n    for (let index = 0; index < valueA.length; index += 1) {\n      if (!equals(valueA[index], valueB[index])) {\n        return false;\n      }\n    }\n    // Found no conflicts\n    return true;\n  };\n}\n\nexport default function memoize(...config: Config): Function => Function {\n  let limit: number = 1;\n  let equals: Equals = (valueA, valueB) => valueA === valueB;\n  let deepObjects: boolean = false;\n\n  if (typeof config[0] === \"number\") {\n    limit = ((config.shift(): any): number);\n  }\n  if (typeof config[0] === \"function\") {\n    equals = ((config.shift(): any): Function);\n  } else if (typeof config[0] === \"undefined\") {\n    // Support passing undefined equal argument;\n    config.shift();\n  }\n  if (typeof config[0] === \"boolean\") {\n    deepObjects = config[0];\n  }\n\n  const cache = createCache(limit, createEqualsFn(equals, deepObjects));\n\n  return fn => (...args: any[]) => {\n    let value = cache.get(args);\n    if (value === undefined) {\n      value = fn.apply(fn, args);\n      cache.put(args, value);\n    }\n    return value;\n  };\n}\n"
  },
  {
    "path": "src/singletonCache.js",
    "content": "// @flow\nimport type { Entry, Equals } from \".\";\n\nexport default function singletonCache(equals: Equals) {\n  let entry: Entry;\n  return {\n    get(key: any) {\n      if (entry && equals(key, entry.key)) {\n        return entry.value;\n      }\n    },\n\n    put(key: any, value: any) {\n      entry = { key, value };\n    }\n  };\n}\n"
  }
]