[
  {
    "path": ".eslintrc.json",
    "content": "{\n  \"extends\": \"eslint:recommended\",\n  \"ecmaFeatures\": {\n    \"modules\": true,\n    \"spread\": true,\n    \"restParams\": true\n  },\n  \"env\": {\n    \"browser\": true,\n    \"node\": true,\n    \"es6\": true\n  },\n  \"parserOptions\": {\n    \"ecmaVersion\": 9,\n    \"sourceType\": \"module\"\n  },\n  \"rules\": {\n    \"no-unused-vars\": [\"error\", { \"argsIgnorePattern\": \"^_\" }]\n  }\n}\n"
  },
  {
    "path": ".gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# TypeScript v1 declaration files\ntypings/\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variables file\n.env\n\n# next.js build output\n.next\n\n# Node specific modules\ncjs/\n"
  },
  {
    "path": ".npmignore",
    "content": "# dev-oly folders\n.babelrc*\n.eslintrc*\n.bookignore\nbook.json\ntest\nexamples\nnode_modules\n\n# doc folders\ntest\ndocs\nexamples\n_book"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Yassine Elouafi\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": "\n# focused\n\nYet another Optics library for JavaScript, based on the famous lens library from Haskell. Wrapped in a convenient Proxy interface.\n\nPut simply, this library will allow you to:\n\n- Create functional references (Optics), i.e. like pointers to nested parts in data structures (e.g. Object properties, Array elements, Map keys/values, or even fancier parts like a number inside a string ...).\n- Apply immutable updates to data structures pointed by those functional references.\n\n# Install\n\n```js\nyarn add focused\n```\n\nor\n\n```sh\nnpm install --save focused\n```\n\n# Tutorial\n\nLenses, or Optics in general, are an elegant way, from functional programming, to access and update immutable data structures. Simply put, an optic gives us a reference, also called a _focus_, to a nested part of a data structure. Once we build a focus (using some helper), we can use given functions to access or update, immutably, the embedded value.\n\nIn the following tutorial, we'll introduce Optics using `focused` helpers. The library is meant to be friendly for JavaScript developers who are not used to FP jargon.\n\nWe'll use the following object as a test bed\n\n```js\nimport { lensProxy, set, ... } from \"focused\";\n\nconst state = {\n  name: \"Luffy\",\n  level: 4,\n  nakama: [\n    { name: \"Zoro\", level: 3 },\n    { name: \"Sanji\", level: 3 },\n    { name: \"Chopper\", level: 2 }\n  ]\n};\n\n// we'll use this as a convenient way to access deep properties in the state\nconst _ = lensProxy();\n```\n\n## Focusing on a single value\n\nHere is our first example, using the `set` function:\n\n```js\nconst newState = set(_.name, \"Mugiwara\", state);\n// => { name: \"Mugiwara\", ... }\n```\n\nabove, `set` takes 3 arguments:\n\n1. `_.name` is a _Lens_ which lets us focus on the `name` property inside the `state` object\n2. The new value which replaces the old one\n3. The state to operate on.\n\nIt then returns a new state, with the `name` property replaced with the new value.\n\n`over` is like `set` but takes a function instead of a constant value\n\n```js\nconst newState = over(_.level, x => x * 2, state);\n// => { name: \"Luffy\", level: 8, ... }\n```\n\nAs you may have noticed, `set` is just a shortcut for `over(lens, _ => newValue, state)`.\n\nBesides properties, we can access elements inside an array\n\n```js\nset(_.nakama[0].name, \"Jimbi\", state);\n```\n\nIt's important to remember that a Lens focuses _exactly_ on 1 value. no more, no less. In the above example, accessing a non existing property on `state` (or out of bound index) will throw an error.\n\nIf you want the access to silently fail, you can prefix the property name with `$`.\n\n```js\nconst newState = over(_.$assistant.$level, x => x * 2, state);\n// newState == state\n```\n\n`_.$assistant` is sometimes called an _Affine_, which is a focus on _at most_ one value (ie 0 or 1 value).\n\nThere is also a `view` function, which provides a read only access to a Lens\n\n```js\nview(_.name, state);\n// => Luffy\n```\n\nYou're probably wondering, what's the utility of the above function, since the access can be trivially achieved with `state.name`. That's true, but Lenses allows more advanced accesses that are not as trivial to achieve as the above case, especially when combined with other Optics as we'll see.\n\nSimilarly, `preview` can be used with Affines to safely dereference deeply nested values\n\n```js\npreview(_.$assitant.$level, state);\n// null\n```\n\n## Focusing on multiple values\n\nAs we said, Lenses can focus on a single value. To focus on multiple values, we can use the `each` Optic together with `toList` function (`view` can only view a single value).\n\nFor example, to gets the `name`s of all Luffy's `nakama`\n\n```js\ntoList(_.nakama.$(each).name, state);\n// => [\"Zoro\", \"Sanji\", \"Chopper\"]\n```\n\nNote how we wrapped `each` inside the `.$()` method of the proxy. `.$()` lets us insert arbitrary Optics in the access path which will be automatically composed with the other Optics in the chain.\n\nIn Optics jargon, `each` is called a _Traversal_. It's an optic which can focus on multiple parts inside a data structure. Note that Traversals are not restricted to lists. You can create your own Traversals for any _Traversable_ data structure (eg Maps, trees, linked lists ...).\n\nOf course, Traversals work automatically with update functions like `over`. For example\n\n```js\nover(_.nakama.$(each).name, s => s.toUpperCase(), state);\n```\n\nreturns a new state with all `nakama` names uppercased.\n\nAnother Traversal is `filtered` which can restrict the focus only to parts meeting some criteria. For example\n\n```js\ntoList(_.nakama.$(filtered(x => x.level > 2)).name, state);\n// => [\"Zoro\", \"Sanji\"]\n```\n\nretrieves all `nakama`s names with level above `2`. While\n\n```js\nover(_.nakama.$(filtered(x => x.level > 2)).name, s => s.toUpperCase(), state);\n```\n\nupdates all `nakama`s names with level above `2`.\n\n## When the part and the whole matches\n\nSuppose we have the following json\n\n```js\nconst pkgJson = `{\n  \"name\": \"my-package\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Simple package\",\n  \"main\": \"index.html\",\n  \"scripts\": {\n    \"start\": \"parcel index.html --open\",\n    \"build\": \"parcel build index.html\"\n  },\n  \"dependencies\": {\n      \"mydep\": \"6.0.0\"\n  }\n}\n`;\n```\n\nAnd we want to focus on the `mydep` field inside `dependencies`. With normal JS code, we can call `JSON.parse` on the json string, modify the field on the created object, then call `JSON.stringify` on the same object to create the new json string.\n\nIt turns out that Optics has got a first class concept for the above operations. When the whole (source JSON) and the part (object created by `JSON.parse`) _matches_ we call that an _Isomorphism_ (or simply _Iso_). In the above example we can create an Isomorphism between the JSON string and the corresponding JS object using the `iso` function\n\n```js\nconst json = iso(JSON.parse, JSON.stringify);\n```\n\n`iso` takes 2 functions: one to go from the source to the target, and the other to go back.\n\n> Note this is a partial Optic since `JSON.parse` can fail. We've got another Optic (oh yeah) to account for failure\n\nOk, so having the `json` Iso, we can use it with the standard functions, for example\n\n```js\nset(_.$(json).dependencies.mydep, \"6.1.0\", pkgJson);\n```\n\nreturns another JSON string with the `mydep` modified. Abstracting over the parsing/stringifying steps.\n\nThe previous example is nice, but it'd be nicer if we can get access to the semver string `6.0.0` as a regular JS object. Let's go a little further and create another Isomorphism for semver like strings\n\n```js\nconst semver = iso(\n  s => {\n    const [major, minor, patch] = s.split(\".\").map(x => +x);\n    return { major, minor, patch };\n  },\n  ({ major, minor, patch }) => [major, minor, patch].join(\".\")\n);\n```\n\nNow we can have a focus directly on the parts of a semver string as numbers. Below\n\n```js\nover(_.$(json).dependencies.mydep.$(semver).minor, x => x + 1, jsonObj);\n```\n\nincrements the minor directly in the JSON string.\n\n> Of course, we abstracted over failures in the semver Iso.\n\n## When the match can't always succeed\n\nAs I mentioned, the previous case was not a total Isomorphism because JSON strings aren't always parsed to JS objects. So, as you may expect, we need to introduce another fancy name, this time our Optic is called a `Prism`. Which is an Isomorphism that may fail when going from the source to the target (but which always succeeds when going back).\n\nA simple way to create a Prism is the `simplePrism` function. It's like `iso` but you return `null` when the conversion fails.\n\n```js\nconst maybeJson = simplePrism(s => {\n  try {\n    return JSON.parse(s);\n  } catch (e) {\n    return null;\n  }\n}, JSON.stringify);\n```\n\nSo now, something like\n\n```js\nconst badJSonObj = \"@#\" + jsonObj;\nset(_.$(maybeJson).dependencies.mydep, \"6.1.0\", badJSonObj);\n```\n\nwill simply return the original JSON string. The conversion of the `semver` Iso to a Prism is left as an exercise.\n\n# Documentation\n\nUsing Optics follows a uniform pattern\n- First we create an Optic which focuses on some value(s) inside a container\n- Then we use an operation to access or modify the value through the created Optic\n\n>In the following, all showcased functions are imported from the `focused` package\n  \n## Creating Optics\n\nAs seen in the tutorial,`lensProxy` offers a convenient way to create Optics which focus on javascript objects and arrays. `lensProxy` is essentially a façade API which uses explicit functions behind the scene. In the following examples, we'll see both the proxy and the coresponding explicit functions.\n\n### Object properties\n\nAs we saw in the tutorial, we use the familiar property access notation to focus on an object property. For example\n\n```js\nconst _ = lensProxy()\nconst nameProp = _.name\n```\n\ncreates a Lens which focuses on the `name` property of an object.\n\nUsing the explicit style, we can use the the `prop` function\n\n```js\nconst nameProp = prop(\"name\")\n```\nAs said previously, **a Lens focuses exactly on one value**, it means the value must exist in the target container (in this sense the `prop` lens is *partial*). For example, if you use `nameProp` on an object which doesn't have a `name` property, it will throw an error.\n\n### Array elements\n\nAs with object properties, we use the array index notation to focus on an array element at a specific index. For example\n\n```js\nconst _ = lensProxy()\nconst firstElem = _[0]\n```\ncreates a lens that focuses on the first element on an array. The underlying function is `index`, so we could also write\n\n```js\nconst firstElem = index(0)\n```\n\n`index` is also a partial Lens, meaning it will throw if given index is out of the bounds of the target array.\n\n### Creating custom lenses\n\nThe `lens` function can be used to create arbitrary Lenses. The function takes 2 parameters\n\n- `getter` is used to extract the focus value from the target container\n- `setter` is used to update the target container with a new focus value.\n\nIn the following example, `nameProp` is equivalent to the `nameProp` Lens we saw earlier.\n\n```js\nconst nameProp = lens(\n  s => s.name,\n  (value, s) => ({...s, name: value})\n) \n```\n\nAs you may have guessed, both `prop` and `index` can be implemented using `lens`\n\n### Composing Lenses\n\n>Generally you can combine any 2 Optics together, even if they're of different kind (eg you can combine Lenses with Traversals)\n\nA nice property of Lenses, and Optics in general, is that they can be combined to create a focus on deeply nested values. For example\n\n```js\nconst _ = lensProxy()\nconst street = _.freinds[0].address.street\n```\n\ncreates a Lens which focuses  on the `street` of the `address` of the first element of the `freinds` array. As a matter of comparaison, let's say we want to update, immutably, the `street` property on a given object `person`. Using JavaScript spread syntax\n\n\n```js\nconst firstFreind = person.freinds[0];\nconst newPerson = {\n  ...person,\n  freinds: [\n    {\n      ...firstFreind,\n      address: {\n        ...firstFreind.address,\n        street: \"new street\"\n      }\n    },\n    ...person.freinds.slice(1)\n  ]\n};\n```\n\nThe equivalent operation in `focused` Lenses is\n\n```js\nconst newPerson = set(_.freinds[0].address.street, \"new street\", person)\n```\n\nWe're chaining `.` accesses to successively focus on deeply nested values. Behind the scene, `lensProxy` is creating the necessary `prop` and `index` Lenses, then composing them using `compose` function. Using explicit style, the above Lens could be rewritten like\n\n```js\nconst streetLens = compose(\n  prop(\"freinds\"),\n  index(0),\n  prop(\"address\"),\n  prop(\"street\")\n);\n```\n\nThe important thing to remember here, is that`lensProxy` is essentially doing the same thing in the above `compose` example. Plus some memoization tricks to ensure that Lenses are created only once and reused on subsequent operations.\n\n## Creating Isomorphisms\n\nIsomorphisms, or simply Isos, are useful when we want to switch between different representations of the same object. In the tutorial, we already saw `json` which create an Iso between a JSON string and the underlying object that the string parses to.\n\nAs we saw, we can use the `iso` function to create a simple Iso. It takes a couple of functions \n\n- the firs function is used to convert from the source representation to the target one\n- the second function is used to convert back\n\nWe'll see another interesting example of Isos in the next section\n\n## Creating Traversals\n\nWhile Lenses can focus exactly on one value. Traversals has the ability to focus on many values (including `0`).\n\n### Array Traversals\n\nPerhaps the most familiar Traversal is `each` which focuses on all elements of an array\n\n```js\nconst todos = [\"each\", \"pray\", \"love\"];\nover(each, x => x.toUpperCase(), todos)\n// [\"EACH\", \"PRAY\", \"LOVE\"]\n```\n\nwhich is essentially equivalent to the `map` operation of array. However, as we said, what sets Optics apart is their ability to compose with other Optics\n\n```js\nconst todos = [\n  { title: \"eat\", done: false },\n  { title: \"pray\", done: false },\n  { title: \"love\", done: false }\n];\n// set done to `true` for all todos\nset(\n  compose(each, prop(\"done\")),\n  true,\n  todos\n)\n```\n\nThis can be more concisely formulated using the proxy interface\n\n```js\nconst _ = lensProxy();\nset(_.$(each).done, true, todos)\n```\n\nNote that when Traversals are composed with another Optic, the result is always a Traversal.\n\n### Traversing Map's keys/values\n\nAnother useful example is traversing keys or values of a JavaScript `Map` object. Although the library already provides `eachMapKey` and `eachMapValue` Traversals for that purpose, it would be instructive to see how we can build them by simple composition of more primitive Optics.\n\nFirst, we can observe that a `Map` object can be seen also as a collection of `[key, value]` pairs. So we can start by creating an Iso between `Map` and `Array<[key, value]>`\n\n```js\nconst mapEntries = iso(\n  map => [...map.entries()], \n  entries => new Map(entries)\n);\n```\n\nThen from here, we can traverse keys or values by simply focusing on the appropriate index (`0` or `1`) of each pair in the returned array. \n\n```js\neachMapValue = compose(mapEntries, each, index(1));\neachMapKey = compose(mapEntries, each, index(0));\n```\n\nSince composition with a Traversal is also a Traversal. In the above examples, we obtain, in both cases, a Traversal that focuses on all key/values of the Map.\n\nAs an illustration, the following example use `eachMapValue` combined with the `prop(\"score\")` lens to increase the score of each player stored in the Map. \n\n```js\nconst playerMap = new Map([\n  [\"Yassine\", { name: \"Yassine\", score: 41 }], \n  [\"Yahya\", { name: \"Yahya\", score: 800 }], \n  [\"Ayman\", { name: \"Ayman\", score: 410} ]\n]);\nconst _ = lensProxy();\nover(\n  _.$(eachMapValue).score, \n  x => x + 1000, \n  playerMap\n);\n```\n\n### Filtered Traversals\n\nAnother useful function is `filtered`. It can be used to restrict the set of values obtained from another Traversal. The function takes 2 arguments\n\n- A predicate used to filter traversed elements\n- The Traversal to be filtered (defaults to `each`)\n\n```js\nconst todos = [\n  { title: \"eat\", done: false },\n  { title: \"pray\", done: true },\n  { title: \"love\", done: true }\n];\n\nconst isDone = t => t.done\n// view title of all done todos\ntoList(_.$(filtered(isDone)).title, todos);\n// => [\"pray\", \"love\"]\n// set done of all done todos to false\nset(_.$(filtered(isDone)).done, false, todos)\n```\n\nNote that `filtered` can work with arbitrary traversals, not just arrays.\n\n```js\nconst playersAbove300 = filtered(p => p.score > 300, eachMapValue)\nover(\n  _.$(playersAbove300).score, \n  x => x + 1000, \n  playerMap\n);\n```\n\n(TBC)\n\n## Todos\n- [ ] API docs\n- [x] add typings\n- [ ] Indexed Traversals\n"
  },
  {
    "path": "index.d.ts",
    "content": "// convenient shortcut for functions taking 1 param\nexport type Fn<A, B> = (x: A) => B;\n\nexport type Const<R, A> = R & { _brand: A };\n\nexport type Either<A, B> =\n  | { type: \"Left\"; value: A }\n  | { type: \"Right\"; value: B };\n\nexport interface Monoid<A> {\n  empty: () => A;\n  concat: (xs: A[]) => A;\n}\n\nexport interface Functor<A, B, FA, FB> {\n  map(f: Fn<A, B>, x: FA): FB;\n}\n\nexport interface Applicative<A, B, FA, FB> extends Functor<A, B, FA, FB> {\n  pure: Fn<B, FB>;\n  combine: (f: Fn<A[], B>, fas: FA[]) => FB;\n}\n\nexport interface Getting<R, S, A> {\n  \"~~type~~\": \"Getting\";\n  \"~~apply~~\": <FA extends Const<R, A>, FS extends Const<R, S>>(\n    F: Applicative<A, S, FA, FS>,\n    f: Fn<A, FA>,\n    s: S\n  ) => FS;\n}\n\nexport interface Getter<S, A> {\n  \"~~type~~\": \"Getting\";\n  \"~~apply~~\": <R, FA extends Const<R, A>, FS extends Const<R, S>>(\n    F: Functor<A, S, FA, FS>,\n    f: Fn<A, FA>,\n    s: S\n  ) => FS;\n}\n\nexport interface Iso<S, T, A, B> {\n  \"~~type~~\": \"Getting\" & \"Iso\" & \"Lens\" & \"Traversal\";\n  \"~~apply~~\": (<FB, FT>(F: Functor<B, T, FB, FT>, f: Fn<A, FB>, s: S) => FT);\n  from: (s: S) => A;\n  to: (b: B) => T;\n}\n\nexport interface Prism<S, T, A, B> {\n  \"~~type~~\": \"Getting\" & \"Prism\" & \"Traversal\";\n  \"~~apply~~\": (<FB, FT>(\n    F: Applicative<B, T, FB, FT>,\n    f: Fn<A, FB>,\n    s: S\n  ) => FT);\n  match: (s: S) => Either<T, A>;\n  build: (b: B) => T;\n}\n\nexport interface Lens<S, T, A, B> {\n  \"~~type~~\": \"Getting\" & \"Lens\" & \"Traversal\";\n  \"~~apply~~\": (<FB, FT>(F: Functor<B, T, FB, FT>, f: Fn<A, FB>, s: S) => FT);\n}\n\nexport interface Traversal<S, T, A, B> {\n  \"~~type~~\": \"Getting\" & \"Traversal\";\n  \"~~apply~~\": (<FB, FT>(\n    F: Applicative<B, T, FB, FT>,\n    f: Fn<A, FB>,\n    s: S\n  ) => FT);\n}\n\n// Monomorphic version\nexport type SimpleIso<S, A> = Iso<S, S, A, A>;\nexport type SimplePrism<S, A> = Prism<S, S, A, A>;\nexport type SimpleLens<S, A> = Lens<S, S, A, A>;\nexport type SimpleTraversal<S, A> = Traversal<S, S, A, A>;\n\n// arity 2\nexport function compose<S, T, A, B, C, D>(\n  parent: Iso<S, T, A, B>,\n  child: Iso<A, B, C, D>\n): Iso<S, T, C, D>;\nexport function compose<S, T, A, B, C, D>(\n  parent: Prism<S, T, A, B>,\n  child: Prism<A, B, C, D>\n): Prism<S, T, C, D>;\nexport function compose<S, T, A, B, C, D>(\n  parent: Lens<S, T, A, B>,\n  child: Lens<A, B, C, D>\n): Lens<S, T, C, D>;\nexport function compose<S, T, A, B, C, D>(\n  parent: Traversal<S, T, A, B>,\n  child: Traversal<A, B, C, D>\n): Traversal<S, T, C, D>;\nexport function compose<S, A, B>(\n  parent: Getter<S, A>,\n  child: Getter<A, B>\n): Getter<S, B>;\n// arity 3\nexport function compose<S, T, A, B, C, D, E, F>(\n  parent: Iso<S, T, A, B>,\n  child1: Iso<A, B, C, D>,\n  child2: Iso<C, D, E, F>\n): Iso<S, T, E, F>;\nexport function compose<S, T, A, B, C, D, E, F>(\n  parent: Prism<S, T, A, B>,\n  child1: Prism<A, B, C, D>,\n  child2: Prism<C, D, E, F>\n): Prism<S, T, E, F>;\nexport function compose<S, T, A, B, C, D, E, F>(\n  parent: Traversal<S, T, A, B>,\n  child1: Traversal<A, B, C, D>,\n  child2: Traversal<C, D, E, F>\n): Traversal<S, T, E, F>;\nexport function compose<S, A, B, C>(\n  parent: Getter<S, A>,\n  child1: Getter<A, B>,\n  child2: Getter<B, C>\n): Getter<S, C>;\n// arity 4\nexport function compose<S, T, A, B, C, D, E, F, G, H>(\n  parent: Iso<S, T, A, B>,\n  child1: Iso<A, B, C, D>,\n  child2: Iso<C, D, E, F>,\n  child3: Iso<E, F, G, H>\n): Iso<S, T, G, H>;\nexport function compose<S, T, A, B, C, D, E, F, G, H>(\n  parent: Prism<S, T, A, B>,\n  child1: Prism<A, B, C, D>,\n  child2: Prism<C, D, E, F>,\n  child3: Prism<E, F, G, H>\n): Prism<S, T, G, H>;\nexport function compose<S, T, A, B, C, D, E, F, G, H>(\n  parent: Lens<S, T, A, B>,\n  child1: Lens<A, B, C, D>,\n  child2: Lens<C, D, E, F>,\n  child3: Lens<E, F, G, H>\n): Lens<S, T, G, H>;\nexport function compose<S, T, A, B, C, D, E, F, G, H>(\n  parent: Traversal<S, T, A, B>,\n  child1: Traversal<A, B, C, D>,\n  child2: Traversal<C, D, E, F>,\n  child3: Traversal<E, F, G, H>\n): Traversal<S, T, G, H>;\nexport function compose<S, A, B, C, D>(\n  parent: Getter<S, A>,\n  child1: Getter<A, B>,\n  child2: Getter<B, C>,\n  child3: Getter<C, D>\n): Getter<S, D>;\n// arity 5\nexport function compose<S, T, A, B, C, D, E, F, G, H, I, J>(\n  parent: Iso<S, T, A, B>,\n  child1: Iso<A, B, C, D>,\n  child2: Iso<C, D, E, F>,\n  child3: Iso<E, F, G, H>,\n  child4: Iso<G, H, I, J>\n): Iso<S, T, I, J>;\nexport function compose<S, T, A, B, C, D, E, F, G, H, I, J>(\n  parent: Prism<S, T, A, B>,\n  child1: Prism<A, B, C, D>,\n  child2: Prism<C, D, E, F>,\n  child3: Prism<E, F, G, H>,\n  child4: Prism<G, H, I, J>\n): Prism<S, T, I, J>;\nexport function compose<S, T, A, B, C, D, E, F, G, H, I, J>(\n  parent: Lens<S, T, A, B>,\n  child1: Lens<A, B, C, D>,\n  child2: Lens<C, D, E, F>,\n  child3: Lens<E, F, G, H>,\n  child4: Lens<G, H, I, J>\n): Lens<S, T, I, J>;\nexport function compose<S, T, A, B, C, D, E, F, G, H, I, J>(\n  parent: Traversal<S, T, A, B>,\n  child1: Traversal<A, B, C, D>,\n  child2: Traversal<C, D, E, F>,\n  child3: Traversal<E, F, G, H>,\n  child4: Traversal<G, H, I, J>\n): Traversal<S, T, I, J>;\nexport function compose<S, A, B, C, D, E>(\n  parent: Getter<S, A>,\n  child1: Getter<A, B>,\n  child2: Getter<B, C>,\n  child3: Getter<C, D>,\n  child4: Getter<D, E>\n): Getter<S, E>;\n// for higher arities you can use _.$().$()... of nest compose calls\n\nexport function over<S, T, A, B>(\n  optic: Traversal<S, T, A, B>,\n  updater: (a: A) => B,\n  state: S\n): T;\n\nexport function set<S, T, A, B>(\n  optic: Traversal<S, T, A, B>,\n  value: B,\n  state: S\n): T;\n\nexport function view<S, A>(optic: Getting<A, S, A>, state: S): A;\n\nexport function preview<S, A>(\n  optic: Getting<A | null, S, A>,\n  state: S\n): A | null;\n\nexport function has<S, A>(optic: Getting<boolean, S, A>, state: S): boolean;\n\nexport function toList<S, A>(optic: Getting<A[], S, A>, state: S): A[];\n\nexport function append<S, A>(\n  optic: SimpleTraversal<S, A[]>,\n  item: A,\n  state: S\n): S;\nexport function insertAt<S, A>(\n  optic: SimpleTraversal<S, A[]>,\n  index: number,\n  item: A,\n  state: S\n): S;\nexport function removeAt<S, A>(\n  optic: SimpleTraversal<S, A[]>,\n  index: number,\n  state: S\n): S;\nexport function removeIf<S, A>(\n  optic: SimpleTraversal<S, A[]>,\n  f: (x: A) => boolean,\n  state: S\n): S;\n\nexport function iso<S, T, A, B>(\n  from: (s: S) => A,\n  to: (b: B) => T\n): Iso<S, T, A, B>;\nexport function from<S, T, A, B>(anIso: Iso<S, T, A, B>): Iso<B, A, T, S>;\nexport function withIso<S, T, A, B, R>(\n  anIso: Iso<S, T, A, B>,\n  f: (from: Fn<S, A>, to: Fn<B, T>) => R\n): R;\nexport function non<A>(x: A): SimpleIso<A | null, A>;\nexport function anon<A>(x: A, f: Fn<A, boolean>): SimpleIso<A | null, A>;\n// TODO: json :: SimpleIso<String,Object>\n// TODO: mapEntries :: SimpleIso<Map<Key,Value>>, Array<[Key,Value]>\n\nexport function lens<S, T, A, B>(\n  get: (s: S) => A,\n  set: (b: B, s: S) => T\n): Lens<S, T, A, B>;\nexport function prop<S, K extends keyof S>(name: K): SimpleLens<S, S[K]>;\nexport function index<A>(i: number): SimpleLens<[A], A>;\nexport function atProp<S, K extends keyof S>(\n  name: K\n): SimpleLens<S | null, S[K] | null>;\nexport function to<S, A>(getter: (s: S) => A): Getter<S, A>;\n\nexport function eachOf<A>(): SimpleTraversal<A[], A>;\nexport const each: SimpleTraversal<any[], any>;\n\nexport function filtered<A, B>(\n  f: (x: A) => Boolean,\n  traversal?: Traversal<A[], B[], A, B>\n): Traversal<A[], B[], A, B>;\nexport function maybeProp<S, K extends keyof S>(\n  name: K\n): SimpleTraversal<S, S[K]>;\n// TODO: eachValue :: SimpleTraversal<Map<K,V>, V>\n// TODO: eachKey :: SimpleTraversal<Map<K,V>, K>\n\nexport function left<A, B>(a: A): Either<A, B>;\nexport function rght<A, B>(b: B): Either<A, B>;\nexport function prism<S, T, A, B>(\n  match: (s: S) => Either<T, A>,\n  build: (b: B) => T\n): Prism<S, T, A, B>;\nexport function simplePrism<S, A>(\n  match: (s: S) => A | null,\n  build: (a: A) => S\n): SimplePrism<S, A>;\nexport function withPrism<S, T, A, B, R>(\n  aPrism: Prism<S, T, A, B>,\n  f: (match: (s: S) => Either<T, A>, build: (b: B) => T) => R\n): R;\n// TODO: maybeJson :: SimplePrism<String,Object>\n\nexport type LensProxy<P, S> = SimpleLens<P, S> &\n  (S extends object ? { [K in keyof S]: LensProxy<P, S[K]> } : {}) & {\n    $<A>(child: SimpleLens<S, A>): LensProxy<P, A>;\n    $<A>(child: SimpleTraversal<S, A>): TraversalProxy<P, A>;\n    $<A>(child: Getter<S, A>): GetterProxy<P, A>;\n  };\n\nexport type TraversalProxy<P, S> = SimpleTraversal<P, S> &\n  (S extends object ? { [K in keyof S]: TraversalProxy<P, S[K]> } : {}) & {\n    $<A>(child: SimpleTraversal<S, A>): TraversalProxy<P, A>;\n    $<A>(child: Getter<S, A>): GetterProxy<P, A>;\n  };\n\nexport type GetterProxy<P, S> = Getter<P, S> &\n  (S extends object ? { [K in keyof S]: GetterProxy<P, S[K]> } : {}) & {\n    $<A>(child: Getter<S, A>): GetterProxy<P, A>;\n  };\n\nexport function lensProxy<P, S = P>(parent?: SimpleLens<P, S>): LensProxy<P, S>;\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"focused\",\n  \"version\": \"0.7.2\",\n  \"description\": \"Lens/Optics library for JavaScript\",\n  \"module\": \"src/index.js\",\n  \"main\": \"cjs/index.js\",\n  \"typings\": \"./index.d.ts\",\n  \"repository\": \"https://github.com/yelouafi/focused.git\",\n  \"author\": \"Yassine Elouafi <yelouafi@gmail.com>\",\n  \"license\": \"MIT\",\n  \"keywords\": [\n    \"optic\",\n    \"lens\",\n    \"isomorphism\",\n    \"prism\",\n    \"traversal\"\n  ],\n  \"devDependencies\": {\n    \"babel-cli\": \"^6.26.0\",\n    \"babel-preset-env\": \"^1.7.0\",\n    \"eslint\": \"^5.8.0\",\n    \"esm\": \"^3.0.84\",\n    \"faucet\": \"^0.0.1\",\n    \"rimraf\": \"^2.6.2\",\n    \"tape\": \"^4.9.1\"\n  },\n  \"scripts\": {\n    \"lint\": \"eslint src test\",\n    \"test\": \"node -r esm test/index.test | faucet\",\n    \"check\": \"npm run lint && npm run test\",\n    \"clean\": \"rimraf cjs\",\n    \"build\": \"npm run clean && babel src --out-dir cjs\",\n    \"prepare\": \"npm run build\",\n    \"prerelease\": \"npm run check && npm run prepare\",\n    \"release:patch\": \"npm run prerelease && npm version patch && git push --follow-tags && npm publish\",\n    \"release:minor\": \"npm run prerelease && npm version minor && git push --follow-tags && npm publish\",\n    \"release:major\": \"npm run prerelease && npm version major && git push --follow-tags && npm publish\"\n  },\n  \"babel\": {\n    \"presets\": [\n      [\n        \"env\",\n        {\n          \"targets\": {\n            \"node\": \"current\"\n          }\n        }\n      ]\n    ]\n  }\n}\n"
  },
  {
    "path": "src/index.js",
    "content": "import { curry3, curry4 } from \"./utils\";\nimport { over } from \"./operations\";\nexport {\n  iso,\n  from,\n  withIso,\n  non,\n  anon,\n  json,\n  mapEntries,\n  compose2Isos\n} from \"./iso\";\nexport { prop, index, lens, atProp } from \"./lens\";\nexport {\n  prism,\n  withPrism,\n  simplePrism,\n  left,\n  right,\n  maybeJson,\n  compose2Prisms\n} from \"./prism\";\nexport {\n  each,\n  eachOf,\n  filtered,\n  maybeProp,\n  eachMapKey,\n  eachMapValue\n} from \"./traversal\";\nexport {\n  view,\n  preview,\n  toList,\n  has,\n  over,\n  set,\n  compose,\n  compose2\n} from \"./operations\";\nexport { lensProxy, idLens } from \"./lensProxy\";\n\nfunction _append(lens, x, s) {\n  return over(lens, xs => xs.concat([x]), s);\n}\n\nfunction _insertAt(lens, index, x, s) {\n  return over(\n    lens,\n    xs => {\n      return xs\n        .slice(0, index)\n        .concat([x])\n        .concat(xs.slice(index));\n    },\n    s\n  );\n}\n\nfunction _removeIf(lens, p, s) {\n  return over(lens, xs => xs.filter((x, i) => !p(x, i)), s);\n}\n\nfunction _removeAt(lens, index, s) {\n  return removeIf(lens, (_, i) => i === index, s);\n}\n\nexport const append = curry3(_append);\nexport const insertAt = curry4(_insertAt);\nexport const removeIf = curry3(_removeIf);\nexport const removeAt = curry3(_removeAt);\n"
  },
  {
    "path": "src/iso.js",
    "content": "/*\n    type Iso<S,T,A,B> = (Functor<F>, A => F<B>, S) => F<T>  &   \n                        { from: S => A, to: B => T }\n\n    type SimpleIso<S,A> = Iso<S,S,A,A>\n*/\n\n// iso : (S => A, B => T) => Iso<S,T,A,B>\nexport function iso(from, to) {\n  function isoFn(aFunctor, f, s) {\n    return aFunctor.map(to, f(from(s)));\n  }\n  // escape hatch to avoid profunctors\n  Object.assign(isoFn, {\n    __IS_ISO: true,\n    from,\n    to\n  });\n  return isoFn;\n}\n\n// withIso : (Iso<S,T,A,B>, (S => A, B => T) => R) => R\nexport function withIso(anIso, f) {\n  return f(anIso.from, anIso.to);\n}\n\n// parent : Iso<S,T,A,B>       from: S => A, to: B => T\n// child  : Iso<A,B,X,Y>       from: A => X, to: Y => B\n// return : Iso<S,T,X,Y>       from: S => X, to: Y => T\nexport function compose2Isos(parent, child) {\n  const { from: sa, to: bt } = parent;\n  const { from: ax, to: yb } = child;\n  return iso(s => ax(sa(s)), y => bt(yb(y)));\n}\n\n// from : Iso<S,T,A,B> => Iso<B,A,T,S>\nexport function from(anIso) {\n  return iso(anIso.to, anIso.from);\n}\n\n// non : a => SimpleIso<Maybe<A> without a, A>\nexport function non(a) {\n  return iso(\n    //from : Maybe<A\\a> -> a\n    m => (m === null ? a : m),\n    //to   : a -> Maybe<A\\a>\n    x => (x === a ? null : x)\n  );\n}\n\n// non : (a, A -> boolean) => SimpleIso<Maybe<A> where pred(A) == false, a>\nexport function anon(a, pred) {\n  return iso(m => (m === null ? a : m), x => (pred(x) ? null : x));\n}\n\n// json : SimpleIso<String,Object>\nexport const json = iso(JSON.parse, JSON.stringify);\n\n// SimpleIso<Map<Key,Value>>, Array<[Key,Value]>\nexport const mapEntries = iso(map => [...map.entries()], kvs => new Map(kvs));\n"
  },
  {
    "path": "src/lens.js",
    "content": "/*\n    type Lens<S,T,A,B> = (Functor<F>, A => F<B>, S) => F<T>\n    type SimpleLens<S,A> = Lens<S,S,A,A>\n*/\n\n// lens : (S => A, (B,S) => T) => Lens<S,T,A,B>\nexport function lens(getter, setter) {\n  return function gsLens(aFunctor, f, s) {\n    return aFunctor.map(a2 => setter(a2, s), f(getter(s)));\n  };\n}\n\n// prop : K => SimpleLens<S,S[K]>\n// PARTIAL : will throw if name isn't a prop of the target\nexport function prop(name) {\n  return lens(\n    s => {\n      if (!s.hasOwnProperty(name)) {\n        throw new Error(\n          `object ${JSON.stringify(s)} doesn't have property ${name}`\n        );\n      }\n      return s[name];\n    },\n    (a, s) =>\n      Object.assign({}, s, {\n        [name]: a\n      })\n  );\n}\n\n// index : number => SimpleLens<[A], A>\n// PARTIAL : will throw if idx is out of bounds\nexport function index(idx) {\n  return function indexLens(aFunctor, f, xs) {\n    if (idx < 0 || idx >= xs.length) {\n      throw new Error(\"index out of bounds!\");\n    }\n    return aFunctor.map(a2 => {\n      const ys = xs.slice();\n      ys[idx] = a2;\n      return ys;\n    }, f(xs[idx]));\n  };\n}\n\n// atProp : K => SimpleLens<Maybe<S>, Maybe<S[K]>>\nexport function atProp(key) {\n  return function atKeyLens(aFunctor, f, s) {\n    let a = s !== null && s.hasOwnProperty(key) ? s[key] : null;\n    return aFunctor.map(a2 => {\n      if (a2 === null) {\n        if (a === null || s === null) return s;\n        const copy = Object.assign({}, s);\n        delete copy[key];\n        return copy;\n      } else {\n        return Object.assign({}, s, { [key]: a2 });\n      }\n    }, f(a));\n  };\n}\n\n// to : (S => A) => SimpleLens<S,A>\nexport function to(getter) {\n  return lens(getter, () => {\n    throw new Error(\"Can not modify the value of a getter\");\n  });\n}\n"
  },
  {
    "path": "src/lensProxy.js",
    "content": "import { prop, index } from \"./lens\";\nimport { maybeProp } from \"./traversal\";\nimport { compose2 } from \"./operations\";\n\n// idLens : SimpleLens<S,S>\nexport function idLens(_, f, s) {\n  return f(s);\n}\n\n/**\n *  returns a Proxy object for easing creation & composition of optics\n *\n *  const _ = lensProxy()\n *  _.name          <=>     prop(\"name\")\n *  _.todo.title    <=>     compose(prop(\"todo\"), prop(\"title\"))\n *\n *  For convenience, safe access to non existing is provided by perfixng the prop name with '$'\n *\n * _.$name          <=>     maybeProp(\"name\")\n *\n * You can also insert other optics usin '$' method of the proxy lensProxy, for example\n *\n *  _.todos.$(each).title   <=>    compose(prop(\"todos\"), each, prop(\"title\"))\n *\n * is a traversal that focuses on all titles of the todo array\n */\n\nfunction getOrCreateLens(memo, parent, key) {\n  let l = memo.get(key);\n  if (l == null) {\n    let child;\n    const num = Number(key);\n    if (String(num) === key) {\n      child = index(num);\n    } else if (key[0] === \"$\") {\n      child = maybeProp(key.slice(1));\n    } else {\n      child = prop(key);\n    }\n    l = lensProxy(compose2(parent, child));\n    memo.set(key, l);\n  }\n  return l;\n}\n\nexport function lensProxy(parent = idLens) {\n  const memo = new Map();\n  return new Proxy(() => {}, {\n    get(target, key) {\n      if (key === \"$\") {\n        return child => {\n          return lensProxy(compose2(parent, child));\n        };\n      }\n      return getOrCreateLens(memo, parent, key);\n    },\n    apply(target, thiz, [F, f, s]) {\n      return parent(F, f, s);\n    }\n  });\n}\n"
  },
  {
    "path": "src/operations.js",
    "content": "import { id, konst, curry2, curry3 } from \"./utils\";\nimport {\n  ConstAny,\n  ConstFirst,\n  ConstList,\n  ConstVoid,\n  Identity,\n  List\n} from \"./typeClasses\";\nimport { compose2Isos } from \"./iso\";\nimport { compose2Prisms } from \"./prism\";\n\n/*\n  type Settable<S,T,A,B>  = (Identity, A => Identity<B>, S) => Identity<T>\n  type Getting<R,S,A>     = (Const<R>, A => Const<R,A>, S) => Const<R,S>\n  type Getter<S,A>        = <R>Getting<R,S,A> -- ie should work for any R\n */\n\n// view : Getting<A,S,A> => S => A\nexport const view = curry2(function _view(aGetter, s) {\n  return aGetter(ConstVoid, id, s);\n});\n\nfunction _over(aSettable, f, s) {\n  return aSettable(Identity, f, s);\n}\n\n// over : Settable<S,T,A,B> => (A => B) => S => T\nexport const over = curry3(_over);\n\n// set : Settable<S,T,A,B> => B => S => T\nexport const set = curry3(function _set(aSettable, v, s) {\n  return _over(aSettable, konst(v), s);\n});\n\n// toList : Getting<[A], S,A> => S => [A]\nexport const toList = curry2(function toList(aGetting, s) {\n  return aGetting(ConstList, List.pure, s);\n});\n\n// preview : Getting<A | null, S,A> => S => (A | null)\nexport const preview = curry2(function _preview(aGetting, s) {\n  return aGetting(ConstFirst, id, s);\n});\n\n// has : (Getting<Boolean, S,A>, S) => Boolean\nexport const has = curry2(function _has(aGetting, s) {\n  return aGetting(ConstAny, konst(true), s);\n});\n\n/**\n * Compose 2 optics, Abstarcting the constraints, the type can be seen as\n *\n *    compose2 : (Optic<S,T,A,B>, Optic<A,B,X,Y>) => Optic<S,T,A,B>\n *\n * However, we need also to combine 2 Isos into an Iso and idem for Prisms\n * In Haskell this is acheived using type classes & Profunctors\n *\n * Here we're just inspecting types at runtime, it's ugly and less flexible but\n * works for our limited cases. Most notably, I don't want to introduce Profunctors\n * for performance reasons.\n */\nexport function compose2(parent, child) {\n  // ad-hoc polymporphism FTW\n  if (parent.__IS_ISO && child.__IS_ISO) {\n    return compose2Isos(parent, child);\n  }\n  if (parent.__IS_PRISM && child.__IS_PRISM) {\n    return compose2Prisms(parent, child);\n  }\n  return function composedOptics(F, f, s) {\n    return parent(F, a => child(F, f, a), s);\n  };\n}\n\nexport function compose(...ls) {\n  return ls.reduce(compose2);\n}\n"
  },
  {
    "path": "src/prism.js",
    "content": "/*\n    type Either<T,A> = { type: \"LEFT\", value: T } | { type: \"RIGHT\", value: A }\n\n    type Prism<S,T,A,B> = \n            (Applicative<F>, A => F<B>, S) => F<T> \n        &   { __IS_PRISM: true, match: S => Either<T,A>, to: B => T }\n\n    type SimplePrism<S,A> = Prism<S,S,A,A>\n*/\n\nexport function left(value) {\n  return { type: \"LEFT\", value };\n}\n\nexport function right(value) {\n  return { type: \"RIGHT\", value };\n}\n\n// prism : (S => Either<T,A>, B => T) => Prism<S,T,A,B>\nexport function prism(match, build) {\n  function prismFn(anApplicative, f, s) {\n    const result = match(s);\n    if (result.type === \"LEFT\") return anApplicative.pure(result.value);\n    const fa = f(result.value);\n    return anApplicative.map(build, fa);\n  }\n  // escape hatch to avoid profunctors\n  Object.assign(prismFn, {\n    __IS_PRISM: true,\n    build,\n    match\n  });\n  return prismFn;\n}\n\n// simplePrism : (S => Maybe<A>, A => S) => SimplePrism<S,A>\nexport function simplePrism(match, build) {\n  return prism(s => {\n    const result = match(s);\n    return result === null\n      ? { type: \"LEFT\", value: s }\n      : { type: \"RIGHT\", value: result };\n  }, build);\n}\n\n// withPrism : (Prism<S,T,A,B>, (S => Either<T,A>, B => T) => R) => R\nexport function withPrism(aPrism, f) {\n  return f(aPrism.match, aPrism.build);\n}\n\n// parent : Prism<S,T,A,B>  &   { match: S => Either<T,A>, to: B => T }\n// child  : Prism<A,B,X,Y>  &   { match: A => Either<B,X>, to: Y => B }\n// return : Prism<S,T,X,Y>  &   { match: S => Either<T,X>, to: Y => T }\nexport function compose2Prisms(parentL, childL) {\n  const { match: sta, build: bt } = parentL;\n  const { match: abx, build: yb } = childL;\n  return prism(\n    s => {\n      const ta = sta(s);\n      if (ta.type === \"LEFT\") return ta;\n      const bx = abx(ta.value);\n      if (bx.type === \"RIGHT\") return bx;\n      return bt(bx.value);\n    },\n    y => bt(yb(y))\n  );\n}\n\n// json : SimplePrism<String,Object>\nexport const maybeJson = simplePrism(s => {\n  try {\n    return JSON.parse(s);\n  } catch (e) {\n    return null;\n  }\n}, JSON.stringify);\n"
  },
  {
    "path": "src/traversal.js",
    "content": "import { id } from \"./utils\";\nimport { compose } from \"./operations\";\nimport { mapEntries } from \"./iso\";\nimport { index } from \"./lens\";\n/*\n    type Traversal<S,T,A,B> = (Applicative<F>, A => F<B>, S) => F<T>\n    type SimpleTraversal<S,A> = Traversal<S,S,A,A>\n*/\n\n// each : Traversal< Array<A>, Array<B>, A, B>\nexport function each(anApplicative, f, xs) {\n  return anApplicative.combine(id, xs.map(f));\n}\n\n// eachOf: <A>() => Traversal< Array<A>, Array<B>, A, B>\n// this of the convenience of typings since TypeScript doesn't\n// allow type parameters on non functions\nexport function eachOf() {\n  return each;\n}\n\n// filter : (A => Boolean) => Traversal< Array<A>, Array<B>, A, B>\nexport function filtered(pred, traverse = each) {\n  return function filterTraversal(anApplicative, f, s) {\n    return traverse(anApplicative, update, s);\n\n    function update(v) {\n      return pred(v) ? f(v) : anApplicative.pure(v);\n    }\n  };\n}\n\n// maybeProp :: K => SimpleTraversal<S, S[K]>\n// This is an Affine Traversal; ie focus on 0 or 1 value\nexport function maybeProp(name) {\n  return function propTraversal(anApplicative, f, s) {\n    if (!s.hasOwnProperty(name)) {\n      return anApplicative.pure(s);\n    }\n    return anApplicative.map(a2 => {\n      return Object.assign({}, s, {\n        [name]: a2\n      });\n    }, f(s[name]));\n  };\n}\n\n// eachValue :: SimpleTraversal<Map<K,V>, V>\nexport const eachMapValue = compose(\n  mapEntries,\n  each,\n  index(1)\n);\n\n// eachKey :: SimpleTraversal<Map<K,V>, K>\nexport const eachMapKey = compose(\n  mapEntries,\n  each,\n  index(0)\n);\n"
  },
  {
    "path": "src/typeClasses.js",
    "content": "export const Void = {\n  empty: () => {\n    throw \"Void.empty! (you're likely using view with a Traversal, try preview or toList instead)\";\n  },\n  concat: () => {\n    throw \"Void.concat! (you're likely using view with a Traversal, try preview or toList instead)\";\n  }\n};\n\nexport const List = {\n  empty: () => [],\n  concat: xxs => [].concat(...xxs),\n  pure: x => [x],\n  map: (f, xs) => xs.map(f)\n};\n\nexport const First = {\n  empty: () => null,\n  concat2: (x1, x2) => (x1 !== null ? x1 : x2),\n  concat: xs => xs.reduce(First.concat2, null)\n};\n\nexport const Any = {\n  empty: () => false,\n  concat2: (x1, x2) => x1 || x2,\n  concat: xs => xs.reduce(Any.concat2, false)\n};\n\nexport const Identity = {\n  pure: x => x,\n  map: (f, x) => f(x),\n  combine: (f, xs) => f(xs)\n};\n\nexport const Const = aMonoid => ({\n  pure: _ => aMonoid.empty(),\n  map: (f, x) => x,\n  combine: (_, xs) => aMonoid.concat(xs)\n});\n\nexport const ConstVoid = Const(Void);\nexport const ConstList = Const(List);\nexport const ConstFirst = Const(First);\nexport const ConstAny = Const(Any);\n"
  },
  {
    "path": "src/utils.js",
    "content": "export const id = x => x;\nexport const konst = x => _ => x;\n\nexport function curry2(f) {\n  return function curried2(x, y) {\n    if (arguments.length >= 2) return f(x, y);\n    return function curried2_1arg(y) {\n      return f(x, y);\n    };\n  };\n}\n\nexport function curry3(f) {\n  return function curried3(x, y, z) {\n    if (arguments.length >= 3) return f(x, y, z);\n    if (arguments.length === 2) {\n      return function curried3_2args(z) {\n        return f(x, y, z);\n      };\n    }\n    return curry2(function curried3_1(y, z) {\n      return f(x, y, z);\n    });\n  };\n}\n\nexport function curry4(f) {\n  return function curried4(w, x, y, z) {\n    if (arguments.length >= 4) return f(w, x, y, z);\n    if (arguments.length === 3) {\n      return function curried4_3args(z) {\n        return f(w, x, y, z);\n      };\n    }\n    if (arguments.length === 2) {\n      return curry2(function curried4_2args(y, z) {\n        return f(w, x, y, z);\n      });\n    }\n    return curry3(function curried4_1(x, y, z) {\n      return f(w, x, y, z);\n    });\n  };\n}\n"
  },
  {
    "path": "test/curry.test.js",
    "content": "import test from \"tape\";\nimport { curry2, curry3, curry4 } from \"../src/utils\";\n\nconst add2 = curry2((x, y) => x + y);\nconst add3 = curry3((x, y, z) => x + y + z);\nconst add4 = curry4((w, x, y, z) => w + x + y + z);\n\ntest(\"curry2\", assert => {\n  assert.equal(add2(1, 2), 3);\n  assert.equal(add2(1)(2), 3);\n  assert.end();\n});\n\ntest(\"curry3\", assert => {\n  assert.equal(add3(1, 2, 3), 6);\n  assert.equal(add3(1, 2)(3), 6);\n  assert.equal(add3(1)(2, 3), 6);\n  assert.equal(add3(1)(2)(3), 6);\n  assert.end();\n});\n\ntest(\"curry4\", assert => {\n  assert.equal(add4(1, 2, 3, 4), 10);\n\n  assert.equal(add4(1, 2, 3)(4), 10);\n  assert.equal(add4(1, 2)(3, 4), 10);\n  assert.equal(add4(1, 2)(3)(4), 10);\n  assert.equal(add4(1)(2, 3, 4), 10);\n  assert.equal(add4(1)(2, 3)(4), 10);\n  assert.equal(add4(1)(2)(3, 4), 10);\n  assert.equal(add4(1)(2)(3)(4), 10);\n  assert.end();\n});\n"
  },
  {
    "path": "test/index.test.js",
    "content": "import \"./curry.test\";\nimport \"./optics.test\";\n"
  },
  {
    "path": "test/optics.test.js",
    "content": "import test from \"tape\";\nimport {\n  iso,\n  maybeJson,\n  view,\n  over,\n  toList,\n  preview,\n  set,\n  each,\n  filtered,\n  json,\n  lensProxy,\n  anon,\n  atProp,\n  compose,\n  append,\n  insertAt,\n  removeIf,\n  removeAt\n} from \"../src\";\n\nconst state = {\n  name: \"Luffy\",\n  level: 4,\n  nakama: [\n    { name: \"Zorro\", level: 3 },\n    { name: \"Sanji\", level: 3 },\n    { name: \"Chooper\", level: 2 }\n  ]\n};\n\nconst _ = lensProxy();\n\ntest(\"view/prop\", assert => {\n  assert.equal(view(_.name, state), \"Luffy\");\n  assert.end();\n});\n\ntest(\"preview/maybeProp\", assert => {\n  assert.deepEqual(preview(_.$lastname.level, state), null);\n  assert.end();\n});\n\ntest(\"over/maybeProp\", assert => {\n  assert.deepEqual(over(_.$assitant.$level, x => x * 2, state), state);\n  assert.end();\n});\n\ntest(\"over/prop\", assert => {\n  assert.deepEqual(over(_.level, x => x * 2, state), {\n    ...state,\n    level: state.level * 2\n  });\n  assert.end();\n});\n\ntest(\"view/atProp\", assert => {\n  assert.equal(\n    view(atProp(\"surname\"), { name: \"Luffy\" }),\n    null,\n    \"should return null if property is absent\"\n  );\n\n  assert.end();\n});\n\ntest(\"view/atProp\", assert => {\n  assert.deepEqual(\n    set(atProp(\"surname\"), \"Monkey D.\", { name: \"Luffy\" }),\n    {\n      name: \"Luffy\",\n      surname: \"Monkey D.\"\n    },\n    \"Should add the property if absent\"\n  );\n\n  assert.deepEqual(\n    set(\n      compose(\n        atProp(\"navigator\"),\n        atProp(\"name\")\n      ),\n      \"Nami\",\n      { name: \"Luffy\" }\n    ),\n    {\n      name: \"Luffy\",\n      navigator: { name: \"Nami\" }\n    },\n    \"Should add deeply nested property if absent\"\n  );\n\n  assert.end();\n});\n\n// _.at('address').at('street')\n// Lens<{}, Maybe<{}>>  .  Lens<{}, Maybe<String>>\n\ntest(\"toList/each\", assert => {\n  assert.deepEqual(\n    toList(_.nakama.$(each).name, state),\n    state.nakama.map(n => n.name)\n  );\n  assert.end();\n});\n\ntest(\"toList/filtered\", assert => {\n  assert.deepEqual(\n    toList(_.nakama.$(filtered(x => x.level > 2)).name, state),\n    state.nakama.filter(n => n.level > 2).map(n => n.name)\n  );\n  assert.end();\n});\n\ntest(\"over/filtered\", assert => {\n  assert.deepEqual(\n    over(_.nakama.$(filtered(x => x.level > 2)).name, s => `**${s}**`, state),\n    {\n      ...state,\n      nakama: state.nakama.map(n =>\n        n.level > 2 ? { ...n, name: `**${n.name}**` } : n\n      )\n    }\n  );\n  assert.end();\n});\n\ntest(\"set/[0]\", assert => {\n  assert.deepEqual(set(_.nakama[0].name, \"Jimbi\", state), {\n    ...state,\n    nakama: state.nakama.map((n, i) => (i === 0 ? { ...n, name: \"Jimbi\" } : n))\n  });\n  assert.end();\n});\n\ntest(\"iso/anon\", assert => {\n  // nonZero is an Iso from Maybe<negative number> to number (with 1 as default value)\n  // source is either null or a negative number\n  // target is any number\n  const negative = anon(0, x => x >= 0);\n  assert.equal(view(negative, -10), -10);\n  assert.equal(view(negative, null), 0);\n\n  assert.equal(\n    set(negative, -3, -10),\n    -3,\n    \"should allow setting to negative numbers\"\n  );\n  assert.equal(\n    set(negative, -3, null),\n    -3,\n    \"should allow setting on null values\"\n  );\n  assert.equal(\n    set(negative, 10, -3),\n    null,\n    \"should not allow setting non-negative numbers\"\n  );\n  assert.end();\n});\n\nconst jsonObj = `{\n  \"name\": \"my-package\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Simple package\",\n  \"main\": \"index.html\",\n  \"scripts\": {\n    \"start\": \"parcel index.html --open\",\n    \"build\": \"parcel build index.html\"\n  },\n  \"dependencies\": {\n      \"mydep\": \"6.0.0\"\n  }\n}\n`;\n\nconst semver = iso(\n  s => {\n    const [major, minor, patch] = s.split(\".\").map(x => +x);\n    return { major, minor, patch };\n  },\n  ({ major, minor, patch }) => [major, minor, patch].join(\".\")\n);\n\ntest(\"over/iso\", assert => {\n  const actualJSON = over(\n    _.$(json).dependencies.mydep.$(semver).minor,\n    x => x + 1,\n    jsonObj\n  );\n  const js = JSON.parse(jsonObj);\n  js.dependencies.mydep = \"6.1.0\";\n\n  assert.deepEqual(JSON.parse(actualJSON), js);\n  assert.end();\n});\n\ntest(\"over/prism\", assert => {\n  const badJSonObj = \"@#\" + jsonObj;\n\n  assert.equal(\n    set(_.$(maybeJson).dependencies.mydep, \"6.1.0\", badJSonObj),\n    badJSonObj\n  );\n  assert.end();\n});\n\ntest(\"append\", assert => {\n  assert.deepEqual(append(_.nakama, { name: \"Nami\", level: 1 }, state), {\n    ...state,\n    nakama: state.nakama.concat({ name: \"Nami\", level: 1 })\n  });\n  assert.end();\n});\n\ntest(\"insertAt\", assert => {\n  assert.deepEqual(insertAt(_.nakama, 1, { name: \"Nami\", level: 1 }, state), {\n    ...state,\n    nakama: [\n      state.nakama[0],\n      { name: \"Nami\", level: 1 },\n      ...state.nakama.slice(1)\n    ]\n  });\n  assert.end();\n});\n\ntest(\"removeIf\", assert => {\n  assert.deepEqual(removeIf(_.nakama, n => n.level > 2, state), {\n    ...state,\n    nakama: state.nakama.filter(n => n.level <= 2)\n  });\n  assert.end();\n});\n\ntest(\"removeAt\", assert => {\n  assert.deepEqual(removeAt(_.nakama, 2, state), {\n    ...state,\n    nakama: state.nakama.filter((_, i) => i !== 2)\n  });\n  assert.end();\n});\n"
  }
]