{"id":13709601,"url":"https://github.com/JordanMartinez/purescript-tidy-codegen-lens","last_synced_at":"2025-05-06T16:32:03.220Z","repository":{"id":96612043,"uuid":"442638555","full_name":"JordanMartinez/purescript-tidy-codegen-lens","owner":"JordanMartinez","description":"Generate lenses and prisms for your data types automatically.","archived":false,"fork":false,"pushed_at":"2022-01-08T00:41:12.000Z","size":704,"stargazers_count":11,"open_issues_count":3,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-11-07T04:02:59.448Z","etag":null,"topics":["codegen","purescript","tools"],"latest_commit_sha":null,"homepage":"","language":"PureScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JordanMartinez.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-12-29T02:29:47.000Z","updated_at":"2024-07-29T22:48:51.000Z","dependencies_parsed_at":"2024-02-21T14:50:20.861Z","dependency_job_id":null,"html_url":"https://github.com/JordanMartinez/purescript-tidy-codegen-lens","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JordanMartinez%2Fpurescript-tidy-codegen-lens","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JordanMartinez%2Fpurescript-tidy-codegen-lens/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JordanMartinez%2Fpurescript-tidy-codegen-lens/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JordanMartinez%2Fpurescript-tidy-codegen-lens/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JordanMartinez","download_url":"https://codeload.github.com/JordanMartinez/purescript-tidy-codegen-lens/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224513441,"owners_count":17323807,"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":["codegen","purescript","tools"],"created_at":"2024-08-02T23:00:42.283Z","updated_at":"2024-11-13T19:31:52.890Z","avatar_url":"https://github.com/JordanMartinez.png","language":"PureScript","funding_links":[],"categories":["Lenses"],"sub_categories":[],"readme":"# purescript-tidy-codegen-lens\n\nGenerate lenses and prisms for your data types automatically.\n\nAn input file, `./Foo.purs`, will generate an output file `./Foo/Lens.purs` if `Foo.purs` contains any type declarations.\n\nThis is currently a WIP.\n\n## Usage\n\nFor testing a local version, run `spago build` and then `./tidy-mklens.js \u003cCLI args\u003e`. To build a bundled one, use `./build-tidy-mklens.sh`.\n\n```\n$ ./tidy-mklens.js --help\ntidy-mklens\n    A CLI for generating optics for your data types\n\n    Expected usage:\n      tidy-mklens [OPTIONS] PURS_GLOBS...\n\n    Examples:\n      tidy-mklens src\n      tidy-mklens --global-record-lens-module RecordLens src\n      tidy-mklens --label-style-abc src\n      tidy-mklens --gen-type-alias-lenses src\n      tidy-mklens --output-dir src .spago/*/*/src/**/*.purs:4\n\n    --gen-type-alias-isos,-t                      Generate isos for type aliases\n    --global-record-lens-module,-m MODULE_PATH    The full module path to use for the single record label lenses file\n                                                  (e.g `Foo.Bar.Lens`). The module will be outtputed to a file based\n                                                  on the module path (e.g. `Foo.Bar.Lens` will be saved to\n                                                  `\u003coutputDir\u003e/Foo/Bar/Lens.purs`).\n    --help,-h                                     Show this help message.\n    --label-prefix,-l PREFIX                      Use `_PREFIXFoo` for the lens for a record '{ foo :: a }'\n    --label-prefix-none,-n                        Use '_foo' for the lens for a record '{ foo :: a }'\n    --label-style-abc,-b                          Data constructors with 3+ args will use record labels based on the alphabet (e.g. 'a', 'b', ..., 'z', 'aa', 'ab', ...)\n    --label-style-arg,-a                          Data constructors with 3+ args will use record labels of 'argN' (e.g. 'arg1', 'arg2', ..., 'argN')\n    --output-dir,-o                               The directory into which to write the generated files\n                                                  (defaults to `src`).\n    --version,-v                                  Shows the current version\n\n    GLOB[:DIR_STRIP_COUNT]                        Globs for PureScript sources (e.g. `src` `test/**/*.purs`)\n                                                  and the number of root directories to strip from each file\n                                                  path (defaults to 1) that are separated by the OS-specific\n                                                  path delimiter (POSIX: ':', Windows: ';')\n```\n\n## Examples\n\nThe table illustrates some of the CLI args above via the current output on the files stored in the [snapshots folder](./snapshots). You can verify that these compile via `spago -x snapshots.dhall build --purs-args \"--output output-snapshots\"`.\n\n| Purpose | Files |\n| - | - |\n| Show the 'arg' label style | \u003cul\u003e\u003cli\u003e\u003cp\u003eSource file\u003c/p\u003e\u003cul\u003e\u003cli\u003e[UseArgLabelStyle.purs](./snapshots/UseArgLabelStyle.purs)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eOutput file(s)\u003c/p\u003e\u003cul\u003e\u003cli\u003e[UseArgLabelStyle/Lens.purs](./snapshots/UseArgLabelStyle/Lens.purs)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e |\n| Show the 'abc' label style | \u003cul\u003e\u003cli\u003e\u003cp\u003eSource file\u003c/p\u003e\u003cul\u003e\u003cli\u003e[UseAbcLabelStyle.purs](./snapshots/UseAbcLabelStyle.purs)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eOutput file(s)\u003c/p\u003e\u003cul\u003e\u003cli\u003e[UseAbcLabelStyle/Lens.purs](./snapshots/UseAbcLabelStyle/Lens.purs)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e |\n| Show the `--gen-type-alias-isos` option | \u003cul\u003e\u003cli\u003e\u003cp\u003eSource file\u003c/p\u003e\u003cul\u003e\u003cli\u003e[UseTypeAliases.purs](./snapshots/UseTypeAliases.purs)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eOutput file(s)\u003c/p\u003e\u003cul\u003e\u003cli\u003e[UseTypeAliases/Lens.purs](./snapshots/UseTypeAliases/Lens.purs)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e |\n| Show the `--label-prefix-none` option | \u003cul\u003e\u003cli\u003e\u003cp\u003eSource file\u003c/p\u003e\u003cul\u003e\u003cli\u003e[UseNoLabelPrefix.purs](./snapshots/UseNoLabelPrefix.purs)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eOutput file(s)\u003c/p\u003e\u003cul\u003e\u003cli\u003e[UseNoLabelPrefix/Lens.purs](./snapshots/UseNoLabelPrefix/Lens.purs)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e |\n| Show the `--label-prefix \"prop\"` option (default) | \u003cul\u003e\u003cli\u003e\u003cp\u003eSource file\u003c/p\u003e\u003cul\u003e\u003cli\u003e[UseLabelPrefix.purs](./snapshots/UseLabelPrefix.purs)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eOutput file(s)\u003c/p\u003e\u003cul\u003e\u003cli\u003e[UseLabelPrefix/Lens.purs](./snapshots/UseLabelPrefix/Lens.purs)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e |\n| The record label lenses will be duplicated in each module. This is why the `--gen-record-lens-*` options exist | \u003cul\u003e\u003cli\u003e\u003cp\u003eSource file\u003c/p\u003e\u003cul\u003e\u003cli\u003e[UseLocalProps/Module1.purs](./snapshots/UseLocalProps/Module1.purs)\u003c/li\u003e\u003cli\u003e[UseLocalProps/Module2.purs](./snapshots/UseLocalProps/Module2.purs)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eOutput file(s)\u003c/p\u003e\u003cul\u003e\u003cli\u003e[UseLocalProps/Module1/Lens.purs](./snapshots/UseLocalProps/Module1/Lens.purs)\u003c/li\u003e\u003cli\u003e[UseLocalProps/Module2/Lens.purs](./snapshots/UseLocalProps/Module2/Lens.purs)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e |\n| Demo the `--gen-record-lens-*` options | \u003cul\u003e\u003cli\u003e\u003cp\u003eSource file\u003c/p\u003e\u003cul\u003e\u003cli\u003e[UseGlobalPropFile/Module1.purs](./snapshots/UseGlobalPropFile/Module1.purs)\u003c/li\u003e\u003cli\u003e[UseGlobalPropFile/Module2.purs](./snapshots/UseGlobalPropFile/Module2.purs)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eOutput file(s)\u003c/p\u003e\u003cul\u003e\u003cli\u003e[UseGlobalPropFile/GlobalRecordLens.purs](./snapshots/UseGlobalPropFile/GlobalRecordLens.purs)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e |\n| Primary example | \u003cul\u003e\u003cli\u003e\u003cp\u003eSource file\u003c/p\u003e\u003cul\u003e\u003cli\u003e[PrimaryExample.purs](./snapshots/PrimaryExample.purs)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eOutput file(s)\u003c/p\u003e\u003cul\u003e\u003cli\u003e[PrimaryExample/Lens.purs](./snapshots/PrimaryExample/Lens.purs)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e |\n\nFiles were generated using the below commands, which are stored in [regen-snapshots.sh](./regen-snapshots.sh):\n\n```bash\n# Note: the `arg` style is the default\n./tidy-mklens.js --label-style-arg --output-dir snapshots snapshots/UseArgLabelStyle.purs\n\n./tidy-mklens.js --label-style-abc --output-dir snapshots snapshots/UseAbcLabelStyle.purs\n\n# Can optionally generate lenses for type aliases\n# Useful when just getting familiar with a library and type signatures\n# and typed holes are all you have\n./tidy-mklens.js --gen-type-alias-isos --output-dir snapshots snapshots/UseTypeAliases.purs\n\n# By default, any record labels referenced in your types will\n# have their corresponding lense generated using the style\n# `_propLabelName`. You can swap out 'prop' for your own\n# custom prefix...\n./tidy-mklens.js --label-prefix \"prop\" --output-dir snapshots snapshots/UseLabelPrefix.purs\n\n# ... or none at all (e.g. `_labelName`).\n./tidy-mklens.js --label-prefix-none --output-dir snapshots snapshots/UseNoLabelPrefix.purs\n\n# If the same label is used in multiple types,\n# a lens for that label will be stored in each file,\n# thereby duplicating the lens. This can lead to\n# import frency.\n\n./tidy-mklens.js --output-dir snapshots snapshots/UseLocalProps/\n\n# One way around this is to generate a single file\n# that stores all lenses for the deduplicated labels,\n# ensuring that label lenses are only imported from\n# one place.\n./tidy-mklens.js \\\n  --output-dir snapshots \\\n  --global-record-lens-module UseGlobalPropFile.GlobalRecordLens \\\n  snapshots/UseGlobalPropFile\n\n# Here's the primary example, showing the full power of the code\n./tidy-mklens.js --gen-type-alias-isos  --output-dir snapshots snapshots/PrimaryExample.purs\n\n# Open imports aren't always handled correctly. See these snapshots\n./tidy-mklens.js --output-dir snapshots snapshots/CheckOpenImports\n```\n\n### Explaining the `GLOB[:DIR_STRIP_COUNT]` arg\n\nThe generated file's file path is based on the input file's file path. Most of the time, one will use this program to generate optics for the `src` directory. However, in monorepos, there may be multiple directories that contains PureScript source code. This feature exists to account for those use cases.\n\nThe `glob:\u003cint\u003e` indicates how many parent directories, starting from the file's relative path's root, to strip from the outputted file's file path. When not specified, the `DIR_STIP_COUNT` defaults to `1`.\n\nFor example, let's say the `src` directory has the following structure:\n```\n/src\n  /Foo\n    /Bar.purs\n```\n\nRunning `./tidy-mklens.js --output-dir lenses src:X` where `X` is one of the integers listed in the below table will produce the corresponding output:\n\n| X |  Output file | Explanation |\n| - | - | - |\n| 1\u003cbr /\u003e(default) | `lenses/Foo/Bar/Lens.purs` | the `src` segment was removed |\n| 2 | `lenses/Bar/Lens.purs` | the `src` and `Foo` segments were removed |\n| 3 | `lenses/Lens.purs` | the `src`, `Foo`, and `Bar` segments were removed |\n| 4 | `lenses/Lens.purs` | Since there are only 3 segments available, this is no different than when X is 3 |\n\nThis feature enables one to run this program against all of a projects dependencies (as stored in the `.spago` folder) and output the results into a new folder. This can be accomplished via the glob `.spago/*/*/src/**/*.purs:4`, which says, \"If you come across a file `.spago/packageName/version/src/Foo/Bar.purs`, strip the first four root directories (e.g. `.spago/packageName/version/src`), and append the result (e.g. `Foo/Bar.purs`) to the output directory (e.g. `\u003coutputDir\u003e/Foo/Bar.purs`).\n\nFor example, the `lenses` folder contains the output of running this command, which is stored in [regen-lenses.sh](./regen-lenses.sh):\n```sh\n./tidy-mklens.js \\\n  --output-dir lenses \\\n  --gen-type-alias-isos \\\n  --label-prefix-none \\\n  --global-record-lens-module Dependencies.RecordLens \\\n  .spago/*/*/src/**/*.purs:4\n```\n\n## Assumptions\n\n**In general, the generated `Lens.purs` file(s) will compile so long as the source file compiles and does not contain any warnings regarding your imports. However, the generated file may produce compiler warnings.**\n\n`tidy-mklens` uses limited information to generate a `Lens.purs` file. There are some ambiguous situations it cannot handle without more information (e.g. type checking).\n\nMore specifically, the generated `Lens.purs` file will compile if the following is true about your source file:\n```purescript\nmodule ModuleName where\n\n-- Assumption #1:\n-- To ensure types referenced in the source file's types are imported\n-- in the generated file, always re-import all open imports.\n--\n-- If the types referenced in the source file's types are from imports,\n-- the generated file will not compile unless they are imported\n-- in the generated file, too.\n--\n-- However, this will produce compiler warnings in the generated file\n-- if the open imports' members aren't used.\n-- `tidy-mklens` can't know what these modules import\n-- and thus whether they would be used in the generated file.\n--\n-- Note: the compiler warns if 2+ open imports are used.\nimport Prelude\nimport SomethingElse\nimport MyModule hiding (someMember)\n\n-- Assumption #2:\n-- Each module alias to an open import refers to at most one module.\n--\n-- Without this constraint, `tidy-mklens` cannot know which module\n-- (e.g. `Module1` or `Module2`) to import in the generated file.\n--\n-- Note: the compiler warns if an alias refers to 2+ open imports.\nimport ImportWithModuleAlias as ThisIsOk\nimport SomeModule hiding (someMember) as ThisIsAlsoOk\nimport Module1 as ThisIsBadBecauseItRefersToMultipleModules\nimport Module2 as ThisIsBadBecauseItRefersToMultipleModules\n\n-- That being said, module aliases to closed imports are ok,\n-- even if one alias refers to the multipe modules.\n--\n-- All usages of such members will use the qualified notation\n-- for them (e.g. `Mod.Type1`), so `tidy-mklens` can determine\n-- which module to import to ensure that type is included\n-- in the generated `Lens.purs` file.\nimport ModuleA (Type1, Type2) as Mod\nimport ModuleB (Type3, Type4) as Mod\n\n-- Explicit imports work fine without issues\nimport ModuleWithExplicitExports (Foo, bar, baz)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FJordanMartinez%2Fpurescript-tidy-codegen-lens","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FJordanMartinez%2Fpurescript-tidy-codegen-lens","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FJordanMartinez%2Fpurescript-tidy-codegen-lens/lists"}