diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..1c6afb9 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,26 @@ +{ + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "module" + }, + "extends": "eslint:recommended", + "rules": { + "strict": [2, "global"], + "block-scoped-var": 2, + "consistent-return": 2, + "eqeqeq": [2, "smart"], + "guard-for-in": 2, + "no-caller": 2, + "no-extend-native": 2, + "no-loop-func": 2, + "no-new": 2, + "no-param-reassign": 2, + "no-return-assign": 2, + "no-unused-expressions": 2, + "no-use-before-define": 2, + "radix": [2, "always"], + "indent": [2, 2], + "quotes": [2, "double"], + "semi": [2, "always"] + } +} diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md new file mode 100644 index 0000000..9e67483 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -0,0 +1,25 @@ +**Do You make bug report? Fix it and merge it Yourself!** + +Ask for an invite ANYONE in this organization! + +https://github.com/purescript-open-community/.github/tree/main/profile + +--- +name: Bug report +about: Report an issue +title: "" +labels: bug +assignees: "" +--- + +**Describe the bug** +A clear and concise description of the bug. + +**To Reproduce** +A minimal code example (preferably a runnable example on [Try PureScript](https://try.purescript.org)!) or steps to reproduce the issue. + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/change-request.md b/.github/ISSUE_TEMPLATE/change-request.md new file mode 100644 index 0000000..f576f81 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/change-request.md @@ -0,0 +1,27 @@ +**Do You make bug report? Fix it and merge it Yourself!** + +Ask for an invite ANYONE in this organization! + +https://github.com/purescript-open-community/.github/tree/main/profile + +--- +name: Change request +about: Propose an improvement to this library +title: "" +labels: "" +assignees: "" +--- + +**Is your change request related to a problem? Please describe.** +A clear and concise description of the problem. + +Examples: + +- It's frustrating to have to [...] +- I was looking for a function to [...] + +**Describe the solution you'd like** +A clear and concise description of what a good solution to you looks like, including any solutions you've already considered. + +**Additional context** +Add any other context about the change request here. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..c47a263 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: PureScript Discourse + url: https://discourse.purescript.org/ + about: Ask and answer questions here. + - name: Functional Programming Slack + url: https://functionalprogramming.slack.com + about: For casual chat and questions (use https://fpchat-invite.herokuapp.com to join). diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..4f14d96 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,17 @@ +**Do You make pull request? Merge it Yourself!** + +Ask for an invite ANYONE in this organization! + +https://github.com/purescript-open-community/.github/tree/main/profile + +**Description of the change** +Clearly and concisely describe the purpose of the pull request. If this PR relates to an existing issue or change proposal, please link to it. Include any other background context that would help reviewers understand the motivation for this PR. + +--- + +**Checklist:** + +- [ ] Added the change to the changelog's "Unreleased" section with a link to this PR and your username +- [ ] Linked any existing issues or proposals that this pull request should close +- [ ] Updated or added relevant documentation in the README and/or documentation directory +- [ ] Added a test for the contribution (if applicable) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..cd362a0 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,36 @@ +name: CI + +on: + push: + branches: [master] + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - uses: purescript-contrib/setup-purescript@main + with: + purescript: "latest" + purs-tidy: "latest" + spago: "unstable" + + - name: Cache PureScript dependencies + uses: actions/cache@v2 + with: + key: ${{ runner.os }}-spago-${{ hashFiles('**/spago.lock') }} + path: | + .spago + output + + - name: Build source + run: spago build --censor-stats --strict --pedantic-packages + + - name: Run tests + run: spago test --censor-stats --strict --pedantic-packages + + - name: Verify formatting + run: purs-tidy check src test diff --git a/.gitignore b/.gitignore index da6c2f6..d06ae43 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ node_modules/ output/ .psc-package .psc-ide-port +.purs-repl +.spago +.purs* diff --git a/.travis.yml b/.travis.yml index ebd09cd..51546f8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,10 +3,9 @@ dist: trusty sudo: required node_js: stable install: - - npm install -g bower + - npm install -g spago - npm install script: - - bower install --production + - spago install - npm run -s build - - bower install - npm run -s test diff --git a/LICENSE b/LICENSE index 846498f..5e608f0 100644 --- a/LICENSE +++ b/LICENSE @@ -18,27 +18,3 @@ Copyright (c) 2017 Phil Freeman COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -purescript-foreign-generic uses code taken from the purescript-foreign library, -which is used under the terms of the MIT license, below: - - The MIT License (MIT) - - Copyright (c) 2014 PureScript - - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - the Software, and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/LICENSE_THIRDPARTY b/LICENSE_THIRDPARTY new file mode 100644 index 0000000..227e0b3 --- /dev/null +++ b/LICENSE_THIRDPARTY @@ -0,0 +1,23 @@ +purescript-foreign-generic uses code taken from the purescript-foreign library, +which is used under the terms of the MIT license, below: + + The MIT License (MIT) + + Copyright (c) 2014 PureScript + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index f318957..042a66b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -# purescript-foreign-generic +# purescript-open-foreign-generic + +[![Build Status](https://github.com/paf31/purescript-foreign-generic/actions/workflows/ci.yml/badge.svg)](https://github.com/paf31/purescript-foreign-generic/actions/workflows/ci.yml) [![Build Status](https://travis-ci.org/paf31/purescript-foreign-generic.svg?branch=master)](https://travis-ci.org/paf31/purescript-foreign-generic) @@ -13,46 +15,46 @@ Generic deriving for `purescript-foreign`. First, define some data type and derive `Generic`: ```purescript -> import Prelude -> import Data.Generic.Rep (class Generic) -> import Data.Show.Generic (genericShow) +import Prelude +import Data.Generic.Rep (class Generic) +import Data.Generic.Rep.Show (genericShow) -> newtype MyRecord = MyRecord { a :: Int } -> derive instance genericMyRecord :: Generic MyRecord _ -> instance showMyRecord :: Show MyRecord where show = genericShow +newtype MyRecord = MyRecord { a :: Int } +derive instance genericMyRecord :: Generic MyRecord _ +instance showMyRecord :: Show MyRecord where show = genericShow ``` To encode JSON, use `genericEncodeJSON`: ```purescript -> import Foreign.Generic (defaultOptions, genericEncodeJSON) +import Foreign.Generic (defaultOptions, genericEncodeJSON) -> opts = defaultOptions { unwrapSingleConstructors = true } +opts = defaultOptions { unwrapSingleConstructors = true } -> genericEncodeJSON opts (MyRecord { a: 1 }) -"{\"a\":1}" +genericEncodeJSON opts (MyRecord { a: 1 }) +-- "{\"a\":1}" ``` And to decode JSON, use `genericDecodeJSON`: ```purescript -> import Control.Monad.Except (runExcept) -> import Foreign.Generic (genericDecodeJSON) +import Control.Monad.Except (runExcept) +import Foreign.Generic (genericDecodeJSON) -> runExcept (genericDecodeJSON opts "{\"a\":1}" :: _ MyRecord) -(Right (MyRecord { a: 1 })) +runExcept (genericDecodeJSON opts "{\"a\":1}" :: _ MyRecord) +-- (Right (MyRecord { a: 1 })) ``` Badly formed JSON will result in a useful error, which can be inspected or pretty-printed: ```purescript -> import Data.Bifunctor (lmap) -> import Foreign (renderForeignError) - -> lmap (map renderForeignError) $ runExcept (genericDecodeJSON opts "{\"a\":\"abc\"}" :: _ MyRecord) -(Left - (NonEmptyList - (NonEmpty - "Error at array index 0: (ErrorAtProperty \"a\" (TypeMismatch \"Int\" \"String\"))" - Nil))) +import Data.Bifunctor (lmap) +import Foreign (renderForeignError) + +lmap (map renderForeignError) $ runExcept (genericDecodeJSON opts "{\"a\":\"abc\"}" :: _ MyRecord) +-- (Left +-- (NonEmptyList +-- (NonEmpty +-- "Error at array index 0: (ErrorAtProperty \"a\" (TypeMismatch \"Int\" \"String\"))" +-- Nil))) ``` diff --git a/bower.json b/bower.json deleted file mode 100644 index 3507559..0000000 --- a/bower.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "purescript-foreign-generic", - "moduleType": [ - "node" - ], - "ignore": [ - "**/.*", - "node_modules", - "bower_components", - "output" - ], - "license": "MIT", - "repository": { - "type": "git", - "url": "git://github.com/paf31/purescript-foreign-generic.git" - }, - "dependencies": { - "purescript-effect": "^3.0.0", - "purescript-foreign": "^6.0.0", - "purescript-foreign-object": "^3.0.0", - "purescript-ordered-collections": "^2.0.0", - "purescript-exceptions": "^5.0.0", - "purescript-record": "^3.0.0", - "purescript-identity": "^5.0.0" - }, - "devDependencies": { - "purescript-assert": "^5.0.0", - "purescript-psci-support": "^5.0.0" - } -} diff --git a/package.json b/package.json index 38e6586..4063f07 100644 --- a/package.json +++ b/package.json @@ -2,13 +2,11 @@ "private": true, "scripts": { "clean": "rimraf output && rimraf .pulp-cache", - "build": "pulp build -- --censor-lib --strict", - "test": "pulp test" + "build": "eslint src && spago build -- --censor-lib --strict", + "test": "spago test" }, "devDependencies": { - "pulp": "^15.0.0", - "purescript": "^0.14.0", - "purescript-psa": "^0.5.0", - "rimraf": "^2.5.0" + "eslint": "^7.15.0", + "rimraf": "^3.0.2" } } diff --git a/spago.lock b/spago.lock new file mode 100644 index 0000000..09c68a4 --- /dev/null +++ b/spago.lock @@ -0,0 +1,1222 @@ +{ + "workspace": { + "packages": { + "open-foreign-generic": { + "path": "./", + "core": { + "dependencies": [ + { + "arrays": ">=7.3.0 <8.0.0" + }, + { + "bifunctors": ">=6.0.0 <7.0.0" + }, + { + "control": ">=6.0.0 <7.0.0" + }, + { + "effect": ">=4.0.0 <5.0.0" + }, + { + "either": ">=6.1.0 <7.0.0" + }, + { + "exceptions": ">=6.1.0 <7.0.0" + }, + { + "foldable-traversable": ">=6.0.0 <7.0.0" + }, + { + "foreign": ">=7.0.0 <8.0.0" + }, + { + "foreign-object": ">=4.1.0 <5.0.0" + }, + { + "identity": ">=6.0.0 <7.0.0" + }, + { + "lists": ">=7.0.0 <8.0.0" + }, + { + "maybe": ">=6.0.0 <7.0.0" + }, + { + "newtype": ">=5.0.0 <6.0.0" + }, + { + "ordered-collections": ">=3.2.0 <4.0.0" + }, + { + "partial": ">=4.0.0 <5.0.0" + }, + { + "prelude": ">=6.0.1 <7.0.0" + }, + { + "record": ">=4.0.0 <5.0.0" + }, + { + "transformers": ">=6.1.0 <7.0.0" + }, + { + "tuples": ">=7.0.0 <8.0.0" + }, + { + "unsafe-coerce": ">=6.0.0 <7.0.0" + } + ], + "build_plan": [ + "arrays", + "bifunctors", + "const", + "contravariant", + "control", + "distributive", + "effect", + "either", + "enums", + "exceptions", + "exists", + "foldable-traversable", + "foreign", + "foreign-object", + "functions", + "functors", + "gen", + "identity", + "integers", + "invariant", + "lazy", + "lists", + "maybe", + "newtype", + "nonempty", + "numbers", + "ordered-collections", + "orders", + "partial", + "prelude", + "profunctor", + "record", + "refs", + "safe-coerce", + "st", + "strings", + "tailrec", + "transformers", + "tuples", + "type-equality", + "typelevel-prelude", + "unfoldable", + "unsafe-coerce" + ] + }, + "test": { + "dependencies": [ + "assert", + "console", + "safe-coerce", + "strings" + ], + "build_plan": [ + "arrays", + "assert", + "bifunctors", + "console", + "const", + "contravariant", + "control", + "distributive", + "effect", + "either", + "enums", + "exists", + "foldable-traversable", + "functions", + "functors", + "gen", + "identity", + "integers", + "invariant", + "maybe", + "newtype", + "nonempty", + "numbers", + "orders", + "partial", + "prelude", + "profunctor", + "refs", + "safe-coerce", + "st", + "strings", + "tailrec", + "tuples", + "type-equality", + "unfoldable", + "unsafe-coerce" + ] + } + } + }, + "package_set": { + "address": { + "registry": "60.0.1" + }, + "compiler": ">=0.15.15 <0.16.0", + "content": { + "abc-parser": "2.0.1", + "ace": "9.1.0", + "address-rfc2821": "0.1.1", + "aff": "8.0.0", + "aff-bus": "6.0.0", + "aff-coroutines": "9.0.0", + "aff-promise": "4.0.0", + "aff-retry": "2.0.0", + "affjax": "13.0.0", + "affjax-node": "1.0.0", + "affjax-web": "1.0.0", + "ansi": "7.0.0", + "apexcharts": "0.5.0", + "applicative-phases": "1.0.0", + "argonaut": "9.0.0", + "argonaut-aeson-generic": "0.4.1", + "argonaut-codecs": "9.1.0", + "argonaut-core": "7.0.0", + "argonaut-generic": "8.0.0", + "argonaut-traversals": "10.0.0", + "argparse-basic": "2.0.0", + "array-builder": "0.1.2", + "array-search": "0.6.0", + "arraybuffer": "13.2.0", + "arraybuffer-builder": "3.1.0", + "arraybuffer-types": "3.0.2", + "arrays": "7.3.0", + "arrays-extra": "0.6.1", + "arrays-zipper": "2.0.1", + "ask": "1.0.0", + "assert": "6.0.0", + "assert-multiple": "0.4.0", + "avar": "5.0.0", + "b64": "0.0.8", + "barbies": "1.0.1", + "barlow-lens": "0.9.0", + "bifunctors": "6.0.0", + "bigints": "7.0.1", + "bolson": "0.3.9", + "bookhound": "0.1.7", + "bower-json": "3.0.0", + "call-by-name": "4.0.1", + "canvas": "6.0.0", + "canvas-action": "9.0.0", + "cartesian": "1.0.6", + "catenable-lists": "7.0.0", + "cbor-stream": "1.3.0", + "chameleon": "1.0.0", + "chameleon-halogen": "1.0.3", + "chameleon-react-basic": "1.1.0", + "chameleon-styled": "2.5.0", + "chameleon-transformers": "1.0.0", + "channel": "1.0.0", + "checked-exceptions": "3.1.1", + "choku": "1.0.1", + "classless": "0.1.1", + "classless-arbitrary": "0.1.1", + "classless-decode-json": "0.1.1", + "classless-encode-json": "0.1.3", + "classnames": "2.0.0", + "codec": "6.1.0", + "codec-argonaut": "10.0.0", + "codec-json": "2.0.0", + "colors": "7.0.1", + "concur-core": "0.5.0", + "concur-react": "0.5.0", + "concurrent-queues": "3.0.0", + "console": "6.1.0", + "const": "6.0.0", + "contravariant": "6.0.0", + "control": "6.0.0", + "convertable-options": "1.0.0", + "coroutines": "7.0.0", + "css": "6.0.0", + "css-frameworks": "1.0.1", + "csv-stream": "2.3.0", + "data-mvc": "0.0.2", + "datetime": "6.1.0", + "datetime-parsing": "0.2.0", + "debounce": "0.1.0", + "debug": "6.0.2", + "decimals": "7.1.0", + "default-values": "1.0.1", + "deku": "0.9.23", + "deno": "0.0.5", + "dissect": "1.0.0", + "distributive": "6.0.0", + "dom-filereader": "7.0.0", + "dom-indexed": "12.0.0", + "dom-simple": "0.4.0", + "dotenv": "4.0.3", + "droplet": "0.6.0", + "dts": "1.0.0", + "dual-numbers": "1.0.3", + "dynamic-buffer": "3.0.1", + "echarts-simple": "0.0.1", + "effect": "4.0.0", + "either": "6.1.0", + "elmish": "0.13.0", + "elmish-enzyme": "0.1.1", + "elmish-hooks": "0.10.3", + "elmish-html": "0.9.0", + "elmish-testing-library": "0.3.2", + "email-validate": "7.0.0", + "encoding": "0.0.9", + "enums": "6.0.1", + "env-names": "0.4.0", + "error": "2.0.0", + "eta-conversion": "0.3.2", + "exceptions": "6.1.0", + "exists": "6.0.0", + "exitcodes": "4.0.0", + "expect-inferred": "3.0.0", + "ezfetch": "1.0.0", + "fahrtwind": "2.0.0", + "fallback": "0.1.0", + "fast-vect": "1.2.0", + "fetch": "4.1.0", + "fetch-argonaut": "1.0.1", + "fetch-core": "5.1.0", + "fetch-yoga-json": "1.1.0", + "ffi-simple": "0.5.1", + "fft-js": "0.1.0", + "filterable": "5.0.0", + "fix-functor": "0.1.0", + "fixed-points": "7.0.0", + "fixed-precision": "5.0.0", + "flame": "1.3.0", + "float32": "2.0.0", + "fmt": "0.2.1", + "foldable-traversable": "6.0.0", + "foldable-traversable-extra": "0.0.6", + "foreign": "7.0.0", + "foreign-object": "4.1.0", + "foreign-readwrite": "3.4.0", + "forgetmenot": "0.1.0", + "fork": "6.0.0", + "form-urlencoded": "7.0.0", + "formatters": "7.0.0", + "framer-motion": "1.0.1", + "free": "7.1.0", + "freeap": "7.0.0", + "freer-free": "0.0.1", + "freet": "7.0.0", + "functions": "6.0.0", + "functor1": "3.0.0", + "functors": "5.0.0", + "fuzzy": "0.4.0", + "gen": "4.0.0", + "generate-values": "1.0.1", + "generic-router": "0.0.1", + "geojson": "0.0.5", + "geometria": "2.2.0", + "gojs": "0.1.1", + "grain": "3.0.0", + "grain-router": "3.0.0", + "grain-virtualized": "3.0.0", + "graphs": "8.1.0", + "group": "4.1.1", + "halogen": "7.0.0", + "halogen-bootstrap5": "5.3.2", + "halogen-canvas": "1.0.0", + "halogen-css": "10.0.0", + "halogen-echarts-simple": "0.0.4", + "halogen-formless": "4.0.3", + "halogen-helix": "1.0.1", + "halogen-hooks": "0.6.3", + "halogen-hooks-extra": "0.9.0", + "halogen-infinite-scroll": "1.1.0", + "halogen-store": "0.5.4", + "halogen-storybook": "2.0.0", + "halogen-subscriptions": "2.0.0", + "halogen-svg-elems": "8.0.0", + "halogen-typewriter": "1.0.4", + "halogen-vdom": "8.0.0", + "halogen-vdom-string-renderer": "0.5.0", + "halogen-xterm": "2.0.0", + "heckin": "2.0.1", + "heterogeneous": "0.6.0", + "homogeneous": "0.4.0", + "http-methods": "6.0.0", + "httpurple": "4.0.0", + "huffman": "0.4.0", + "humdrum": "0.0.1", + "hyrule": "2.3.8", + "identity": "6.0.0", + "identy": "4.0.1", + "indexed-db": "1.0.0", + "indexed-monad": "3.0.0", + "int64": "3.0.0", + "integers": "6.0.0", + "interpolate": "5.0.2", + "intersection-observer": "1.0.1", + "invariant": "6.0.0", + "jarilo": "1.0.1", + "jelly": "0.10.0", + "jelly-router": "0.3.0", + "jelly-signal": "0.4.0", + "jest": "1.0.0", + "js-abort-controller": "1.0.0", + "js-bigints": "2.2.1", + "js-date": "8.0.0", + "js-fetch": "0.2.1", + "js-fileio": "3.0.0", + "js-intl": "1.0.4", + "js-iterators": "0.1.1", + "js-maps": "0.1.2", + "js-promise": "1.0.0", + "js-promise-aff": "1.0.0", + "js-timers": "6.1.0", + "js-uri": "3.1.0", + "json": "1.1.0", + "json-codecs": "5.0.0", + "justifill": "0.5.0", + "jwt": "0.0.9", + "labeled-data": "0.2.0", + "language-cst-parser": "0.14.0", + "lazy": "6.0.0", + "lazy-joe": "1.0.0", + "lcg": "4.0.0", + "leibniz": "5.0.0", + "leveldb": "1.0.1", + "liminal": "1.0.1", + "linalg": "6.0.0", + "lists": "7.0.0", + "literals": "1.0.2", + "logging": "3.0.0", + "logging-journald": "0.4.0", + "lumi-components": "18.0.0", + "machines": "7.0.0", + "maps-eager": "0.5.0", + "marionette": "1.0.0", + "marionette-react-basic-hooks": "0.1.1", + "marked": "0.1.0", + "matrices": "5.0.1", + "matryoshka": "1.0.0", + "maybe": "6.0.0", + "media-types": "6.0.0", + "meowclient": "1.0.0", + "midi": "4.0.0", + "milkis": "9.0.0", + "minibench": "4.0.1", + "mmorph": "7.0.0", + "monad-control": "5.0.0", + "monad-logger": "1.3.1", + "monad-loops": "0.5.0", + "monad-unlift": "1.0.1", + "monoid-extras": "0.0.1", + "monoidal": "0.16.0", + "morello": "0.4.0", + "mote": "3.0.0", + "motsunabe": "2.0.0", + "mvc": "0.0.1", + "mysql": "6.0.1", + "n3": "0.1.0", + "nano-id": "1.1.0", + "nanoid": "0.1.0", + "naturals": "3.0.0", + "nested-functor": "0.2.1", + "newtype": "5.0.0", + "nextjs": "0.1.1", + "nextui": "0.2.0", + "node-buffer": "9.0.0", + "node-child-process": "11.1.0", + "node-event-emitter": "3.0.0", + "node-execa": "5.0.0", + "node-fs": "9.2.0", + "node-glob-basic": "1.3.0", + "node-http": "9.1.0", + "node-http2": "1.1.1", + "node-human-signals": "1.0.0", + "node-net": "5.1.0", + "node-os": "5.1.0", + "node-path": "5.0.0", + "node-process": "11.2.0", + "node-readline": "8.1.1", + "node-sqlite3": "8.0.0", + "node-stream-pipes": "2.1.6", + "node-streams": "9.0.0", + "node-tls": "0.3.1", + "node-url": "7.0.1", + "node-zlib": "0.4.0", + "nonempty": "7.0.0", + "now": "6.0.0", + "npm-package-json": "2.0.0", + "nullable": "6.0.0", + "numberfield": "0.2.2", + "numbers": "9.0.1", + "oak": "3.1.1", + "oak-debug": "1.2.2", + "object-maps": "0.3.0", + "ocarina": "1.5.4", + "oooooooooorrrrrrrmm-lib": "0.0.1", + "open-folds": "6.4.0", + "open-memoize": "6.2.0", + "open-mkdirp-aff": "1.2.0", + "open-pairing": "6.2.0", + "options": "7.0.0", + "optparse": "5.0.1", + "ordered-collections": "3.2.0", + "ordered-set": "0.4.0", + "orders": "6.0.0", + "owoify": "1.2.0", + "pairs": "9.0.1", + "parallel": "7.0.0", + "parsing": "10.2.0", + "parsing-dataview": "3.2.4", + "partial": "4.0.0", + "pathy": "9.0.0", + "pha": "0.13.0", + "phaser": "0.7.0", + "phylio": "1.1.2", + "pipes": "8.0.0", + "pirates-charm": "0.0.1", + "pmock": "0.9.0", + "point-free": "1.0.0", + "pointed-list": "0.5.1", + "polymorphic-vectors": "4.0.0", + "posix-types": "6.0.0", + "postgresql": "2.0.19", + "precise": "6.0.0", + "precise-datetime": "7.0.0", + "prelude": "6.0.1", + "prettier-printer": "3.0.0", + "priority-queue": "0.1.2", + "profunctor": "6.0.1", + "profunctor-lenses": "8.0.0", + "protobuf": "4.3.0", + "psa-utils": "8.0.0", + "psci-support": "6.0.0", + "punycode": "1.0.0", + "qualified-do": "2.2.0", + "quantities": "12.2.0", + "quickcheck": "8.0.1", + "quickcheck-combinators": "0.1.3", + "quickcheck-laws": "7.0.0", + "quickcheck-utf8": "0.0.0", + "random": "6.0.0", + "rationals": "6.0.0", + "rdf": "0.1.0", + "react": "11.0.0", + "react-aria": "0.2.0", + "react-basic": "17.0.0", + "react-basic-classic": "3.0.0", + "react-basic-dnd": "10.1.0", + "react-basic-dom": "6.1.0", + "react-basic-emotion": "7.1.0", + "react-basic-hooks": "8.2.0", + "react-basic-storybook": "2.0.0", + "react-dom": "8.0.0", + "react-halo": "3.0.0", + "react-icons": "1.1.5", + "react-markdown": "0.1.0", + "react-testing-library": "4.0.1", + "react-virtuoso": "1.0.0", + "reactix": "0.6.1", + "read": "1.0.1", + "recharts": "1.1.0", + "record": "4.0.0", + "record-extra": "5.0.1", + "record-ptional-fields": "0.1.2", + "record-studio": "1.0.4", + "refs": "6.0.0", + "remotedata": "5.0.1", + "repr": "0.5.0", + "resize-observer": "1.0.0", + "resource": "2.0.1", + "resourcet": "1.0.0", + "result": "1.0.3", + "return": "0.2.0", + "ring-modules": "5.0.1", + "rito": "0.3.4", + "roman": "0.4.0", + "rough-notation": "1.0.2", + "routing": "11.0.0", + "routing-duplex": "0.7.0", + "run": "5.0.0", + "safe-coerce": "2.0.0", + "safely": "4.0.1", + "school-of-music": "1.3.0", + "selection-foldable": "0.2.0", + "selective-functors": "1.0.1", + "semirings": "7.0.0", + "signal": "13.0.0", + "simple-emitter": "3.0.1", + "simple-i18n": "2.0.1", + "simple-json": "9.0.0", + "simple-json-generics": "0.2.1", + "simple-ulid": "3.0.0", + "sized-matrices": "1.0.0", + "sized-vectors": "5.0.2", + "slug": "3.1.0", + "small-ffi": "4.0.1", + "soundfonts": "4.1.0", + "sparse-matrices": "2.0.1", + "sparse-polynomials": "3.0.1", + "spec": "8.0.0", + "spec-discovery": "8.3.0", + "spec-mocha": "5.1.1", + "spec-node": "0.0.2", + "spec-quickcheck": "5.0.2", + "spec-reporter-xunit": "0.7.1", + "splitmix": "2.1.0", + "ssrs": "1.0.0", + "st": "6.2.0", + "statistics": "0.3.2", + "strictlypositiveint": "1.0.1", + "string-parsers": "8.0.0", + "strings": "6.0.1", + "strings-extra": "4.0.0", + "stringutils": "0.0.12", + "substitute": "0.2.3", + "supply": "0.2.0", + "svg-parser": "3.0.0", + "systemd-journald": "0.3.0", + "tagged": "4.0.2", + "tailrec": "6.1.0", + "tecton": "0.2.1", + "tecton-halogen": "0.2.0", + "test-unit": "17.0.0", + "thermite": "6.3.1", + "thermite-dom": "0.3.1", + "these": "6.0.0", + "threading": "0.0.3", + "tldr": "0.0.0", + "toestand": "0.9.0", + "transformation-matrix": "1.0.1", + "transformers": "6.1.0", + "tree-rose": "4.0.2", + "ts-bridge": "4.0.0", + "tuples": "7.0.0", + "two-or-more": "1.0.0", + "type-equality": "4.0.1", + "typedenv": "2.0.1", + "typelevel": "6.0.0", + "typelevel-lists": "2.1.0", + "typelevel-peano": "1.0.1", + "typelevel-prelude": "7.0.0", + "typelevel-regex": "0.0.3", + "typelevel-rows": "0.1.0", + "typisch": "0.4.0", + "uint": "7.0.0", + "ulid": "3.0.1", + "uncurried-transformers": "1.1.0", + "undefined": "2.0.0", + "undefined-is-not-a-problem": "1.1.0", + "unfoldable": "6.0.0", + "unicode": "6.0.0", + "unique": "0.6.1", + "unlift": "1.0.1", + "unordered-collections": "3.1.0", + "unsafe-coerce": "6.0.0", + "unsafe-reference": "5.0.0", + "untagged-to-tagged": "0.1.4", + "untagged-union": "1.0.0", + "uri": "9.0.0", + "url-immutable": "1.0.0", + "uuid": "9.0.0", + "uuidv4": "1.0.0", + "validation": "6.0.0", + "variant": "8.0.0", + "variant-encodings": "2.0.0", + "vectorfield": "1.0.1", + "vectors": "2.1.0", + "versions": "7.0.0", + "visx": "0.0.2", + "web-clipboard": "6.0.0", + "web-cssom": "2.0.0", + "web-cssom-view": "0.1.0", + "web-dom": "6.0.0", + "web-dom-parser": "8.0.0", + "web-dom-xpath": "3.0.0", + "web-encoding": "3.0.0", + "web-events": "4.0.0", + "web-fetch": "4.0.1", + "web-file": "4.0.0", + "web-geometry": "0.1.0", + "web-html": "4.1.0", + "web-pointerevents": "2.0.0", + "web-proletarian": "1.0.0", + "web-promise": "3.2.0", + "web-resize-observer": "2.1.0", + "web-router": "1.0.0", + "web-socket": "4.0.0", + "web-storage": "5.0.0", + "web-streams": "4.0.0", + "web-touchevents": "4.0.0", + "web-uievents": "5.0.0", + "web-url": "2.0.0", + "web-workers": "1.1.0", + "web-xhr": "5.0.1", + "webextension-polyfill": "0.1.0", + "webgpu": "0.0.1", + "which": "2.0.0", + "xterm": "1.0.0", + "yoga-fetch": "1.0.1", + "yoga-json": "5.1.0", + "yoga-om": "0.1.0", + "yoga-postgres": "6.0.0", + "yoga-tree": "1.0.0", + "z3": "0.0.2", + "zipperarray": "2.0.0" + } + }, + "extra_packages": {} + }, + "packages": { + "arrays": { + "type": "registry", + "version": "7.3.0", + "integrity": "sha256-tmcklBlc/muUtUfr9RapdCPwnlQeB3aSrC4dK85gQlc=", + "dependencies": [ + "bifunctors", + "control", + "foldable-traversable", + "functions", + "maybe", + "nonempty", + "partial", + "prelude", + "safe-coerce", + "st", + "tailrec", + "tuples", + "unfoldable", + "unsafe-coerce" + ] + }, + "assert": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-hCSYcCw9kj3qujoDcriWhCdmrpPZoguSPDZhEMnTl3A=", + "dependencies": [ + "console", + "effect", + "prelude" + ] + }, + "bifunctors": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-/gZwC9YhNxZNQpnHa5BIYerCGM2jeX9ukZiEvYxm5Nw=", + "dependencies": [ + "const", + "either", + "newtype", + "prelude", + "tuples" + ] + }, + "console": { + "type": "registry", + "version": "6.1.0", + "integrity": "sha256-CxmAzjgyuGDmt9FZW51VhV6rBPwR6o0YeKUzA9rSzcM=", + "dependencies": [ + "effect", + "prelude" + ] + }, + "const": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-tNrxDW8D8H4jdHE2HiPzpLy08zkzJMmGHdRqt5BQuTc=", + "dependencies": [ + "invariant", + "newtype", + "prelude" + ] + }, + "contravariant": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-TP+ooAp3vvmdjfQsQJSichF5B4BPDHp3wAJoWchip6c=", + "dependencies": [ + "const", + "either", + "newtype", + "prelude", + "tuples" + ] + }, + "control": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-sH7Pg9E96JCPF9PIA6oQ8+BjTyO/BH1ZuE/bOcyj4Jk=", + "dependencies": [ + "newtype", + "prelude" + ] + }, + "distributive": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-HTDdmEnzigMl+02SJB88j+gAXDx9VKsbvR4MJGDPbOQ=", + "dependencies": [ + "identity", + "newtype", + "prelude", + "tuples", + "type-equality" + ] + }, + "effect": { + "type": "registry", + "version": "4.0.0", + "integrity": "sha256-eBtZu+HZcMa5HilvI6kaDyVX3ji8p0W9MGKy2K4T6+M=", + "dependencies": [ + "prelude" + ] + }, + "either": { + "type": "registry", + "version": "6.1.0", + "integrity": "sha256-6hgTPisnMWVwQivOu2PKYcH8uqjEOOqDyaDQVUchTpY=", + "dependencies": [ + "control", + "invariant", + "maybe", + "prelude" + ] + }, + "enums": { + "type": "registry", + "version": "6.0.1", + "integrity": "sha256-HWaD73JFLorc4A6trKIRUeDMdzE+GpkJaEOM1nTNkC8=", + "dependencies": [ + "control", + "either", + "gen", + "maybe", + "newtype", + "nonempty", + "partial", + "prelude", + "tuples", + "unfoldable" + ] + }, + "exceptions": { + "type": "registry", + "version": "6.1.0", + "integrity": "sha256-K0T89IHtF3vBY7eSAO7eDOqSb2J9kZGAcDN5+IKsF8E=", + "dependencies": [ + "effect", + "either", + "maybe", + "prelude" + ] + }, + "exists": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-A0JQHpTfo1dNOj9U5/Fd3xndlRSE0g2IQWOGor2yXn8=", + "dependencies": [ + "unsafe-coerce" + ] + }, + "foldable-traversable": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-fLeqRYM4jUrZD5H4WqcwUgzU7XfYkzO4zhgtNc3jcWM=", + "dependencies": [ + "bifunctors", + "const", + "control", + "either", + "functors", + "identity", + "maybe", + "newtype", + "orders", + "prelude", + "tuples" + ] + }, + "foreign": { + "type": "registry", + "version": "7.0.0", + "integrity": "sha256-1ORiqoS3HW+qfwSZAppHPWy4/6AQysxZ2t29jcdUMNA=", + "dependencies": [ + "either", + "functions", + "identity", + "integers", + "lists", + "maybe", + "prelude", + "strings", + "transformers" + ] + }, + "foreign-object": { + "type": "registry", + "version": "4.1.0", + "integrity": "sha256-q24okj6mT+yGHYQ+ei/pYPj5ih6sTbu7eDv/WU56JVo=", + "dependencies": [ + "arrays", + "foldable-traversable", + "functions", + "gen", + "lists", + "maybe", + "prelude", + "st", + "tailrec", + "tuples", + "typelevel-prelude", + "unfoldable" + ] + }, + "functions": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-adMyJNEnhGde2unHHAP79gPtlNjNqzgLB8arEOn9hLI=", + "dependencies": [ + "prelude" + ] + }, + "functors": { + "type": "registry", + "version": "5.0.0", + "integrity": "sha256-zfPWWYisbD84MqwpJSZFlvM6v86McM68ob8p9s27ywU=", + "dependencies": [ + "bifunctors", + "const", + "contravariant", + "control", + "distributive", + "either", + "invariant", + "maybe", + "newtype", + "prelude", + "profunctor", + "tuples", + "unsafe-coerce" + ] + }, + "gen": { + "type": "registry", + "version": "4.0.0", + "integrity": "sha256-f7yzAXWwr+xnaqEOcvyO3ezKdoes8+WXWdXIHDBCAPI=", + "dependencies": [ + "either", + "foldable-traversable", + "identity", + "maybe", + "newtype", + "nonempty", + "prelude", + "tailrec", + "tuples", + "unfoldable" + ] + }, + "identity": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-4wY0XZbAksjY6UAg99WkuKyJlQlWAfTi2ssadH0wVMY=", + "dependencies": [ + "control", + "invariant", + "newtype", + "prelude" + ] + }, + "integers": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-sf+sK26R1hzwl3NhXR7WAu9zCDjQnfoXwcyGoseX158=", + "dependencies": [ + "maybe", + "numbers", + "prelude" + ] + }, + "invariant": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-RGWWyYrz0Hs1KjPDA+87Kia67ZFBhfJ5lMGOMCEFoLo=", + "dependencies": [ + "control", + "prelude" + ] + }, + "lazy": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-lMsfFOnlqfe4KzRRiW8ot5ge6HtcU3Eyh2XkXcP5IgU=", + "dependencies": [ + "control", + "foldable-traversable", + "invariant", + "prelude" + ] + }, + "lists": { + "type": "registry", + "version": "7.0.0", + "integrity": "sha256-EKF15qYqucuXP2lT/xPxhqy58f0FFT6KHdIB/yBOayI=", + "dependencies": [ + "bifunctors", + "control", + "foldable-traversable", + "lazy", + "maybe", + "newtype", + "nonempty", + "partial", + "prelude", + "tailrec", + "tuples", + "unfoldable" + ] + }, + "maybe": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-5cCIb0wPwbat2PRkQhUeZO0jcAmf8jCt2qE0wbC3v2Q=", + "dependencies": [ + "control", + "invariant", + "newtype", + "prelude" + ] + }, + "newtype": { + "type": "registry", + "version": "5.0.0", + "integrity": "sha256-gdrQu8oGe9eZE6L3wOI8ql/igOg+zEGB5ITh2g+uttw=", + "dependencies": [ + "prelude", + "safe-coerce" + ] + }, + "nonempty": { + "type": "registry", + "version": "7.0.0", + "integrity": "sha256-54ablJZUHGvvlTJzi3oXyPCuvY6zsrWJuH/dMJ/MFLs=", + "dependencies": [ + "control", + "foldable-traversable", + "maybe", + "prelude", + "tuples", + "unfoldable" + ] + }, + "numbers": { + "type": "registry", + "version": "9.0.1", + "integrity": "sha256-/9M6aeMDBdB4cwYDeJvLFprAHZ49EbtKQLIJsneXLIk=", + "dependencies": [ + "functions", + "maybe" + ] + }, + "ordered-collections": { + "type": "registry", + "version": "3.2.0", + "integrity": "sha256-o9jqsj5rpJmMdoe/zyufWHFjYYFTTsJpgcuCnqCO6PM=", + "dependencies": [ + "arrays", + "foldable-traversable", + "gen", + "lists", + "maybe", + "partial", + "prelude", + "st", + "tailrec", + "tuples", + "unfoldable" + ] + }, + "orders": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-nBA0g3/ai0euH8q9pSbGqk53W2q6agm/dECZTHcoink=", + "dependencies": [ + "newtype", + "prelude" + ] + }, + "partial": { + "type": "registry", + "version": "4.0.0", + "integrity": "sha256-fwXerld6Xw1VkReh8yeQsdtLVrjfGiVuC5bA1Wyo/J4=", + "dependencies": [] + }, + "prelude": { + "type": "registry", + "version": "6.0.1", + "integrity": "sha256-o8p6SLYmVPqzXZhQFd2hGAWEwBoXl1swxLG/scpJ0V0=", + "dependencies": [] + }, + "profunctor": { + "type": "registry", + "version": "6.0.1", + "integrity": "sha256-E58hSYdJvF2Qjf9dnWLPlJKh2Z2fLfFLkQoYi16vsFk=", + "dependencies": [ + "control", + "distributive", + "either", + "exists", + "invariant", + "newtype", + "prelude", + "tuples" + ] + }, + "record": { + "type": "registry", + "version": "4.0.0", + "integrity": "sha256-Za5U85bTRJEfGK5Sk4hM41oXy84YQI0I8TL3WUn1Qzg=", + "dependencies": [ + "functions", + "prelude", + "unsafe-coerce" + ] + }, + "refs": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-Vgwne7jIbD3ZMoLNNETLT8Litw6lIYo3MfYNdtYWj9s=", + "dependencies": [ + "effect", + "prelude" + ] + }, + "safe-coerce": { + "type": "registry", + "version": "2.0.0", + "integrity": "sha256-a1ibQkiUcbODbLE/WAq7Ttbbh9ex+x33VCQ7GngKudU=", + "dependencies": [ + "unsafe-coerce" + ] + }, + "st": { + "type": "registry", + "version": "6.2.0", + "integrity": "sha256-z9X0WsOUlPwNx9GlCC+YccCyz8MejC8Wb0C4+9fiBRY=", + "dependencies": [ + "partial", + "prelude", + "tailrec", + "unsafe-coerce" + ] + }, + "strings": { + "type": "registry", + "version": "6.0.1", + "integrity": "sha256-WssD3DbX4OPzxSdjvRMX0yvc9+pS7n5gyPv5I2Trb7k=", + "dependencies": [ + "arrays", + "control", + "either", + "enums", + "foldable-traversable", + "gen", + "integers", + "maybe", + "newtype", + "nonempty", + "partial", + "prelude", + "tailrec", + "tuples", + "unfoldable", + "unsafe-coerce" + ] + }, + "tailrec": { + "type": "registry", + "version": "6.1.0", + "integrity": "sha256-Xx19ECVDRrDWpz9D2GxQHHV89vd61dnXxQm0IcYQHGk=", + "dependencies": [ + "bifunctors", + "effect", + "either", + "identity", + "maybe", + "partial", + "prelude", + "refs" + ] + }, + "transformers": { + "type": "registry", + "version": "6.1.0", + "integrity": "sha256-3Bm+Z6tsC/paG888XkywDngJ2JMos+JfOhRlkVfb7gI=", + "dependencies": [ + "control", + "distributive", + "effect", + "either", + "exceptions", + "foldable-traversable", + "identity", + "lazy", + "maybe", + "newtype", + "prelude", + "st", + "tailrec", + "tuples", + "unfoldable" + ] + }, + "tuples": { + "type": "registry", + "version": "7.0.0", + "integrity": "sha256-1rXgTomes9105BjgXqIw0FL6Fz1lqqUTLWOumhWec1M=", + "dependencies": [ + "control", + "invariant", + "prelude" + ] + }, + "type-equality": { + "type": "registry", + "version": "4.0.1", + "integrity": "sha256-Hs9D6Y71zFi/b+qu5NSbuadUQXe5iv5iWx0226vOHUw=", + "dependencies": [] + }, + "typelevel-prelude": { + "type": "registry", + "version": "7.0.0", + "integrity": "sha256-uFF2ph+vHcQpfPuPf2a3ukJDFmLhApmkpTMviHIWgJM=", + "dependencies": [ + "prelude", + "type-equality" + ] + }, + "unfoldable": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-JtikvJdktRap7vr/K4ITlxUX1QexpnqBq0G/InLr6eg=", + "dependencies": [ + "foldable-traversable", + "maybe", + "partial", + "prelude", + "tuples" + ] + }, + "unsafe-coerce": { + "type": "registry", + "version": "6.0.0", + "integrity": "sha256-IqIYW4Vkevn8sI+6aUwRGvd87tVL36BBeOr0cGAE7t0=", + "dependencies": [] + } + } +} diff --git a/spago.yaml b/spago.yaml new file mode 100644 index 0000000..ea9de82 --- /dev/null +++ b/spago.yaml @@ -0,0 +1,40 @@ +package: + publish: + version: 11.0.3 + license: "MIT" + location: + githubOwner: purescript-open-community + githubRepo: purescript-open-foreign-generic + name: open-foreign-generic + dependencies: + - arrays: ">=7.3.0 <8.0.0" + - bifunctors: ">=6.0.0 <7.0.0" + - control: ">=6.0.0 <7.0.0" + - effect: ">=4.0.0 <5.0.0" + - either: ">=6.1.0 <7.0.0" + - exceptions: ">=6.1.0 <7.0.0" + - foldable-traversable: ">=6.0.0 <7.0.0" + - foreign: ">=7.0.0 <8.0.0" + - foreign-object: ">=4.1.0 <5.0.0" + - identity: ">=6.0.0 <7.0.0" + - lists: ">=7.0.0 <8.0.0" + - maybe: ">=6.0.0 <7.0.0" + - newtype: ">=5.0.0 <6.0.0" + - ordered-collections: ">=3.2.0 <4.0.0" + - partial: ">=4.0.0 <5.0.0" + - prelude: ">=6.0.1 <7.0.0" + - record: ">=4.0.0 <5.0.0" + - transformers: ">=6.1.0 <7.0.0" + - tuples: ">=7.0.0 <8.0.0" + - unsafe-coerce: ">=6.0.0 <7.0.0" + test: + main: Test.Main + dependencies: + - assert + - console + - safe-coerce + - strings +workspace: + packageSet: + registry: 60.2.1 + extraPackages: {} diff --git a/src/Foreign/Class.purs b/src/Foreign/Class.purs deleted file mode 100644 index a8f1e14..0000000 --- a/src/Foreign/Class.purs +++ /dev/null @@ -1,9 +0,0 @@ --- | This module is provided for backwards-compatibility with the old API. --- | --- | It is liable to be removed in a future release. - -module Foreign.Class - ( module Reexports - ) where - -import Foreign.Generic.Class (class Decode, class Encode, decode, encode) as Reexports diff --git a/src/Foreign/Generic/Class.purs b/src/Foreign/Generic/Class.purs index 9370082..81c0097 100644 --- a/src/Foreign/Generic/Class.purs +++ b/src/Foreign/Generic/Class.purs @@ -3,6 +3,7 @@ module Foreign.Generic.Class where import Prelude import Control.Alt ((<|>)) +import Control.Bind (bindFlipped) import Control.Monad.Except (except, mapExcept) import Data.Array ((..), zipWith, length) import Data.Bifunctor (lmap) @@ -13,12 +14,15 @@ import Data.List (List(..), (:)) import Data.List as List import Data.Maybe (Maybe(..), maybe) import Data.Newtype (unwrap) -import Data.Symbol (class IsSymbol, SProxy(..), reflectSymbol) +import Data.Set (Set) +import Data.Set as Set +import Data.Symbol (class IsSymbol, reflectSymbol) import Data.Traversable (sequence) +import Data.Tuple (Tuple(..)) import Foreign (F, Foreign, ForeignError(..), fail, readArray, readBoolean, readChar, readInt, readNumber, readString, unsafeToForeign) import Foreign.Generic.Internal (readObject) -import Foreign.Index (index) -import Foreign.NullOrUndefined (readNullOrUndefined, null) +import Foreign.Index (index, readProp) +import Foreign.NullOrUndefined (readNullOrUndefined, aNull) import Foreign.Object (Object) import Foreign.Object as Object import Prim.Row (class Cons, class Lacks) @@ -26,10 +30,13 @@ import Prim.RowList (class RowToList, Nil, Cons) import Record as Record import Record.Builder (Builder) import Record.Builder as Builder -import Type.Data.RowList (RLProxy(..)) import Type.Proxy (Proxy(..)) import Unsafe.Coerce (unsafeCoerce) +newtype Poly a = Poly a + +derive newtype instance eqPoly :: Eq a => Eq (Poly a) + -- | Encoding/Decoding options which can be used to customize -- | `Decode` and `Encode` instances which are derived via -- | `Generic` (see `genericEncode` and `genericDecode`). @@ -43,12 +50,11 @@ type Options = -- | The encoding of sum types for your type. -- | `TaggedObject`s will be encoded in the form `{ [tagFieldName]: "ConstructorTag", [contentsFieldName]: "Contents"}`. -- | `constructorTagTransform` can be provided to transform the constructor tag to a form you use, e.g. `toLower`/`toUpper`. -data SumEncoding - = TaggedObject - { tagFieldName :: String - , contentsFieldName :: String - , constructorTagTransform :: String -> String - } +data SumEncoding = TaggedObject + { tagFieldName :: String + , contentsFieldName :: String + , constructorTagTransform :: String -> String + } -- | Default decoding/encoding options: -- | @@ -112,17 +118,37 @@ instance numberDecode :: Decode Number where instance intDecode :: Decode Int where decode = readInt +instance eitherDecode :: (Decode a, Decode b) => Decode (Either a b) where + decode val = + Left <$> (readProp "Left" val >>= decode) + <|> Right <$> (readProp "Right" val >>= decode) + +instance tupleDecode :: (Decode a, Decode b) => Decode (Tuple a b) where + decode = readArray >=> case _ of + [ a, b ] -> Tuple <$> decode a <*> decode b + _ -> except $ Left $ pure $ ForeignError "Decode tuple: array has incorrect length" + instance identityDecode :: Decode a => Decode (Identity a) where decode = map Identity <<< decode instance arrayDecode :: Decode a => Decode (Array a) where - decode = readArray >=> readElements where + decode = readArray >=> readElements + where readElements :: Array Foreign -> F (Array a) readElements arr = sequence (zipWith readElement (0 .. length arr) arr) readElement :: Int -> Foreign -> F a readElement i value = mapExcept (lmap (map (ErrorAtIndex i))) (decode value) +instance setDecode :: (Decode a, Ord a) => Decode (Set a) where + decode = (decode :: _ -> F (Array a)) >>> bindFlipped arrayToSetNoDuplicates + where + arrayToSetNoDuplicates :: Array a -> F (Set a) + arrayToSetNoDuplicates array = case Set.fromFoldable array of + set + | length array == Set.size set -> pure set + _ -> except $ Left $ pure $ ForeignError "Decode set: The foreign value contains duplicates" + instance maybeDecode :: Decode a => Decode (Maybe a) where decode = readNullOrUndefined decode @@ -132,6 +158,9 @@ instance objectDecode :: Decode v => Decode (Object v) where instance recordDecode :: (RowToList r rl, DecodeRecord r rl) => Decode (Record r) where decode = decodeWithOptions defaultOptions +instance polyDecode :: Decode a => Decode (Poly a) where + decode = map Poly <<< decode + -- | The `Encode` class is used to generate encoding functions -- | of the form `a -> Foreign` using `generics-rep` deriving. -- | @@ -180,8 +209,19 @@ instance identityEncode :: Encode a => Encode (Identity a) where instance arrayEncode :: Encode a => Encode (Array a) where encode = unsafeToForeign <<< map encode +instance setEncode :: (Encode a, Ord a) => Encode (Set a) where + encode = (Set.toUnfoldable :: Set a -> Array a) >>> encode + instance maybeEncode :: Encode a => Encode (Maybe a) where - encode = maybe null encode + encode = maybe aNull encode + +instance eitherEncode :: (Encode a, Encode b) => Encode (Either a b) where + encode = case _ of + Left value -> unsafeToForeign $ { "Left": encode value } + Right value -> unsafeToForeign $ { "Right": encode value } + +instance tupleEncode :: (Encode a, Encode b) => Encode (Tuple a b) where + encode (Tuple a b) = encode [ encode a, encode b ] instance objectEncode :: Encode v => Encode (Object v) where encode = unsafeToForeign <<< Object.mapWithKey (\_ -> encode) @@ -189,6 +229,9 @@ instance objectEncode :: Encode v => Encode (Object v) where instance recordEncode :: (RowToList r rl, EncodeRecord r rl) => Encode (Record r) where encode = encodeWithOptions defaultOptions +instance polyEncode :: Encode a => Encode (Poly a) where + encode (Poly a) = encode a + -- | When deriving `En`/`Decode` instances using `Generic`, we want -- | the `Options` object to apply to the outermost record type(s) -- | under the data constructors. @@ -206,20 +249,26 @@ class EncodeWithOptions a where encodeWithOptions :: Options -> a -> Foreign instance decodeWithOptionsRecord :: (RowToList r rl, DecodeRecord r rl) => DecodeWithOptions (Record r) where - decodeWithOptions opts = map (flip Builder.build {}) <$> decodeRecordWithOptions (RLProxy :: RLProxy rl) opts + decodeWithOptions opts = map (flip Builder.build {}) <$> decodeRecordWithOptions (Proxy :: Proxy rl) opts +else instance decodeWithOptionsPoly :: Decode a => DecodeWithOptions (Poly a) where + decodeWithOptions _ = decode else instance decodeWithOptionsOther :: Decode a => DecodeWithOptions a where decodeWithOptions _ = decode instance encodeWithOptionsRecord :: (RowToList r rl, EncodeRecord r rl) => EncodeWithOptions (Record r) where - encodeWithOptions opts = unsafeToForeign <<< encodeRecordWithOptions (RLProxy :: RLProxy rl) opts + encodeWithOptions opts = unsafeToForeign <<< encodeRecordWithOptions (Proxy :: Proxy rl) opts +else instance encodeWithOptionsPoly :: Encode a => EncodeWithOptions (Poly a) where + encodeWithOptions _ = encode else instance encodeWithOptionsOther :: Encode a => EncodeWithOptions a where encodeWithOptions _ = encode +class DecodeRecord :: forall k. Row Type -> k -> Constraint class DecodeRecord r rl | rl -> r where - decodeRecordWithOptions :: RLProxy rl -> Options -> Foreign -> F (Builder {} (Record r)) + decodeRecordWithOptions :: Proxy rl -> Options -> Foreign -> F (Builder {} (Record r)) +class EncodeRecord :: forall k. Row Type -> k -> Constraint class EncodeRecord r rl | rl -> r where - encodeRecordWithOptions :: RLProxy rl -> Options -> Record r -> Object Foreign + encodeRecordWithOptions :: Proxy rl -> Options -> Record r -> Object Foreign instance decodeRecordNil :: DecodeRecord () Nil where decodeRecordWithOptions _ _ _ = pure identity @@ -227,35 +276,38 @@ instance decodeRecordNil :: DecodeRecord () Nil where instance encodeRecordNil :: EncodeRecord () Nil where encodeRecordWithOptions _ _ _ = Object.empty -instance decodeRecordCons - :: ( Cons l a r_ r - , DecodeRecord r_ rl_ - , IsSymbol l - , DecodeWithOptions a - , Lacks l r_ - ) - => DecodeRecord r (Cons l a rl_) +instance decodeRecordCons :: + ( Cons l a r_ r + , DecodeRecord r_ rl_ + , IsSymbol l + , DecodeWithOptions a + , Lacks l r_ + ) => + DecodeRecord r (Cons l a rl_) where - decodeRecordWithOptions _ opts f = do - builder <- decodeRecordWithOptions (RLProxy :: RLProxy rl_) opts f - let l = reflectSymbol (SProxy :: SProxy l) - l_transformed = (opts.fieldTransform l) - f_ <- index f l_transformed - a <- mapExcept (lmap (map (ErrorAtProperty l_transformed))) (decodeWithOptions opts f_) - pure (builder >>> Builder.insert (SProxy :: SProxy l) a) - -instance encodeRecordCons - :: ( Cons l a r_ r - , EncodeRecord r_ rl_ - , IsSymbol l - , EncodeWithOptions a - ) - => EncodeRecord r (Cons l a rl_) + decodeRecordWithOptions _ opts f = do + builder <- decodeRecordWithOptions (Proxy :: Proxy rl_) opts f + let + l = reflectSymbol (Proxy :: Proxy l) + l_transformed = (opts.fieldTransform l) + f_ <- index f l_transformed + a <- mapExcept (lmap (map (ErrorAtProperty l_transformed))) (decodeWithOptions opts f_) + pure (builder >>> Builder.insert (Proxy :: Proxy l) a) + +instance encodeRecordCons :: + ( Cons l a r_ r + , EncodeRecord r_ rl_ + , IsSymbol l + , EncodeWithOptions a + ) => + EncodeRecord r (Cons l a rl_) where - encodeRecordWithOptions _ opts rec = - let obj = encodeRecordWithOptions (RLProxy :: RLProxy rl_) opts (unsafeCoerce rec) - l = reflectSymbol (SProxy :: SProxy l) - in Object.insert (opts.fieldTransform l) (encodeWithOptions opts (Record.get (SProxy :: SProxy l) rec)) obj + encodeRecordWithOptions _ opts rec = + let + obj = encodeRecordWithOptions (Proxy :: Proxy rl_) opts (unsafeCoerce rec) + l = reflectSymbol (Proxy :: Proxy l) + in + Object.insert (opts.fieldTransform l) (encodeWithOptions opts (Record.get (Proxy :: Proxy l) rec)) obj class GenericDecode a where decodeOpts :: Options -> Foreign -> F a @@ -264,10 +316,15 @@ class GenericEncode a where encodeOpts :: Options -> a -> Foreign class GenericDecodeArgs a where - decodeArgs :: Options -> Int -> List Foreign -> F { result :: a - , rest :: List Foreign - , next :: Int - } + decodeArgs + :: Options + -> Int + -> List Foreign + -> F + { result :: a + , rest :: List Foreign + , next :: Int + } class GenericEncodeArgs a where encodeArgs :: Options -> a -> List Foreign @@ -276,81 +333,90 @@ class GenericCountArgs a where countArgs :: Proxy a -> Either a Int instance genericDecodeNoConstructors :: GenericDecode NoConstructors where - decodeOpts opts _ = fail (ForeignError "No constructors") + decodeOpts _ _ = fail (ForeignError "No constructors") instance genericEncodeNoConstructors :: GenericEncode NoConstructors where encodeOpts opts a = encodeOpts opts a -instance genericDecodeConstructor - :: (IsSymbol name, GenericDecodeArgs rep, GenericCountArgs rep) - => GenericDecode (Constructor name rep) where +instance genericDecodeConstructor :: + ( IsSymbol name + , GenericDecodeArgs rep + , GenericCountArgs rep + ) => + GenericDecode (Constructor name rep) where decodeOpts opts f = - if opts.unwrapSingleConstructors - then Constructor <$> readArguments f - else case opts.sumEncoding of - TaggedObject { tagFieldName, contentsFieldName, constructorTagTransform } -> do - tag <- mapExcept (lmap (map (ErrorAtProperty tagFieldName))) do - tag <- index f tagFieldName >>= readString - let expected = constructorTagTransform ctorName - unless (tag == expected) $ - fail (ForeignError ("Expected " <> show expected <> " tag")) - pure tag - args <- mapExcept (lmap (map (ErrorAtProperty contentsFieldName))) - (index f contentsFieldName >>= readArguments) - pure (Constructor args) + if opts.unwrapSingleConstructors then Constructor <$> readArguments f + else case opts.sumEncoding of + TaggedObject { tagFieldName, contentsFieldName, constructorTagTransform } -> do + _ <- mapExcept (lmap (map (ErrorAtProperty tagFieldName))) do + tag <- index f tagFieldName >>= readString + let expected = constructorTagTransform ctorName + unless (tag == expected) $ + fail (ForeignError ("Expected " <> show expected <> " tag")) + pure tag + args <- mapExcept (lmap (map (ErrorAtProperty contentsFieldName))) + (index f contentsFieldName >>= readArguments) + pure (Constructor args) where - ctorName = reflectSymbol (SProxy :: SProxy name) - - numArgs = countArgs (Proxy :: Proxy rep) - - readArguments args = - case numArgs of - Left a -> pure a - Right 1 | opts.unwrapSingleArguments -> do - { result, rest } <- decodeArgs opts 0 (List.singleton args) - unless (List.null rest) $ - fail (ForeignError "Expected a single argument") - pure result - Right n -> do - vals <- readArray args - { result, rest } <- decodeArgs opts 0 (List.fromFoldable vals) - unless (List.null rest) $ - fail (ForeignError ("Expected " <> show n <> " constructor arguments")) - pure result - -instance genericEncodeConstructor - :: (IsSymbol name, GenericEncodeArgs rep) - => GenericEncode (Constructor name rep) where + ctorName = reflectSymbol (Proxy :: Proxy name) + + numArgs = countArgs (Proxy :: Proxy rep) + + readArguments args = + case numArgs of + Left a -> pure a + Right 1 | opts.unwrapSingleArguments -> do + { result, rest } <- decodeArgs opts 0 (List.singleton args) + unless (List.null rest) $ + fail (ForeignError "Expected a single argument") + pure result + Right n -> do + vals <- readArray args + { result, rest } <- decodeArgs opts 0 (List.fromFoldable vals) + unless (List.null rest) $ + fail (ForeignError ("Expected " <> show n <> " constructor arguments")) + pure result + +instance genericEncodeConstructor :: + ( IsSymbol name + , GenericEncodeArgs rep + ) => + GenericEncode (Constructor name rep) where encodeOpts opts (Constructor args) = - if opts.unwrapSingleConstructors - then maybe (unsafeToForeign {}) unsafeToForeign (encodeArgsArray args) - else case opts.sumEncoding of - TaggedObject { tagFieldName, contentsFieldName, constructorTagTransform } -> - unsafeToForeign (Object.singleton tagFieldName (unsafeToForeign $ constructorTagTransform ctorName) - `Object.union` maybe Object.empty (Object.singleton contentsFieldName) (encodeArgsArray args)) + if opts.unwrapSingleConstructors then maybe (unsafeToForeign {}) unsafeToForeign (encodeArgsArray args) + else case opts.sumEncoding of + TaggedObject { tagFieldName, contentsFieldName, constructorTagTransform } -> + unsafeToForeign + ( Object.singleton tagFieldName (unsafeToForeign $ constructorTagTransform ctorName) + `Object.union` maybe Object.empty (Object.singleton contentsFieldName) (encodeArgsArray args) + ) where - ctorName = reflectSymbol (SProxy :: SProxy name) + ctorName = reflectSymbol (Proxy :: Proxy name) - encodeArgsArray :: rep -> Maybe Foreign - encodeArgsArray = unwrapArguments <<< List.toUnfoldable <<< encodeArgs opts + encodeArgsArray :: rep -> Maybe Foreign + encodeArgsArray = unwrapArguments <<< List.toUnfoldable <<< encodeArgs opts - unwrapArguments :: Array Foreign -> Maybe Foreign - unwrapArguments [] = Nothing - unwrapArguments [x] | opts.unwrapSingleArguments = Just x - unwrapArguments xs = Just (unsafeToForeign xs) + unwrapArguments :: Array Foreign -> Maybe Foreign + unwrapArguments [] = Nothing + unwrapArguments [ x ] | opts.unwrapSingleArguments = Just x + unwrapArguments xs = Just (unsafeToForeign xs) -instance genericDecodeSum - :: (GenericDecode a, GenericDecode b) - => GenericDecode (Sum a b) where +instance genericDecodeSum :: + ( GenericDecode a + , GenericDecode b + ) => + GenericDecode (Sum a b) where decodeOpts opts f = Inl <$> decodeOpts opts' f <|> Inr <$> decodeOpts opts' f where - -- Reuse the unwrapSingleConstructors flag, since we cannot have a single - -- constructor at this point anyway. - opts' = opts { unwrapSingleConstructors = false } - -instance genericEncodeSum - :: (GenericEncode a, GenericEncode b) - => GenericEncode (Sum a b) where + -- Reuse the unwrapSingleConstructors flag, since we cannot have a single + -- constructor at this point anyway. + opts' = opts { unwrapSingleConstructors = false } + +instance genericEncodeSum :: + ( GenericEncode a + , GenericEncode b + ) => + GenericEncode (Sum a b) where encodeOpts opts (Inl a) = encodeOpts (opts { unwrapSingleConstructors = false }) a encodeOpts opts (Inr b) = encodeOpts (opts { unwrapSingleConstructors = false }) b @@ -361,30 +427,34 @@ instance genericDecodeArgsNoArguments :: GenericDecodeArgs NoArguments where instance genericEncodeArgsNoArguments :: GenericEncodeArgs NoArguments where encodeArgs _ = mempty -instance genericDecodeArgsArgument - :: DecodeWithOptions a - => GenericDecodeArgs (Argument a) where +instance genericDecodeArgsArgument :: + DecodeWithOptions a => + GenericDecodeArgs (Argument a) where decodeArgs opts i (x : xs) = do a <- mapExcept (lmap (map (ErrorAtIndex i))) (decodeWithOptions opts x) pure { result: Argument a, rest: xs, next: i + 1 } decodeArgs _ _ _ = fail (ForeignError "Not enough constructor arguments") -instance genericEncodeArgsArgument - :: EncodeWithOptions a - => GenericEncodeArgs (Argument a) where +instance genericEncodeArgsArgument :: + EncodeWithOptions a => + GenericEncodeArgs (Argument a) where encodeArgs opts (Argument a) = List.singleton (encodeWithOptions opts a) -instance genericDecodeArgsProduct - :: (GenericDecodeArgs a, GenericDecodeArgs b) - => GenericDecodeArgs (Product a b) where +instance genericDecodeArgsProduct :: + ( GenericDecodeArgs a + , GenericDecodeArgs b + ) => + GenericDecodeArgs (Product a b) where decodeArgs opts i xs = do { result: resA, rest: xs1, next: i1 } <- decodeArgs opts i xs { result: resB, rest, next } <- decodeArgs opts i1 xs1 pure { result: Product resA resB, rest, next } -instance genericEncodeArgsProduct - :: (GenericEncodeArgs a, GenericEncodeArgs b) - => GenericEncodeArgs (Product a b) where +instance genericEncodeArgsProduct :: + ( GenericEncodeArgs a + , GenericEncodeArgs b + ) => + GenericEncodeArgs (Product a b) where encodeArgs opts (Product a b) = encodeArgs opts a <> encodeArgs opts b instance genericCountArgsNoArguments :: GenericCountArgs NoArguments where @@ -393,12 +463,14 @@ instance genericCountArgsNoArguments :: GenericCountArgs NoArguments where instance genericCountArgsArgument :: GenericCountArgs (Argument a) where countArgs _ = Right 1 -instance genericCountArgsProduct - :: (GenericCountArgs a, GenericCountArgs b) - => GenericCountArgs (Product a b) where +instance genericCountArgsProduct :: + ( GenericCountArgs a + , GenericCountArgs b + ) => + GenericCountArgs (Product a b) where countArgs _ = case countArgs (Proxy :: Proxy a), countArgs (Proxy :: Proxy b) of - Left a , Left b -> Left (Product a b) - Left _ , Right n -> Right n - Right n, Left _ -> Right n + Left a, Left b -> Left (Product a b) + Left _, Right n -> Right n + Right n, Left _ -> Right n Right n, Right m -> Right (n + m) diff --git a/src/Foreign/Generic/Enum.purs b/src/Foreign/Generic/Enum.purs index 5a8381f..d8f4a21 100644 --- a/src/Foreign/Generic/Enum.purs +++ b/src/Foreign/Generic/Enum.purs @@ -4,10 +4,11 @@ import Prelude import Control.Alt ((<|>)) import Data.Generic.Rep (class Generic, Argument, Constructor(..), NoArguments(..), Product, Sum(..), from, to) -import Data.Symbol (class IsSymbol, SProxy(..), reflectSymbol) +import Data.Symbol (class IsSymbol, reflectSymbol) import Foreign (F, Foreign, ForeignError(..), fail, readString, unsafeToForeign) import Partial.Unsafe (unsafeCrashWith) import Prim.TypeError (class Fail, Text) +import Type.Proxy (Proxy(..)) type GenericEnumOptions = { constructorTagTransform :: String -> String @@ -63,51 +64,55 @@ class GenericDecodeEnum a where class GenericEncodeEnum a where encodeEnum :: GenericEnumOptions -> a -> Foreign -instance sumGenericDecodeEnum - :: (GenericDecodeEnum a, GenericDecodeEnum b) - => GenericDecodeEnum (Sum a b) where +instance sumGenericDecodeEnum :: + ( GenericDecodeEnum a + , GenericDecodeEnum b + ) => + GenericDecodeEnum (Sum a b) where decodeEnum opts f = Inl <$> decodeEnum opts f <|> Inr <$> decodeEnum opts f -instance ctorNoArgsGenericDecodeEnum - :: IsSymbol name - => GenericDecodeEnum (Constructor name NoArguments) where - decodeEnum {constructorTagTransform} f = do +instance ctorNoArgsGenericDecodeEnum :: + IsSymbol name => + GenericDecodeEnum (Constructor name NoArguments) where + decodeEnum { constructorTagTransform } f = do tag <- readString f unless (tag == ctorName) $ fail (ForeignError ("Expected " <> show ctorName <> " tag for unary constructor literal " <> ctorName)) pure $ Constructor NoArguments where - ctorName = constructorTagTransform $ reflectSymbol (SProxy :: SProxy name) + ctorName = constructorTagTransform $ reflectSymbol (Proxy :: Proxy name) -instance ctorArgumentGenericDecodeEnum - :: Fail (Text "genericEncode/DecodeEnum cannot be used on types that are not sums of constructors with no arguments.") - => GenericDecodeEnum (Constructor name (Argument a)) where +instance ctorArgumentGenericDecodeEnum :: + Fail (Text "genericEncode/DecodeEnum cannot be used on types that are not sums of constructors with no arguments.") => + GenericDecodeEnum (Constructor name (Argument a)) where decodeEnum _ _ = unsafeCrashWith "unreachable decodeEnum was reached." -instance ctorProductGenericDecodeEnum - :: Fail (Text "genericEncode/DecodeEnum cannot be used on types that are not sums of constructors with no arguments.") - => GenericDecodeEnum (Constructor name (Product a b)) where +instance ctorProductGenericDecodeEnum :: + Fail (Text "genericEncode/DecodeEnum cannot be used on types that are not sums of constructors with no arguments.") => + GenericDecodeEnum (Constructor name (Product a b)) where decodeEnum _ _ = unsafeCrashWith "unreachable decodeEnum was reached." -instance sumGenericEncodeEnum - :: (GenericEncodeEnum a, GenericEncodeEnum b) - => GenericEncodeEnum (Sum a b) where +instance sumGenericEncodeEnum :: + ( GenericEncodeEnum a + , GenericEncodeEnum b + ) => + GenericEncodeEnum (Sum a b) where encodeEnum opts (Inl a) = encodeEnum opts a encodeEnum opts (Inr b) = encodeEnum opts b -instance ctorNoArgsGenericEncodeEnum - :: IsSymbol name - => GenericEncodeEnum (Constructor name NoArguments) where - encodeEnum {constructorTagTransform} _ = unsafeToForeign ctorName +instance ctorNoArgsGenericEncodeEnum :: + IsSymbol name => + GenericEncodeEnum (Constructor name NoArguments) where + encodeEnum { constructorTagTransform } _ = unsafeToForeign ctorName where - ctorName = constructorTagTransform $ reflectSymbol (SProxy :: SProxy name) + ctorName = constructorTagTransform $ reflectSymbol (Proxy :: Proxy name) -instance ctorArgumentGenericEncodeEnum - :: Fail (Text "genericEncode/DecodeEnum cannot be used on types that are not sums of constructors with no arguments.") - => GenericEncodeEnum (Constructor name (Argument a)) where +instance ctorArgumentGenericEncodeEnum :: + Fail (Text "genericEncode/DecodeEnum cannot be used on types that are not sums of constructors with no arguments.") => + GenericEncodeEnum (Constructor name (Argument a)) where encodeEnum _ _ = unsafeCrashWith "unreachable encodeEnum was reached." -instance ctorProductGenericEncodeEnum - :: Fail (Text "genericEncode/DecodeEnum cannot be used on types that are not sums of constructors with no arguments.") - => GenericEncodeEnum (Constructor name (Product a b)) where +instance ctorProductGenericEncodeEnum :: + Fail (Text "genericEncode/DecodeEnum cannot be used on types that are not sums of constructors with no arguments.") => + GenericEncodeEnum (Constructor name (Product a b)) where encodeEnum _ _ = unsafeCrashWith "unreachable encodeEnum was reached." diff --git a/src/Foreign/Internal/Stringify.js b/src/Foreign/Internal/Stringify.js index 97f76db..5ce2dc8 100644 --- a/src/Foreign/Internal/Stringify.js +++ b/src/Foreign/Internal/Stringify.js @@ -1,3 +1 @@ -exports.unsafeStringify = function (x) { - return JSON.stringify(x); -}; +export const unsafeStringify = (x) => JSON.stringify(x); diff --git a/src/Foreign/JSON.js b/src/Foreign/JSON.js index 5ec76c1..ad36fec 100644 --- a/src/Foreign/JSON.js +++ b/src/Foreign/JSON.js @@ -1,5 +1 @@ -"use strict"; - -exports.parseJSONImpl = function (str) { - return JSON.parse(str); -}; +export const parseJSONImpl = (str) => JSON.parse(str); diff --git a/src/Foreign/JSON.purs b/src/Foreign/JSON.purs index 565d253..f828610 100644 --- a/src/Foreign/JSON.purs +++ b/src/Foreign/JSON.purs @@ -18,11 +18,11 @@ foreign import parseJSONImpl :: EffectFn1 String Foreign parseJSON :: String -> F Foreign parseJSON = ExceptT - <<< Identity - <<< lmap (pure <<< ForeignError <<< message) - <<< unsafePerformEffect - <<< try - <<< runEffectFn1 parseJSONImpl + <<< Identity + <<< lmap (pure <<< ForeignError <<< message) + <<< unsafePerformEffect + <<< try + <<< runEffectFn1 parseJSONImpl decodeJSONWith :: forall a. (Foreign -> F a) -> String -> F a decodeJSONWith f = f <=< parseJSON diff --git a/src/Foreign/NullOrUndefined.js b/src/Foreign/NullOrUndefined.js index 9fd0fcf..0d80ad6 100644 --- a/src/Foreign/NullOrUndefined.js +++ b/src/Foreign/NullOrUndefined.js @@ -1,3 +1,2 @@ -exports['null'] = null; - -exports['undefined'] = undefined; +export const aNull = null; +export const anUndefined = undefined; diff --git a/src/Foreign/NullOrUndefined.purs b/src/Foreign/NullOrUndefined.purs index 507fd0d..cc20432 100644 --- a/src/Foreign/NullOrUndefined.purs +++ b/src/Foreign/NullOrUndefined.purs @@ -3,13 +3,13 @@ module Foreign.NullOrUndefined where import Prelude import Data.Maybe (Maybe(..)) -import Foreign (F, Foreign, isUndefined, isNull) +import Foreign (F, Foreign, isNull, isUndefined) -- | Read a value which may be null or undefined. readNullOrUndefined :: forall a. (Foreign -> F a) -> Foreign -> F (Maybe a) readNullOrUndefined _ value | isNull value || isUndefined value = pure Nothing readNullOrUndefined f value = Just <$> f value -foreign import undefined :: Foreign +foreign import anUndefined :: Foreign -foreign import null :: Foreign +foreign import aNull :: Foreign diff --git a/test/Main.purs b/test/Main.purs index 0dc683e..b59d911 100644 --- a/test/Main.purs +++ b/test/Main.purs @@ -13,6 +13,7 @@ import Effect (Effect) import Effect.Console (log) import Foreign (isNull, unsafeToForeign) import Foreign.Generic (class Decode, class Encode, class GenericDecode, class GenericEncode, Options, decode, encode, defaultOptions, decodeJSON, encodeJSON, genericDecodeJSON, genericEncodeJSON) +import Foreign.Generic.Class (Poly(..)) import Foreign.Generic.EnumEncoding (class GenericDecodeEnum, class GenericEncodeEnum, GenericEnumOptions, genericDecodeEnum, genericEncodeEnum) import Foreign.Index (readProp) import Foreign.Internal.Stringify (unsafeStringify) @@ -79,31 +80,32 @@ testOption options string value = do Right (Tuple x y) -> assert (value == y && value == x) Left err -> throw (show err) where - decode' = genericDecodeEnum options <=< parseJSON + decode' = genericDecodeEnum options <=< parseJSON testUnaryConstructorLiteral :: Effect Unit testUnaryConstructorLiteral = do - testOption (makeCasingOptions toUpper) "\"FRIKANDEL\"" Frikandel - testOption (makeCasingOptions toLower) "\"frikandel\"" Frikandel + testOption (makeCasingOptions toUpper) "\"FRIKANDEL\"" Frikandel + testOption (makeCasingOptions toLower) "\"frikandel\"" Frikandel where - makeCasingOptions f = - { constructorTagTransform: f - } + makeCasingOptions f = + { constructorTagTransform: f + } -- Test that `Nothing` record fields, when encoded to JSON, are present and -- encoded as `null` testNothingToNull :: Effect Unit testNothingToNull = let - json = encode (UndefinedTest {a: Nothing}) - in do - log (encodeJSON json) - case runExcept (pure json >>= readProp "contents" >>= readProp "a") of - Right val -> - when (not (isNull val)) - (throw ("property 'a' was not null; got: " <> encodeJSON val)) - Left err -> - throw (show err) + json = encode (UndefinedTest { a: Nothing }) + in + do + log (encodeJSON json) + case runExcept (pure json >>= readProp "contents" >>= readProp "a") of + Right val -> + when (not (isNull val)) + (throw ("property 'a' was not null; got: " <> encodeJSON val)) + Left err -> + throw (show err) -- Test that `Maybe` fields which are not present in the JSON are decoded to -- `Nothing` @@ -111,9 +113,9 @@ testNothingFromMissing :: Effect Unit testNothingFromMissing = let json = unsafeToForeign - { tag: "UndefinedTest" - , contents: 0 - } + { tag: "UndefinedTest" + , contents: 0 + } in case runExcept (decode json) of Right (UndefinedTest x) -> @@ -126,14 +128,15 @@ main :: Effect Unit main = do testRoundTrip (RecordTest { foo: 1, bar: "test", baz: 'a' }) testRoundTrip (Cons 1 (Cons 2 (Cons 3 Nil))) - testRoundTrip (UndefinedTest {a: Just "test"}) - testRoundTrip (UndefinedTest {a: Nothing}) - testRoundTrip [Just "test"] - testRoundTrip [Nothing :: Maybe String] + testRoundTrip (UndefinedTest { a: Just "test" }) + testRoundTrip (UndefinedTest { a: Nothing }) + testRoundTrip [ Just "test" ] + testRoundTrip [ Nothing :: Maybe String ] testRoundTrip (Apple) + testRoundTrip (Poly { foo: "foo" }) testRoundTrip (makeTree 0) testRoundTrip (makeTree 5) - testRoundTrip (Object.fromFoldable [Tuple "one" 1, Tuple "two" 2]) + testRoundTrip (Object.fromFoldable [ Tuple "one" 1, Tuple "two" 2 ]) testUnaryConstructorLiteral let opts = defaultOptions { fieldTransform = toUpper } testGenericRoundTrip opts (RecordTest { foo: 1, bar: "test", baz: 'a' }) diff --git a/test/Types.purs b/test/Types.purs index ad2d060..333b1b5 100644 --- a/test/Types.purs +++ b/test/Types.purs @@ -3,14 +3,16 @@ module Test.Types where import Prelude import Data.Bifunctor (class Bifunctor) -import Foreign (ForeignError(..), fail, readArray, unsafeToForeign) -import Foreign.Generic (class Encode, class Decode, Options, SumEncoding(..), encode, decode, defaultOptions, genericDecode, genericEncode) -import Foreign.Generic.EnumEncoding (defaultGenericEnumOptions, genericDecodeEnum, genericEncodeEnum) -import Data.Generic.Rep (class Generic) import Data.Eq.Generic (genericEq) -import Data.Show.Generic (genericShow) +import Data.Generic.Rep (class Generic) import Data.Maybe (Maybe) +import Data.Show.Generic (genericShow) import Data.Tuple (Tuple(..)) +import Foreign (ForeignError(..), fail, readArray, unsafeToForeign) +import Foreign.Generic (class Encode, class Decode, Options, SumEncoding(..), encode, decode, defaultOptions, genericDecode, genericEncode) +import Foreign.Generic.Class (Poly(..)) +import Foreign.Generic.EnumEncoding (defaultGenericEnumOptions, genericDecodeEnum, genericEncodeEnum) +import Safe.Coerce (coerce) newtype TupleArray a b = TupleArray (Tuple a b) @@ -28,11 +30,11 @@ instance decodeTupleArray :: (Decode a, Decode b) => Decode (TupleArray a b) whe decode x = do arr <- readArray x case arr of - [y, z] -> TupleArray <$> (Tuple <$> decode y <*> decode z) + [ y, z ] -> TupleArray <$> (Tuple <$> decode y <*> decode z) _ -> fail (ForeignError "Expected two array elements") instance encodeTupleArray :: (Encode a, Encode b) => Encode (TupleArray a b) where - encode (TupleArray (Tuple a b)) = unsafeToForeign [encode a, encode b] + encode (TupleArray (Tuple a b)) = unsafeToForeign [ encode a, encode b ] -- | An example record newtype RecordTest = RecordTest @@ -68,14 +70,16 @@ instance eqIntList :: Eq IntList where intListOptions :: Options intListOptions = - defaultOptions { unwrapSingleConstructors = true - , sumEncoding = TaggedObject { tagFieldName: "tag" - , contentsFieldName: "contents" - , constructorTagTransform: \tag -> case tag of - "Cons" -> "cOnS" - _ -> "" - } - } + defaultOptions + { unwrapSingleConstructors = true + , sumEncoding = TaggedObject + { tagFieldName: "tag" + , contentsFieldName: "contents" + , constructorTagTransform: \tag -> case tag of + "Cons" -> "cOnS" + _ -> "" + } + } instance decodeIntList :: Decode IntList where decode x = genericDecode intListOptions x @@ -95,10 +99,10 @@ instance eqTree :: Eq a => Eq (Tree a) where eq x y = genericEq x y instance decodeTree :: Decode a => Decode (Tree a) where - decode x = genericDecode defaultOptions x + decode x = (coerce :: Tree (Poly a) -> Tree a) <$> genericDecode defaultOptions x -instance encodeTree :: Encode a => Encode (Tree a) where - encode x = genericEncode defaultOptions x +instance Encode a => Encode (Tree a) where + encode x = genericEncode defaultOptions ((coerce :: Tree a -> Tree (Poly a)) x) newtype UndefinedTest = UndefinedTest { a :: Maybe String @@ -109,6 +113,7 @@ derive instance geUT :: Generic UndefinedTest _ instance dUT :: Decode UndefinedTest where decode = genericDecode $ defaultOptions + instance eUT :: Encode UndefinedTest where encode = genericEncode $ defaultOptions @@ -122,5 +127,6 @@ derive instance geFruit :: Generic Fruit _ instance dFruit :: Decode Fruit where decode = genericDecodeEnum defaultGenericEnumOptions + instance eFruit :: Encode Fruit where encode = genericEncodeEnum defaultGenericEnumOptions