{"id":13687551,"url":"https://github.com/haskell-waargonaut/waargonaut","last_synced_at":"2025-09-05T21:03:31.111Z","repository":{"id":44142075,"uuid":"140663176","full_name":"haskell-waargonaut/waargonaut","owner":"haskell-waargonaut","description":"JSON decoding/encoding/manipulation library.","archived":false,"fork":false,"pushed_at":"2022-07-11T11:49:34.000Z","size":1061,"stargazers_count":94,"open_issues_count":9,"forks_count":14,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-05-02T01:48:11.153Z","etag":null,"topics":["haskell","haskell-library","json","json-parser","json-serialization"],"latest_commit_sha":null,"homepage":null,"language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/haskell-waargonaut.png","metadata":{"files":{"readme":"README.md","changelog":"changelog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-07-12T05:01:13.000Z","updated_at":"2023-09-08T17:42:41.000Z","dependencies_parsed_at":"2022-08-20T13:00:49.757Z","dependency_job_id":null,"html_url":"https://github.com/haskell-waargonaut/waargonaut","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haskell-waargonaut%2Fwaargonaut","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haskell-waargonaut%2Fwaargonaut/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haskell-waargonaut%2Fwaargonaut/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haskell-waargonaut%2Fwaargonaut/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/haskell-waargonaut","download_url":"https://codeload.github.com/haskell-waargonaut/waargonaut/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224257779,"owners_count":17281772,"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":["haskell","haskell-library","json","json-parser","json-serialization"],"created_at":"2024-08-02T15:00:56.452Z","updated_at":"2025-05-01T12:34:27.909Z","avatar_url":"https://github.com/haskell-waargonaut.png","language":"Haskell","funding_links":[],"categories":["Haskell"],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/qfpl/waargonaut.svg?branch=master)](https://travis-ci.org/qfpl/waargonaut)\n\n# Waargonaut\n\nFlexible, precise, and efficient JSON decoding/encoding library. This package\nprovides a plethora of tools for decoding, encoding, and manipulating JSON data.\n\n## Features\n\n* Fully RFC compliant, with property based testing used to ensure the desired\n  invariants are preserved.\n\n* Encoders and Decoders are values, they are not tied to a typeclass and as such\n  you are not tied to a single interpretation of how a particular type\n  \"_should_\" be handled.\n  \n* No information is discarded on parsing. Trailing whitespace, and any\n  formatting whitespace (carriage returns etc) are all preserved. \n\n* A history keeping zipper is used for Decoding, providing precise control of\n  how _you_ decode _your_ JSON data. With informative error messages if things\n  don't go according to plan.\n\n* Flexible and expressive Decoder \u0026 Encoder functions let you parse and build\n  the JSON structures _you_ require, with no surprises.\n\n* BYO parsing library, the parser built into Waargonaut does not tie you to a\n  particular parsing library. With the caveat that your parsing library must\n  have an instance of `CharParsing` from the [parsers](https://hackage.haskell.org/package/parsers) package.\n\n* Generic functions are provided to make the creation of Encoders and Decoders\n  are bit easier. However these _are_ tied to typeclasses, so they do come with\n  some assumptions.\n\n* Lenses, Prisms, and Traversals are provided to allow you to investigate and\n  manipulate the JSON data structures to your hearts content, without breaking\n  the invariants.\n\n* The awesome work on succinct data structures by John Ky and [Haskell Works](https://github.com/haskell-works/) \n  is used to power the decoder. Providing the same zipper capabilities and\n  property based guarantees, but with all the speed and efficiency capabilities\n  that succinct data structures have to offer.\n\n## Example\n\n- Data Structure:\n```haskell\ndata Image = Image\n  { _imageWidth    :: Int\n  , _imageHeight   :: Int\n  , _imageTitle    :: Text\n  , _imageAnimated :: Bool\n  , _imageIDs      :: [Int]\n  }\n```\n\n- Encoder:\n```haskell\nencodeImage :: Applicative f =\u003e Encoder f Image\nencodeImage = E.mapLikeObj $ \\img -\u003e\n    E.intAt \"Width\" (_imageWidth img)\n  . E.intAt \"Height\" (_imageHeight img)\n  . E.textAt \"Title\" (_imageTitle img)\n  . E.boolAt \"Animated\" (_imageAnimated img)\n  . E.listAt E.int \"IDs\" (_imageIDs img)\n```\n\n- Decoder:\n```haskell\nimageDecoder :: Monad f =\u003e D.Decoder f Image\nimageDecoder = D.withCursor $ \\curs -\u003e do\n  -- Move down into the JSON object.\n  io \u003c- D.down curs\n  -- We need individual values off of our object,\n  Image\n    \u003c$\u003e D.fromKey \"Width\" D.int io\n    \u003c*\u003e D.fromKey \"Height\" D.int io\n    \u003c*\u003e D.fromKey \"Title\" D.text io\n    \u003c*\u003e D.fromKey \"Animated\" D.bool io\n    \u003c*\u003e D.fromKey \"IDs\" (D.list D.int) io\n```\n\n### Zippers\n\nWaargonaut uses zippers for its decoding which allows for precise control in\nhow you interrogate your JSON input. Take JSON structures and decode them\nprecisely as you require:\n\n##### Input:\n\n```JSON\n[\"a\",\"fred\",1,2,3,4]\n```\n\n##### Data Structure:\n\n```haskell\ndata Foo = Foo (Char,String,[Int])\n```\n\n##### Decoder:\n\nThe zipper starts the very root of the JSON input, we tell it to move 'down'\ninto the first element.\n```haskell\nfooDecoder :: Monad f =\u003e Decoder f Foo\nfooDecoder = D.withCursor $ \\cursor -\u003e do\n  fstElem \u003c- D.down cursor\n```\nFrom the first element we can then decode the focus of the zipper using a\nspecific decoder:\n```haskell\n  aChar \u003c- D.focus D.unboundedChar fstElem\n```\nThe next thing we want to decode is the second element of the array, so we\nmove right one step or tooth, and then attempt to decode a string at the\nfocus.\n```haskell\n  aString \u003c- D.moveRight1 fstElem \u003e\u003e= D.focus D.string\n```\nFinally we want to take everything else in the list and combine them into a\nsingle list of Int values. Starting from the first element, we move right\ntwo positions (over the char and the string elements), then we use one of\nthe provided decoder functions that will repeatedly move in a direction and\ncombine all of the elements it can until it can no longer move.\n```haskell\n  aIntList \u003c- D.moveRightN 2 fstElem \u003e\u003e= D.rightwardSnoc [] D.int\n```\nLastly, we build the Foo using the decoded values.\n```haskell\n  pure $ Foo (aChar, aString, aIntList)\n```\n\nThe zipper stores the history of your movements, so any errors provide\ninformation about the path they took prior to encountering an error. Making\ndebugging precise and straight-forward.\n\n### Property Driven Development\n\nThis library is built to parse and produce JSON in accordance with the [RFC\n8259](https://tools.ietf.org/html/rfc8259) standard. The data structures,\nparser, and printer are built to satify the [Round Trip Property](https://teh.id.au/posts/2017/06/07/round-trip-property/):\n\nWhich may be expressed using the following pseudocode:\n\n```\nparse . print = id\n```\nThis indicates that any JSON produced by this library will be parsed back in as\nthe exact data structure that produced it. This includes whitespace such as\ncarriage returns and trailing whitespace. There is no loss of information.\n\nThere is also this property, again in pseudocode:\n\n```\nprint . parse . print = print\n```\nThis states that the printed form of the JSON will not change will be identical\nafter parsing and then re-printing. There is no loss of information.\n\nThis provides a solid foundation to build upon.\n\n**NB:** The actual code will of course return values that account for the\npossibility of failure. Computers being what they are.\n\n### TODO(s)\n\nIn no particular order...\n\n- [ ] improve/bikeshed encoding object api \n- [ ] gather feedback on tests/benchmarks that matter\n- [ ] provide testing functions so users can be more confident in their Encoder/Decoder construction\n- [x] (feedback required) documentation in the various modules to explain any weirdness or things that users may consider to be 'missing' or 'wrong'.\n- [x] (mostly) provide greater rationale behind lack of reliance in typeclasses for encoding/decoding\n- [ ] provide functions to add preset whitespace layouts to encoded json.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhaskell-waargonaut%2Fwaargonaut","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhaskell-waargonaut%2Fwaargonaut","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhaskell-waargonaut%2Fwaargonaut/lists"}