{"id":16339053,"url":"https://github.com/phadej/optika","last_synced_at":"2025-03-16T14:31:26.049Z","repository":{"id":66242183,"uuid":"85822655","full_name":"phadej/optika","owner":"phadej","description":"Optics library for JavaScript","archived":false,"fork":false,"pushed_at":"2018-10-15T17:07:38.000Z","size":69,"stargazers_count":141,"open_issues_count":4,"forks_count":9,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-02-11T10:23:50.634Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/phadej.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2017-03-22T12:03:16.000Z","updated_at":"2024-11-11T07:12:22.000Z","dependencies_parsed_at":"2023-02-20T16:46:10.325Z","dependency_job_id":null,"html_url":"https://github.com/phadej/optika","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phadej%2Foptika","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phadej%2Foptika/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phadej%2Foptika/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phadej%2Foptika/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/phadej","download_url":"https://codeload.github.com/phadej/optika/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243819056,"owners_count":20352810,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-10T23:53:24.103Z","updated_at":"2025-03-16T14:31:25.114Z","avatar_url":"https://github.com/phadej.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Optika\n\n\u003cimg src=\"https://raw.githubusercontent.com/phadej/optika/master/optika-300.png\" align=\"right\" height=\"100\" /\u003e\n\n\u003e Optics: modular data access\n\n[![Build Status](https://secure.travis-ci.org/phadej/optika.svg?branch=master)](http://travis-ci.org/phadej/optika)\n[![NPM version](https://badge.fury.io/js/optika.svg)](http://badge.fury.io/js/optika)\n[![Dependency Status](https://david-dm.org/phadej/optika.svg)](https://david-dm.org/phadej/optika)\n[![devDependency Status](https://david-dm.org/phadej/optika/dev-status.svg)](https://david-dm.org/phadej/optika#info=devDependencies)\n\n## Getting Started\n\nInstall the module with: `npm install optika`\n\n## Synopsis\n\n```javascript\nvar o = require(\"optika\");\n\nvar value = {\n  foo: [\n    { bar: 2, baz: 3 },\n    { bar: 4, baz: 5 },\n  ]\n};\n\n// [2, 4]\no.key(\"foo\").traversed().key(\"bar\").arrayOf(value);\n\n// { foo: [ { bar: 9, baz: 3 }, { bar: 11, baz: 5 } ] }\no.key(\"foo\").traversed().key(\"bar\").over(value, function (x) {\n  return x + 7;\n});\n```\n\n## Motivation\n\n[Immutable.js](https://facebook.github.io/immutable-js/) is great!\nBut working with immutable containers \u0026 nested records is un-easy:\n\n```javascript\nreturn data.update(\"months\", months =\u003e\n  months.map(month =\u003e\n    month.update(\"days\", days =\u003e\n      days.map(day =\u003e injectAuxData(day, auxiliaryData))\n    )\n  )\n);\n```\n\nThe `updateIn` isn't powerful enough to make the drilling less boilerplaty\n(and less error-prone).\n\nIf you are a Haskell programmer, you might know that *lenses* are a solution\nto this problem:\n\n```haskell\ndata_ \u0026 months . traversed . days . traversed %~ \\day -\u003e\n  injectAuxData day auxData\n\n-- or without operators:\nover\n  (months . traversed . days . traversed)\n  (\\day -\u003e injectAuxData day auxData)\n  data_\n```\n\nAnd with this library you can write similar code in JavaScript:\n\n```javascript\no.imkey(\"months\").traversed().imkey(\"days\").traversed().over(data, day =\u003e\n  injectAuxData(day, auxData)\n);\n```\n\n## Documentation\n\nThere is small amount of run-time validation.\nFor example, if you try to *set* over `Getter`, the exception will be thrown:\n```javascript\no.key(\"foo\").to(function (x) { return x[0]; }).set(value, 42);\n// throws: Trying to run Traversal operation via Getter\n```\n\n### Operations\n\n- `get(this: Getter\u003cS,A\u003e, value: S): A`\n\n- `set(this: Traversal\u003cS,T,A,B\u003e, value: S, b: B): T`\n\n- `over(this: Traversal\u003cS,T,A,B\u003e, value: S, f: A =\u003e B): T`\n\n- `review(this: Prism\u003cS,T,A,B\u003e, value: B): T`\n- `review(this: Iso\u003cS,T,A,B\u003e, value: B): T`\n\n  Construct value thru `Prism` or `Iso`.\n\n- `affineView(this: Affine\u003cS,T,A,B\u003e, def: A): A\n\n  For operation working with `Fold`, see `firstOf`.\n\n- `reduceOf(this: Fold\u003cS,T,A,B\u003e, value: S, init: I, combine: (I, A) =\u003e I): I`\n\n  Fold starting with initial value `init`, and combining results with `combine`,\n  in the `this` Fold's order.\n\n- `arrayOf(this: Fold\u003cS,T,A,B\u003e, value: S): Array\u003cA\u003e`\n\n- `sumOf(this: Fold\u003cS,T,number,B\u003e, value: S): number`\n\n### Constructors\n\n- `lens(getter: S =\u003e A, setter: (S, B) =\u003e T): Lens\u003cS,T,A,B\u003e`\n\n- `traversed(): Traversal\u003cF\u003cA\u003e,F\u003cB\u003e,A,B\u003e`\n\n  Creates traversal for everything with `.map` and `.forEach`.\n\n- `to(f: S =\u003e A): Getter\u003cS,A\u003e`\n\n### Convenient optics\n\n- `key(K: keyof (S \u0026 T)): Lens\u003cS,T,S[K],T[K]\u003e`\n\n  Works for *plain-old-javascriot-objects*, i.e. POJOs :)\n\n- `idx(i: number)): Lens\u003cArray\u003cA\u003e,Array\u003cA\u003e,A,A\u003e`\n\n- `imkey(K: keyof (S \u0026 T)): Lens\u003cRecord\u003cS\u003e,Record\u003cT\u003e,S[K],T[K]\u003e`\n\n  Works with everyting supporting `.get` and `.set`, e.g.\n  [Immutable](http://facebook.github.io/immutable-js/).\n\n- `imidx(i: number)): Lens\u003cList\u003cA\u003e,List\u003cA\u003e,A,A\u003e`\n\n  Works with everyting supporting `.get` and `.set`, e.g.\n  [Immutable](http://facebook.github.io/immutable-js/).\n\n  *Note:* doesn't perform bounds check.\n\n- `filtered(pred: A =\u003e boolean): Prism\u003cA,A,A',A'\u003e`\n\n*Note*: The predicate is checked when the value is injected (via `Traversal`)\nor constructed via `Prism`.\n\n- `safeFiltered(pred: A =\u003e boolean): Prism\u003cA,A,A',A'\u003e`\n\nLike `filtered` but predicate is checked on construction.\n\n### Internals\n\nFunctions which you probably never need to use directly.\n\n`.o(this: Optic\u003cS,T,A,B\u003e, other: Optic\u003cA,B,U,V\u003e): Optic\u003cS,T,U,V\u003e`\n\nCompose two optics.\n\n`.run(this: Optic\u003cS,T,A,B\u003e, p: Profunctor\u003cA,B\u003e): Profunctor\u003cS,T\u003e`\n\n## Contributing\n\n- `README.md` is generated from the source with [ljs](https://github.com/phadej/ljs), say `make literate`.\n- `optika.standalone.js` is also generated by the build process\n- Before creating a pull request run `make test`, yet travis will do it for you.\n\n## Release History\n\n- **0.0.2** \u0026mdash; *2017-04-01* \u0026mdash; Neglect for speedups\n- **0.0.1** \u0026mdash; *2017-03-24* \u0026mdash; More features\n- **0.0.0** \u0026mdash; *2017-03-22* \u0026mdash; Initial preview\n\n## Implementation details\n\n- pair is represented as two-element array: `Pair\u003cA,B\u003e = [A,B]`.\n- `Either` is represtented by `[boolean, A | B]`, where\n  `false` and `true` reprsent whether the value is `Left` or `Right` respectively.\n- `Maybe` is encoded as the value + some unique value nothing can equal to (think: `Symbol`).\n- See [Compiling lenses](http://oleg.fi/gists/posts/2017-03-31-compiling-lenses.html)\n  for ideas behind `Neglect`.\n\n## Related work\n\n### JavaScript\n\n- [partial.lenses](https://github.com/calmm-js/partial.lenses)\n- [ramda-lens](https://github.com/ramda/ramda-lens)\n- [flunc-optics](https://github.com/flunc/optics)\n- [monocle-ts](https://github.com/gcanti/monocle-ts)\n\nThe MIT License (MIT)\n\nCopyright (c) 2017 Oleg Grenrus\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\nall copies 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\nTHE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphadej%2Foptika","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphadej%2Foptika","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphadej%2Foptika/lists"}