git.iko.soy/rowtype-yoga/purescript-yoga-json
on main help sign in
.github/workflows/ci.yml+7−5
since splitsnapshots
unifiedsplit
@@ -13,13 +13,15 @@ jobs:
13 - uses: actions/checkout@v2
13 - uses: actions/checkout@v2
14
14
15 - uses: purescript-contrib/setup-purescript@main
15 - uses: purescript-contrib/setup-purescript@main
16+ with:
17+ spago: "unstable"
16
18
17 - uses: actions/setup-node@v2
19 - uses: actions/setup-node@v2
18 with:
20 with:
19− node-version: "14"
21+ node-version: "20"
20
22
21 - name: Cache PureScript dependencies
23 - name: Cache PureScript dependencies
22− uses: actions/cache@v2
24+ uses: actions/cache@v4
23 # This cache uses the .dhall files to know when it should reinstall
25 # This cache uses the .dhall files to know when it should reinstall
24 # and rebuild packages. It caches both the installed packages from
26 # and rebuild packages. It caches both the installed packages from
25 # the `.spago` directory and compilation artifacts from the `output`
27 # the `.spago` directory and compilation artifacts from the `output`
@@ -27,11 +29,11 @@ jobs:
27 # have changed. If you do not want to cache compiled output, remove
29 # have changed. If you do not want to cache compiled output, remove
28 # the `output` path.
30 # the `output` path.
29 with:
31 with:
30− key: ${{ runner.os }}-spago-${{ hashFiles('**/*.dhall') }}
32+ key: ${{ runner.os }}-spago-${{ hashFiles('**/*.yaml') }}
31 path: |
33 path: |
32 .spago
34 .spago
33 output
35 output
34−
36+ - run: npm install
35 - run: spago build
37 - run: spago build
36
38
37− - run: spago -x test.dhall test
39+ - run: npm run coverage
.gitignore+5
@@ -6,3 +6,8 @@
6/.purs*
6/.purs*
7/.psa*
7/.psa*
8/.spago/
8/.spago/
9+/.nyc_output/
10+/coverage/
11+/.idea/
12+.spec-results
13+.DS_Store
.nycrc.jsonnew file+8
@@ -0,0 +1,8 @@
1+{
2+ "all": true,
3+ "extension": [".purs"],
4+ "include": [ "src/**/*.purs"],
5+ "exclude": [ "src/Yoga/JSON/Generics.purs"],
6+ "excludeAfterRemap": true,
7+ "sourceMap": true
8+}
.tidyrc.json+1−1
@@ -6,5 +6,5 @@
6 "ribbon": 1,
6 "ribbon": 1,
7 "typeArrowPlacement": "last",
7 "typeArrowPlacement": "last",
8 "unicode": "always",
8 "unicode": "always",
9− "width": 80
9+ "width": 160
10}
10}
.vscode/settings.json+1−1
@@ -1,3 +1,3 @@
1{
1{
2− "purescript.buildCommand": "spago -x test.dhall build -- --purs-args --json-errors"
2+ "purescript.buildCommand": "spago -x test.dhall build --purs-args --json-errors"
3}
3}
CHANGELOG.mdnew file+34
@@ -0,0 +1,34 @@
1+# Changelog
2+
3+## v5.2.2
4+
5+- Fix variant decoding selecting absent branches whose payload decoders accept missing values, such as empty records and `Maybe`. Branches now require an own property matching their label.
6+
7+## v4.0.1
8+
9+- Allow the type of `read*` functions to be visibly applied (#24 by @postsolar)
10+
11+## v4.0.0
12+- Replace `bigints` dependency with `js-bigints` so that no more external npm dependency is needed (#11 by @sigma-andex)
13+
14+## v3.0.2
15+- Minor internal updates
16+- Improve error handling
17+- Add codecs and `JSDate` (@i-am-the-slime)
18+
19+## v3.0.1
20+- Readme update
21+
22+## v3.0.0
23+- Add codecs for enums and more instances (#9 by @i-am-the-slime)
24+- Add codecs for `Map` and `Map` with newtype (#4 by @i-am-the-slime)
25+
26+## v2.0.0
27+- Add support for `BigInt` (#5 by @sigma-andex)
28+- Improve Generics (#3 by @i-am-the-slime)
29+
30+## v1.0.1
31+- Add Generics (#2 by @i-am-the-slime)
32+
33+## v1.0.0
34+- Initial commit
README.md+153−5
@@ -1,14 +1,162 @@
1−# 🐏👑 purescript-yoga-json
1+# purescript-yoga-json
2
2
3−**Note**: This is a fork [simple-json](https://github.com/justinwoo/purescript-simple-json) ([MIT Licence](./LICENSE/simple-json.LICENSE)).
3+`yoga-json` is a light-weight and simple json library for purescript.
4
4
5+**Note**: This library was initially forked from the amazing [simple-json](https://github.com/justinwoo/purescript-simple-json) ([MIT Licence](./LICENSE/simple-json.LICENSE)).
6+Replace your imports from `Simple.JSON` to `Yoga.JSON` to migrate.
5## Table of Contents
7## Table of Contents
8+* [features](#features)
9+* [installation](#installation)
6* [usage](#usage)
10* [usage](#usage)
7−* [migrate from `simple-json`](#migrate-from-purescript-simple-json)
11+
12+## Features
13+
14+* 😌 simple and easy to use json codecs
15+* 🪶 light-weight
16+* 🤖 built-in support for many common types (`Sum` types, Tuples, BigInts, Maps, JSDate, DateTime, Eithers, NonEmptyStrings )
17+* 🖍 human-friendly error reporting
18+
19+## Installation
20+
21+```
22+spago install yoga-json
23+```
8
24
9## Usage
25## Usage
10
26
27+`purescript-yoga-json` basically provides two functions `writeJSON` and `readJSON`.
28+
29+Use `writeJSON` to serialise a type to a JSON string:
30+
31+```purescript
32+import Yoga.JSON as JSON
33+
34+serialised :: String
35+serialised =
36+ JSON.writeJSON { first_name: "Lola", last_name: "Flores" }
37+ -- {"last_name":"Flores","first_name":"Lola"}
38+```
39+
40+Use `readJSON` to deserialise a JSON string:
41+```purescript
42+import Yoga.JSON as JSON
43+
44+deserialised :: Either MultipleErrors { first_name :: String, last_name :: String }
45+deserialised = JSON.readJSON """{ "first_name": "Lola", "last_name": "Flores" }"""
46+-- Right { first_name: "Lola", last_name: "Flores" }
47+```
48+
49+As the parsing can fail, `readJSON` returns an `Either`, potentially containing a `Left` data constructor with `MultipleErrors`. If you don't care about the specific errors, you can use `readJSON_`, which returns a `Maybe`:
50+
51+```purescript
52+deserialised :: Maybe { first_name :: String, last_name :: String }
53+deserialised = JSON.readJSON_ """{ "first_name": "Lola", "last_name": "Flores" }"""
54+-- Just { first_name: "Lola", last_name: "Flores" }
55+```
56+
57+
58+## Sum types
59+
60+`purescript-yoga-json` provides utility functions to easily generate serialisers and deserialisers for your sum types.
61+
62+Let's start with a simple example of a sum type where our data constructors do not contain any further values:
63+
64+```
65+import Data.Either (Either)
66+import Data.Generic.Rep (class Generic)
67+import Yoga.JSON as JSON
68+import Yoga.JSON.Generics (genericReadForeignEnum, genericWriteForeignEnum)
69+import Yoga.JSON.Generics.EnumSumRep as Enum
70+
71+data MyEnum = Enum1 | Enum2 | Enum3
72+```
73+
74+Now, we need to derive a `Generic` instance for it:
75+
76+```
77+derive instance Generic MyEnum _
78+-- and optionally a Show instance
79+instance Show MyEnum where
80+ show = genericShow
81+```
82+
83+Next, we define a `WriteForeign` instance and implement the `writeImpl` function using `genericWriteForeignEnum Enum.defaultOptions`.
84+
85+```purescript
86+instance WriteForeign MyEnum
87+ where
88+ writeImpl = genericWriteForeignEnum Enum.defaultOptions
89+```
90+
91+Similarly, we implement the `ReadForeign` instance using `genericReadForeignEnum Enum.defaultOptions`
92+```purescript
93+instance ReadForeign MyEnum
94+ where
95+ readImpl = genericReadForeignEnum Enum.defaultOptions
96+```
97+
98+That's all, we can now serialise our data type:
99+```purescript
100+serialised = writeJSON { "myEnum": Enum3 }
101+-- {"myEnum":"Enum3"}
102+```
103+and deserialise it:
104+```purescript
105+deserialised :: E { "myEnum" :: MyEnum }
106+deserialised = readJSON serialised
107+-- Right { myEnum: Enum3 }
108+```
109+
110+### Writing custom codecs
111+
112+In order to write your own, custom codecs you will need to provide instances for `WriteForeign` and `ReadForeign`.
113+
114+Let's see an example. We define a simple data type `TrafficLight` that has three data constructors `Red`, `Yellow` and `Green`:
115+```purescript
116+data TrafficLight = Red | Yellow | Green
117+```
118+We would like to serialise these constructors as lower case strings `"red"`, `"yellow"` and `"green"`.
119+
120+First we need to provide an implementation for the `WriteForeign` type class, that tells `yoga-json` how to serialise the type. We pattern match on the three different data constructors and write them as the three `String`s red, yellow and green, using the same `writeImpl` function:
121+```purescript
122+instance WriteForeign TrafficLight where
123+ writeImpl Red = writeImpl "red"
124+ writeImpl Yellow = writeImpl "yellow"
125+ writeImpl Green = writeImpl "green"
126+```
127+This works, because `yoga-json` already knows how to serialise a `String`.
128+
129+Similarly, we need to provide an implementation for the `ReadForeign` type class, that tells `yoga-json` how to deserialise the type. We start by deserialising into a primitive type, typically a String or an Object, and then convert it to our desired Purescript type.
130+
131+Since we don't know the input `String`, it might contain invalid data and therefore deserialisation might fail. `yoga-json` uses the `ExceptT` monad to reflect this. We can return valid values using `pure` and `fail` on invalid values:
132+
133+```purescript
134+instance ReadForeign TrafficLight where
135+ readImpl json = do
136+ -- deserialise into a string
137+ str :: String <- readImpl json
138+ -- now we pattern match on our valid types
139+ case str of
140+ "red" -> pure Red
141+ "yellow" -> pure Yellow
142+ "green" -> pure Green
143+ -- and fail if we get an invalid type
144+ other -> fail $ ForeignError $ "Failed to parse " <> other <> " as TrafficLight"
145+```
146+
147+Now we can serialise our data type:
148+```purescript
149+serialised = writeJSON { "trafficLight": Red }
150+-- {"trafficLight":"red"}
151+```
11
152
153+and deserialise it:
12−## Migrate from `purescript-simple-json`
154+```purescript
155+deserialised :: E { "trafficLight" :: TrafficLight }
156+deserialised = readJSON """{ "trafficLight": "green" }"""
157+-- Right { trafficLight: Green }
13
158
14−`purescript-yoga-json` is a drop-in replacement for `purescript-simple-json`. Just change the imports from `Simple.JSON` to `Yoga.JSON`.
159+deserialisedUnknown :: E { "trafficLight" :: TrafficLight }
160+deserialisedUnknown = readJSON """{ "trafficLight": "purple" }"""
161+-- Left (NonEmptyList (NonEmpty (ErrorAtProperty "trafficLight" (ForeignError "Failed to parse purple as TrafficLight")) Nil))
162+```
bower.jsondeleted−39
@@ -1,39 +0,0 @@
1−{
2− "name": "purescript-yoga-json",
3− "license": [
4− "MIT"
5− ],
6− "repository": {
7− "type": "git",
8− "url": "https://github.com/rowtype-yoga/purescript-yoga-json.git"
9− },
10− "ignore": [
11− "**/.*",
12− "node_modules",
13− "bower_components",
14− "output"
15− ],
16− "dependencies": {
17− "purescript-arrays": "^v7.0.0",
18− "purescript-bifunctors": "^v6.0.0",
19− "purescript-console": "^v6.0.0",
20− "purescript-control": "^v6.0.0",
21− "purescript-effect": "^v4.0.0",
22− "purescript-either": "^v6.0.0",
23− "purescript-exceptions": "^v6.0.0",
24− "purescript-foldable-traversable": "^v6.0.0",
25− "purescript-foreign": "^v7.0.0",
26− "purescript-foreign-object": "^v4.0.0",
27− "purescript-identity": "^v6.0.0",
28− "purescript-lists": "^v7.0.0",
29− "purescript-maybe": "^v6.0.0",
30− "purescript-nonempty": "^v7.0.0",
31− "purescript-nullable": "^v6.0.0",
32− "purescript-partial": "^v4.0.0",
33− "purescript-prelude": "^v6.0.0",
34− "purescript-record": "^v4.0.0",
35− "purescript-transformers": "^v6.0.0",
36− "purescript-typelevel-prelude": "^v7.0.0",
37− "purescript-variant": "^v8.0.0"
38− }
39−}
docs/simple-json-migration.mdnew file+47
@@ -0,0 +1,47 @@
1+# Migrate from `purescript-simple-json`
2+
3+`purescript-yoga-json` is a fork of [simple-json](https://github.com/justinwoo/purescript-simple-json) ([MIT Licence](./LICENSE/simple-json.LICENSE)) and almost (read below if you use variants) a drop-in replacement for `purescript-simple-json`. Just change the imports from `Simple.JSON` to `Yoga.JSON`.
4+
5+## Additions over `simple-json`
6+
7+### Errors
8+yoga-json will actually report multiple errors at once in the case of records, objects, and arrays.
9+There's also a way to make errors more readable with `renderHumanError`:
10+(e.g. `Must provide a value of type 'Int' instead of 'Object' at $.a.b.c.d[1]`)
11+
12+
13+### Tuples
14+There is an inbuilt codec for `Tuple`s thanks to @ursi
15+`yoga-json` represents tuples as arrays in JSON.
16+
17+### Eithers
18+There is an inbuilt codec for `Either`s.
19+`yoga-json` represents eithers as objects with a `type` and a `value` tag in JSON.
20+
21+### JSDate and DateTime
22+Both are encoded as ISO8601 strings as spat out by `JSDate.toISOString`.
23+
24+### Generics
25+It includes @justinwoo's codecs for en- and decoding generics inspired by
26+[simple-json-generics](https://github.com/justinwoo/purescript-simple-json-generics)
27+
28+It is possible to customise the representation of enums, tagged sum types, and untagged sum types via options.
29+
30+### BigInts
31+There is an inbuilt codec for `BigInt`. Writing a `BigInt` however will result in a String. This is a current limitation of JavaScript and the only way around it - it seems - is writing your own JSON.stringify method (which is out of scope of this project).
32+
33+## Differences to `simple-json`
34+
35+### 💣 Variant codec
36+If you want to emulate `simple-json`'s format you may use the newtype `TaggedVariant`
37+
38+```purescript
39+type YourVariantRow = ( a :: Int, b :: String )
40+type YourVariant = Variant YourVariantRow
41+x :: YourVariant
42+x = inj (Proxy :: Proxy "a") 5
43+-- encoded = writeJSON x
44+-- ^ Let's say you had this before
45+-- You can now do:
46+encoded = writeJSON (TaggedVariant "type" "value" x)
47+```
package-lock.jsonnew file+1157
@@ -0,0 +1,1157 @@
1+{
2+ "name": "purescript-yoga-json",
3+ "lockfileVersion": 2,
4+ "requires": true,
5+ "packages": {
6+ "": {
7+ "name": "purescript-yoga-json",
8+ "devDependencies": {
9+ "c8": "^7.12.0",
10+ "rimraf": "^3.0.2"
11+ }
12+ },
13+ "node_modules/@bcoe/v8-coverage": {
14+ "version": "0.2.3",
15+ "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
16+ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
17+ "dev": true
18+ },
19+ "node_modules/@istanbuljs/schema": {
20+ "version": "0.1.3",
21+ "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
22+ "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
23+ "dev": true,
24+ "engines": {
25+ "node": ">=8"
26+ }
27+ },
28+ "node_modules/@jridgewell/resolve-uri": {
29+ "version": "3.1.0",
30+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
31+ "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
32+ "dev": true,
33+ "engines": {
34+ "node": ">=6.0.0"
35+ }
36+ },
37+ "node_modules/@jridgewell/sourcemap-codec": {
38+ "version": "1.4.14",
39+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
40+ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
41+ "dev": true
42+ },
43+ "node_modules/@jridgewell/trace-mapping": {
44+ "version": "0.3.17",
45+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
46+ "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
47+ "dev": true,
48+ "dependencies": {
49+ "@jridgewell/resolve-uri": "3.1.0",
50+ "@jridgewell/sourcemap-codec": "1.4.14"
51+ }
52+ },
53+ "node_modules/@types/istanbul-lib-coverage": {
54+ "version": "2.0.4",
55+ "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
56+ "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==",
57+ "dev": true
58+ },
59+ "node_modules/ansi-regex": {
60+ "version": "5.0.1",
61+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
62+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
63+ "dev": true,
64+ "engines": {
65+ "node": ">=8"
66+ }
67+ },
68+ "node_modules/ansi-styles": {
69+ "version": "4.3.0",
70+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
71+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
72+ "dev": true,
73+ "dependencies": {
74+ "color-convert": "^2.0.1"
75+ },
76+ "engines": {
77+ "node": ">=8"
78+ },
79+ "funding": {
80+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
81+ }
82+ },
83+ "node_modules/balanced-match": {
84+ "version": "1.0.2",
85+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
86+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
87+ "dev": true
88+ },
89+ "node_modules/brace-expansion": {
90+ "version": "1.1.11",
91+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
92+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
93+ "dev": true,
94+ "dependencies": {
95+ "balanced-match": "^1.0.0",
96+ "concat-map": "0.0.1"
97+ }
98+ },
99+ "node_modules/c8": {
100+ "version": "7.12.0",
101+ "resolved": "https://registry.npmjs.org/c8/-/c8-7.12.0.tgz",
102+ "integrity": "sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A==",
103+ "dev": true,
104+ "dependencies": {
105+ "@bcoe/v8-coverage": "^0.2.3",
106+ "@istanbuljs/schema": "^0.1.3",
107+ "find-up": "^5.0.0",
108+ "foreground-child": "^2.0.0",
109+ "istanbul-lib-coverage": "^3.2.0",
110+ "istanbul-lib-report": "^3.0.0",
111+ "istanbul-reports": "^3.1.4",
112+ "rimraf": "^3.0.2",
113+ "test-exclude": "^6.0.0",
114+ "v8-to-istanbul": "^9.0.0",
115+ "yargs": "^16.2.0",
116+ "yargs-parser": "^20.2.9"
117+ },
118+ "bin": {
119+ "c8": "bin/c8.js"
120+ },
121+ "engines": {
122+ "node": ">=10.12.0"
123+ }
124+ },
125+ "node_modules/cliui": {
126+ "version": "7.0.4",
127+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
128+ "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
129+ "dev": true,
130+ "dependencies": {
131+ "string-width": "^4.2.0",
132+ "strip-ansi": "^6.0.0",
133+ "wrap-ansi": "^7.0.0"
134+ }
135+ },
136+ "node_modules/color-convert": {
137+ "version": "2.0.1",
138+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
139+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
140+ "dev": true,
141+ "dependencies": {
142+ "color-name": "~1.1.4"
143+ },
144+ "engines": {
145+ "node": ">=7.0.0"
146+ }
147+ },
148+ "node_modules/color-name": {
149+ "version": "1.1.4",
150+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
151+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
152+ "dev": true
153+ },
154+ "node_modules/concat-map": {
155+ "version": "0.0.1",
156+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
157+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
158+ "dev": true
159+ },
160+ "node_modules/convert-source-map": {
161+ "version": "1.9.0",
162+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
163+ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
164+ "dev": true
165+ },
166+ "node_modules/cross-spawn": {
167+ "version": "7.0.6",
168+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
169+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
170+ "dev": true,
171+ "license": "MIT",
172+ "dependencies": {
173+ "path-key": "^3.1.0",
174+ "shebang-command": "^2.0.0",
175+ "which": "^2.0.1"
176+ },
177+ "engines": {
178+ "node": ">= 8"
179+ }
180+ },
181+ "node_modules/emoji-regex": {
182+ "version": "8.0.0",
183+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
184+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
185+ "dev": true
186+ },
187+ "node_modules/escalade": {
188+ "version": "3.1.1",
189+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
190+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
191+ "dev": true,
192+ "engines": {
193+ "node": ">=6"
194+ }
195+ },
196+ "node_modules/find-up": {
197+ "version": "5.0.0",
198+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
199+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
200+ "dev": true,
201+ "dependencies": {
202+ "locate-path": "^6.0.0",
203+ "path-exists": "^4.0.0"
204+ },
205+ "engines": {
206+ "node": ">=10"
207+ },
208+ "funding": {
209+ "url": "https://github.com/sponsors/sindresorhus"
210+ }
211+ },
212+ "node_modules/foreground-child": {
213+ "version": "2.0.0",
214+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz",
215+ "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==",
216+ "dev": true,
217+ "dependencies": {
218+ "cross-spawn": "^7.0.0",
219+ "signal-exit": "^3.0.2"
220+ },
221+ "engines": {
222+ "node": ">=8.0.0"
223+ }
224+ },
225+ "node_modules/fs.realpath": {
226+ "version": "1.0.0",
227+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
228+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
229+ "dev": true
230+ },
231+ "node_modules/get-caller-file": {
232+ "version": "2.0.5",
233+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
234+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
235+ "dev": true,
236+ "engines": {
237+ "node": "6.* || 8.* || >= 10.*"
238+ }
239+ },
240+ "node_modules/glob": {
241+ "version": "7.2.3",
242+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
243+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
244+ "dev": true,
245+ "dependencies": {
246+ "fs.realpath": "^1.0.0",
247+ "inflight": "^1.0.4",
248+ "inherits": "2",
249+ "minimatch": "^3.1.1",
250+ "once": "^1.3.0",
251+ "path-is-absolute": "^1.0.0"
252+ },
253+ "engines": {
254+ "node": "*"
255+ },
256+ "funding": {
257+ "url": "https://github.com/sponsors/isaacs"
258+ }
259+ },
260+ "node_modules/has-flag": {
261+ "version": "4.0.0",
262+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
263+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
264+ "dev": true,
265+ "engines": {
266+ "node": ">=8"
267+ }
268+ },
269+ "node_modules/html-escaper": {
270+ "version": "2.0.2",
271+ "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
272+ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
273+ "dev": true
274+ },
275+ "node_modules/inflight": {
276+ "version": "1.0.6",
277+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
278+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
279+ "dev": true,
280+ "dependencies": {
281+ "once": "^1.3.0",
282+ "wrappy": "1"
283+ }
284+ },
285+ "node_modules/inherits": {
286+ "version": "2.0.4",
287+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
288+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
289+ "dev": true
290+ },
291+ "node_modules/is-fullwidth-code-point": {
292+ "version": "3.0.0",
293+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
294+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
295+ "dev": true,
296+ "engines": {
297+ "node": ">=8"
298+ }
299+ },
300+ "node_modules/isexe": {
301+ "version": "2.0.0",
302+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
303+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
304+ "dev": true
305+ },
306+ "node_modules/istanbul-lib-coverage": {
307+ "version": "3.2.0",
308+ "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
309+ "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==",
310+ "dev": true,
311+ "engines": {
312+ "node": ">=8"
313+ }
314+ },
315+ "node_modules/istanbul-lib-report": {
316+ "version": "3.0.0",
317+ "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
318+ "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
319+ "dev": true,
320+ "dependencies": {
321+ "istanbul-lib-coverage": "^3.0.0",
322+ "make-dir": "^3.0.0",
323+ "supports-color": "^7.1.0"
324+ },
325+ "engines": {
326+ "node": ">=8"
327+ }
328+ },
329+ "node_modules/istanbul-reports": {
330+ "version": "3.1.5",
331+ "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz",
332+ "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==",
333+ "dev": true,
334+ "dependencies": {
335+ "html-escaper": "^2.0.0",
336+ "istanbul-lib-report": "^3.0.0"
337+ },
338+ "engines": {
339+ "node": ">=8"
340+ }
341+ },
342+ "node_modules/locate-path": {
343+ "version": "6.0.0",
344+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
345+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
346+ "dev": true,
347+ "dependencies": {
348+ "p-locate": "^5.0.0"
349+ },
350+ "engines": {
351+ "node": ">=10"
352+ },
353+ "funding": {
354+ "url": "https://github.com/sponsors/sindresorhus"
355+ }
356+ },
357+ "node_modules/make-dir": {
358+ "version": "3.1.0",
359+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
360+ "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
361+ "dev": true,
362+ "dependencies": {
363+ "semver": "^6.0.0"
364+ },
365+ "engines": {
366+ "node": ">=8"
367+ },
368+ "funding": {
369+ "url": "https://github.com/sponsors/sindresorhus"
370+ }
371+ },
372+ "node_modules/minimatch": {
373+ "version": "3.1.2",
374+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
375+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
376+ "dev": true,
377+ "dependencies": {
378+ "brace-expansion": "^1.1.7"
379+ },
380+ "engines": {
381+ "node": "*"
382+ }
383+ },
384+ "node_modules/once": {
385+ "version": "1.4.0",
386+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
387+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
388+ "dev": true,
389+ "dependencies": {
390+ "wrappy": "1"
391+ }
392+ },
393+ "node_modules/p-limit": {
394+ "version": "3.1.0",
395+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
396+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
397+ "dev": true,
398+ "dependencies": {
399+ "yocto-queue": "^0.1.0"
400+ },
401+ "engines": {
402+ "node": ">=10"
403+ },
404+ "funding": {
405+ "url": "https://github.com/sponsors/sindresorhus"
406+ }
407+ },
408+ "node_modules/p-locate": {
409+ "version": "5.0.0",
410+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
411+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
412+ "dev": true,
413+ "dependencies": {
414+ "p-limit": "^3.0.2"
415+ },
416+ "engines": {
417+ "node": ">=10"
418+ },
419+ "funding": {
420+ "url": "https://github.com/sponsors/sindresorhus"
421+ }
422+ },
423+ "node_modules/path-exists": {
424+ "version": "4.0.0",
425+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
426+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
427+ "dev": true,
428+ "engines": {
429+ "node": ">=8"
430+ }
431+ },
432+ "node_modules/path-is-absolute": {
433+ "version": "1.0.1",
434+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
435+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
436+ "dev": true,
437+ "engines": {
438+ "node": ">=0.10.0"
439+ }
440+ },
441+ "node_modules/path-key": {
442+ "version": "3.1.1",
443+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
444+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
445+ "dev": true,
446+ "engines": {
447+ "node": ">=8"
448+ }
449+ },
450+ "node_modules/require-directory": {
451+ "version": "2.1.1",
452+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
453+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
454+ "dev": true,
455+ "engines": {
456+ "node": ">=0.10.0"
457+ }
458+ },
459+ "node_modules/rimraf": {
460+ "version": "3.0.2",
461+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
462+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
463+ "deprecated": "Rimraf versions prior to v4 are no longer supported",
464+ "dev": true,
465+ "license": "ISC",
466+ "dependencies": {
467+ "glob": "^7.1.3"
468+ },
469+ "bin": {
470+ "rimraf": "bin.js"
471+ },
472+ "funding": {
473+ "url": "https://github.com/sponsors/isaacs"
474+ }
475+ },
476+ "node_modules/semver": {
477+ "version": "6.3.1",
478+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
479+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
480+ "dev": true,
481+ "license": "ISC",
482+ "bin": {
483+ "semver": "bin/semver.js"
484+ }
485+ },
486+ "node_modules/shebang-command": {
487+ "version": "2.0.0",
488+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
489+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
490+ "dev": true,
491+ "dependencies": {
492+ "shebang-regex": "^3.0.0"
493+ },
494+ "engines": {
495+ "node": ">=8"
496+ }
497+ },
498+ "node_modules/shebang-regex": {
499+ "version": "3.0.0",
500+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
501+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
502+ "dev": true,
503+ "engines": {
504+ "node": ">=8"
505+ }
506+ },
507+ "node_modules/signal-exit": {
508+ "version": "3.0.7",
509+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
510+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
511+ "dev": true
512+ },
513+ "node_modules/string-width": {
514+ "version": "4.2.3",
515+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
516+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
517+ "dev": true,
518+ "dependencies": {
519+ "emoji-regex": "^8.0.0",
520+ "is-fullwidth-code-point": "^3.0.0",
521+ "strip-ansi": "^6.0.1"
522+ },
523+ "engines": {
524+ "node": ">=8"
525+ }
526+ },
527+ "node_modules/strip-ansi": {
528+ "version": "6.0.1",
529+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
530+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
531+ "dev": true,
532+ "dependencies": {
533+ "ansi-regex": "^5.0.1"
534+ },
535+ "engines": {
536+ "node": ">=8"
537+ }
538+ },
539+ "node_modules/supports-color": {
540+ "version": "7.2.0",
541+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
542+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
543+ "dev": true,
544+ "dependencies": {
545+ "has-flag": "^4.0.0"
546+ },
547+ "engines": {
548+ "node": ">=8"
549+ }
550+ },
551+ "node_modules/test-exclude": {
552+ "version": "6.0.0",
553+ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
554+ "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
555+ "dev": true,
556+ "dependencies": {
557+ "@istanbuljs/schema": "^0.1.2",
558+ "glob": "^7.1.4",
559+ "minimatch": "^3.0.4"
560+ },
561+ "engines": {
562+ "node": ">=8"
563+ }
564+ },
565+ "node_modules/v8-to-istanbul": {
566+ "version": "9.0.1",
567+ "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz",
568+ "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==",
569+ "dev": true,
570+ "dependencies": {
571+ "@jridgewell/trace-mapping": "^0.3.12",
572+ "@types/istanbul-lib-coverage": "^2.0.1",
573+ "convert-source-map": "^1.6.0"
574+ },
575+ "engines": {
576+ "node": ">=10.12.0"
577+ }
578+ },
579+ "node_modules/which": {
580+ "version": "2.0.2",
581+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
582+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
583+ "dev": true,
584+ "dependencies": {
585+ "isexe": "^2.0.0"
586+ },
587+ "bin": {
588+ "node-which": "bin/node-which"
589+ },
590+ "engines": {
591+ "node": ">= 8"
592+ }
593+ },
594+ "node_modules/wrap-ansi": {
595+ "version": "7.0.0",
596+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
597+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
598+ "dev": true,
599+ "dependencies": {
600+ "ansi-styles": "^4.0.0",
601+ "string-width": "^4.1.0",
602+ "strip-ansi": "^6.0.0"
603+ },
604+ "engines": {
605+ "node": ">=10"
606+ },
607+ "funding": {
608+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
609+ }
610+ },
611+ "node_modules/wrappy": {
612+ "version": "1.0.2",
613+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
614+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
615+ "dev": true
616+ },
617+ "node_modules/y18n": {
618+ "version": "5.0.8",
619+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
620+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
621+ "dev": true,
622+ "engines": {
623+ "node": ">=10"
624+ }
625+ },
626+ "node_modules/yargs": {
627+ "version": "16.2.0",
628+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
629+ "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
630+ "dev": true,
631+ "dependencies": {
632+ "cliui": "^7.0.2",
633+ "escalade": "^3.1.1",
634+ "get-caller-file": "^2.0.5",
635+ "require-directory": "^2.1.1",
636+ "string-width": "^4.2.0",
637+ "y18n": "^5.0.5",
638+ "yargs-parser": "^20.2.2"
639+ },
640+ "engines": {
641+ "node": ">=10"
642+ }
643+ },
644+ "node_modules/yargs-parser": {
645+ "version": "20.2.9",
646+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
647+ "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
648+ "dev": true,
649+ "engines": {
650+ "node": ">=10"
651+ }
652+ },
653+ "node_modules/yocto-queue": {
654+ "version": "0.1.0",
655+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
656+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
657+ "dev": true,
658+ "engines": {
659+ "node": ">=10"
660+ },
661+ "funding": {
662+ "url": "https://github.com/sponsors/sindresorhus"
663+ }
664+ }
665+ },
666+ "dependencies": {
667+ "@bcoe/v8-coverage": {
668+ "version": "0.2.3",
669+ "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
670+ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
671+ "dev": true
672+ },
673+ "@istanbuljs/schema": {
674+ "version": "0.1.3",
675+ "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
676+ "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
677+ "dev": true
678+ },
679+ "@jridgewell/resolve-uri": {
680+ "version": "3.1.0",
681+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
682+ "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
683+ "dev": true
684+ },
685+ "@jridgewell/sourcemap-codec": {
686+ "version": "1.4.14",
687+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
688+ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
689+ "dev": true
690+ },
691+ "@jridgewell/trace-mapping": {
692+ "version": "0.3.17",
693+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
694+ "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
695+ "dev": true,
696+ "requires": {
697+ "@jridgewell/resolve-uri": "3.1.0",
698+ "@jridgewell/sourcemap-codec": "1.4.14"
699+ }
700+ },
701+ "@types/istanbul-lib-coverage": {
702+ "version": "2.0.4",
703+ "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
704+ "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==",
705+ "dev": true
706+ },
707+ "ansi-regex": {
708+ "version": "5.0.1",
709+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
710+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
711+ "dev": true
712+ },
713+ "ansi-styles": {
714+ "version": "4.3.0",
715+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
716+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
717+ "dev": true,
718+ "requires": {
719+ "color-convert": "^2.0.1"
720+ }
721+ },
722+ "balanced-match": {
723+ "version": "1.0.2",
724+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
725+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
726+ "dev": true
727+ },
728+ "brace-expansion": {
729+ "version": "1.1.11",
730+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
731+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
732+ "dev": true,
733+ "requires": {
734+ "balanced-match": "^1.0.0",
735+ "concat-map": "0.0.1"
736+ }
737+ },
738+ "c8": {
739+ "version": "7.12.0",
740+ "resolved": "https://registry.npmjs.org/c8/-/c8-7.12.0.tgz",
741+ "integrity": "sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A==",
742+ "dev": true,
743+ "requires": {
744+ "@bcoe/v8-coverage": "^0.2.3",
745+ "@istanbuljs/schema": "^0.1.3",
746+ "find-up": "^5.0.0",
747+ "foreground-child": "^2.0.0",
748+ "istanbul-lib-coverage": "^3.2.0",
749+ "istanbul-lib-report": "^3.0.0",
750+ "istanbul-reports": "^3.1.4",
751+ "rimraf": "^3.0.2",
752+ "test-exclude": "^6.0.0",
753+ "v8-to-istanbul": "^9.0.0",
754+ "yargs": "^16.2.0",
755+ "yargs-parser": "^20.2.9"
756+ }
757+ },
758+ "cliui": {
759+ "version": "7.0.4",
760+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
761+ "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
762+ "dev": true,
763+ "requires": {
764+ "string-width": "^4.2.0",
765+ "strip-ansi": "^6.0.0",
766+ "wrap-ansi": "^7.0.0"
767+ }
768+ },
769+ "color-convert": {
770+ "version": "2.0.1",
771+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
772+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
773+ "dev": true,
774+ "requires": {
775+ "color-name": "~1.1.4"
776+ }
777+ },
778+ "color-name": {
779+ "version": "1.1.4",
780+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
781+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
782+ "dev": true
783+ },
784+ "concat-map": {
785+ "version": "0.0.1",
786+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
787+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
788+ "dev": true
789+ },
790+ "convert-source-map": {
791+ "version": "1.9.0",
792+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
793+ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
794+ "dev": true
795+ },
796+ "cross-spawn": {
797+ "version": "7.0.6",
798+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
799+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
800+ "dev": true,
801+ "requires": {
802+ "path-key": "^3.1.0",
803+ "shebang-command": "^2.0.0",
804+ "which": "^2.0.1"
805+ }
806+ },
807+ "emoji-regex": {
808+ "version": "8.0.0",
809+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
810+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
811+ "dev": true
812+ },
813+ "escalade": {
814+ "version": "3.1.1",
815+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
816+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
817+ "dev": true
818+ },
819+ "find-up": {
820+ "version": "5.0.0",
821+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
822+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
823+ "dev": true,
824+ "requires": {
825+ "locate-path": "^6.0.0",
826+ "path-exists": "^4.0.0"
827+ }
828+ },
829+ "foreground-child": {
830+ "version": "2.0.0",
831+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz",
832+ "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==",
833+ "dev": true,
834+ "requires": {
835+ "cross-spawn": "^7.0.0",
836+ "signal-exit": "^3.0.2"
837+ }
838+ },
839+ "fs.realpath": {
840+ "version": "1.0.0",
841+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
842+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
843+ "dev": true
844+ },
845+ "get-caller-file": {
846+ "version": "2.0.5",
847+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
848+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
849+ "dev": true
850+ },
851+ "glob": {
852+ "version": "7.2.3",
853+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
854+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
855+ "dev": true,
856+ "requires": {
857+ "fs.realpath": "^1.0.0",
858+ "inflight": "^1.0.4",
859+ "inherits": "2",
860+ "minimatch": "^3.1.1",
861+ "once": "^1.3.0",
862+ "path-is-absolute": "^1.0.0"
863+ }
864+ },
865+ "has-flag": {
866+ "version": "4.0.0",
867+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
868+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
869+ "dev": true
870+ },
871+ "html-escaper": {
872+ "version": "2.0.2",
873+ "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
874+ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
875+ "dev": true
876+ },
877+ "inflight": {
878+ "version": "1.0.6",
879+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
880+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
881+ "dev": true,
882+ "requires": {
883+ "once": "^1.3.0",
884+ "wrappy": "1"
885+ }
886+ },
887+ "inherits": {
888+ "version": "2.0.4",
889+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
890+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
891+ "dev": true
892+ },
893+ "is-fullwidth-code-point": {
894+ "version": "3.0.0",
895+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
896+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
897+ "dev": true
898+ },
899+ "isexe": {
900+ "version": "2.0.0",
901+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
902+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
903+ "dev": true
904+ },
905+ "istanbul-lib-coverage": {
906+ "version": "3.2.0",
907+ "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
908+ "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==",
909+ "dev": true
910+ },
911+ "istanbul-lib-report": {
912+ "version": "3.0.0",
913+ "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
914+ "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
915+ "dev": true,
916+ "requires": {
917+ "istanbul-lib-coverage": "^3.0.0",
918+ "make-dir": "^3.0.0",
919+ "supports-color": "^7.1.0"
920+ }
921+ },
922+ "istanbul-reports": {
923+ "version": "3.1.5",
924+ "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz",
925+ "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==",
926+ "dev": true,
927+ "requires": {
928+ "html-escaper": "^2.0.0",
929+ "istanbul-lib-report": "^3.0.0"
930+ }
931+ },
932+ "locate-path": {
933+ "version": "6.0.0",
934+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
935+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
936+ "dev": true,
937+ "requires": {
938+ "p-locate": "^5.0.0"
939+ }
940+ },
941+ "make-dir": {
942+ "version": "3.1.0",
943+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
944+ "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
945+ "dev": true,
946+ "requires": {
947+ "semver": "^6.0.0"
948+ }
949+ },
950+ "minimatch": {
951+ "version": "3.1.2",
952+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
953+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
954+ "dev": true,
955+ "requires": {
956+ "brace-expansion": "^1.1.7"
957+ }
958+ },
959+ "once": {
960+ "version": "1.4.0",
961+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
962+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
963+ "dev": true,
964+ "requires": {
965+ "wrappy": "1"
966+ }
967+ },
968+ "p-limit": {
969+ "version": "3.1.0",
970+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
971+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
972+ "dev": true,
973+ "requires": {
974+ "yocto-queue": "^0.1.0"
975+ }
976+ },
977+ "p-locate": {
978+ "version": "5.0.0",
979+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
980+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
981+ "dev": true,
982+ "requires": {
983+ "p-limit": "^3.0.2"
984+ }
985+ },
986+ "path-exists": {
987+ "version": "4.0.0",
988+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
989+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
990+ "dev": true
991+ },
992+ "path-is-absolute": {
993+ "version": "1.0.1",
994+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
995+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
996+ "dev": true
997+ },
998+ "path-key": {
999+ "version": "3.1.1",
1000+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
1001+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
1002+ "dev": true
1003+ },
1004+ "require-directory": {
1005+ "version": "2.1.1",
1006+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
1007+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
1008+ "dev": true
1009+ },
1010+ "rimraf": {
1011+ "version": "3.0.2",
1012+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
1013+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
1014+ "dev": true,
1015+ "requires": {
1016+ "glob": "^7.1.3"
1017+ }
1018+ },
1019+ "semver": {
1020+ "version": "6.3.1",
1021+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
1022+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
1023+ "dev": true
1024+ },
1025+ "shebang-command": {
1026+ "version": "2.0.0",
1027+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
1028+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
1029+ "dev": true,
1030+ "requires": {
1031+ "shebang-regex": "^3.0.0"
1032+ }
1033+ },
1034+ "shebang-regex": {
1035+ "version": "3.0.0",
1036+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
1037+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
1038+ "dev": true
1039+ },
1040+ "signal-exit": {
1041+ "version": "3.0.7",
1042+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
1043+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
1044+ "dev": true
1045+ },
1046+ "string-width": {
1047+ "version": "4.2.3",
1048+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
1049+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
1050+ "dev": true,
1051+ "requires": {
1052+ "emoji-regex": "^8.0.0",
1053+ "is-fullwidth-code-point": "^3.0.0",
1054+ "strip-ansi": "^6.0.1"
1055+ }
1056+ },
1057+ "strip-ansi": {
1058+ "version": "6.0.1",
1059+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
1060+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
1061+ "dev": true,
1062+ "requires": {
1063+ "ansi-regex": "^5.0.1"
1064+ }
1065+ },
1066+ "supports-color": {
1067+ "version": "7.2.0",
1068+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
1069+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
1070+ "dev": true,
1071+ "requires": {
1072+ "has-flag": "^4.0.0"
1073+ }
1074+ },
1075+ "test-exclude": {
1076+ "version": "6.0.0",
1077+ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
1078+ "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
1079+ "dev": true,
1080+ "requires": {
1081+ "@istanbuljs/schema": "^0.1.2",
1082+ "glob": "^7.1.4",
1083+ "minimatch": "^3.0.4"
1084+ }
1085+ },
1086+ "v8-to-istanbul": {
1087+ "version": "9.0.1",
1088+ "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz",
1089+ "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==",
1090+ "dev": true,
1091+ "requires": {
1092+ "@jridgewell/trace-mapping": "^0.3.12",
1093+ "@types/istanbul-lib-coverage": "^2.0.1",
1094+ "convert-source-map": "^1.6.0"
1095+ }
1096+ },
1097+ "which": {
1098+ "version": "2.0.2",
1099+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
1100+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
1101+ "dev": true,
1102+ "requires": {
1103+ "isexe": "^2.0.0"
1104+ }
1105+ },
1106+ "wrap-ansi": {
1107+ "version": "7.0.0",
1108+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
1109+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
1110+ "dev": true,
1111+ "requires": {
1112+ "ansi-styles": "^4.0.0",
1113+ "string-width": "^4.1.0",
1114+ "strip-ansi": "^6.0.0"
1115+ }
1116+ },
1117+ "wrappy": {
1118+ "version": "1.0.2",
1119+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
1120+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
1121+ "dev": true
1122+ },
1123+ "y18n": {
1124+ "version": "5.0.8",
1125+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
1126+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
1127+ "dev": true
1128+ },
1129+ "yargs": {
1130+ "version": "16.2.0",
1131+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
1132+ "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
1133+ "dev": true,
1134+ "requires": {
1135+ "cliui": "^7.0.2",
1136+ "escalade": "^3.1.1",
1137+ "get-caller-file": "^2.0.5",
1138+ "require-directory": "^2.1.1",
1139+ "string-width": "^4.2.0",
1140+ "y18n": "^5.0.5",
1141+ "yargs-parser": "^20.2.2"
1142+ }
1143+ },
1144+ "yargs-parser": {
1145+ "version": "20.2.9",
1146+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
1147+ "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
1148+ "dev": true
1149+ },
1150+ "yocto-queue": {
1151+ "version": "0.1.0",
1152+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
1153+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
1154+ "dev": true
1155+ }
1156+ }
1157+}
package.jsonnew file+11
@@ -0,0 +1,11 @@
1+{
2+ "scripts": {
3+ "test": "spago test",
4+ "precoverage": "npm run test",
5+ "coverage": "c8 --lines=99 --branches=75 --statements=99 npm run test"
6+ },
7+ "type": "module",
8+ "devDependencies": {
9+ "c8": "^7.12.0"
10+ }
11+}
packages.dhalldeleted−5
@@ -1,5 +0,0 @@
1−let upstream =
2− https://github.com/purescript/package-sets/releases/download/psc-0.15.0-20220509/packages.dhall
3− sha256:d4c1a03606efdbb7bb7745a9d3aa908cb1ba5611921373659a4c7bf1c41c106c
4−
5−in upstream
spago.dhalldeleted−30
@@ -1,30 +0,0 @@
1−{ name = "yoga-json"
2−, license = "MIT"
3−, repository = "https://github.com/rowtype-yoga/purescript-yoga-json.git"
4−, dependencies =
5− [ "arrays"
6− , "bifunctors"
7− , "console"
8− , "control"
9− , "effect"
10− , "either"
11− , "exceptions"
12− , "foldable-traversable"
13− , "foreign"
14− , "foreign-object"
15− , "identity"
16− , "lists"
17− , "maybe"
18− , "nonempty"
19− , "nullable"
20− , "partial"
21− , "prelude"
22− , "record"
23− , "transformers"
24− , "tuples"
25− , "typelevel-prelude"
26− , "variant"
27− ]
28−, packages = ./packages.dhall
29−, sources = [ "src/**/*.purs" ]
30−}
spago.locknew file+1747
@@ -0,0 +1,1747 @@
1+{
2+ "workspace": {
3+ "packages": {
4+ "yoga-json": {
5+ "path": "./",
6+ "core": {
7+ "dependencies": [
8+ {
9+ "arrays": ">=7.3.0 <8.0.0"
10+ },
11+ {
12+ "bifunctors": ">=6.0.0 <7.0.0"
13+ },
14+ {
15+ "control": ">=6.0.0 <7.0.0"
16+ },
17+ {
18+ "datetime": ">=6.1.0 <7.0.0"
19+ },
20+ {
21+ "effect": ">=4.0.0 <5.0.0"
22+ },
23+ {
24+ "either": ">=6.1.0 <7.0.0"
25+ },
26+ {
27+ "exceptions": ">=6.1.0 <7.0.0"
28+ },
29+ {
30+ "foldable-traversable": ">=6.0.0 <7.0.0"
31+ },
32+ {
33+ "foreign": ">=7.0.0 <8.0.0"
34+ },
35+ {
36+ "foreign-object": ">=4.1.0 <5.0.0"
37+ },
38+ {
39+ "free": ">=7.1.0 <8.0.0"
40+ },
41+ {
42+ "identity": ">=6.0.0 <7.0.0"
43+ },
44+ {
45+ "integers": ">=6.0.0 <7.0.0"
46+ },
47+ {
48+ "js-bigints": ">=2.2.1 <3.0.0"
49+ },
50+ {
51+ "js-date": ">=8.0.0 <9.0.0"
52+ },
53+ {
54+ "lists": ">=7.0.0 <8.0.0"
55+ },
56+ {
57+ "maybe": ">=6.0.0 <7.0.0"
58+ },
59+ {
60+ "newtype": ">=5.0.0 <6.0.0"
61+ },
62+ {
63+ "nullable": ">=6.0.0 <7.0.0"
64+ },
65+ {
66+ "numbers": ">=9.0.1 <10.0.0"
67+ },
68+ {
69+ "ordered-collections": ">=3.2.0 <4.0.0"
70+ },
71+ {
72+ "partial": ">=4.0.0 <5.0.0"
73+ },
74+ {
75+ "prelude": ">=6.0.2 <7.0.0"
76+ },
77+ {
78+ "record": ">=4.0.0 <5.0.0"
79+ },
80+ {
81+ "safe-coerce": ">=2.0.0 <3.0.0"
82+ },
83+ {
84+ "strings": ">=6.0.1 <7.0.0"
85+ },
86+ {
87+ "transformers": ">=6.1.0 <7.0.0"
88+ },
89+ {
90+ "tuples": ">=7.0.0 <8.0.0"
91+ },
92+ {
93+ "typelevel-prelude": ">=7.0.0 <8.0.0"
94+ },
95+ {
96+ "unsafe-coerce": ">=6.0.0 <7.0.0"
97+ },
98+ {
99+ "variant": ">=8.0.0 <9.0.0"
100+ },
101+ {
102+ "yoga-tree": ">=1.0.0 <2.0.0"
103+ }
104+ ]
105+ },
106+ "test": {
107+ "dependencies": [
108+ "spec",
109+ "spec-discovery",
110+ "spec-node",
111+ "strings-extra"
112+ ]
113+ }
114+ }
115+ },
116+ "package_set": {
117+ "address": {
118+ "registry": "63.2.1"
119+ },
120+ "compiler": ">=0.15.15 <0.16.0",
121+ "content": {
122+ "abc-parser": "2.0.1",
123+ "ace": "9.1.0",
124+ "address-rfc2821": "0.1.1",
125+ "aff": "8.0.0",
126+ "aff-bus": "6.0.0",
127+ "aff-coroutines": "9.0.0",
128+ "aff-promise": "4.0.0",
129+ "aff-retry": "2.0.0",
130+ "affjax": "13.0.0",
131+ "affjax-node": "1.0.0",
132+ "affjax-web": "1.0.0",
133+ "ansi": "7.0.0",
134+ "apexcharts": "0.5.0",
135+ "applicative-phases": "1.0.0",
136+ "argonaut": "9.0.0",
137+ "argonaut-aeson-generic": "0.4.1",
138+ "argonaut-codecs": "9.1.0",
139+ "argonaut-core": "7.0.0",
140+ "argonaut-generic": "8.0.0",
141+ "argonaut-traversals": "10.0.0",
142+ "argparse-basic": "2.0.0",
143+ "array-builder": "0.1.2",
144+ "array-search": "0.6.0",
145+ "arraybuffer": "13.2.0",
146+ "arraybuffer-builder": "3.1.0",
147+ "arraybuffer-types": "3.0.2",
148+ "arrays": "7.3.0",
149+ "arrays-extra": "0.6.1",
150+ "arrays-zipper": "2.0.1",
151+ "ask": "1.0.0",
152+ "assert": "6.0.0",
153+ "assert-multiple": "0.4.0",
154+ "avar": "5.0.1",
155+ "b64": "0.0.8",
156+ "barbies": "1.0.1",
157+ "barlow-lens": "0.9.0",
158+ "bifunctors": "6.0.0",
159+ "bigints": "7.0.1",
160+ "bolson": "0.3.9",
161+ "bookhound": "0.1.7",
162+ "bower-json": "3.0.0",
163+ "call-by-name": "4.0.1",
164+ "canvas": "6.0.0",
165+ "canvas-action": "9.0.0",
166+ "cartesian": "1.0.6",
167+ "catenable-lists": "7.0.0",
168+ "cbor-stream": "1.3.0",
169+ "chameleon": "1.0.0",
170+ "chameleon-halogen": "1.0.3",
171+ "chameleon-react-basic": "1.1.0",
172+ "chameleon-styled": "2.5.0",
173+ "chameleon-transformers": "1.0.0",
174+ "channel": "1.0.0",
175+ "checked-exceptions": "3.1.1",
176+ "choku": "1.0.2",
177+ "classless": "0.1.1",
178+ "classless-arbitrary": "0.1.1",
179+ "classless-decode-json": "0.1.1",
180+ "classless-encode-json": "0.1.3",
181+ "classnames": "2.0.0",
182+ "codec": "6.1.0",
183+ "codec-argonaut": "10.0.0",
184+ "codec-json": "2.0.0",
185+ "colors": "7.0.1",
186+ "concur-core": "0.5.0",
187+ "concur-react": "0.5.0",
188+ "concurrent-queues": "3.0.0",
189+ "console": "6.1.0",
190+ "const": "6.0.0",
191+ "contravariant": "6.0.0",
192+ "control": "6.0.0",
193+ "convertable-options": "1.0.0",
194+ "coroutines": "7.0.0",
195+ "css": "6.0.0",
196+ "css-class-name-extractor": "0.0.4",
197+ "css-frameworks": "1.0.1",
198+ "csv-stream": "2.3.0",
199+ "data-mvc": "0.0.2",
200+ "datetime": "6.1.0",
201+ "datetime-parsing": "0.2.0",
202+ "debounce": "0.1.0",
203+ "debug": "6.0.2",
204+ "decimals": "7.1.0",
205+ "default-values": "1.0.1",
206+ "deku": "0.9.23",
207+ "deno": "0.0.5",
208+ "dissect": "1.0.0",
209+ "distributive": "6.0.0",
210+ "dodo-printer": "2.2.3",
211+ "dom-filereader": "7.0.0",
212+ "dom-indexed": "12.0.0",
213+ "dom-simple": "0.4.0",
214+ "dotenv": "4.0.3",
215+ "droplet": "0.6.0",
216+ "dts": "1.0.0",
217+ "dual-numbers": "1.0.3",
218+ "dynamic-buffer": "3.0.1",
219+ "echarts-simple": "0.0.1",
220+ "effect": "4.0.0",
221+ "either": "6.1.0",
222+ "elmish": "0.13.0",
223+ "elmish-enzyme": "0.1.1",
224+ "elmish-hooks": "0.10.3",
225+ "elmish-html": "0.9.0",
226+ "elmish-testing-library": "0.3.2",
227+ "email-validate": "7.0.0",
228+ "encoding": "0.0.9",
229+ "enums": "6.0.1",
230+ "env-names": "0.4.0",
231+ "error": "2.0.0",
232+ "eta-conversion": "0.3.2",
233+ "exceptions": "6.1.0",
234+ "exists": "6.0.0",
235+ "exitcodes": "4.0.0",
236+ "expect-inferred": "3.0.0",
237+ "ezfetch": "1.1.0",
238+ "fahrtwind": "2.0.0",
239+ "fallback": "0.1.0",
240+ "fast-vect": "1.2.0",
241+ "fetch": "4.1.0",
242+ "fetch-argonaut": "1.0.1",
243+ "fetch-core": "5.1.0",
244+ "fetch-yoga-json": "1.1.0",
245+ "ffi-simple": "0.5.1",
246+ "fft-js": "0.1.0",
247+ "filterable": "5.0.0",
248+ "fix-functor": "0.1.0",
249+ "fixed-points": "7.0.0",
250+ "fixed-precision": "5.0.0",
251+ "flame": "1.3.0",
252+ "float32": "2.0.0",
253+ "fmt": "0.2.1",
254+ "foldable-traversable": "6.0.0",
255+ "foldable-traversable-extra": "0.0.6",
256+ "foreign": "7.0.0",
257+ "foreign-object": "4.1.0",
258+ "foreign-readwrite": "3.4.0",
259+ "forgetmenot": "0.1.0",
260+ "fork": "6.0.0",
261+ "form-urlencoded": "7.0.0",
262+ "formatters": "7.0.0",
263+ "framer-motion": "1.0.1",
264+ "free": "7.1.0",
265+ "freeap": "7.0.0",
266+ "freer-free": "0.0.1",
267+ "freet": "7.0.0",
268+ "functions": "6.0.0",
269+ "functor1": "3.0.0",
270+ "functors": "5.0.0",
271+ "fuzzy": "0.4.0",
272+ "gen": "4.0.0",
273+ "generate-values": "1.0.1",
274+ "generic-router": "0.0.1",
275+ "geojson": "0.0.5",
276+ "geometria": "2.2.0",
277+ "gojs": "0.1.1",
278+ "grain": "3.0.0",
279+ "grain-router": "3.0.0",
280+ "grain-virtualized": "3.0.0",
281+ "graphs": "8.1.0",
282+ "group": "4.1.1",
283+ "halogen": "7.0.0",
284+ "halogen-bootstrap5": "5.3.2",
285+ "halogen-canvas": "1.0.0",
286+ "halogen-css": "10.0.0",
287+ "halogen-echarts-simple": "0.0.4",
288+ "halogen-formless": "4.0.3",
289+ "halogen-helix": "1.0.1",
290+ "halogen-hooks": "0.6.3",
291+ "halogen-hooks-extra": "0.9.0",
292+ "halogen-infinite-scroll": "1.1.0",
293+ "halogen-store": "0.5.4",
294+ "halogen-storybook": "2.0.0",
295+ "halogen-subscriptions": "2.0.0",
296+ "halogen-svg-elems": "8.0.0",
297+ "halogen-typewriter": "1.0.4",
298+ "halogen-vdom": "8.0.0",
299+ "halogen-vdom-string-renderer": "0.5.0",
300+ "halogen-xterm": "2.0.0",
301+ "heckin": "2.0.1",
302+ "heterogeneous": "0.6.0",
303+ "homogeneous": "0.4.0",
304+ "http-methods": "6.0.0",
305+ "httpurple": "4.0.0",
306+ "huffman": "0.4.0",
307+ "humdrum": "0.0.1",
308+ "hyrule": "2.3.8",
309+ "identity": "6.0.0",
310+ "identy": "4.0.1",
311+ "indexed-db": "1.0.0",
312+ "indexed-monad": "3.0.0",
313+ "int64": "3.0.0",
314+ "integers": "6.0.0",
315+ "interpolate": "5.0.2",
316+ "intersection-observer": "1.0.1",
317+ "invariant": "6.0.0",
318+ "jarilo": "1.0.1",
319+ "jelly": "0.10.0",
320+ "jelly-router": "0.3.0",
321+ "jelly-signal": "0.4.0",
322+ "jest": "1.0.0",
323+ "js-abort-controller": "1.0.0",
324+ "js-bigints": "2.2.1",
325+ "js-date": "8.0.0",
326+ "js-fetch": "0.2.1",
327+ "js-fileio": "3.0.0",
328+ "js-intl": "1.1.4",
329+ "js-iterators": "0.1.1",
330+ "js-maps": "0.1.2",
331+ "js-promise": "1.0.0",
332+ "js-promise-aff": "1.0.0",
333+ "js-timers": "6.1.0",
334+ "js-uri": "3.1.0",
335+ "jsdom": "1.0.0",
336+ "json": "1.1.0",
337+ "json-codecs": "5.0.0",
338+ "justifill": "0.5.0",
339+ "jwt": "0.0.9",
340+ "labeled-data": "0.2.0",
341+ "language-cst-parser": "0.14.1",
342+ "lazy": "6.0.0",
343+ "lazy-joe": "1.0.0",
344+ "lcg": "4.0.0",
345+ "leibniz": "5.0.0",
346+ "leveldb": "1.0.1",
347+ "liminal": "1.0.1",
348+ "linalg": "6.0.0",
349+ "lists": "7.0.0",
350+ "literals": "1.0.2",
351+ "logging": "3.0.0",
352+ "logging-journald": "0.4.0",
353+ "lumi-components": "18.0.0",
354+ "machines": "7.0.0",
355+ "maps-eager": "0.5.0",
356+ "marionette": "1.0.0",
357+ "marionette-react-basic-hooks": "0.1.1",
358+ "marked": "0.1.0",
359+ "matrices": "5.0.1",
360+ "matryoshka": "1.0.0",
361+ "maybe": "6.0.0",
362+ "media-types": "6.0.0",
363+ "meowclient": "1.0.0",
364+ "midi": "4.0.0",
365+ "milkis": "9.0.0",
366+ "minibench": "4.0.1",
367+ "mmorph": "7.0.0",
368+ "monad-control": "5.0.0",
369+ "monad-logger": "1.3.1",
370+ "monad-loops": "0.5.0",
371+ "monad-unlift": "1.0.1",
372+ "monoid-extras": "0.0.1",
373+ "monoidal": "0.16.0",
374+ "morello": "0.4.0",
375+ "mote": "3.0.0",
376+ "motsunabe": "2.0.0",
377+ "mvc": "0.0.1",
378+ "mysql": "6.0.1",
379+ "n3": "0.1.0",
380+ "nano-id": "1.1.0",
381+ "nanoid": "0.1.0",
382+ "naturals": "3.0.0",
383+ "nested-functor": "0.2.1",
384+ "newtype": "5.0.0",
385+ "nextjs": "0.1.1",
386+ "nextui": "0.2.0",
387+ "node-buffer": "9.0.0",
388+ "node-child-process": "11.1.0",
389+ "node-event-emitter": "3.0.0",
390+ "node-execa": "5.0.0",
391+ "node-fs": "9.2.0",
392+ "node-glob-basic": "2.0.0",
393+ "node-http": "9.1.0",
394+ "node-http2": "1.1.1",
395+ "node-human-signals": "1.0.0",
396+ "node-net": "5.1.0",
397+ "node-os": "5.1.0",
398+ "node-path": "5.0.1",
399+ "node-process": "11.2.0",
400+ "node-readline": "8.1.1",
401+ "node-sqlite3": "8.0.0",
402+ "node-stream-pipes": "2.1.6",
403+ "node-streams": "9.0.1",
404+ "node-tls": "0.3.1",
405+ "node-url": "7.0.1",
406+ "node-workerbees": "0.3.1",
407+ "node-zlib": "0.4.0",
408+ "nonempty": "7.0.0",
409+ "now": "6.0.0",
410+ "npm-package-json": "2.0.0",
411+ "nullable": "6.0.0",
412+ "numberfield": "0.2.2",
413+ "numbers": "9.0.1",
414+ "oak": "3.1.1",
415+ "oak-debug": "1.2.2",
416+ "object-maps": "0.3.0",
417+ "ocarina": "1.5.4",
418+ "oooooooooorrrrrrrmm-lib": "0.0.1",
419+ "open-colors-scales-and-schemes": "1.0.0",
420+ "open-folds": "6.4.0",
421+ "open-foreign-generic": "11.0.3",
422+ "open-memoize": "6.2.0",
423+ "open-mkdirp-aff": "1.2.0",
424+ "open-pairing": "6.2.0",
425+ "open-smolder": "12.0.2",
426+ "options": "7.0.0",
427+ "optparse": "5.0.1",
428+ "ordered-collections": "3.2.0",
429+ "ordered-set": "0.4.0",
430+ "orders": "6.0.0",
431+ "owoify": "1.2.0",
432+ "pairs": "9.0.1",
433+ "parallel": "7.0.0",
434+ "parsing": "10.2.0",
435+ "parsing-dataview": "3.2.4",
436+ "partial": "4.0.0",
437+ "pathy": "9.0.0",
438+ "pha": "0.13.0",
439+ "phaser": "0.7.0",
440+ "phylio": "1.1.2",
441+ "pipes": "8.0.0",
442+ "pirates-charm": "0.0.1",
443+ "pmock": "0.9.0",
444+ "point-free": "1.0.0",
445+ "pointed-list": "0.5.1",
446+ "polymorphic-vectors": "4.0.0",
447+ "posix-types": "6.0.0",
448+ "postgresql": "2.0.20",
449+ "precise": "6.0.0",
450+ "precise-datetime": "7.0.0",
451+ "prelude": "6.0.2",
452+ "prettier-printer": "3.0.0",
453+ "printf": "0.1.0",
454+ "priority-queue": "0.1.2",
455+ "profunctor": "6.0.1",
456+ "profunctor-lenses": "8.0.0",
457+ "protobuf": "4.4.0",
458+ "psa-utils": "8.0.0",
459+ "psci-support": "6.0.0",
460+ "punycode": "1.0.0",
461+ "qualified-do": "2.2.0",
462+ "quantities": "12.2.0",
463+ "quickcheck": "8.0.1",
464+ "quickcheck-combinators": "0.1.3",
465+ "quickcheck-laws": "7.0.0",
466+ "quickcheck-utf8": "0.0.0",
467+ "random": "6.0.0",
468+ "rationals": "6.0.0",
469+ "rdf": "0.1.0",
470+ "react": "11.0.0",
471+ "react-aria": "0.2.0",
472+ "react-basic": "17.0.0",
473+ "react-basic-classic": "3.0.0",
474+ "react-basic-dnd": "10.1.0",
475+ "react-basic-dom": "7.0.0",
476+ "react-basic-dom-beta": "0.1.1",
477+ "react-basic-emotion": "7.1.0",
478+ "react-basic-hooks": "8.2.0",
479+ "react-basic-storybook": "2.0.0",
480+ "react-dom": "8.0.0",
481+ "react-halo": "3.0.0",
482+ "react-icons": "1.1.5",
483+ "react-markdown": "0.1.0",
484+ "react-testing-library": "4.0.1",
485+ "react-virtuoso": "1.0.0",
486+ "reactix": "0.6.1",
487+ "read": "1.0.1",
488+ "recharts": "1.1.0",
489+ "record": "4.0.0",
490+ "record-extra": "5.0.1",
491+ "record-ptional-fields": "0.1.2",
492+ "record-studio": "1.0.4",
493+ "refs": "6.0.0",
494+ "remotedata": "5.0.1",
495+ "repr": "0.5.0",
496+ "resize-observer": "1.0.0",
497+ "resource": "2.0.1",
498+ "resourcet": "1.0.0",
499+ "result": "1.0.3",
500+ "return": "0.2.0",
501+ "ring-modules": "5.0.1",
502+ "rito": "0.3.4",
503+ "roman": "0.4.0",
504+ "rough-notation": "1.0.2",
505+ "routing": "11.0.0",
506+ "routing-duplex": "0.7.0",
507+ "run": "5.0.0",
508+ "safe-coerce": "2.0.0",
509+ "safely": "4.0.1",
510+ "school-of-music": "1.3.0",
511+ "selection-foldable": "0.2.0",
512+ "selective-functors": "1.0.1",
513+ "semirings": "7.0.0",
514+ "shuffle": "1.1.0",
515+ "signal": "13.0.0",
516+ "simple-emitter": "3.0.1",
517+ "simple-i18n": "2.0.1",
518+ "simple-json": "9.0.0",
519+ "simple-json-generics": "0.2.1",
520+ "simple-ulid": "3.0.0",
521+ "sized-matrices": "1.0.0",
522+ "sized-vectors": "5.0.2",
523+ "slug": "3.1.0",
524+ "small-ffi": "4.0.1",
525+ "soundfonts": "4.1.0",
526+ "sparse-matrices": "2.0.1",
527+ "sparse-polynomials": "3.0.1",
528+ "spec": "8.1.1",
529+ "spec-discovery": "8.4.0",
530+ "spec-mocha": "5.1.1",
531+ "spec-node": "0.0.3",
532+ "spec-quickcheck": "5.0.2",
533+ "spec-reporter-xunit": "0.7.1",
534+ "splitmix": "2.1.0",
535+ "ssrs": "1.0.0",
536+ "st": "6.2.0",
537+ "statistics": "0.3.2",
538+ "strictlypositiveint": "1.0.1",
539+ "string-parsers": "8.0.0",
540+ "strings": "6.0.1",
541+ "strings-extra": "4.0.0",
542+ "stringutils": "0.0.12",
543+ "substitute": "0.2.3",
544+ "supply": "0.2.0",
545+ "svg-parser": "3.0.0",
546+ "systemd-journald": "0.3.0",
547+ "tagged": "4.0.2",
548+ "tailrec": "6.1.0",
549+ "tanstack-query": "2.0.0",
550+ "tecton": "0.2.1",
551+ "tecton-halogen": "0.2.0",
552+ "test-unit": "17.0.0",
553+ "thermite": "6.3.1",
554+ "thermite-dom": "0.3.1",
555+ "these": "6.0.0",
556+ "threading": "0.0.3",
557+ "tidy": "0.11.1",
558+ "tidy-codegen": "4.0.1",
559+ "tldr": "0.0.0",
560+ "toestand": "0.9.0",
561+ "transformation-matrix": "1.0.1",
562+ "transformers": "6.1.0",
563+ "tree-rose": "4.0.2",
564+ "ts-bridge": "4.0.0",
565+ "tuples": "7.0.0",
566+ "two-or-more": "1.0.0",
567+ "type-equality": "4.0.1",
568+ "typedenv": "2.0.1",
569+ "typelevel": "6.0.0",
570+ "typelevel-lists": "2.1.0",
571+ "typelevel-peano": "1.0.1",
572+ "typelevel-prelude": "7.0.0",
573+ "typelevel-regex": "0.0.3",
574+ "typelevel-rows": "0.1.0",
575+ "typisch": "0.4.0",
576+ "uint": "7.0.0",
577+ "ulid": "3.0.1",
578+ "uncurried-transformers": "1.1.0",
579+ "undefined": "2.0.0",
580+ "undefined-is-not-a-problem": "1.1.0",
581+ "unfoldable": "6.0.0",
582+ "unicode": "6.0.0",
583+ "unique": "0.6.1",
584+ "unlift": "1.0.1",
585+ "unordered-collections": "3.1.0",
586+ "unsafe-coerce": "6.0.0",
587+ "unsafe-reference": "5.0.0",
588+ "untagged-to-tagged": "0.1.4",
589+ "untagged-union": "1.0.0",
590+ "uri": "9.0.0",
591+ "url-immutable": "1.0.0",
592+ "uuid": "9.0.0",
593+ "uuidv4": "1.0.0",
594+ "validation": "6.0.0",
595+ "variant": "8.0.0",
596+ "variant-encodings": "2.0.0",
597+ "vectorfield": "1.0.1",
598+ "vectors": "2.1.0",
599+ "versions": "7.0.0",
600+ "visx": "0.0.2",
601+ "vitest": "1.0.0",
602+ "web-clipboard": "6.0.0",
603+ "web-cssom": "2.0.0",
604+ "web-cssom-view": "0.1.0",
605+ "web-dom": "6.0.0",
606+ "web-dom-parser": "8.0.0",
607+ "web-dom-xpath": "3.0.0",
608+ "web-encoding": "3.0.0",
609+ "web-events": "4.0.0",
610+ "web-fetch": "4.0.1",
611+ "web-file": "4.0.0",
612+ "web-geometry": "0.1.0",
613+ "web-html": "4.1.0",
614+ "web-pointerevents": "2.0.0",
615+ "web-proletarian": "1.0.0",
616+ "web-promise": "3.2.0",
617+ "web-resize-observer": "2.1.0",
618+ "web-router": "1.0.0",
619+ "web-socket": "4.0.0",
620+ "web-storage": "5.0.0",
621+ "web-streams": "4.0.0",
622+ "web-touchevents": "4.0.0",
623+ "web-uievents": "5.0.0",
624+ "web-url": "2.0.0",
625+ "web-workers": "1.1.0",
626+ "web-xhr": "5.0.1",
627+ "webextension-polyfill": "0.1.0",
628+ "webgpu": "0.0.1",
629+ "which": "2.0.0",
630+ "whine-core": "0.0.28",
631+ "xterm": "1.0.0",
632+ "yoga-fetch": "1.0.1",
633+ "yoga-json": "5.1.0",
634+ "yoga-om": "0.1.0",
635+ "yoga-postgres": "6.0.0",
636+ "yoga-react-dom": "1.0.1",
637+ "yoga-subtlecrypto": "0.1.0",
638+ "yoga-tree": "1.0.0",
639+ "z3": "0.0.2",
640+ "zipperarray": "2.0.0"
641+ }
642+ },
643+ "extra_packages": {}
644+ },
645+ "packages": {
646+ "aff": {
647+ "type": "registry",
648+ "version": "8.0.0",
649+ "integrity": "sha256-9BRIrSdRoYybfiUmBqgKJ66cPqxYHb277bVWQMn/9sg=",
650+ "dependencies": [
651+ "control",
652+ "datetime",
653+ "effect",
654+ "either",
655+ "exceptions",
656+ "functions",
657+ "newtype",
658+ "parallel",
659+ "partial",
660+ "prelude",
661+ "st",
662+ "tailrec",
663+ "transformers",
664+ "unsafe-coerce"
665+ ]
666+ },
667+ "ansi": {
668+ "type": "registry",
669+ "version": "7.0.0",
670+ "integrity": "sha256-tOUaXJFzPSfBVAqLI8hc+Tz2M1rg16cXqyHaK/3SmFg=",
671+ "dependencies": [
672+ "foldable-traversable",
673+ "lists",
674+ "prelude"
675+ ]
676+ },
677+ "argonaut-codecs": {
678+ "type": "registry",
679+ "version": "9.1.0",
680+ "integrity": "sha256-K910SBrmYallESsm8pxJYThs7lig6hxX3M4PW33Cgew=",
681+ "dependencies": [
682+ "argonaut-core",
683+ "arrays",
684+ "bifunctors",
685+ "either",
686+ "foldable-traversable",
687+ "foreign-object",
688+ "identity",
689+ "integers",
690+ "lists",
691+ "maybe",
692+ "nonempty",
693+ "ordered-collections",
694+ "prelude",
695+ "record",
696+ "strings",
697+ "tuples"
698+ ]
699+ },
700+ "argonaut-core": {
701+ "type": "registry",
702+ "version": "7.0.0",
703+ "integrity": "sha256-gYZihtBIKthVuXXoiPphMookSf8M5aHyFYkcIWqlxTM=",
704+ "dependencies": [
705+ "arrays",
706+ "control",
707+ "either",
708+ "foreign-object",
709+ "functions",
710+ "gen",
711+ "maybe",
712+ "nonempty",
713+ "prelude",
714+ "strings",
715+ "tailrec"
716+ ]
717+ },
718+ "arraybuffer-types": {
719+ "type": "registry",
720+ "version": "3.0.2",
721+ "integrity": "sha256-p05cJnSkyeoB7VHzMyc2Eb1RwUaB7Nl0sQSqEGNEUD8=",
722+ "dependencies": []
723+ },
724+ "arrays": {
725+ "type": "registry",
726+ "version": "7.3.0",
727+ "integrity": "sha256-GD4z7LCi9wzi7FCQqbWhvs8paoUK9NO+HwgXZ+KP8Rk=",
728+ "dependencies": [
729+ "bifunctors",
730+ "control",
731+ "foldable-traversable",
732+ "functions",
733+ "maybe",
734+ "nonempty",
735+ "partial",
736+ "prelude",
737+ "safe-coerce",
738+ "st",
739+ "tailrec",
740+ "tuples",
741+ "unfoldable",
742+ "unsafe-coerce"
743+ ]
744+ },
745+ "avar": {
746+ "type": "registry",
747+ "version": "5.0.1",
748+ "integrity": "sha256-8V4SxF4TIWZ9Ik1P4lPzIRUAZeFBe8w5WA2VcCEKsIk=",
749+ "dependencies": [
750+ "aff",
751+ "effect",
752+ "either",
753+ "exceptions",
754+ "functions",
755+ "maybe",
756+ "prelude"
757+ ]
758+ },
759+ "bifunctors": {
760+ "type": "registry",
761+ "version": "6.0.0",
762+ "integrity": "sha256-tXhmlMiyVy6mbUreVZQt/2EGEsPr0T1PjJi+YCG5J7E=",
763+ "dependencies": [
764+ "const",
765+ "either",
766+ "newtype",
767+ "prelude",
768+ "tuples"
769+ ]
770+ },
771+ "catenable-lists": {
772+ "type": "registry",
773+ "version": "7.0.0",
774+ "integrity": "sha256-7+i/MHBLIRh604iCNT4ENWRWE/wuHIotER4kpdX9Ve0=",
775+ "dependencies": [
776+ "control",
777+ "foldable-traversable",
778+ "lists",
779+ "maybe",
780+ "prelude",
781+ "tuples",
782+ "unfoldable"
783+ ]
784+ },
785+ "const": {
786+ "type": "registry",
787+ "version": "6.0.0",
788+ "integrity": "sha256-S+m0lQsxnji0z1XRUmkn+3RFuWJ5CXWuIr1u3i8Bfoc=",
789+ "dependencies": [
790+ "invariant",
791+ "newtype",
792+ "prelude"
793+ ]
794+ },
795+ "contravariant": {
796+ "type": "registry",
797+ "version": "6.0.0",
798+ "integrity": "sha256-nuckEWqL80NaPmR/l9AUyrfycNh18XcvlZV9PAamwqc=",
799+ "dependencies": [
800+ "const",
801+ "either",
802+ "newtype",
803+ "prelude",
804+ "tuples"
805+ ]
806+ },
807+ "control": {
808+ "type": "registry",
809+ "version": "6.0.0",
810+ "integrity": "sha256-0vxyYh5FL+ilxgLo954w1LqCUC0RSIivNNlb9CaNUQg=",
811+ "dependencies": [
812+ "newtype",
813+ "prelude"
814+ ]
815+ },
816+ "datetime": {
817+ "type": "registry",
818+ "version": "6.1.0",
819+ "integrity": "sha256-tbv6eDXy6QOD7YSknxYSbsDF32OC2JrNbSBpzMs7Doc=",
820+ "dependencies": [
821+ "bifunctors",
822+ "control",
823+ "either",
824+ "enums",
825+ "foldable-traversable",
826+ "functions",
827+ "gen",
828+ "integers",
829+ "lists",
830+ "maybe",
831+ "newtype",
832+ "numbers",
833+ "ordered-collections",
834+ "partial",
835+ "prelude",
836+ "tuples"
837+ ]
838+ },
839+ "distributive": {
840+ "type": "registry",
841+ "version": "6.0.0",
842+ "integrity": "sha256-netyJK4B32PDYHD0tF2AenKgo3urzbI770ycM0pArAo=",
843+ "dependencies": [
844+ "identity",
845+ "newtype",
846+ "prelude",
847+ "tuples",
848+ "type-equality"
849+ ]
850+ },
851+ "effect": {
852+ "type": "registry",
853+ "version": "4.0.0",
854+ "integrity": "sha256-DdqU3bncRTjgMVPPRlAuGHVeajSPEcRaRhNuio7if6s=",
855+ "dependencies": [
856+ "prelude"
857+ ]
858+ },
859+ "either": {
860+ "type": "registry",
861+ "version": "6.1.0",
862+ "integrity": "sha256-tBHx3PgtH4GZOApZCDkcM7szRTYJinrUrVGWazQCUUg=",
863+ "dependencies": [
864+ "control",
865+ "invariant",
866+ "maybe",
867+ "prelude"
868+ ]
869+ },
870+ "enums": {
871+ "type": "registry",
872+ "version": "6.0.1",
873+ "integrity": "sha256-sdZOmLX5+5pASGpvVyT0vSD5BBYQjZiayjV5XiPutso=",
874+ "dependencies": [
875+ "control",
876+ "either",
877+ "gen",
878+ "maybe",
879+ "newtype",
880+ "nonempty",
881+ "partial",
882+ "prelude",
883+ "tuples",
884+ "unfoldable"
885+ ]
886+ },
887+ "exceptions": {
888+ "type": "registry",
889+ "version": "6.1.0",
890+ "integrity": "sha256-nRrr+N0wk0TUFOWLR7e1n1oxcXo/X345bQUtoY9lW6A=",
891+ "dependencies": [
892+ "effect",
893+ "either",
894+ "maybe",
895+ "prelude"
896+ ]
897+ },
898+ "exists": {
899+ "type": "registry",
900+ "version": "6.0.0",
901+ "integrity": "sha256-vtLbrWNaI+pzx/2fw2AQnCovoLtcosClIhjO26QKkh8=",
902+ "dependencies": [
903+ "unsafe-coerce"
904+ ]
905+ },
906+ "exitcodes": {
907+ "type": "registry",
908+ "version": "4.0.0",
909+ "integrity": "sha256-xBl4aFSEQ05Owp1ZvO6OxxvLK3LVzU35RSbj79SsePQ=",
910+ "dependencies": [
911+ "enums",
912+ "maybe",
913+ "prelude"
914+ ]
915+ },
916+ "foldable-traversable": {
917+ "type": "registry",
918+ "version": "6.0.0",
919+ "integrity": "sha256-NGGWyCio/xjce6fPP7y3wwg7CheqllID6aJudDxbWhA=",
920+ "dependencies": [
921+ "bifunctors",
922+ "const",
923+ "control",
924+ "either",
925+ "functors",
926+ "identity",
927+ "maybe",
928+ "newtype",
929+ "orders",
930+ "prelude",
931+ "tuples"
932+ ]
933+ },
934+ "foreign": {
935+ "type": "registry",
936+ "version": "7.0.0",
937+ "integrity": "sha256-jiDRMVQfovGsbbA/FzbzYf6iWk9i2b5gNrIjz+gFfsI=",
938+ "dependencies": [
939+ "either",
940+ "functions",
941+ "integers",
942+ "lists",
943+ "maybe",
944+ "prelude",
945+ "strings",
946+ "transformers",
947+ "unsafe-coerce"
948+ ]
949+ },
950+ "foreign-object": {
951+ "type": "registry",
952+ "version": "4.1.0",
953+ "integrity": "sha256-x/Q7r80z/vmHRKvPwhYmHP/DnJciPtsyGfRTMzayKIU=",
954+ "dependencies": [
955+ "arrays",
956+ "foldable-traversable",
957+ "functions",
958+ "gen",
959+ "lists",
960+ "maybe",
961+ "prelude",
962+ "st",
963+ "tailrec",
964+ "tuples",
965+ "typelevel-prelude",
966+ "unfoldable",
967+ "unsafe-coerce"
968+ ]
969+ },
970+ "fork": {
971+ "type": "registry",
972+ "version": "6.0.0",
973+ "integrity": "sha256-0keBVeZZg1eCZEy/En1CohVW829gQUqKtqBNIRa93/A=",
974+ "dependencies": [
975+ "aff",
976+ "prelude",
977+ "transformers"
978+ ]
979+ },
980+ "free": {
981+ "type": "registry",
982+ "version": "7.1.0",
983+ "integrity": "sha256-tUBInfUpRQEw4u94GWcYW7EYdmSdDHSRn88a+C0eltU=",
984+ "dependencies": [
985+ "catenable-lists",
986+ "control",
987+ "distributive",
988+ "either",
989+ "exists",
990+ "foldable-traversable",
991+ "invariant",
992+ "lazy",
993+ "maybe",
994+ "prelude",
995+ "tailrec",
996+ "transformers",
997+ "tuples",
998+ "unsafe-coerce"
999+ ]
1000+ },
1001+ "functions": {
1002+ "type": "registry",
1003+ "version": "6.0.0",
1004+ "integrity": "sha256-0jgtOr+SFO4UScKc40oA/9Vdcf2rLn3h3vZlY0KfqVo=",
1005+ "dependencies": [
1006+ "prelude"
1007+ ]
1008+ },
1009+ "functors": {
1010+ "type": "registry",
1011+ "version": "5.0.0",
1012+ "integrity": "sha256-W1o/4wcp6S3chodYL8uixlXK2mfr1L+SzM1R+whqUco=",
1013+ "dependencies": [
1014+ "bifunctors",
1015+ "const",
1016+ "contravariant",
1017+ "control",
1018+ "distributive",
1019+ "either",
1020+ "invariant",
1021+ "maybe",
1022+ "newtype",
1023+ "prelude",
1024+ "profunctor",
1025+ "tuples",
1026+ "unsafe-coerce"
1027+ ]
1028+ },
1029+ "gen": {
1030+ "type": "registry",
1031+ "version": "4.0.0",
1032+ "integrity": "sha256-kyOateeOtQa07vfTMYeSuCKdelgKE1R65fwKkZ10wsY=",
1033+ "dependencies": [
1034+ "either",
1035+ "foldable-traversable",
1036+ "identity",
1037+ "maybe",
1038+ "newtype",
1039+ "nonempty",
1040+ "prelude",
1041+ "tailrec",
1042+ "tuples",
1043+ "unfoldable"
1044+ ]
1045+ },
1046+ "identity": {
1047+ "type": "registry",
1048+ "version": "6.0.0",
1049+ "integrity": "sha256-RY/iXPpxpqvKHYfJeFVNI1J06kohB9rbtWYuha8t0LE=",
1050+ "dependencies": [
1051+ "control",
1052+ "invariant",
1053+ "newtype",
1054+ "prelude"
1055+ ]
1056+ },
1057+ "integers": {
1058+ "type": "registry",
1059+ "version": "6.0.0",
1060+ "integrity": "sha256-Y8yozC1uHRLcruobEyv5/bMKzE1BoKJ/olHv6o+bgm8=",
1061+ "dependencies": [
1062+ "maybe",
1063+ "numbers",
1064+ "prelude"
1065+ ]
1066+ },
1067+ "invariant": {
1068+ "type": "registry",
1069+ "version": "6.0.0",
1070+ "integrity": "sha256-HyoT1I5qIHRq8RSZji6zZDvqnpVjLw748utrKwZtqsw=",
1071+ "dependencies": [
1072+ "control",
1073+ "prelude"
1074+ ]
1075+ },
1076+ "js-bigints": {
1077+ "type": "registry",
1078+ "version": "2.2.1",
1079+ "integrity": "sha256-r1rE6Olv5b3JrP32lY2uKJ+eBRTsrVnC983K8VWwqe4=",
1080+ "dependencies": [
1081+ "integers",
1082+ "maybe",
1083+ "prelude"
1084+ ]
1085+ },
1086+ "js-date": {
1087+ "type": "registry",
1088+ "version": "8.0.0",
1089+ "integrity": "sha256-DNQrp4xYc8o80jtxo0aOkUeXGi6h0Xidkk2ZQ8Y4l5Y=",
1090+ "dependencies": [
1091+ "datetime",
1092+ "effect",
1093+ "enums",
1094+ "foreign",
1095+ "functions",
1096+ "integers",
1097+ "maybe",
1098+ "prelude"
1099+ ]
1100+ },
1101+ "lazy": {
1102+ "type": "registry",
1103+ "version": "6.0.0",
1104+ "integrity": "sha256-MHRC+1Pc+AjortBp4b/e1e6KpEpsDwaJBNBB7TOL+1I=",
1105+ "dependencies": [
1106+ "control",
1107+ "foldable-traversable",
1108+ "invariant",
1109+ "prelude"
1110+ ]
1111+ },
1112+ "lists": {
1113+ "type": "registry",
1114+ "version": "7.0.0",
1115+ "integrity": "sha256-/mGd7wLoU+wsTcqii7SSUByxsvwvjnu2PjwAD47yYb4=",
1116+ "dependencies": [
1117+ "bifunctors",
1118+ "control",
1119+ "foldable-traversable",
1120+ "lazy",
1121+ "maybe",
1122+ "newtype",
1123+ "nonempty",
1124+ "partial",
1125+ "prelude",
1126+ "tailrec",
1127+ "tuples",
1128+ "unfoldable"
1129+ ]
1130+ },
1131+ "maybe": {
1132+ "type": "registry",
1133+ "version": "6.0.0",
1134+ "integrity": "sha256-8X6XEgtZ5lqfkEuc1hWOofnL6mwhk8gSJTxwvbR/SbY=",
1135+ "dependencies": [
1136+ "control",
1137+ "invariant",
1138+ "newtype",
1139+ "prelude"
1140+ ]
1141+ },
1142+ "mmorph": {
1143+ "type": "registry",
1144+ "version": "7.0.0",
1145+ "integrity": "sha256-Cfltaq+tfYjuSoSBN/b8cSQZbvZTqIRs6ebQewbIkGs=",
1146+ "dependencies": [
1147+ "bifunctors",
1148+ "either",
1149+ "free",
1150+ "functors",
1151+ "identity",
1152+ "maybe",
1153+ "newtype",
1154+ "prelude",
1155+ "transformers",
1156+ "tuples"
1157+ ]
1158+ },
1159+ "newtype": {
1160+ "type": "registry",
1161+ "version": "5.0.0",
1162+ "integrity": "sha256-dt6w0cty4OS+Pjt9fsh3iU6ottqSU83mdAZkaEEvo6c=",
1163+ "dependencies": [
1164+ "prelude",
1165+ "safe-coerce"
1166+ ]
1167+ },
1168+ "node-buffer": {
1169+ "type": "registry",
1170+ "version": "9.0.0",
1171+ "integrity": "sha256-RdQjilmEHqsT4fwpCr8Mavw8KTafYrS3ZM6zeAAVAl8=",
1172+ "dependencies": [
1173+ "arraybuffer-types",
1174+ "effect",
1175+ "functions",
1176+ "maybe",
1177+ "nullable",
1178+ "partial",
1179+ "prelude",
1180+ "st",
1181+ "unsafe-coerce"
1182+ ]
1183+ },
1184+ "node-event-emitter": {
1185+ "type": "registry",
1186+ "version": "3.0.0",
1187+ "integrity": "sha256-wodx71NxJBPXOaawFn01V1ByYB2vT+I3RuV2giOVKMg=",
1188+ "dependencies": [
1189+ "effect",
1190+ "either",
1191+ "functions",
1192+ "maybe",
1193+ "nullable",
1194+ "prelude",
1195+ "unsafe-coerce"
1196+ ]
1197+ },
1198+ "node-fs": {
1199+ "type": "registry",
1200+ "version": "9.2.0",
1201+ "integrity": "sha256-fxioTSm9y47WuYs9F/7nxCh/RVDCl3Kr3Hg779J4SJA=",
1202+ "dependencies": [
1203+ "aff",
1204+ "datetime",
1205+ "effect",
1206+ "either",
1207+ "enums",
1208+ "exceptions",
1209+ "functions",
1210+ "integers",
1211+ "js-date",
1212+ "maybe",
1213+ "node-buffer",
1214+ "node-path",
1215+ "node-streams",
1216+ "nullable",
1217+ "partial",
1218+ "prelude",
1219+ "strings"
1220+ ]
1221+ },
1222+ "node-path": {
1223+ "type": "registry",
1224+ "version": "5.0.1",
1225+ "integrity": "sha256-j7n/SmpVz0FOMJl4XZop3ofJ+MeIPkMNqUEUKHEL6Us=",
1226+ "dependencies": [
1227+ "effect"
1228+ ]
1229+ },
1230+ "node-process": {
1231+ "type": "registry",
1232+ "version": "11.2.0",
1233+ "integrity": "sha256-onzKeNmaeYfN3HSDPqSFTrrP2Yl9tnVsfKKhnf2plxM=",
1234+ "dependencies": [
1235+ "effect",
1236+ "exceptions",
1237+ "foreign",
1238+ "foreign-object",
1239+ "maybe",
1240+ "node-event-emitter",
1241+ "node-streams",
1242+ "nullable",
1243+ "posix-types",
1244+ "prelude",
1245+ "strings"
1246+ ]
1247+ },
1248+ "node-streams": {
1249+ "type": "registry",
1250+ "version": "9.0.1",
1251+ "integrity": "sha256-yuVGm/R/tBr4Nphi+a1a984Z0fkmN9Q5wWtSmbmJTpA=",
1252+ "dependencies": [
1253+ "aff",
1254+ "arrays",
1255+ "effect",
1256+ "either",
1257+ "exceptions",
1258+ "maybe",
1259+ "node-buffer",
1260+ "node-event-emitter",
1261+ "nullable",
1262+ "prelude",
1263+ "refs",
1264+ "st",
1265+ "tailrec",
1266+ "unsafe-coerce"
1267+ ]
1268+ },
1269+ "nonempty": {
1270+ "type": "registry",
1271+ "version": "7.0.0",
1272+ "integrity": "sha256-Ctkq8/+KiGqCE53Y/LvibA/coy7ev9HtRZU+GYS7yfQ=",
1273+ "dependencies": [
1274+ "control",
1275+ "foldable-traversable",
1276+ "maybe",
1277+ "prelude",
1278+ "tuples",
1279+ "unfoldable"
1280+ ]
1281+ },
1282+ "now": {
1283+ "type": "registry",
1284+ "version": "6.0.0",
1285+ "integrity": "sha256-mTyG4s8tps3XIf0jjV/lME2/QlwMzrQly2wqfSSUM3o=",
1286+ "dependencies": [
1287+ "datetime",
1288+ "effect",
1289+ "prelude"
1290+ ]
1291+ },
1292+ "nullable": {
1293+ "type": "registry",
1294+ "version": "6.0.0",
1295+ "integrity": "sha256-CDAZk+L9Sc0GCFTkE8n+qdp4Ys8avvnkU+m2hVALt7M=",
1296+ "dependencies": [
1297+ "functions",
1298+ "maybe",
1299+ "prelude"
1300+ ]
1301+ },
1302+ "numbers": {
1303+ "type": "registry",
1304+ "version": "9.0.1",
1305+ "integrity": "sha256-ZydYckgwRAnRaFC7pu6fADhzdwX+UqHZrfJyet64zls=",
1306+ "dependencies": [
1307+ "functions",
1308+ "maybe",
1309+ "prelude"
1310+ ]
1311+ },
1312+ "open-memoize": {
1313+ "type": "registry",
1314+ "version": "6.2.0",
1315+ "integrity": "sha256-yJLuVYX8FocHIJ+6q7efH/Pj4S+e1Y57DZ5Dn7qf4ww=",
1316+ "dependencies": [
1317+ "either",
1318+ "integers",
1319+ "lazy",
1320+ "lists",
1321+ "maybe",
1322+ "partial",
1323+ "prelude",
1324+ "strings",
1325+ "tuples"
1326+ ]
1327+ },
1328+ "optparse": {
1329+ "type": "registry",
1330+ "version": "5.0.1",
1331+ "integrity": "sha256-2btDjHPRR0uujUQJuZAN9AzvVoXe7yG6IwnY5evERhQ=",
1332+ "dependencies": [
1333+ "arrays",
1334+ "bifunctors",
1335+ "control",
1336+ "effect",
1337+ "either",
1338+ "enums",
1339+ "exists",
1340+ "exitcodes",
1341+ "foldable-traversable",
1342+ "free",
1343+ "integers",
1344+ "lazy",
1345+ "lists",
1346+ "maybe",
1347+ "newtype",
1348+ "node-buffer",
1349+ "node-process",
1350+ "node-streams",
1351+ "nonempty",
1352+ "numbers",
1353+ "open-memoize",
1354+ "partial",
1355+ "prelude",
1356+ "strings",
1357+ "tailrec",
1358+ "transformers",
1359+ "tuples"
1360+ ]
1361+ },
1362+ "ordered-collections": {
1363+ "type": "registry",
1364+ "version": "3.2.0",
1365+ "integrity": "sha256-NaEXc2cz/7lJfxPWEja4XlZbGxuRqJwFKQJjsJf51kQ=",
1366+ "dependencies": [
1367+ "arrays",
1368+ "control",
1369+ "foldable-traversable",
1370+ "functions",
1371+ "gen",
1372+ "lists",
1373+ "maybe",
1374+ "newtype",
1375+ "partial",
1376+ "prelude",
1377+ "safe-coerce",
1378+ "tailrec",
1379+ "tuples",
1380+ "unfoldable"
1381+ ]
1382+ },
1383+ "orders": {
1384+ "type": "registry",
1385+ "version": "6.0.0",
1386+ "integrity": "sha256-nSMxZK7wxyDULkjZqvMyB71mVo6b0AyLLHosDVbv1XM=",
1387+ "dependencies": [
1388+ "newtype",
1389+ "prelude"
1390+ ]
1391+ },
1392+ "parallel": {
1393+ "type": "registry",
1394+ "version": "7.0.0",
1395+ "integrity": "sha256-bAGpVhrFz2IyHkA4MR7+tE/19FZ7dzYBdYPgK5svkqw=",
1396+ "dependencies": [
1397+ "control",
1398+ "effect",
1399+ "either",
1400+ "foldable-traversable",
1401+ "functors",
1402+ "maybe",
1403+ "newtype",
1404+ "prelude",
1405+ "profunctor",
1406+ "refs",
1407+ "transformers"
1408+ ]
1409+ },
1410+ "partial": {
1411+ "type": "registry",
1412+ "version": "4.0.0",
1413+ "integrity": "sha256-mdrlJBAgFMh79hNRW39uv7c+BwnnaOrAMmdh7+VhEhs=",
1414+ "dependencies": []
1415+ },
1416+ "pipes": {
1417+ "type": "registry",
1418+ "version": "8.0.0",
1419+ "integrity": "sha256-dtUNpG8BGVr7pu6mQZyAnUAftUHgNS7f0QH3Kw5UTpQ=",
1420+ "dependencies": [
1421+ "aff",
1422+ "control",
1423+ "effect",
1424+ "either",
1425+ "foldable-traversable",
1426+ "identity",
1427+ "lists",
1428+ "maybe",
1429+ "mmorph",
1430+ "newtype",
1431+ "prelude",
1432+ "tailrec",
1433+ "transformers",
1434+ "tuples"
1435+ ]
1436+ },
1437+ "posix-types": {
1438+ "type": "registry",
1439+ "version": "6.0.0",
1440+ "integrity": "sha256-Je5jG439F/SFO/IvVevZnWVxDIonrehlKuJkefP2lHE=",
1441+ "dependencies": [
1442+ "maybe",
1443+ "newtype",
1444+ "prelude"
1445+ ]
1446+ },
1447+ "prelude": {
1448+ "type": "registry",
1449+ "version": "6.0.2",
1450+ "integrity": "sha256-IqykrDRquGUD/LRSad7y75hZv3bUsGQ4knc8tdez8Qw=",
1451+ "dependencies": []
1452+ },
1453+ "profunctor": {
1454+ "type": "registry",
1455+ "version": "6.0.1",
1456+ "integrity": "sha256-Ow0mJC+PIIRq/a3mzCWY5vxuTgR/e+Ee68+mWeSRnWY=",
1457+ "dependencies": [
1458+ "control",
1459+ "distributive",
1460+ "either",
1461+ "exists",
1462+ "invariant",
1463+ "newtype",
1464+ "prelude",
1465+ "tuples"
1466+ ]
1467+ },
1468+ "record": {
1469+ "type": "registry",
1470+ "version": "4.0.0",
1471+ "integrity": "sha256-WQ8fqp4X1wTA70J4qUcPW4Z7DCwx6e5KJnT/EuTdWSc=",
1472+ "dependencies": [
1473+ "functions",
1474+ "prelude",
1475+ "unsafe-coerce"
1476+ ]
1477+ },
1478+ "refs": {
1479+ "type": "registry",
1480+ "version": "6.0.0",
1481+ "integrity": "sha256-KKD5G9dR2SauuDGULUJsxjqDOEi1Jqm+2Sq5U2mY8YU=",
1482+ "dependencies": [
1483+ "effect",
1484+ "prelude"
1485+ ]
1486+ },
1487+ "safe-coerce": {
1488+ "type": "registry",
1489+ "version": "2.0.0",
1490+ "integrity": "sha256-EJrxtKt5xC7TYjBZrSBO/J7Aw3DmtilYjt4olpAXWVc=",
1491+ "dependencies": [
1492+ "unsafe-coerce"
1493+ ]
1494+ },
1495+ "spec": {
1496+ "type": "registry",
1497+ "version": "8.1.1",
1498+ "integrity": "sha256-b6qjDb7lUJGLV+WEoywLu6BCXC4zGpfbN43mTL+vBeI=",
1499+ "dependencies": [
1500+ "aff",
1501+ "ansi",
1502+ "arrays",
1503+ "avar",
1504+ "bifunctors",
1505+ "control",
1506+ "datetime",
1507+ "effect",
1508+ "either",
1509+ "exceptions",
1510+ "foldable-traversable",
1511+ "fork",
1512+ "identity",
1513+ "integers",
1514+ "lists",
1515+ "maybe",
1516+ "newtype",
1517+ "now",
1518+ "ordered-collections",
1519+ "parallel",
1520+ "pipes",
1521+ "prelude",
1522+ "refs",
1523+ "strings",
1524+ "tailrec",
1525+ "transformers",
1526+ "tuples"
1527+ ]
1528+ },
1529+ "spec-discovery": {
1530+ "type": "registry",
1531+ "version": "8.4.0",
1532+ "integrity": "sha256-aFp8bllT/wrxQu8hMlDchQQY08dQAz+Xdq2hZi5z3yY=",
1533+ "dependencies": [
1534+ "aff",
1535+ "effect",
1536+ "foldable-traversable",
1537+ "prelude",
1538+ "spec",
1539+ "spec-node"
1540+ ]
1541+ },
1542+ "spec-node": {
1543+ "type": "registry",
1544+ "version": "0.0.3",
1545+ "integrity": "sha256-8/9+g0obbamV0YtqzmttbWs8HaWF7CEeW+eDtqzuAAo=",
1546+ "dependencies": [
1547+ "aff",
1548+ "argonaut-codecs",
1549+ "argonaut-core",
1550+ "arrays",
1551+ "control",
1552+ "datetime",
1553+ "effect",
1554+ "either",
1555+ "foldable-traversable",
1556+ "identity",
1557+ "integers",
1558+ "maybe",
1559+ "newtype",
1560+ "node-buffer",
1561+ "node-fs",
1562+ "node-process",
1563+ "now",
1564+ "numbers",
1565+ "optparse",
1566+ "ordered-collections",
1567+ "partial",
1568+ "prelude",
1569+ "spec",
1570+ "strings",
1571+ "tuples"
1572+ ]
1573+ },
1574+ "st": {
1575+ "type": "registry",
1576+ "version": "6.2.0",
1577+ "integrity": "sha256-WI4MEkkwUd4pnwZQ3G8VKWgX5t1RSNJludm5e9boaRo=",
1578+ "dependencies": [
1579+ "effect",
1580+ "partial",
1581+ "prelude",
1582+ "tailrec",
1583+ "unsafe-coerce"
1584+ ]
1585+ },
1586+ "strings": {
1587+ "type": "registry",
1588+ "version": "6.0.1",
1589+ "integrity": "sha256-FNto2hoNW5Da6W6crIk77YXMagBvOGHZE1kO7eZ1vLM=",
1590+ "dependencies": [
1591+ "arrays",
1592+ "control",
1593+ "either",
1594+ "enums",
1595+ "foldable-traversable",
1596+ "gen",
1597+ "integers",
1598+ "maybe",
1599+ "newtype",
1600+ "nonempty",
1601+ "partial",
1602+ "prelude",
1603+ "tailrec",
1604+ "tuples",
1605+ "unfoldable",
1606+ "unsafe-coerce"
1607+ ]
1608+ },
1609+ "strings-extra": {
1610+ "type": "registry",
1611+ "version": "4.0.0",
1612+ "integrity": "sha256-Wlsa9A4hg4PnZYa9WsE0e820xilquVwm33nn067qNIA=",
1613+ "dependencies": [
1614+ "arrays",
1615+ "foldable-traversable",
1616+ "prelude",
1617+ "strings",
1618+ "unicode"
1619+ ]
1620+ },
1621+ "tailrec": {
1622+ "type": "registry",
1623+ "version": "6.1.0",
1624+ "integrity": "sha256-xrorCfP0xV1wubs27idQCHQqdvSUuqmmL/am7Ji1wVU=",
1625+ "dependencies": [
1626+ "bifunctors",
1627+ "effect",
1628+ "either",
1629+ "identity",
1630+ "maybe",
1631+ "partial",
1632+ "prelude",
1633+ "refs"
1634+ ]
1635+ },
1636+ "transformers": {
1637+ "type": "registry",
1638+ "version": "6.1.0",
1639+ "integrity": "sha256-QJmgNT/y7ljPHSsXaW4zxF/982BFiQ90KNL1g/NtEOQ=",
1640+ "dependencies": [
1641+ "control",
1642+ "distributive",
1643+ "effect",
1644+ "either",
1645+ "exceptions",
1646+ "foldable-traversable",
1647+ "identity",
1648+ "lazy",
1649+ "maybe",
1650+ "newtype",
1651+ "prelude",
1652+ "st",
1653+ "tailrec",
1654+ "tuples",
1655+ "unfoldable"
1656+ ]
1657+ },
1658+ "tuples": {
1659+ "type": "registry",
1660+ "version": "7.0.0",
1661+ "integrity": "sha256-BKy7EfK8S1KeTCwyWqyW1wwcpSAQuh3IsczSVgS6fzY=",
1662+ "dependencies": [
1663+ "control",
1664+ "invariant",
1665+ "prelude"
1666+ ]
1667+ },
1668+ "type-equality": {
1669+ "type": "registry",
1670+ "version": "4.0.1",
1671+ "integrity": "sha256-BBqYOSnAKmayRvR5mtZoCf4SlYs2ipatD/+5nQx73aw=",
1672+ "dependencies": []
1673+ },
1674+ "typelevel-prelude": {
1675+ "type": "registry",
1676+ "version": "7.0.0",
1677+ "integrity": "sha256-+pHi14/40mTj/+lmCWqL0T7iXIXD1+NSg/KItyyoB0A=",
1678+ "dependencies": [
1679+ "prelude",
1680+ "type-equality"
1681+ ]
1682+ },
1683+ "unfoldable": {
1684+ "type": "registry",
1685+ "version": "6.0.0",
1686+ "integrity": "sha256-BK/6By1sKp/ztk+9CF3q43SV0QDTLVdsGqFerKHSmbg=",
1687+ "dependencies": [
1688+ "foldable-traversable",
1689+ "maybe",
1690+ "partial",
1691+ "prelude",
1692+ "tuples"
1693+ ]
1694+ },
1695+ "unicode": {
1696+ "type": "registry",
1697+ "version": "6.0.0",
1698+ "integrity": "sha256-5KugCNyYxscmZpnMbssOQA96XimuBN/bjHpdrtd5qaY=",
1699+ "dependencies": [
1700+ "arrays",
1701+ "enums",
1702+ "integers",
1703+ "maybe",
1704+ "partial",
1705+ "prelude",
1706+ "strings",
1707+ "unsafe-coerce"
1708+ ]
1709+ },
1710+ "unsafe-coerce": {
1711+ "type": "registry",
1712+ "version": "6.0.0",
1713+ "integrity": "sha256-0L1QsaY20OILjfU5TV72d3U/tSjhmL9hJ32WMp857Lk=",
1714+ "dependencies": []
1715+ },
1716+ "variant": {
1717+ "type": "registry",
1718+ "version": "8.0.0",
1719+ "integrity": "sha256-Ydrgl8liWEwYQOWW76PdZtg3vxKpoKgsnmFyTLgZkoU=",
1720+ "dependencies": [
1721+ "control",
1722+ "enums",
1723+ "foldable-traversable",
1724+ "lists",
1725+ "maybe",
1726+ "partial",
1727+ "prelude",
1728+ "type-equality",
1729+ "unsafe-coerce"
1730+ ]
1731+ },
1732+ "yoga-tree": {
1733+ "type": "registry",
1734+ "version": "1.0.0",
1735+ "integrity": "sha256-s8rIVEQkRi1VrMc92T9ceXcY0X6r5A4QqT6f7GgmDQI=",
1736+ "dependencies": [
1737+ "arrays",
1738+ "control",
1739+ "foldable-traversable",
1740+ "free",
1741+ "maybe",
1742+ "prelude",
1743+ "tailrec"
1744+ ]
1745+ }
1746+ }
1747+}
spago.yamlnew file+52
@@ -0,0 +1,52 @@
1+package:
2+ name: yoga-json
3+ dependencies:
4+ - arrays: ">=7.3.0 <8.0.0"
5+ - bifunctors: ">=6.0.0 <7.0.0"
6+ - control: ">=6.0.0 <7.0.0"
7+ - datetime: ">=6.1.0 <7.0.0"
8+ - effect: ">=4.0.0 <5.0.0"
9+ - either: ">=6.1.0 <7.0.0"
10+ - exceptions: ">=6.1.0 <7.0.0"
11+ - foldable-traversable: ">=6.0.0 <7.0.0"
12+ - foreign: ">=7.0.0 <8.0.0"
13+ - foreign-object: ">=4.1.0 <5.0.0"
14+ - free: ">=7.1.0 <8.0.0"
15+ - identity: ">=6.0.0 <7.0.0"
16+ - integers: ">=6.0.0 <7.0.0"
17+ - js-bigints: ">=2.2.1 <3.0.0"
18+ - js-date: ">=8.0.0 <9.0.0"
19+ - lists: ">=7.0.0 <8.0.0"
20+ - maybe: ">=6.0.0 <7.0.0"
21+ - newtype: ">=5.0.0 <6.0.0"
22+ - nullable: ">=6.0.0 <7.0.0"
23+ - numbers: ">=9.0.1 <10.0.0"
24+ - ordered-collections: ">=3.2.0 <4.0.0"
25+ - partial: ">=4.0.0 <5.0.0"
26+ - prelude: ">=6.0.2 <7.0.0"
27+ - record: ">=4.0.0 <5.0.0"
28+ - safe-coerce: ">=2.0.0 <3.0.0"
29+ - strings: ">=6.0.1 <7.0.0"
30+ - transformers: ">=6.1.0 <7.0.0"
31+ - tuples: ">=7.0.0 <8.0.0"
32+ - typelevel-prelude: ">=7.0.0 <8.0.0"
33+ - unsafe-coerce: ">=6.0.0 <7.0.0"
34+ - variant: ">=8.0.0 <9.0.0"
35+ - yoga-tree: ">=1.0.0 <2.0.0"
36+ test:
37+ main: Test.Main
38+ dependencies:
39+ - spec
40+ - spec-node
41+ - spec-discovery
42+ - strings-extra
43+
44+ publish:
45+ version: 5.2.2
46+ license: MIT
47+ location:
48+ githubOwner: rowtype-yoga
49+ githubRepo: purescript-yoga-json
50+workspace:
51+ packageSet:
52+ registry: 63.2.1
src/Yoga/JSON.js+16−2
@@ -1,5 +1,19 @@
1+function reviver(key, value) {
2+ if (key === "big") {
3+ return BigInt(value);
4+ }
5+ return value;
6+}
1−export const _parseJSON = JSON.parse;
7+export const _parseJSON = (payload) => JSON.parse(payload, reviver);
2
8
3export const _undefined = undefined;
9export const _undefined = undefined;
4
10
11+function replacer(key, value) {
12+ if (typeof value === "bigint") {
13+ return value.toString();
14+ }
15+ return value;
16+}
17+
5−export const _unsafeStringify = JSON.stringify;
18+export const _unsafeStringify = (data) => JSON.stringify(data, replacer);
19+export const _unsafePrettyStringify = spaces => data => JSON.stringify(data, replacer, spaces);
src/Yoga/JSON.purs+258−58
@@ -4,6 +4,7 @@ module Yoga.JSON
4 , readJSON'
4 , readJSON'
5 , readJSON_
5 , readJSON_
6 , writeJSON
6 , writeJSON
7+ , writePrettyJSON
7 , write
8 , write
8 , read
9 , read
9 , read'
10 , read'
@@ -11,7 +12,6 @@ module Yoga.JSON
11 , parseJSON
12 , parseJSON
12 , undefined
13 , undefined
13 , unsafeStringify
14 , unsafeStringify
14−
15 , class ReadForeign
15 , class ReadForeign
16 , readImpl
16 , readImpl
17 , class ReadForeignFields
17 , class ReadForeignFields
@@ -21,41 +21,58 @@ module Yoga.JSON
21 , class ReadTuple
21 , class ReadTuple
22 , readTupleImpl
22 , readTupleImpl
23 , tupleSize
23 , tupleSize
24−
25 , class WriteForeign
24 , class WriteForeign
26 , writeImpl
25 , writeImpl
27 , class WriteForeignFields
26 , class WriteForeignFields
28 , writeImplFields
27 , writeImplFields
29 , class WriteForeignVariant
28 , class WriteForeignVariant
30 , writeVariantImpl
29 , writeVariantImpl
31−
32 ) where
30 ) where
33
31
34import Prelude
32import Prelude
35
33
36import Control.Alt ((<|>))
34import Control.Alt ((<|>))
37import Control.Apply (lift2)
35import Control.Apply (lift2)
36+import Control.Comonad.Cofree as Cofree
38−import Control.Monad.Except (ExceptT(..), except, runExcept, runExceptT, throwError, withExcept)
37+import Control.Monad.Except (ExceptT(..), except, runExcept, throwError, withExcept)
39import Data.Array as Array
38import Data.Array as Array
40import Data.Array.NonEmpty (NonEmptyArray, fromArray, toArray)
39import Data.Array.NonEmpty (NonEmptyArray, fromArray, toArray)
41import Data.Bifunctor (lmap)
40import Data.Bifunctor (lmap)
41+import Data.DateTime (DateTime)
42+import Data.DateTime.Instant (Instant, instant, unInstant)
42import Data.Either (Either(..), hush, note)
43import Data.Either (Either(..), hush, note)
44+import Data.Foldable (class Foldable, foldl)
45+import Data.FoldableWithIndex (foldrWithIndex)
46+import Data.FunctorWithIndex (mapWithIndex)
43import Data.Identity (Identity(..))
47import Data.Identity (Identity(..))
48+import Data.Int as Int
49+import Data.JSDate (JSDate)
50+import Data.JSDate as JSDate
44−import Data.List.NonEmpty (singleton)
51+import Data.List.NonEmpty (NonEmptyList, singleton)
52+import Data.Map (Map)
53+import Data.Map as Map
45−import Data.Maybe (Maybe(..), fromMaybe, maybe)
54+import Data.Maybe (Maybe(..), fromMaybe, fromMaybe', maybe)
55+import Data.Newtype (class Newtype, unwrap, wrap)
46import Data.Nullable (Nullable, toMaybe, toNullable)
56import Data.Nullable (Nullable, toMaybe, toNullable)
57+import Data.Number as Number
58+import Data.Set (Set)
59+import Data.Set as Set
60+import Data.String.NonEmpty.Internal (NonEmptyString)
61+import Data.String.NonEmpty.Internal as NonEmptyString
47import Data.Symbol (class IsSymbol, reflectSymbol)
62import Data.Symbol (class IsSymbol, reflectSymbol)
63+import Data.Time.Duration (Days, Hours, Milliseconds, Minutes, Seconds)
48−import Data.Traversable (sequence, traverse)
64+import Data.Traversable (traverse)
49−import Data.TraversableWithIndex (traverseWithIndex)
50import Data.Tuple (Tuple(..))
65import Data.Tuple (Tuple(..))
51import Data.Variant (Variant, inj, on)
66import Data.Variant (Variant, inj, on)
52import Effect.Exception (message, try)
67import Effect.Exception (message, try)
53import Effect.Uncurried as EU
68import Effect.Uncurried as EU
54import Effect.Unsafe (unsafePerformEffect)
69import Effect.Unsafe (unsafePerformEffect)
55−import Foreign (F, Foreign, ForeignError(..), MultipleErrors, fail, isNull, isUndefined, readArray, readBoolean, readChar, readInt, readNull, readNumber, readString, tagOf, unsafeFromForeign, unsafeToForeign)
70+import Foreign (F, Foreign, ForeignError(..), MultipleErrors, fail, isNull, isUndefined, readArray, readBoolean, readChar, readInt, readNull, readNumber, readString, tagOf, unsafeFromForeign, unsafeReadTagged, unsafeToForeign)
56−import Foreign.Index (readProp)
71+import Foreign.Index (hasOwnProperty, readProp)
57import Foreign.Object (Object)
72import Foreign.Object (Object)
58import Foreign.Object as Object
73import Foreign.Object as Object
74+import JS.BigInt (BigInt)
75+import JS.BigInt (fromInt, fromNumber, fromString, toString) as BigInt
59import Partial.Unsafe (unsafeCrashWith)
76import Partial.Unsafe (unsafeCrashWith)
60import Prim.Row as Row
77import Prim.Row as Row
61import Prim.RowList (class RowToList, Cons, Nil, RowList)
78import Prim.RowList (class RowToList, Cons, Nil, RowList)
@@ -63,6 +80,9 @@ import Record (get)
63import Record.Builder (Builder)
80import Record.Builder (Builder)
64import Record.Builder as Builder
81import Record.Builder as Builder
65import Type.Prelude (Proxy(..))
82import Type.Prelude (Proxy(..))
83+import Unsafe.Coerce (unsafeCoerce)
84+import Yoga.Tree (Tree)
85+import Yoga.Tree as Tree
66
86
67-- | An alias for the Either result of decoding
87-- | An alias for the Either result of decoding
68type E a = Either MultipleErrors a
88type E a = Either MultipleErrors a
@@ -70,7 +90,7 @@ type E a = Either MultipleErrors a
70-- | Read a JSON string to a type `a` while returning a `MultipleErrors` if the
90-- | Read a JSON string to a type `a` while returning a `MultipleErrors` if the
71-- | parsing failed.
91-- | parsing failed.
72readJSON ∷
92readJSON ∷
73− ∀ a.
93+ ∀ @a.
74 ReadForeign a ⇒
94 ReadForeign a ⇒
75 String →
95 String →
76 E a
96 E a
@@ -78,7 +98,7 @@ readJSON = runExcept <<< (readImpl <=< parseJSON)
78
98
79-- | Read a JSON string to a type `a` using `F a`. Useful with record types.
99-- | Read a JSON string to a type `a` using `F a`. Useful with record types.
80readJSON' ∷
100readJSON' ∷
81− ∀ a.
101+ ∀ @a.
82 ReadForeign a ⇒
102 ReadForeign a ⇒
83 String →
103 String →
84 F a
104 F a
@@ -87,7 +107,7 @@ readJSON' = readImpl <=< parseJSON
87-- | Read a JSON string to a type `a` while returning `Nothing` if the parsing
107-- | Read a JSON string to a type `a` while returning `Nothing` if the parsing
88-- | failed.
108-- | failed.
89readJSON_ ∷
109readJSON_ ∷
90− ∀ a.
110+ ∀ @a.
91 ReadForeign a ⇒
111 ReadForeign a ⇒
92 String →
112 String →
93 Maybe a
113 Maybe a
@@ -96,6 +116,9 @@ readJSON_ = hush <<< readJSON
96-- | JSON.stringify
116-- | JSON.stringify
97foreign import _unsafeStringify ∷ ∀ a. a → String
117foreign import _unsafeStringify ∷ ∀ a. a → String
98
118
119+-- | JSON.stringify with a number of spaces
120+foreign import _unsafePrettyStringify ∷ ∀ a. Int → a → String
121+
99unsafeStringify ∷ ∀ a. a → String
122unsafeStringify ∷ ∀ a. a → String
100unsafeStringify = _unsafeStringify
123unsafeStringify = _unsafeStringify
101
124
@@ -107,6 +130,14 @@ writeJSON ∷
107 String
130 String
108writeJSON = _unsafeStringify <<< writeImpl
131writeJSON = _unsafeStringify <<< writeImpl
109
132
133+writePrettyJSON ∷
134+ ∀ a.
135+ WriteForeign a ⇒
136+ Int →
137+ a →
138+ String
139+writePrettyJSON spaces = _unsafePrettyStringify spaces <<< writeImpl
140+
110write ∷
141write ∷
111 ∀ a.
142 ∀ a.
112 WriteForeign a ⇒
143 WriteForeign a ⇒
@@ -116,14 +147,14 @@ write = writeImpl
116
147
117-- | Read a Foreign value to a type
148-- | Read a Foreign value to a type
118read ∷
149read ∷
119− ∀ a.
150+ ∀ @a.
120 ReadForeign a ⇒
151 ReadForeign a ⇒
121 Foreign →
152 Foreign →
122 E a
153 E a
123read = runExcept <<< readImpl
154read = runExcept <<< readImpl
124
155
125read' ∷
156read' ∷
126− ∀ a.
157+ ∀ @a.
127 ReadForeign a ⇒
158 ReadForeign a ⇒
128 Foreign →
159 Foreign →
129 F a
160 F a
@@ -131,7 +162,7 @@ read' = readImpl
131
162
132-- | Read a Foreign value to a type, as a Maybe of type
163-- | Read a Foreign value to a type, as a Maybe of type
133read_ ∷
164read_ ∷
134− ∀ a.
165+ ∀ @a.
135 ReadForeign a ⇒
166 ReadForeign a ⇒
136 Foreign →
167 Foreign →
137 Maybe a
168 Maybe a
@@ -171,14 +202,45 @@ instance ReadForeign Number where
171instance ReadForeign Int where
202instance ReadForeign Int where
172 readImpl = readInt
203 readImpl = readInt
173
204
205+-- | Attempt to coerce a foreign value to a `BigInt`.
206+readBigInt ∷
207+ ∀ m. Monad m ⇒ Foreign → ExceptT (NonEmptyList ForeignError) m BigInt
208+readBigInt = unsafeReadTagged "BigInt"
209+
210+instance ReadForeign BigInt where
211+ readImpl fValue = tryInt fValue <|> tryNumber fValue <|> readBigInt fValue <|> tryString fValue
212+ where
213+ tryInt f = readInt f <#> BigInt.fromInt
214+ tryNumber f = do
215+ num ← readNumber f
216+ if Number.round num == num then
217+ BigInt.fromNumber num
218+ # note (err $ "Cannot convert Number " <> show num <> " to BigInt")
219+ # except
220+ else
221+ (Left $ err $ "Cannot convert decimal Number " <> show num <> " to BigInt")
222+ # except
223+ tryString f = do
224+ bi ← readString f
225+ BigInt.fromString bi
226+ # note (err $ "Cannot convert String " <> bi <> " to BigInt")
227+ # except
228+ err = pure <<< ForeignError
229+
174instance ReadForeign String where
230instance ReadForeign String where
175 readImpl = readString
231 readImpl = readString
176
232
233+instance ReadForeign NonEmptyString where
234+ readImpl = readString >=>
235+ NonEmptyString.fromString
236+ >>> note (pure $ ForeignError "String must not be empty")
237+ >>> except
238+
177instance ReadForeign Boolean where
239instance ReadForeign Boolean where
178 readImpl = readBoolean
240 readImpl = readBoolean
179
241
180instance ReadForeign a ⇒ ReadForeign (Array a) where
242instance ReadForeign a ⇒ ReadForeign (Array a) where
181− readImpl = traverseWithIndex readAtIdx <=< readArray
243+ readImpl = sequenceCombining <<< mapWithIndex readAtIdx <=< readArray
182
244
183instance ReadForeign a ⇒ ReadForeign (Maybe a) where
245instance ReadForeign a ⇒ ReadForeign (Maybe a) where
184 readImpl = readNullOrUndefined readImpl
246 readImpl = readNullOrUndefined readImpl
@@ -195,9 +257,33 @@ instance ReadForeign a ⇒ ReadForeign (Nullable a) where
195 TypeMismatch inner other → TypeMismatch ("Nullable " <> inner) other
257 TypeMismatch inner other → TypeMismatch ("Nullable " <> inner) other
196 _ → error
258 _ → error
197
259
260+instance (ReadForeign a, ReadForeign b) ⇒ ReadForeign (Either a b) where
261+ readImpl f = do
262+ { type: tpe, value } ∷ { type ∷ String, value ∷ Foreign } ← readImpl f
263+ case tpe of
264+ "left" → Left <$> readImpl value
265+ "right" → Right <$> readImpl value
266+ _ → except $ Left (pure $ ForeignError $ "Invalid Either tag " <> tpe)
267+
198instance ReadForeign a ⇒ ReadForeign (Object.Object a) where
268instance ReadForeign a ⇒ ReadForeign (Object.Object a) where
199− readImpl = sequence <<< Object.mapWithKey (const readImpl) <=< readObject'
269+ readImpl = gatherErrors <<< Object.mapWithKey readProp <=< readObject'
200 where
270 where
271+ gatherErrors ∷ Object (F a) → F (Object a)
272+ gatherErrors = Object.toUnfoldable
273+ >>> Array.foldl fn (Right (Object.empty))
274+ >>> except
275+ where
276+ fn ∷ _ → _ → (Either MultipleErrors (Object a))
277+ fn acc (Tuple k v) = do
278+ case acc, runExcept v of
279+ Left errs, Left errsNew → Left (errs <> errsNew)
280+ Left errs, Right _ → Left errs
281+ Right obj, Right value → Right (Object.insert k value obj)
282+ Right _, Left errs → Left errs
283+
284+ readProp key value = except $ lmap (map (ErrorAtProperty key))
285+ (readImpl value # runExcept)
286+
201 readObject' ∷ Foreign → F (Object Foreign)
287 readObject' ∷ Foreign → F (Object Foreign)
202 readObject' value
288 readObject' value
203 | tagOf value == "Object" = pure $ unsafeFromForeign value
289 | tagOf value == "Object" = pure $ unsafeFromForeign value
@@ -272,37 +358,24 @@ instance
272 , Row.Cons name ty from' to
358 , Row.Cons name ty from' to
273 ) ⇒
359 ) ⇒
274 ReadForeignFields (Cons name ty tail) from to where
360 ReadForeignFields (Cons name ty tail) from to where
275− getFields _ obj = (compose <$> first) `exceptTApply` rest
361+ getFields _ obj = except
362+ case runExcept first, runExcept rest of
363+ Right f, Right r → Right (f <<< r)
364+ Left e1, Left e2 → Left (e1 <> e2)
365+ Right _, Left es → Left es
366+ Left es, Right _ → Left es
276 where
367 where
277− first = do
278− value ← withExcept' (readImpl =<< readProp name obj)
368+ value = enrichErrorWithPropName (readImpl =<< readProp name obj)
279− pure $ Builder.insert nameP value
369+ first = Builder.insert nameP <$> value
280 rest = getFields tailP obj
370 rest = getFields tailP obj
281 nameP = Proxy ∷ Proxy name
371 nameP = Proxy ∷ Proxy name
282 tailP = Proxy ∷ Proxy tail
372 tailP = Proxy ∷ Proxy tail
283 name = reflectSymbol nameP
373 name = reflectSymbol nameP
284− withExcept' = withExcept <<< map $ ErrorAtProperty name
374+ enrichErrorWithPropName = (withExcept <<< map) (ErrorAtProperty name)
285
375
286readAtIdx ∷ ∀ a. ReadForeign a ⇒ Int → Foreign → F a
376readAtIdx ∷ ∀ a. ReadForeign a ⇒ Int → Foreign → F a
287readAtIdx i f = withExcept (map (ErrorAtIndex i)) (readImpl f)
377readAtIdx i f = withExcept (map (ErrorAtIndex i)) (readImpl f)
288
378
289−exceptTApply ∷
290− ∀ a b e m.
291− Semigroup e ⇒
292− Applicative m ⇒
293− ExceptT e m (a → b) →
294− ExceptT e m a →
295− ExceptT e m b
296−exceptTApply fun a = ExceptT $ applyEither
297− <$> runExceptT fun
298− <*> runExceptT a
299−
300−applyEither ∷ ∀ e a b. Semigroup e ⇒ Either e (a → b) → Either e a → Either e b
301−applyEither (Left e) (Right _) = Left e
302−applyEither (Left e1) (Left e2) = Left (e1 <> e2)
303−applyEither (Right _) (Left e) = Left e
304−applyEither (Right fun) (Right a) = Right (fun a)
305−
306instance
379instance
307 ReadForeignFields Nil () () where
380 ReadForeignFields Nil () () where
308 getFields _ _ =
381 getFields _ _ =
@@ -323,11 +396,6 @@ class
323 Foreign →
396 Foreign →
324 F (Variant row)
397 F (Variant row)
325
398
326−instance
327− ReadForeignVariant Nil trash where
328− readVariantImpl _ _ = fail $ ForeignError
329− "Unable to match any variant member."
330−
331instance
399instance
332 ( IsSymbol name
400 ( IsSymbol name
333 , ReadForeign ty
401 , ReadForeign ty
@@ -336,18 +404,20 @@ instance
336 ) ⇒
404 ) ⇒
337 ReadForeignVariant (Cons name ty tail) row where
405 ReadForeignVariant (Cons name ty tail) row where
338 readVariantImpl _ o =
406 readVariantImpl _ o =
339− do
407+ if hasOwnProperty @String @Identity name o then rest <|> ado
340− obj ∷ { type ∷ String, value ∷ Foreign } ← readImpl o
408+ value ∷ ty ← readProp name o >>= readImpl
341− if obj.type == name then do
342− value ∷ ty ← readImpl obj.value
343− pure $ inj namep value
409+ in inj namep value
344− else
410+ else rest
345− (fail <<< ForeignError $ "Did not match variant tag " <> name)
346− <|> readVariantImpl (Proxy ∷ Proxy tail) o
347 where
411 where
412+ rest = readVariantImpl (Proxy ∷ Proxy tail) o
348 namep = Proxy ∷ Proxy name
413 namep = Proxy ∷ Proxy name
349 name = reflectSymbol namep
414 name = reflectSymbol namep
350
415
416+instance
417+ ReadForeignVariant Nil trash where
418+ readVariantImpl _ _ = fail $ ForeignError
419+ "Unable to match any variant member."
420+
351-- -- | A class for writing a value into JSON
421-- -- | A class for writing a value into JSON
352-- -- | need to do this intelligently using Foreign probably, because of null and undefined whatever
422-- -- | need to do this intelligently using Foreign probably, because of null and undefined whatever
353class WriteForeign a where
423class WriteForeign a where
@@ -359,6 +429,9 @@ instance WriteForeign Foreign where
359instance WriteForeign String where
429instance WriteForeign String where
360 writeImpl = unsafeToForeign
430 writeImpl = unsafeToForeign
361
431
432+instance WriteForeign NonEmptyString where
433+ writeImpl = unsafeToForeign
434+
362instance WriteForeign Int where
435instance WriteForeign Int where
363 writeImpl = unsafeToForeign
436 writeImpl = unsafeToForeign
364
437
@@ -368,6 +441,9 @@ instance WriteForeign Char where
368instance WriteForeign Number where
441instance WriteForeign Number where
369 writeImpl = unsafeToForeign
442 writeImpl = unsafeToForeign
370
443
444+instance WriteForeign BigInt where
445+ writeImpl = unsafeToForeign
446+
371instance WriteForeign Boolean where
447instance WriteForeign Boolean where
372 writeImpl = unsafeToForeign
448 writeImpl = unsafeToForeign
373
449
@@ -380,6 +456,11 @@ instance WriteForeign a ⇒ WriteForeign (Maybe a) where
380instance WriteForeign a ⇒ WriteForeign (Nullable a) where
456instance WriteForeign a ⇒ WriteForeign (Nullable a) where
381 writeImpl = maybe (unsafeToForeign $ toNullable Nothing) writeImpl <<< toMaybe
457 writeImpl = maybe (unsafeToForeign $ toNullable Nothing) writeImpl <<< toMaybe
382
458
459+instance (WriteForeign a, WriteForeign b) ⇒ WriteForeign (Either a b) where
460+ writeImpl value = case value of
461+ Left l → writeImpl { type: "left", value: writeImpl l }
462+ Right r → writeImpl { type: "right", value: writeImpl r }
463+
383instance WriteForeign a ⇒ WriteForeign (Object.Object a) where
464instance WriteForeign a ⇒ WriteForeign (Object.Object a) where
384 writeImpl = unsafeToForeign <<< Object.mapWithKey (const writeImpl)
465 writeImpl = unsafeToForeign <<< Object.mapWithKey (const writeImpl)
385
466
@@ -449,7 +530,7 @@ instance
449 WriteForeignVariant Nil () where
530 WriteForeignVariant Nil () where
450 writeVariantImpl _ _ =
531 writeVariantImpl _ _ =
451 -- a PureScript-defined variant cannot reach this path, but a JavaScript FFI one could.
532 -- a PureScript-defined variant cannot reach this path, but a JavaScript FFI one could.
452− unsafeCrashWith "Variant was not able to be writen row WriteForeign."
533+ unsafeCrashWith "Attempted to write empty variant."
453
534
454instance
535instance
455 ( IsSymbol name
536 ( IsSymbol name
@@ -466,10 +547,8 @@ instance
466 variant
547 variant
467 where
548 where
468 namep = Proxy ∷ Proxy name
549 namep = Proxy ∷ Proxy name
469− writeVariant value = unsafeToForeign
470− { type: reflectSymbol namep
550+ name = reflectSymbol namep
471− , value: writeImpl value
551+ writeVariant value = writeImpl $ Object.singleton name (writeImpl value)
472− }
473
552
474instance ReadForeign a ⇒ ReadForeign (NonEmptyArray a) where
553instance ReadForeign a ⇒ ReadForeign (NonEmptyArray a) where
475 readImpl f = do
554 readImpl f = do
@@ -481,3 +560,124 @@ instance ReadForeign a ⇒ ReadForeign (NonEmptyArray a) where
481
560
482instance writeForeignNEArray ∷ WriteForeign a ⇒ WriteForeign (NonEmptyArray a) where
561instance writeForeignNEArray ∷ WriteForeign a ⇒ WriteForeign (NonEmptyArray a) where
483 writeImpl a = writeImpl <<< toArray $ a
562 writeImpl a = writeImpl <<< toArray $ a
563+
564+-- Map instances
565+instance (WriteForeign a) ⇒ WriteForeign (Map String a) where
566+ writeImpl = foldrWithIndex Object.insert Object.empty >>> writeImpl
567+else instance (WriteForeign a) ⇒ WriteForeign (Map Int a) where
568+ writeImpl = foldrWithIndex (show >>> Object.insert) Object.empty >>> writeImpl
569+else instance (WriteForeign a) ⇒ WriteForeign (Map BigInt a) where
570+ writeImpl = foldrWithIndex (BigInt.toString >>> Object.insert) Object.empty >>> writeImpl
571+else instance (Newtype nt key, WriteForeign (Map key value)) ⇒ WriteForeign (Map nt value) where
572+ writeImpl = (unsafeCoerce ∷ (_ → Map key value)) >>> writeImpl
573+
574+instance (ReadForeign a) ⇒ ReadForeign (Map String a) where
575+ readImpl = (readImpl ∷ (_ → _ (Object a))) >>> map (foldrWithIndex Map.insert Map.empty)
576+else instance (ReadForeign a) ⇒ ReadForeign (Map Int a) where
577+ readImpl = (readImpl ∷ (_ → _ (Object a))) >>> map (foldrWithIndex (unsafeStringToInt >>> Map.insert) Map.empty)
578+else instance (ReadForeign a) ⇒ ReadForeign (Map BigInt a) where
579+ readImpl = (readImpl ∷ (_ → _ (Object a))) >>> map (foldrWithIndex (unsafeStringToBigInt >>> Map.insert) Map.empty)
580+else instance (Newtype nt key, ReadForeign (Map key value)) ⇒ ReadForeign (Map nt value) where
581+ readImpl = (readImpl ∷ (_ → _ (Map key value))) >>> map (unsafeCoerce ∷ (Map key value → Map nt value))
582+
583+-- Set instances
584+instance (WriteForeign a) ⇒ WriteForeign (Set a) where
585+ writeImpl set = writeImpl (Set.toUnfoldable set ∷ Array a)
586+
587+instance (Ord a, ReadForeign a) ⇒ ReadForeign (Set a) where
588+ readImpl f = Set.fromFoldable <$> (readImpl f ∷ F (Array a))
589+
590+-- Date instances
591+instance WriteForeign JSDate where
592+ writeImpl = JSDate.toISOString >>> unsafePerformEffect >>> writeImpl
593+
594+instance ReadForeign JSDate where
595+ readImpl = readImpl >>> map (JSDate.parse >>> unsafePerformEffect)
596+
597+instance WriteForeign DateTime where
598+ writeImpl = JSDate.fromDateTime >>> writeImpl
599+
600+instance ReadForeign DateTime where
601+ readImpl = readImpl >=>
602+ JSDate.toDateTime
603+ >>> note (pure $ ForeignError "Invalid date time")
604+ >>> except
605+
606+instance WriteForeign Instant where
607+ writeImpl = unInstant >>> writeImpl
608+
609+instance ReadForeign Instant where
610+ readImpl f = do
611+ millis ← readImpl f
612+ case instant millis of
613+ Nothing → except $ Left (pure $ ForeignError "Invalid instant")
614+ Just ins → pure ins
615+
616+instance WriteForeign Milliseconds where
617+ writeImpl = unwrap >>> writeImpl
618+
619+instance ReadForeign Milliseconds where
620+ readImpl = readImpl >>> map wrap
621+
622+instance WriteForeign Seconds where
623+ writeImpl = unwrap >>> writeImpl
624+
625+instance ReadForeign Seconds where
626+ readImpl = readImpl >>> map wrap
627+
628+instance WriteForeign Minutes where
629+ writeImpl = unwrap >>> writeImpl
630+
631+instance ReadForeign Minutes where
632+ readImpl = readImpl >>> map wrap
633+
634+instance WriteForeign Hours where
635+ writeImpl = unwrap >>> writeImpl
636+
637+instance ReadForeign Hours where
638+ readImpl = readImpl >>> map wrap
639+
640+instance WriteForeign Days where
641+ writeImpl = unwrap >>> writeImpl
642+
643+instance ReadForeign Days where
644+ readImpl = readImpl >>> map wrap
645+
646+unsafeStringToInt ∷ String → Int
647+unsafeStringToInt = Int.fromString >>>
648+ (fromMaybe' \_ → unsafeCrashWith "impossible")
649+
650+unsafeStringToBigInt ∷ String → BigInt
651+unsafeStringToBigInt = BigInt.fromString >>>
652+ (fromMaybe' \_ → unsafeCrashWith "impossible")
653+
654+sequenceCombining ∷
655+ ∀ f a.
656+ Monoid (f a) ⇒
657+ Foldable f ⇒
658+ Applicative f ⇒
659+ f (F a) →
660+ F (f a)
661+sequenceCombining = foldl fn (Right mempty) >>> except
662+ where
663+ fn ∷ _ → _ → (Either MultipleErrors (f a))
664+ fn acc elem = do
665+ case acc, runExcept elem of
666+ Left errs, Left errsNew → Left (errs <> errsNew)
667+ Left errs, Right _ → Left errs
668+ Right values, Right value → Right (values <> pure value)
669+ Right _, Left errs → Left errs
670+
671+instance WriteForeign a ⇒ WriteForeign (Tree a) where
672+ writeImpl ∷ Tree a → Foreign
673+ writeImpl t = write { value: Cofree.head t, children }
674+ where
675+ tail = Cofree.tail t
676+ children = if Array.null tail then Nothing else Just (writeImpl <$> tail)
677+
678+instance ReadForeign a ⇒ ReadForeign (Tree a) where
679+ readImpl f = do
680+ { value, children } ∷ { value ∷ a, children ∷ Maybe (Array Foreign) } ← readImpl f
681+ case children of
682+ Nothing → pure (Tree.leaf value)
683+ Just cs → traverse readImpl cs <#> Tree.mkTree value
src/Yoga/JSON/Derive.pursnew file+13
@@ -0,0 +1,13 @@
1+module Yoga.JSON.Derive where
2+
3+import Prelude
4+
5+import Foreign (Foreign, F)
6+import Safe.Coerce (class Coercible, coerce)
7+import Yoga.JSON (class ReadForeign, class WriteForeign, readImpl, writeImpl)
8+
9+writeVia ∷ ∀ @via a. (Coercible a via) ⇒ WriteForeign via ⇒ a → Foreign
10+writeVia = writeImpl <<< (coerce ∷ _ → via)
11+
12+readVia ∷ ∀ @via a. (Coercible a via) ⇒ ReadForeign via ⇒ Foreign → F a
13+readVia fgn = readImpl fgn # map (coerce ∷ via → _)
src/Yoga/JSON/Error.pursnew file+56
@@ -0,0 +1,56 @@
1+module Yoga.JSON.Error where
2+
3+import Prelude
4+
5+import Foreign (ForeignError(..))
6+import Data.Semigroup.Foldable (intercalateMap)
7+import Data.Bifunctor (lmap)
8+import Yoga.JSON (E)
9+import Data.Either (Either)
10+
11+toJSONPath ∷ ForeignError → String
12+toJSONPath fe = "$" <> path
13+ where
14+ path = go fe
15+ go = case _ of
16+ ForeignError _ → ""
17+ TypeMismatch _ _ → ""
18+ ErrorAtIndex i e → "[" <> show i <> "]" <> go e
19+ ErrorAtProperty _ (TypeMismatch _ "undefined") → ""
20+ ErrorAtProperty prop e → "." <> prop <> go e
21+
22+renderHumanError ∷ ForeignError → String
23+renderHumanError = errorToJSON >>> toHuman
24+ where
25+ toHuman { message, path } = message <> " at " <> path
26+
27+withStringErrors :: forall a. E a -> Either String a
28+withStringErrors = lmap (intercalateMap "\n" renderHumanError)
29+
30+errorToJSON ∷
31+ ForeignError →
32+ { message ∷ String
33+ , path ∷ String
34+ }
35+errorToJSON err = go err
36+ where
37+ path = toJSONPath err
38+ go = case _ of
39+ ForeignError s →
40+ { path
41+ , message: s
42+ }
43+ TypeMismatch exp "Undefined" →
44+ { path
45+ , message: "Must provide a value of type '" <> exp <> "'"
46+ }
47+ TypeMismatch exp "undefined" →
48+ { path
49+ , message: "Must provide a value of type '" <> exp <> "'"
50+ }
51+ TypeMismatch exp act →
52+ { path
53+ , message: "Must provide a value of type '" <> exp <> "' instead of '" <> act <> "'"
54+ }
55+ ErrorAtIndex _ e → go e
56+ ErrorAtProperty _ e → go e
src/Yoga/JSON/Generics.pursnew file+8
@@ -0,0 +1,8 @@
1+module Yoga.JSON.Generics
2+ ( module Exported
3+ ) where
4+
5+import Yoga.JSON.Generics.TaggedSumRep (class ReadGenericTaggedSumRep, class WriteGenericTaggedSumRep, Options, defaultOptions, genericReadForeignTaggedSum, genericReadForeignTaggedSumRep, genericWriteForeignTaggedSum, genericWriteForeignTaggedSumRep) as Exported
6+import Yoga.JSON.Generics.UntaggedSumRep (class ReadGenericUntaggedSumRep, class WriteGenericUntaggedSumRep, genericReadForeignUntaggedSum, genericReadForeignUntaggedSumRep, genericWriteForeignUntaggedSum, genericWriteForeignUntaggedSumRep) as Exported
7+import Yoga.JSON.Generics.EnumSumRep (class GenericEnumSumRep, genericEnumReadForeign, genericEnumWriteForeign, genericReadForeignEnum, genericWriteForeignEnum) as Exported
8+import Yoga.JSON.Generics.UntaggedProductRep (class ReadGenericUntaggedProduct, class WriteGenericUntaggedProduct, Offset, genericReadForeignUntaggedProduct, genericReadForeignUntaggedProductRep, genericWriteForeignUntaggedProduct, genericWriteForeignUntaggedProductRep) as Exported
src/Yoga/JSON/Generics/EnumSumRep.pursnew file+65
@@ -0,0 +1,65 @@
1+module Yoga.JSON.Generics.EnumSumRep where
2+
3+import Prelude
4+
5+import Control.Alt ((<|>))
6+import Data.Generic.Rep as GR
7+import Foreign (Foreign, fail)
8+import Foreign as Foreign
9+import Yoga.JSON as JSON
10+import Type.Prelude (class IsSymbol, Proxy(..), reflectSymbol)
11+
12+type Options =
13+ { toConstructorName ∷ String → String }
14+
15+defaultOptions ∷ Options
16+defaultOptions = { toConstructorName: identity }
17+
18+genericReadForeignEnum ∷
19+ ∀ a rep.
20+ GR.Generic a rep ⇒
21+ GenericEnumSumRep rep ⇒
22+ Options →
23+ Foreign →
24+ Foreign.F a
25+genericReadForeignEnum options f =
26+ GR.to <$> genericEnumReadForeign options f
27+
28+genericWriteForeignEnum ∷
29+ ∀ a rep.
30+ GR.Generic a rep ⇒
31+ GenericEnumSumRep rep ⇒
32+ Options →
33+ a →
34+ Foreign
35+genericWriteForeignEnum options a = genericEnumWriteForeign options (GR.from a)
36+
37+-- | Generic Enum Sum Representations, with constructor names as strings
38+class GenericEnumSumRep rep where
39+ genericEnumReadForeign ∷ Options → Foreign → Foreign.F rep
40+ genericEnumWriteForeign ∷ Options → rep → Foreign
41+
42+instance
43+ ( GenericEnumSumRep a
44+ , GenericEnumSumRep b
45+ ) ⇒
46+ GenericEnumSumRep (GR.Sum a b) where
47+ genericEnumReadForeign options f = GR.Inl <$> genericEnumReadForeign options f
48+ <|> GR.Inr <$> genericEnumReadForeign options f
49+ genericEnumWriteForeign options = case _ of
50+ (GR.Inl a) → genericEnumWriteForeign options a
51+ (GR.Inr a) → genericEnumWriteForeign options a
52+
53+instance
54+ ( IsSymbol name
55+ ) ⇒
56+ GenericEnumSumRep (GR.Constructor name GR.NoArguments) where
57+ genericEnumReadForeign options f = do
58+ s ← JSON.readImpl f
59+ if s == options.toConstructorName name then pure $ GR.Constructor GR.NoArguments
60+ else fail <<< Foreign.ForeignError $
61+ "Enum string " <> s <> " did not match expected string " <> options.toConstructorName name
62+ where
63+ name = reflectSymbol (Proxy ∷ Proxy name)
64+ genericEnumWriteForeign options (GR.Constructor GR.NoArguments) =
65+ JSON.writeImpl $ options.toConstructorName (reflectSymbol (Proxy ∷ Proxy name))
src/Yoga/JSON/Generics/TaggedSumRep.pursnew file+131
@@ -0,0 +1,131 @@
1+module Yoga.JSON.Generics.TaggedSumRep where
2+
3+import Prelude
4+
5+import Control.Alt ((<|>))
6+import Control.Monad.Except (withExcept)
7+import Data.Generic.Rep (NoArguments)
8+import Data.Generic.Rep as GR
9+import Data.Maybe (maybe)
10+import Data.Tuple.Nested ((/\))
11+import Foreign (Foreign, ForeignError(..), fail)
12+import Foreign as Foreign
13+import Foreign.Object (Object)
14+import Foreign.Object as Object
15+import Type.Prelude (class IsSymbol, Proxy(..), reflectSymbol)
16+import Yoga.JSON (undefined)
17+import Yoga.JSON as JSON
18+
19+type Options =
20+ { typeTag ∷ String, valueTag ∷ String, toConstructorName ∷ String → String }
21+
22+defaultOptions ∷ Options
23+defaultOptions = { typeTag: "type", valueTag: "value", toConstructorName: identity }
24+
25+genericReadForeignTaggedSum ∷
26+ ∀ a rep.
27+ GR.Generic a rep ⇒
28+ ReadGenericTaggedSumRep rep ⇒
29+ Options →
30+ Foreign →
31+ Foreign.F a
32+genericReadForeignTaggedSum options f =
33+ GR.to <$> genericReadForeignTaggedSumRep options f
34+
35+-- | Generic Tagged Sum Representations, tagged with a "type" field
36+class ReadGenericTaggedSumRep rep where
37+ genericReadForeignTaggedSumRep ∷ Options → Foreign → Foreign.F rep
38+
39+instance
40+ ( ReadGenericTaggedSumRep a
41+ , ReadGenericTaggedSumRep b
42+ ) ⇒
43+ ReadGenericTaggedSumRep (GR.Sum a b) where
44+ genericReadForeignTaggedSumRep options f = GR.Inl <$> genericReadForeignTaggedSumRep options f
45+ <|> GR.Inr <$> genericReadForeignTaggedSumRep options f
46+
47+else instance
48+ ( IsSymbol name
49+ ) ⇒
50+ ReadGenericTaggedSumRep (GR.Constructor name NoArguments) where
51+ genericReadForeignTaggedSumRep { typeTag, toConstructorName } f = do
52+ o ∷ Object Foreign ← JSON.read' f
53+ typeFgn ← maybe (fail ((ErrorAtProperty typeTag) (ForeignError ("Missing type tag: " <> typeTag)))) pure (Object.lookup typeTag o)
54+ typeStr ← JSON.read' typeFgn
55+ if typeStr == name then withExcept (map $ ErrorAtProperty name) $
56+ pure (GR.Constructor GR.NoArguments)
57+ else
58+ fail $ ForeignError $ "Wrong type tag " <> typeStr <> " where " <> typeTag
59+ <> " was expected."
60+ where
61+ nameP = Proxy ∷ Proxy name
62+ name = toConstructorName (reflectSymbol nameP)
63+else instance
64+ ( ReadGenericTaggedSumRep a
65+ , IsSymbol name
66+ ) ⇒
67+ ReadGenericTaggedSumRep (GR.Constructor name a) where
68+ genericReadForeignTaggedSumRep options@{ typeTag, valueTag, toConstructorName } f = do
69+ o ∷ Object Foreign ← JSON.read' f
70+ typeFgn ← maybe (fail ((ErrorAtProperty typeTag) (ForeignError ("Missing type tag: " <> typeTag)))) pure (Object.lookup typeTag o)
71+ typeStr ← JSON.read' typeFgn
72+ value ← maybe (fail ((ErrorAtProperty valueTag) (ForeignError ("Missing value tag: " <> valueTag)))) pure (Object.lookup valueTag o)
73+ if typeStr == name then withExcept (map $ ErrorAtProperty name) $
74+ GR.Constructor <$> genericReadForeignTaggedSumRep options value
75+ else
76+ fail $ ForeignError $ "Wrong constructor name tag " <> typeStr <> " where " <> name
77+ <> " was expected."
78+ where
79+ nameP = Proxy ∷ Proxy name
80+ name = toConstructorName (reflectSymbol nameP)
81+
82+instance (JSON.ReadForeign a) ⇒ ReadGenericTaggedSumRep (GR.Argument a) where
83+ genericReadForeignTaggedSumRep _ f = GR.Argument <$> JSON.readImpl f
84+
85+-- Write
86+
87+genericWriteForeignTaggedSum ∷
88+ ∀ a rep.
89+ GR.Generic a rep ⇒
90+ WriteGenericTaggedSumRep rep ⇒
91+ Options →
92+ a →
93+ Foreign
94+genericWriteForeignTaggedSum options r =
95+ genericWriteForeignTaggedSumRep options (GR.from r)
96+
97+-- | Generic Tagged Sum Representations, tagged with a "type" field
98+class WriteGenericTaggedSumRep rep where
99+ genericWriteForeignTaggedSumRep ∷ Options → rep → Foreign
100+
101+instance
102+ ( WriteGenericTaggedSumRep a
103+ , WriteGenericTaggedSumRep b
104+ ) ⇒
105+ WriteGenericTaggedSumRep (GR.Sum a b) where
106+ genericWriteForeignTaggedSumRep options = case _ of
107+ GR.Inl a → genericWriteForeignTaggedSumRep options a
108+ GR.Inr b → genericWriteForeignTaggedSumRep options b
109+
110+instance
111+ ( WriteGenericTaggedSumRep a
112+ , IsSymbol name
113+ ) ⇒
114+ WriteGenericTaggedSumRep (GR.Constructor name a) where
115+ genericWriteForeignTaggedSumRep options@{ typeTag, valueTag, toConstructorName } (GR.Constructor a) = do
116+ JSON.write
117+ ( Object.fromFoldable
118+ [ typeTag /\ JSON.write name
119+ , valueTag /\ genericWriteForeignTaggedSumRep options a
120+ ]
121+ )
122+ where
123+ nameP = Proxy ∷ Proxy name
124+ name = toConstructorName (reflectSymbol nameP)
125+
126+instance (JSON.WriteForeign a) ⇒ WriteGenericTaggedSumRep (GR.Argument a) where
127+ genericWriteForeignTaggedSumRep _ (GR.Argument a) = JSON.writeImpl a
128+
129+instance
130+ WriteGenericTaggedSumRep GR.NoArguments where
131+ genericWriteForeignTaggedSumRep _ GR.NoArguments = undefined
src/Yoga/JSON/Generics/UntaggedProductRep.pursnew file+86
@@ -0,0 +1,86 @@
1+module Yoga.JSON.Generics.UntaggedProductRep where
2+
3+import Prelude
4+
5+import Data.Array as Array
6+import Data.Generic.Rep as GR
7+import Foreign (Foreign)
8+import Foreign as Foreign
9+import Foreign.Index (readIndex)
10+import Yoga.JSON as JSON
11+
12+genericReadForeignUntaggedProduct ∷
13+ ∀ a rep.
14+ GR.Generic a rep ⇒
15+ ReadGenericUntaggedProduct rep ⇒
16+ Foreign →
17+ Foreign.F a
18+genericReadForeignUntaggedProduct f = GR.to <$> genericReadForeignUntaggedProductRep 0 f
19+
20+type Offset = Int
21+
22+-- | Generic Untagged Product Representations, as a heterogeneous fixed-length array
23+-- | You should consider using records instead in almost any usage.
24+class ReadGenericUntaggedProduct rep where
25+ genericReadForeignUntaggedProductRep ∷ Offset → Foreign → Foreign.F rep
26+
27+instance
28+ ( ReadGenericUntaggedProduct a
29+ ) ⇒
30+ ReadGenericUntaggedProduct (GR.Constructor name a) where
31+ genericReadForeignUntaggedProductRep i f = GR.Constructor <$> genericReadForeignUntaggedProductRep i
32+ f
33+
34+instance
35+ ( JSON.ReadForeign a
36+ ) ⇒
37+ ReadGenericUntaggedProduct (GR.Argument a) where
38+ genericReadForeignUntaggedProductRep i f = do
39+ x ← JSON.readImpl =<< readIndex i f
40+ pure (GR.Argument x)
41+
42+instance
43+ ( ReadGenericUntaggedProduct a
44+ , ReadGenericUntaggedProduct b
45+ ) ⇒
46+ ReadGenericUntaggedProduct (GR.Product a b) where
47+ genericReadForeignUntaggedProductRep i f =
48+ GR.Product
49+ <$> genericReadForeignUntaggedProductRep i f
50+ <*> genericReadForeignUntaggedProductRep (i + 1) f
51+
52+genericWriteForeignUntaggedProduct ∷
53+ ∀ a rep.
54+ GR.Generic a rep ⇒
55+ WriteGenericUntaggedProduct rep ⇒
56+ a →
57+ Foreign
58+genericWriteForeignUntaggedProduct a =
59+ JSON.write (genericWriteForeignUntaggedProductRep [] (GR.from a))
60+
61+-- | Generic Untagged Product Representations, as a heterogeneous fixed-length array
62+-- | You should consider using records instead in almost any usage.
63+class WriteGenericUntaggedProduct rep where
64+ genericWriteForeignUntaggedProductRep ∷ Array Foreign → rep → Array Foreign
65+
66+instance
67+ ( WriteGenericUntaggedProduct a
68+ ) ⇒
69+ WriteGenericUntaggedProduct (GR.Constructor name a) where
70+ genericWriteForeignUntaggedProductRep arr (GR.Constructor a) =
71+ genericWriteForeignUntaggedProductRep arr a
72+
73+instance
74+ ( JSON.WriteForeign a
75+ ) ⇒
76+ WriteGenericUntaggedProduct (GR.Argument a) where
77+ genericWriteForeignUntaggedProductRep arr (GR.Argument a) =
78+ Array.snoc arr (JSON.write a)
79+
80+instance
81+ ( WriteGenericUntaggedProduct a
82+ , WriteGenericUntaggedProduct b
83+ ) ⇒
84+ WriteGenericUntaggedProduct (GR.Product a b) where
85+ genericWriteForeignUntaggedProductRep arr (GR.Product a b) =
86+ genericWriteForeignUntaggedProductRep (genericWriteForeignUntaggedProductRep arr a) b
src/Yoga/JSON/Generics/UntaggedSumRep.pursnew file+76
@@ -0,0 +1,76 @@
1+module Yoga.JSON.Generics.UntaggedSumRep where
2+
3+import Prelude
4+
5+import Control.Alt ((<|>))
6+import Data.Generic.Rep as GR
7+import Foreign (Foreign)
8+import Foreign as Foreign
9+import Yoga.JSON as JSON
10+
11+genericReadForeignUntaggedSum ∷
12+ ∀ a rep.
13+ GR.Generic a rep ⇒
14+ ReadGenericUntaggedSumRep rep ⇒
15+ Foreign →
16+ Foreign.F a
17+genericReadForeignUntaggedSum f = GR.to <$> genericReadForeignUntaggedSumRep f
18+
19+-- | Generic Untagged Sum Representations
20+-- | Note that because the members are untagged, you should verify your members are not the same type
21+class ReadGenericUntaggedSumRep rep where
22+ genericReadForeignUntaggedSumRep ∷ Foreign → Foreign.F rep
23+
24+instance
25+ ( ReadGenericUntaggedSumRep a
26+ , ReadGenericUntaggedSumRep b
27+ ) ⇒
28+ ReadGenericUntaggedSumRep (GR.Sum a b) where
29+ genericReadForeignUntaggedSumRep f = GR.Inl <$> genericReadForeignUntaggedSumRep f
30+ <|> GR.Inr <$> genericReadForeignUntaggedSumRep f
31+
32+instance
33+ ( ReadGenericUntaggedSumRep a
34+ ) ⇒
35+ ReadGenericUntaggedSumRep (GR.Constructor name a) where
36+ genericReadForeignUntaggedSumRep f = GR.Constructor <$> genericReadForeignUntaggedSumRep f
37+
38+instance
39+ ( JSON.ReadForeign a
40+ ) ⇒
41+ ReadGenericUntaggedSumRep (GR.Argument a) where
42+ genericReadForeignUntaggedSumRep f = GR.Argument <$> JSON.readImpl f
43+
44+genericWriteForeignUntaggedSum ∷
45+ ∀ a rep.
46+ GR.Generic a rep ⇒
47+ WriteGenericUntaggedSumRep rep ⇒
48+ a →
49+ Foreign
50+genericWriteForeignUntaggedSum a = GR.from a # genericWriteForeignUntaggedSumRep
51+
52+-- | Generic Untagged Sum Representations
53+-- | Note that because the members are untagged, you should verify your members are not the same type
54+class WriteGenericUntaggedSumRep rep where
55+ genericWriteForeignUntaggedSumRep ∷ rep → Foreign
56+
57+instance
58+ ( WriteGenericUntaggedSumRep a
59+ , WriteGenericUntaggedSumRep b
60+ ) ⇒
61+ WriteGenericUntaggedSumRep (GR.Sum a b) where
62+ genericWriteForeignUntaggedSumRep = case _ of
63+ GR.Inl a → genericWriteForeignUntaggedSumRep a
64+ GR.Inr a → genericWriteForeignUntaggedSumRep a
65+
66+instance
67+ ( WriteGenericUntaggedSumRep a
68+ ) ⇒
69+ WriteGenericUntaggedSumRep (GR.Constructor name a) where
70+ genericWriteForeignUntaggedSumRep (GR.Constructor a) = genericWriteForeignUntaggedSumRep a
71+
72+instance
73+ ( JSON.WriteForeign a
74+ ) ⇒
75+ WriteGenericUntaggedSumRep (GR.Argument a) where
76+ genericWriteForeignUntaggedSumRep (GR.Argument a) = JSON.write a
src/Yoga/JSON/Variant.pursnew file+197
@@ -0,0 +1,197 @@
1+module Yoga.JSON.Variant where
2+
3+import Prelude
4+
5+import Control.Alt ((<|>))
6+import Data.Newtype (class Newtype)
7+import Data.Symbol (class IsSymbol, reflectSymbol)
8+import Data.Tuple.Nested ((/\))
9+import Data.Variant (Variant, inj, on)
10+import Foreign (F, Foreign, ForeignError(..), fail)
11+import Foreign.Index (readProp)
12+import Foreign.Object as Object
13+import Partial.Unsafe (unsafeCrashWith)
14+import Prim.Row as Row
15+import Prim.RowList (class RowToList, Cons, Nil, RowList)
16+import Type.Proxy (Proxy(..))
17+import Yoga.JSON (class ReadForeign, class WriteForeign, readImpl, writeImpl)
18+
19+newtype TaggedVariant ∷ Symbol → Symbol → Row Type → Type
20+newtype TaggedVariant tt vt v = TaggedVariant (Variant v)
21+
22+instance Newtype (TaggedVariant tt vt v) (Variant v)
23+derive newtype instance (Show (Variant v)) ⇒ Show (TaggedVariant tt vt v)
24+derive newtype instance (Eq (Variant v)) ⇒ Eq (TaggedVariant tt vt v)
25+
26+instance
27+ ( RowToList row rl
28+ , WriteForeignTaggedVariant rl row
29+ , IsSymbol typeTag
30+ , IsSymbol valueTag
31+ ) ⇒
32+ WriteForeign (TaggedVariant typeTag valueTag row) where
33+ writeImpl (TaggedVariant variant) =
34+ writeVariantImpl
35+ (reflectSymbol (Proxy ∷ Proxy typeTag))
36+ (reflectSymbol (Proxy ∷ Proxy valueTag))
37+ (Proxy ∷ Proxy rl)
38+ variant
39+
40+class
41+ WriteForeignTaggedVariant (rl ∷ RowList Type) (row ∷ Row Type)
42+ | rl → row where
43+ writeVariantImpl ∷ ∀ g. String → String → g rl → Variant row → Foreign
44+
45+instance
46+ WriteForeignTaggedVariant Nil () where
47+ writeVariantImpl _ _ _ _ =
48+ -- a PureScript-defined variant cannot reach this path, but a JavaScript FFI one could.
49+ unsafeCrashWith "Attempted to write empty Variant"
50+
51+instance
52+ ( IsSymbol name
53+ , WriteForeign ty
54+ , Row.Cons name ty subRow row
55+ , WriteForeignTaggedVariant tail subRow
56+ ) ⇒
57+ WriteForeignTaggedVariant (Cons name ty tail) row where
58+ writeVariantImpl typeTag valueTag _ variant =
59+ on
60+ namep
61+ writeVariant
62+ (writeVariantImpl typeTag valueTag (Proxy ∷ Proxy tail))
63+ variant
64+ where
65+ namep = Proxy ∷ Proxy name
66+ name = reflectSymbol namep
67+ writeVariant value = writeImpl $
68+ Object.fromFoldable
69+ [ valueTag /\ (writeImpl value)
70+ , typeTag /\ (writeImpl name)
71+ ]
72+
73+instance
74+ ( RowToList variants rl
75+ , ReadForeignTaggedVariant typeTag valueTag rl variants
76+ , IsSymbol typeTag
77+ , IsSymbol valueTag
78+ ) ⇒
79+ ReadForeign (TaggedVariant typeTag valueTag variants) where
80+ readImpl o = readVariantImpl (Proxy ∷ Proxy rl) o
81+
82+class
83+ ReadForeignTaggedVariant typeTag valueTag (xs ∷ RowList Type) (row ∷ Row Type)
84+ | xs → row where
85+ readVariantImpl ∷
86+ Proxy xs →
87+ Foreign →
88+ F (TaggedVariant typeTag valueTag row)
89+
90+instance
91+ ReadForeignTaggedVariant typeTag valueTag Nil trash where
92+ readVariantImpl __ _ = fail $ ForeignError
93+ "Unable to match any variant member."
94+
95+instance
96+ ( IsSymbol name
97+ , IsSymbol typeTag
98+ , IsSymbol valueTag
99+ , ReadForeign ty
100+ , Row.Cons name ty trash row
101+ , ReadForeignTaggedVariant typeTag valueTag tail row
102+ ) ⇒
103+ ReadForeignTaggedVariant typeTag valueTag (Cons name ty tail) row where
104+ readVariantImpl _ o = readVariantImpl (Proxy ∷ Proxy tail) o <|> do
105+ type_ ← readProp typeTag o >>= readImpl
106+ if type_ == name then do
107+ value ∷ ty ← readProp valueTag o >>= readImpl
108+ pure $ TaggedVariant (inj namep value)
109+ else
110+ (fail <<< ForeignError $ "Did not match variant tag " <> name)
111+
112+ where
113+ typeTag = reflectSymbol (Proxy ∷ Proxy typeTag)
114+ valueTag = reflectSymbol (Proxy ∷ Proxy valueTag)
115+ namep = Proxy ∷ Proxy name
116+ name = reflectSymbol namep
117+
118+-- Untagged Variant
119+
120+newtype UntaggedVariant ∷ Row Type → Type
121+newtype UntaggedVariant v = UntaggedVariant (Variant v)
122+
123+instance Newtype (UntaggedVariant v) (Variant v)
124+derive newtype instance (Show (Variant v)) ⇒ Show (UntaggedVariant v)
125+derive newtype instance (Eq (Variant v)) ⇒ Eq (UntaggedVariant v)
126+
127+instance
128+ ( RowToList row rl
129+ , WriteForeignUntaggedVariant rl row
130+ ) ⇒
131+ WriteForeign (UntaggedVariant row) where
132+ writeImpl (UntaggedVariant variant) =
133+ writeUntaggedVariantImpl
134+ (Proxy ∷ Proxy rl)
135+ variant
136+
137+class
138+ WriteForeignUntaggedVariant (rl ∷ RowList Type) (row ∷ Row Type)
139+ | rl → row where
140+ writeUntaggedVariantImpl ∷ ∀ g. g rl → Variant row → Foreign
141+
142+instance
143+ WriteForeignUntaggedVariant Nil () where
144+ writeUntaggedVariantImpl _ _ =
145+ -- a PureScript-defined variant cannot reach this path, but a JavaScript FFI one could.
146+ unsafeCrashWith "Attempted to write empty Variant"
147+
148+instance
149+ ( IsSymbol name
150+ , WriteForeign ty
151+ , Row.Cons name ty subRow row
152+ , WriteForeignUntaggedVariant tail subRow
153+ ) ⇒
154+ WriteForeignUntaggedVariant (Cons name ty tail) row where
155+ writeUntaggedVariantImpl _ variant =
156+ on
157+ namep
158+ writeImpl
159+ (writeUntaggedVariantImpl (Proxy ∷ Proxy tail))
160+ variant
161+ where
162+ namep = Proxy ∷ Proxy name
163+
164+instance
165+ ( RowToList variants rl
166+ , ReadForeignUntaggedVariant rl variants
167+ ) ⇒
168+ ReadForeign (UntaggedVariant variants) where
169+ readImpl o = readUntaggedVariantImpl (Proxy ∷ Proxy rl) o
170+
171+class
172+ ReadForeignUntaggedVariant (xs ∷ RowList Type) (row ∷ Row Type)
173+ | xs → row where
174+ readUntaggedVariantImpl ∷
175+ Proxy xs →
176+ Foreign →
177+ F (UntaggedVariant row)
178+
179+instance
180+ ReadForeignUntaggedVariant Nil trash where
181+ readUntaggedVariantImpl _ _ = fail $ ForeignError
182+ "Unable to match any variant member."
183+
184+instance
185+ ( IsSymbol name
186+ , ReadForeign ty
187+ , Row.Cons name ty trash row
188+ , ReadForeignUntaggedVariant tail row
189+ ) ⇒
190+ ReadForeignUntaggedVariant (Cons name ty tail) row where
191+ readUntaggedVariantImpl _ o =
192+ readUntaggedVariantImpl (Proxy ∷ Proxy tail) o <|> ado
193+ v ← readImpl o
194+ in UntaggedVariant (inj namep v)
195+
196+ where
197+ namep = Proxy ∷ Proxy name
test.dhalldeleted−9
@@ -1,9 +0,0 @@
1−let conf = ./spago.dhall
2−
3−in conf
4− // { sources = conf.sources # [ "test/**/*.purs" ]
5− , dependencies =
6− conf.dependencies
7− # [ "assert"
8− ]
9− }
test/BasicsSpec.pursnew file+257
@@ -0,0 +1,257 @@
1+module Test.BasicsSpec where
2+
3+import Prelude
4+
5+import Data.Array.NonEmpty as NEA
6+import Data.Either (Either(..), isLeft)
7+import Data.Foldable (traverse_)
8+import Data.JSDate as JSDate
9+import Data.List as List
10+import Data.List.Lazy as LazyList
11+import Data.Map as Map
12+import Data.Maybe (Maybe(..), fromJust, fromMaybe')
13+import Data.Newtype (class Newtype, un)
14+import Data.Nullable as Nullable
15+import Data.Set as Set
16+import Data.String.NonEmpty (NonEmptyString, nes)
17+import Data.Time.Duration (Days(..), Hours(..), Milliseconds(..), Minutes(..), Seconds(..))
18+import Data.Tuple (Tuple(..))
19+import Data.Tuple.Nested ((/\))
20+import Data.Variant (Variant, inj)
21+import Effect.Class (liftEffect)
22+import Effect.Now (nowDateTime)
23+import Foreign (ForeignError(..))
24+import Foreign.Object as Object
25+import JS.BigInt (BigInt)
26+import JS.BigInt as BigInt
27+import Partial.Unsafe (unsafeCrashWith, unsafePartial)
28+import Test.Spec (Spec, describe, it)
29+import Test.Spec.Assertions (shouldEqual)
30+import Test.Util (roundtrips)
31+import Type.Proxy (Proxy(..))
32+import Yoga.JSON (class ReadForeign, class WriteForeign, readJSON, writeJSON)
33+import Yoga.JSON.Variant (TaggedVariant(..), UntaggedVariant(..))
34+import Yoga.Tree (Tree, mkLeaf, mkTree, showTree)
35+
36+spec ∷ Spec Unit
37+spec = describe "En- and decoding" do
38+
39+ describe "works on primitive types" do
40+ it "roundtrips Number" $ roundtrips 3.1414
41+ it "roundtrips Int" $ roundtrips (-200)
42+ it "roundtrips Char" $ roundtrips 'a'
43+ it "roundtrips String" $ roundtrips "A"
44+
45+ describe "works on containers types" do
46+ it "roundtrips Maybe" do
47+ roundtrips (Just 3)
48+ -- just roundtrips Nothing doesn't work when rendering the JSON
49+ roundtrips { empty: Nothing ∷ Maybe Int }
50+ it "roundtrips Nullable" $ traverse_ roundtrips [ Nullable.notNull 3, Nullable.null ]
51+ it "roundtrips Either" do
52+ roundtrips ((Left 3) ∷ Either Int Int)
53+ roundtrips ((Right 3) ∷ Either String Int)
54+ writeJSON (Right 3 ∷ Either Int Int) `shouldEqual` """{"value":3,"type":"right"}"""
55+ writeJSON (Left true ∷ Either Boolean Int) `shouldEqual` """{"value":true,"type":"left"}"""
56+
57+ it "roundtrips Tuple" do
58+ roundtrips (Tuple 3 4)
59+ roundtrips ("4" /\ 8 /\ Just 4)
60+ it "roundtrips Array" $ traverse_ roundtrips [ [ "A", "B" ], [] ]
61+ it "roundtrips LazyList" $ traverse_ roundtrips (LazyList.fromFoldable [ [ "A", "B" ], [] ])
62+ it "roundtrips List" $ traverse_ roundtrips (List.fromFoldable [ [ "A", "B" ], [] ])
63+ it "roundtrips NonEmptyArray" $ roundtrips (NEA.cons' "A" [ "B" ])
64+ it "roundtrips Object" $ roundtrips (Object.fromHomogeneous { a: 12, b: 54 })
65+ it "roundtrips String Map" $ roundtrips (Map.fromFoldable [ ("A" /\ 8), ("C" /\ 7) ])
66+ it "roundtrips Int Map" $ roundtrips (Map.fromFoldable [ (4 /\ "B"), (8 /\ "D") ])
67+ it "roundtrips Map with String newtype keys"
68+ $ roundtrips (Map.fromFoldable [ (Stringy "A" /\ "B"), (Stringy "C" /\ "D") ])
69+ it "roundtrips Map with Int newtype keys"
70+ $ roundtrips (Map.fromFoldable [ (Inty 4 /\ "B"), (Inty 8 /\ "D") ])
71+ it "roundtrips Map with BigInt newtype keys"
72+ $ roundtrips (Map.fromFoldable [ (BigInty (BigInt.fromInt 5) /\ "B"), (BigInty big /\ "D") ])
73+ it "roundtrips Set String" $ roundtrips (Set.fromFoldable [ "A", "B", "C" ])
74+ it "roundtrips BigInt" do
75+ let
76+ inputStr = """{ "number":1, "big": 18014398509481982, "mediumBig": 1652955871799, "smallBig": 10 }"""
77+ expected = """{"smallBig":"10","number":1,"mediumBig":"1652955871799","big":"18014398509481982"}"""
78+
79+ parsed ∷ _ ({ number ∷ Int, mediumBig ∷ BigInt, big ∷ BigInt, smallBig ∷ BigInt })
80+ parsed = readJSON inputStr
81+ stringified = parsed <#> writeJSON
82+ stringified `shouldEqual` (Right expected)
83+
84+ it "roundtrips BigInt (2)" do
85+ let
86+ smallBig = BigInt.fromInt 10
87+
88+ expected = { big, smallBig }
89+ json = writeJSON expected
90+
91+ parsed ∷ _ ({ big ∷ BigInt, smallBig ∷ BigInt })
92+ parsed = readJSON json
93+ parsed `shouldEqual` (Right expected)
94+
95+ describe "works with JSDate" do
96+ it "roundtrips" do
97+ now ← JSDate.now # liftEffect
98+ roundtrips now
99+ someDate ← JSDate.parse "2022-01-01:00:00:00Z" # liftEffect
100+ let result = writeJSON someDate
101+ let expected = show "2022-01-01T00:00:00.000Z"
102+ result `shouldEqual` expected
103+
104+ describe "works with DateTime" do
105+ it "roundtrips" do
106+ now ← nowDateTime # liftEffect
107+ roundtrips now
108+ someDate ← JSDate.parse "2022-01-01:00:00:00Z" <#> (JSDate.toDateTime >>> fromMaybe' \_ → unsafeCrashWith "nope") # liftEffect
109+ let result = writeJSON someDate
110+ let expected = show "2022-01-01T00:00:00.000Z"
111+ result `shouldEqual` expected
112+
113+ describe "works with Durations" do
114+ it "roundtrips" do
115+ let millis = Milliseconds 16.67
116+ roundtrips millis
117+ writeJSON millis `shouldEqual` "16.67"
118+
119+ let seconds = Seconds 60.0
120+ roundtrips seconds
121+ writeJSON seconds `shouldEqual` "60"
122+
123+ let minutes = Minutes 10.0
124+ roundtrips minutes
125+ writeJSON minutes `shouldEqual` "10"
126+
127+ let hours = Hours 24.0
128+ roundtrips hours
129+ writeJSON hours `shouldEqual` "24"
130+
131+ let days = Days 365.0
132+ roundtrips days
133+ writeJSON days `shouldEqual` "365"
134+
135+ describe "works on record types" do
136+ it "roundtrips" do
137+ roundtrips { a: 12, b: "54" }
138+ roundtrips { a: 12, b: { c: "54" } }
139+ roundtrips {}
140+
141+ describe "works on newtypes" do
142+ it "roundtrips" do
143+ roundtrips (Stringy "A string is here")
144+
145+ describe "works on variant types" do
146+ it "roundtrips" do
147+ let input = inj (Proxy ∷ _ "a") {} ∷ Variant (a ∷ {}, b ∷ {})
148+ let asJSON = writeJSON input
149+ readJSON asJSON `shouldEqual` Right input
150+
151+ let input2 = inj (Proxy ∷ _ "b") {} ∷ Variant (a ∷ {}, b ∷ {})
152+ let asJSON2 = writeJSON input2
153+ readJSON asJSON2 `shouldEqual` Right input2
154+
155+ roundtrips (inj (Proxy ∷ _ "erwin") "e" ∷ Variant (erwin ∷ String))
156+ roundtrips (inj (Proxy ∷ _ "jackie") 7 ∷ Variant ExampleVariant)
157+
158+ it "does not select an absent optional branch" do
159+ let expected = inj (Proxy ∷ _ "a") 42 ∷ Variant (a ∷ Int, b ∷ Maybe Int)
160+ readJSON """{"a":42}""" `shouldEqual` Right expected
161+
162+ it "accepts an explicitly null optional branch" do
163+ let expected = inj (Proxy ∷ _ "b") Nothing ∷ Variant (a ∷ Int, b ∷ Maybe Int)
164+ readJSON """{"b":null}""" `shouldEqual` Right expected
165+
166+ it "rejects objects without a matching variant key" do
167+ traverse_
168+ (\json → isLeft (readJSON json ∷ _ (Variant (a ∷ {}, b ∷ {}))) `shouldEqual` true)
169+ [ "{}", """{"unknown":{}}""" ]
170+
171+ describe "works on tagged variant types" do
172+ it "roundtrips" do
173+ roundtrips (TaggedVariant (erwin "e") ∷ TaggedVariant "super" "hans" (Erwin ()))
174+ let bareVariant = erwin "e"
175+ let res = writeJSON (TaggedVariant bareVariant ∷ TaggedVariant "type" "value" ExampleVariant)
176+ let expected = """{"value":"e","type":"erwin"}"""
177+ res `shouldEqual` expected
178+ let
179+ parsed ∷ _ (TaggedVariant "type" "value" ExampleVariant)
180+ parsed = readJSON expected
181+ (un TaggedVariant <$> parsed) `shouldEqual` Right bareVariant
182+
183+ describe "works on untagged variant types" do
184+ it "roundtrips" do
185+ roundtrips (UntaggedVariant (erwin "e") ∷ UntaggedVariant (Erwin ()))
186+ let bareVariant = erwin "e"
187+ let res = writeJSON (UntaggedVariant bareVariant ∷ UntaggedVariant ExampleVariant)
188+ let expected = "\"e\""
189+ res `shouldEqual` expected
190+ let
191+ parsed ∷ _ (UntaggedVariant ExampleVariant)
192+ parsed = readJSON expected
193+ (un UntaggedVariant <$> parsed) `shouldEqual` Right bareVariant
194+
195+ describe "works on non empty strings" do
196+ it "roundtrips NonEmptyString" do
197+ roundtrips (nes (Proxy ∷ Proxy "Non-Empty"))
198+ it "fails to decode empty strings" do
199+ let (result ∷ (Either _ NonEmptyString)) = readJSON (show "")
200+ result `shouldEqual` Left (pure $ ForeignError "String must not be empty")
201+
202+ describe "works on trees" do
203+ it "roundtrips" do
204+ let t = mkTree "a" [ mkTree "b" [ mkLeaf "c", mkLeaf "d" ] ]
205+ roundtrips (ShowTree t)
206+
207+ it "encodes as expected" do
208+ let t = mkTree "a" [ mkTree "b" [ mkLeaf "c", mkLeaf "d" ] ]
209+ writeJSON (ShowTree t) `shouldEqual`
210+ """{"value":"a","children":[{"value":"b","children":[{"value":"c"},{"value":"d"}]}]}"""
211+
212+newtype ShowTree = ShowTree (Tree String)
213+
214+instance Show ShowTree where
215+ show (ShowTree t) = showTree t
216+
217+derive newtype instance WriteForeign ShowTree
218+derive newtype instance ReadForeign ShowTree
219+derive newtype instance Eq ShowTree
220+
221+type ExampleVariant = ("erwin" ∷ String, "jackie" ∷ Int)
222+type ExampleTaggedVariant t v = TaggedVariant t v ExampleVariant
223+
224+erwin ∷ ∀ a r. a → Variant (erwin ∷ a | r)
225+erwin = inj (Proxy ∷ Proxy "erwin")
226+
227+type Erwin r = (erwin ∷ String | r)
228+
229+newtype Stringy = Stringy String
230+
231+derive instance Newtype Stringy _
232+derive newtype instance Show Stringy
233+derive newtype instance Eq Stringy
234+derive newtype instance Ord Stringy
235+derive newtype instance WriteForeign Stringy
236+derive newtype instance ReadForeign Stringy
237+
238+newtype Inty = Inty Int
239+
240+derive instance Newtype Inty _
241+derive newtype instance Show Inty
242+derive newtype instance Eq Inty
243+derive newtype instance Ord Inty
244+derive newtype instance WriteForeign Inty
245+derive newtype instance ReadForeign Inty
246+
247+newtype BigInty = BigInty BigInt
248+
249+derive instance Newtype BigInty _
250+derive newtype instance Show BigInty
251+derive newtype instance Eq BigInty
252+derive newtype instance Ord BigInty
253+derive newtype instance WriteForeign BigInty
254+derive newtype instance ReadForeign BigInty
255+
256+big ∷ BigInt
257+big = unsafePartial $ fromJust $ BigInt.fromString "18014398509481982"
test/EnumSumGeneric.pursdeleted−69
@@ -1,69 +0,0 @@
1−module Test.EnumSumGeneric where
2−
3−import Prelude
4−
5−import Control.Alt ((<|>))
6−import Control.Monad.Except (throwError)
7−import Data.Either (Either, isRight)
8−import Data.Generic.Rep (class Generic, Constructor(..), NoArguments(..), Sum(..), to)
9−import Data.Show.Generic (genericShow)
10−import Effect (Effect)
11−import Foreign (Foreign)
12−import Foreign as Foreign
13−import Yoga.JSON as JSON
14−import Test.Assert (assert)
15−import Type.Prelude (class IsSymbol, Proxy(..), reflectSymbol)
16−
17−enumReadForeign ∷
18− ∀ a rep.
19− Generic a rep ⇒
20− EnumReadForeign rep ⇒
21− Foreign →
22− Foreign.F a
23−enumReadForeign f =
24− to <$> enumReadForeignImpl f
25−
26−-- type class for "enums", or nullary sum types
27−class EnumReadForeign rep where
28− enumReadForeignImpl ∷ Foreign → Foreign.F rep
29−
30−instance
31− ( EnumReadForeign a
32− , EnumReadForeign b
33− ) ⇒
34− EnumReadForeign (Sum a b) where
35− enumReadForeignImpl f = Inl <$> enumReadForeignImpl f
36− <|> Inr <$> enumReadForeignImpl f
37−
38−instance
39− ( IsSymbol name
40− ) ⇒
41− EnumReadForeign (Constructor name NoArguments) where
42− enumReadForeignImpl f = do
43− s ← JSON.readImpl f
44− if s == name then pure $ Constructor NoArguments
45− else throwError <<< pure <<< Foreign.ForeignError $
46− "Enum string " <> s <> " did not match expected string " <> name
47− where
48− name = reflectSymbol (Proxy ∷ Proxy name)
49−
50−data Fruit
51− = Abogado
52− | Boat
53− | Candy
54−
55−derive instance Generic Fruit _
56−instance JSON.ReadForeign Fruit where
57− readImpl = enumReadForeign
58−
59−instance Show Fruit where
60− show = genericShow
61−
62−readFruit ∷ String → Either Foreign.MultipleErrors Fruit
63−readFruit = JSON.readJSON
64−
65−main ∷ Effect Unit
66−main = do
67− assert <<< isRight $ readFruit "\"Abogado\""
68− assert <<< isRight $ readFruit "\"Boat\""
69− assert <<< isRight $ readFruit "\"Candy\""
test/ErrorsSpec.pursnew file+84
@@ -0,0 +1,84 @@
1+module Test.ErrorsSpec where
2+
3+import Prelude
4+
5+import Data.Array as Array
6+import Data.Bifunctor (lmap)
7+import Data.Either (Either(..), blush)
8+import Data.Maybe (Maybe(..))
9+import Foreign (ForeignError(..))
10+import Foreign.Object (Object)
11+import Test.Spec (Spec, describe, it)
12+import Test.Spec.Assertions (shouldEqual)
13+import Type.Proxy (Proxy(..))
14+import Yoga.JSON (class ReadForeign, E, readJSON)
15+import Yoga.JSON as JSON
16+import Yoga.JSON.Error (renderHumanError, toJSONPath)
17+
18+spec ∷ Spec Unit
19+spec = describe "Errors" do
20+ describe "are returned at once" do
21+ it "returns multiple errors for object" do
22+ let
23+ res ∷ E (Object Int)
24+ res = JSON.readJSON """{ "something": "no", "else": true }"""
25+ e1 = ErrorAtProperty "something" (TypeMismatch "Int" "String")
26+ e2 = ErrorAtProperty "else" (TypeMismatch "Int" "Boolean")
27+ res `shouldEqual` (Left (pure e1 <> pure e2))
28+
29+ it "returns multiple errors for record" do
30+ let
31+ res ∷ E { a ∷ Int, b ∷ String }
32+ res = JSON.readJSON """{ "b": true }"""
33+ e1 = ErrorAtProperty "a" (TypeMismatch "Int" "Undefined")
34+ e2 = ErrorAtProperty "b" (TypeMismatch "String" "Boolean")
35+ res `shouldEqual` (Left (pure e1 <> pure e2))
36+
37+ it "returns multiple errors for array" do
38+ let
39+ res ∷ E (Array Int)
40+ res = JSON.readJSON """[1,"a",2,true]"""
41+ e1 = ErrorAtIndex 1 (TypeMismatch "Int" "String")
42+ e2 = ErrorAtIndex 3 (TypeMismatch "Int" "Boolean")
43+ res `shouldEqual` (Left (pure e1 <> pure e2))
44+
45+ describe "produces human-friendly errors" do
46+ it "For some object" do
47+ let
48+ res ∷ E (Object Int)
49+ res = JSON.readJSON """{ "something": "no", "else": true }"""
50+ e1 = "Must provide a value of type 'Int' instead of 'String' at $.something"
51+ e2 = "Must provide a value of type 'Int' instead of 'Boolean' at $.else"
52+ (res # lmap (map renderHumanError >>> Array.fromFoldable))
53+ `shouldEqual` (Left [ e1, e2 ])
54+
55+ it "For deeply nested keys" do
56+ let
57+ res ∷ E { a ∷ { b ∷ { c ∷ { d ∷ String } } } }
58+ res = JSON.readJSON """{ "a": { "b": { "c": { }}}}"""
59+ e = "Must provide a value of type 'String' at $.a.b.c.d"
60+ (res # lmap (map renderHumanError >>> Array.fromFoldable))
61+ `shouldEqual` (Left [ e ])
62+
63+ describe "have the correct JSON path" do
64+ it "empty json" do
65+ (getErrorPath (Proxy ∷ _ {}) "") `shouldEqual` Just [ "$" ]
66+ it "nested json json" do
67+ let
68+ xo =
69+ """
70+ { "deeply": { "nested": { "array":
71+ [ { "of": { "values": "hello" } }
72+ , 8
73+ ]
74+ } } }"""
75+ ( getErrorPath (Proxy ∷ _ { deeply ∷ { nested ∷ { array ∷ Array { of ∷ { values ∷ String } } } } })
76+ xo
77+ ) `shouldEqual`
78+ -- [FIXME] I'm not sure about this
79+ Just [ "$.deeply.nested.array[1].of" ]
80+
81+getErrorPath ∷ ∀ a. ReadForeign a ⇒ Proxy a → String → Maybe (Array String)
82+getErrorPath _ x = do
83+ let e = (readJSON x ∷ _ a) # blush
84+ (e <#> map toJSONPath <#> Array.fromFoldable)
test/Generic.pursdeleted−73
@@ -1,73 +0,0 @@
1−module Test.Generic where
2−
3−import Prelude
4−
5−import Control.Alt ((<|>))
6−import Data.Either (Either, isRight)
7−import Data.Generic.Rep as GR
8−import Data.Show.Generic (genericShow)
9−import Effect (Effect)
10−import Foreign (Foreign)
11−import Foreign as Foreign
12−import Yoga.JSON as JSON
13−import Test.Assert (assert)
14−
15−data IntOrBoolean
16− = Int Int
17− | Boolean Boolean
18−
19−instance readForeign ∷ JSON.ReadForeign IntOrBoolean where
20− readImpl f = Int <$> Foreign.readInt f
21− <|> Boolean <$> Foreign.readBoolean f
22−
23−instance showIntOrBoolean ∷ Show IntOrBoolean where
24− show (Int i) = "(Int " <> show i <> ")"
25− show (Boolean i) = "(Boolean " <> show i <> ")"
26−
27−decodeToIntOrBoolean ∷ String → Either Foreign.MultipleErrors IntOrBoolean
28−decodeToIntOrBoolean = JSON.readJSON
29−
30−data IntOrBoolean2
31− = Int2 Int
32− | Boolean2 Boolean
33−
34−derive instance genericIntOrBoolean2 ∷ GR.Generic IntOrBoolean2 _
35−
36−instance showIntOrBoolean2 ∷ Show IntOrBoolean2 where
37− show = genericShow
38−
39−instance readForeignIntOrBoolean2 ∷ JSON.ReadForeign IntOrBoolean2 where
40− readImpl f = GR.to <$> untaggedSumRep f
41−
42−class UntaggedSumRep rep where
43− untaggedSumRep ∷ Foreign → Foreign.F rep
44−
45−instance untaggedSumRepSum ∷
46− ( UntaggedSumRep a
47− , UntaggedSumRep b
48− ) ⇒
49− UntaggedSumRep (GR.Sum a b) where
50− untaggedSumRep f = GR.Inl <$> untaggedSumRep f
51− <|> GR.Inr <$> untaggedSumRep f
52−
53−instance untaggedSumRepConstructor ∷
54− ( UntaggedSumRep a
55− ) ⇒
56− UntaggedSumRep (GR.Constructor name a) where
57− untaggedSumRep f = GR.Constructor <$> untaggedSumRep f
58−
59−instance untaggedSumRepArgument ∷
60− ( JSON.ReadForeign a
61− ) ⇒
62− UntaggedSumRep (GR.Argument a) where
63− untaggedSumRep f = GR.Argument <$> JSON.readImpl f
64−
65−decodeToIntOrBoolean2 ∷ String → Either Foreign.MultipleErrors IntOrBoolean2
66−decodeToIntOrBoolean2 = JSON.readJSON
67−
68−main ∷ Effect Unit
69−main = do
70− assert <<< isRight $ decodeToIntOrBoolean "1" -- (Right (Int 1))
71− assert <<< isRight $ decodeToIntOrBoolean "true" -- (Right (Boolean true))
72− assert <<< isRight $ decodeToIntOrBoolean2 "1" -- (Right (Int2 1))
73− assert <<< isRight $ decodeToIntOrBoolean2 "true" -- (Right (Boolean2 true))
test/GenericsSpec.pursnew file+149
@@ -0,0 +1,149 @@
1+module Test.GenericsSpec where
2+
3+import Prelude
4+
5+import Data.Generic.Rep (class Generic)
6+import Data.Show.Generic (genericShow)
7+import Data.String.Extra (snakeCase)
8+import Test.Spec (Spec, describe, it)
9+import Test.Spec.Assertions (shouldEqual)
10+import Test.Util (roundtrips)
11+import Yoga.JSON (class ReadForeign, class WriteForeign, writeJSON)
12+import Yoga.JSON.Generics (defaultOptions, genericReadForeignEnum, genericReadForeignTaggedSum, genericReadForeignUntaggedProduct, genericReadForeignUntaggedSum, genericWriteForeignEnum, genericWriteForeignTaggedSum, genericWriteForeignUntaggedProduct, genericWriteForeignUntaggedSum)
13+import Yoga.JSON.Generics as GenericTaggedSum
14+import Yoga.JSON.Generics.EnumSumRep as Enum
15+
16+spec ∷ Spec Unit
17+spec = describe "Generics" do
18+
19+ describe "Enum" do
20+ describe "MyEnum = Enum1 | Enum2 | Enum3" do
21+ it "roundtrips" do
22+ roundtrips (Enum1)
23+ roundtrips (Enum3)
24+
25+ describe "works with custom constructor names" do
26+ it "roundtrips" do
27+ roundtrips (SomeOtherEnum2)
28+ writeJSON (SomeThirdEnum3) `shouldEqual` "\"some_third_enum_3\""
29+
30+ describe "Untagged" do
31+
32+ describe "IntOrString = AnInt Int | AString String" do
33+ it "roundtrips" do
34+ roundtrips (AnInt 1)
35+ roundtrips (AString "Abc")
36+ it "serialises without tags" do
37+ writeJSON (AnInt 1) `shouldEqual` "1"
38+ writeJSON (AString "Abc") `shouldEqual` "\"Abc\""
39+
40+ describe "data DoubleTrouble = IntAndString Int String" do
41+ it "roundtrips" do
42+ roundtrips (IntAndString 1 "Freddy")
43+ it "serialises without tags" do
44+ writeJSON (IntAndString 1 "Freddy") `shouldEqual` "[1,\"Freddy\"]"
45+
46+ describe "Tagged" do
47+
48+ describe "IntOrStringTagged = ATaggedInt Int | ATaggedString String" do
49+ it "roundtrips" do
50+ roundtrips (ATaggedInt 1)
51+ roundtrips (ATaggedString "HOHOHOHO")
52+
53+ it "serialises with tags" do
54+ writeJSON (ATaggedInt 1) `shouldEqual` """{"type":"ATaggedInt","value":1}"""
55+ writeJSON (ATaggedString "Abc") `shouldEqual` """{"type":"ATaggedString","value":"Abc"}"""
56+
57+ describe "data HalfEnum = NotEnum Int | IsEnum" do
58+ it "roundtrips" do
59+ roundtrips (NotEnum 1)
60+ roundtrips (IsEnum)
61+
62+ it "serialises with tags" do
63+ writeJSON (NotEnum 1) `shouldEqual` """{"kind":"not_enum","data":1}"""
64+ writeJSON (IsEnum) `shouldEqual` """{"kind":"is_enum"}"""
65+
66+data HalfEnum = NotEnum Int | IsEnum
67+
68+derive instance Generic HalfEnum _
69+derive instance Eq HalfEnum
70+instance Show HalfEnum where
71+ show = genericShow
72+
73+halfEnumOptions ∷ GenericTaggedSum.Options
74+halfEnumOptions = { typeTag: "kind", valueTag: "data", toConstructorName: snakeCase }
75+
76+instance ReadForeign HalfEnum where
77+ readImpl = genericReadForeignTaggedSum halfEnumOptions
78+
79+instance WriteForeign HalfEnum where
80+ writeImpl = genericWriteForeignTaggedSum halfEnumOptions
81+
82+data MyEnum = Enum1 | Enum2 | Enum3
83+
84+derive instance Generic MyEnum _
85+derive instance Eq MyEnum
86+instance Show MyEnum where
87+ show = genericShow
88+
89+instance ReadForeign MyEnum
90+ where
91+ readImpl = genericReadForeignEnum Enum.defaultOptions
92+
93+instance WriteForeign MyEnum
94+ where
95+ writeImpl = genericWriteForeignEnum Enum.defaultOptions
96+
97+data MyEnum2 = SomeEnum2 | SomeOtherEnum2 | SomeThirdEnum3
98+
99+derive instance Generic MyEnum2 _
100+derive instance Eq MyEnum2
101+instance Show MyEnum2 where
102+ show = genericShow
103+
104+instance ReadForeign MyEnum2
105+ where
106+ readImpl = genericReadForeignEnum { toConstructorName: snakeCase }
107+
108+instance WriteForeign MyEnum2
109+ where
110+ writeImpl = genericWriteForeignEnum { toConstructorName: snakeCase }
111+
112+data IntOrString = AnInt Int | AString String
113+
114+derive instance Generic IntOrString _
115+derive instance Eq IntOrString
116+instance Show IntOrString where
117+ show = genericShow
118+
119+instance ReadForeign IntOrString where
120+ readImpl = genericReadForeignUntaggedSum
121+
122+instance WriteForeign IntOrString where
123+ writeImpl = genericWriteForeignUntaggedSum
124+
125+data DoubleTrouble = IntAndString Int String
126+
127+derive instance Generic DoubleTrouble _
128+derive instance Eq DoubleTrouble
129+instance Show DoubleTrouble where
130+ show = genericShow
131+
132+instance ReadForeign DoubleTrouble where
133+ readImpl = genericReadForeignUntaggedProduct
134+
135+instance WriteForeign DoubleTrouble where
136+ writeImpl = genericWriteForeignUntaggedProduct
137+
138+data IntOrStringTagged = ATaggedInt Int | ATaggedString String
139+
140+derive instance Generic IntOrStringTagged _
141+derive instance Eq IntOrStringTagged
142+instance Show IntOrStringTagged where
143+ show = genericShow
144+
145+instance ReadForeign IntOrStringTagged where
146+ readImpl = genericReadForeignTaggedSum defaultOptions
147+
148+instance WriteForeign IntOrStringTagged where
149+ writeImpl = genericWriteForeignTaggedSum defaultOptions
test/Inferred.pursdeleted−54
@@ -1,54 +0,0 @@
1−module Test.Inferred where
2−
3−import Prelude
4−
5−import Control.Alt ((<|>))
6−import Control.Monad.Except (runExcept)
7−import Data.Either (Either(..), isRight)
8−import Effect (Effect)
9−import Foreign (Foreign)
10−import Foreign as Foreign
11−import Record as Record
12−import Yoga.JSON as JSON
13−import Test.Assert (assert)
14−import Type.Prelude (Proxy(..))
15−
16−type RecordWithEither =
17− { apple ∷ Int
18− , banana ∷ Either Int String
19− }
20−
21−readEitherImpl ∷
22− ∀ a b.
23− JSON.ReadForeign a ⇒
24− JSON.ReadForeign b ⇒
25− Foreign →
26− Foreign.F (Either a b)
27−readEitherImpl f = Left <$> JSON.readImpl f
28− <|> Right <$> JSON.readImpl f
29−
30−readRecordWithEitherJSON ∷
31− String → Either Foreign.MultipleErrors RecordWithEither
32−readRecordWithEitherJSON s = runExcept do
33− inter ← JSON.readJSON' s
34− banana ← readEitherImpl inter.banana
35− pure $ inter { banana = banana }
36−
37−type RecordMisnamedField =
38− { cherry ∷ Int
39− }
40−
41−readRecordMisnamedField ∷
42− String → Either Foreign.MultipleErrors RecordMisnamedField
43−readRecordMisnamedField s = do
44− inter ← JSON.readJSON s
45− pure $ Record.rename grapeP cherryP inter
46− where
47− grapeP = Proxy ∷ Proxy "grape"
48− cherryP = Proxy ∷ Proxy "cherry"
49−
50−main ∷ Effect Unit
51−main = do
52− assert <<< isRight $ readRecordWithEitherJSON """{"apple": 1, "banana": 1}"""
53− assert <<< isRight $ readRecordWithEitherJSON
54− """{"apple": 1, "banana": "yellow"}"""
test/Main.purs+8−207
@@ -2,213 +2,14 @@ module Test.Main where
2
2
3import Prelude
3import Prelude
4
4
5−import Data.Either (Either(..), either, fromLeft, isRight)
6−import Data.List (List(..), (:))
7−import Data.List.NonEmpty (NonEmptyList(..))
8−import Data.Maybe (Maybe)
9−import Data.NonEmpty (NonEmpty(..))
10−import Data.Nullable (Nullable)
11−import Data.Tuple.Nested (type (/\))
12−import Data.Variant (Variant)
13import Effect (Effect)
5import Effect (Effect)
14−import Effect.Exception (throw)
6+import Effect.Aff (launchAff_)
15−import Foreign (ForeignError(..), MultipleErrors)
7+import Effect.Class (liftEffect)
16−import Foreign.Object (Object)
8+import Test.Spec.Discovery (discover)
17−import Partial.Unsafe (unsafePartial)
9+import Test.Spec.Reporter (consoleReporter)
18−import Test.Assert (assertEqual)
10+import Test.Spec.Runner.Node (runSpecAndExitProcess)
19−import Test.EnumSumGeneric as Test.EnumSumGeneric
20−import Test.Generic as Test.Generic
21−import Test.Inferred as Test.Inferred
22−import Test.Quickstart as Test.Quickstart
23−import Type.Proxy (Proxy(..))
24−import Yoga.JSON (class ReadForeign, class WriteForeign, readJSON, writeJSON)
25−
26−type E a = Either MultipleErrors a
27−
28−type MyTest =
29− { a ∷ Int
30− , b ∷ String
31− , c ∷ Boolean
32− , d ∷ Array String
33− }
34−
35−type MyTestNull =
36− { a ∷ Int
37− , b ∷ String
38− , c ∷ Boolean
39− , d ∷ Array String
40− , e ∷ Maybe (Array String)
41− }
42−
43−type MyTestStrMap =
44− { a ∷ Int
45− , b ∷ Object Int
46− }
47−
48−type MyTestMaybe =
49− { a ∷ Maybe String
50− }
51−
52−type MyTestManyMaybe =
53− { a ∷ Maybe String
54− , aNull ∷ Maybe String
55− , b ∷ Maybe Int
56− , bNull ∷ Maybe Int
57− , c ∷ Maybe Boolean
58− , cNull ∷ Maybe Boolean
59− , d ∷ Maybe Number
60− , dNull ∷ Maybe Number
61− , e ∷ Maybe (Array (Maybe String))
62− , eNull ∷ Maybe (Array (Maybe String))
63− }
64−
65−type MyTestNullable =
66− { a ∷ Nullable String
67− , b ∷ Nullable String
68− }
69−
70−type MyTestVariant = Variant
71− ( a ∷ String
72− , b ∷ Int
73− )
74−
75−type MyTestTuple =
76− Int /\ String /\ Boolean /\ Char /\ Array (Int /\ String)
77−
78−
79−roundtrips :: forall a. ReadForeign a => WriteForeign a => Proxy a -> String -> Effect Unit
80−roundtrips _ enc0 = do
81− let
82− dec0 ∷ E a
83− dec0 = readJSON enc0
84− enc1 = either (const "bad1") writeJSON dec0
85−
86− dec1 ∷ E a
87− dec1 = readJSON enc1
88− enc2 = either (const "bad2") writeJSON dec1
89− when (enc1 /= enc2) $ throw enc0
90−
91−shouldEqual ∷ ∀ a. Eq a ⇒ Show a ⇒ a → a → Effect Unit
92−shouldEqual a b =
93− assertEqual { actual: a, expected: b }
94
11
95main ∷ Effect Unit
12main ∷ Effect Unit
96−main = do
13+main = launchAff_ $
97− shouldEqual 1 1
14+ discover """\..*Spec"""
98−
15+ >>= runSpecAndExitProcess [ consoleReporter ] >>> liftEffect
99− -- "fails with invalid JSON"
100− let r1 = readJSON """{ "c": 1, "d": 2}"""
101− r1 `shouldEqual`
102− ( Left
103− ( NonEmptyList
104− ( NonEmpty (ErrorAtProperty "a" (TypeMismatch "Int" "Undefined"))
105− ( (ErrorAtProperty "b" (TypeMismatch "String" "Undefined"))
106− : (ErrorAtProperty "c" (TypeMismatch "Boolean" "Number"))
107− : (ErrorAtProperty "d" (TypeMismatch "array" "Number"))
108− : Nil
109− )
110− )
111− )
112− )
113− isRight (r1 ∷ E MyTest) `shouldEqual` false
114−
115− -- "works with missing Maybe fields by setting them to Nothing"
116− let r2 = readJSON "{}"
117− (writeJSON <$> (r2 ∷ E MyTestMaybe)) `shouldEqual` (Right """{}""")
118−
119− -- "fails with undefined for null with correct error message"
120− let
121− r3 = readJSON
122− """
123− { "a": "asdf" }
124− """
125− r3 `shouldEqual`
126− ( Left
127− ( NonEmptyList
128− ( NonEmpty
129− ( ErrorAtProperty "b"
130− (TypeMismatch "Nullable String" "Undefined")
131− )
132− Nil
133− )
134− )
135− )
136− (isRight (r3 ∷ E MyTestNullable)) `shouldEqual` false
137−
138− let r4 = readJSON """[ 1, "test", 1, "a", [ 1 ] ]"""
139− r4 `shouldEqual`
140− (Left (NonEmptyList (NonEmpty (ErrorAtIndex 2 (TypeMismatch "Boolean" "Number")) Nil)))
141− isRight (r4 :: E MyTestTuple) `shouldEqual` false
142−
143− let r5 = readJSON """ [ 1, "test", true, "a", [ 1 ], null ] """
144− r5 `shouldEqual`
145− (Left (NonEmptyList (NonEmpty (TypeMismatch "array of length 5" "array of length 6") Nil)))
146− isRight (r5 :: E MyTestTuple) `shouldEqual` false
147−
148− let r6 = readJSON """ [ 1, "test", true, "a" ] """
149− r6 `shouldEqual`
150− (Left(NonEmptyList (NonEmpty (TypeMismatch "array of length 5" "array of length 4") Nil)))
151− isRight (r6 :: E MyTestTuple) `shouldEqual` false
152−
153− let r7 = readJSON """ [ 1 ] """
154− r7 `shouldEqual`
155− (Left(NonEmptyList (NonEmpty (TypeMismatch "array of length 5" "array of length 1") Nil)))
156− isRight (r7 :: E MyTestTuple) `shouldEqual` false
157−
158− let r8 = readJSON """ [] """
159− r8 `shouldEqual`
160− (Left (NonEmptyList (NonEmpty (TypeMismatch "array of length 5" "array of length 0") Nil)))
161− isRight (r8 :: E MyTestTuple) `shouldEqual` false
162−
163− -- roundtrips
164− -- "works with proper JSON"
165− roundtrips (Proxy ∷ Proxy MyTest)
166− """
167− { "a": 1, "b": "asdf", "c": true, "d": ["A", "B"]}
168− """
169−
170− -- "works with JSON lacking Maybe field"
171− roundtrips (Proxy ∷ Proxy MyTestNull)
172− """
173− { "a": 1, "b": "asdf", "c": true, "d": ["A", "B"]}
174− """
175−
176− -- "works with JSON containing Maybe field"
177− roundtrips (Proxy ∷ Proxy MyTestNull)
178− """
179− { "a": 1, "b": "asdf", "c": true, "d": ["A", "B"], "e": ["C", "D"]}
180− """
181−
182− -- -- "works with JSON containing Object field"
183− roundtrips (Proxy ∷ Proxy MyTestStrMap)
184− """
185− { "a": 1, "b": {"asdf": 1, "c": 2} }
186− """
187−
188− -- "works with Maybe field and existing value"
189− roundtrips (Proxy ∷ Proxy MyTestMaybe)
190− """
191− { "a": "foo" }
192− """
193−
194− -- "works with Nullable"
195− roundtrips (Proxy ∷ Proxy MyTestNullable)
196− """
197− { "a": null, "b": "a" }
198− """
199−
200− -- "works with Variant"
201− roundtrips (Proxy ∷ Proxy MyTestVariant)
202− """
203− { "type": "b", "value": 123 }
204− """
205−
206− roundtrips (Proxy :: Proxy MyTestTuple) """
207− [ 1, "test", true, "a", [ [1, "heinz"], [893, "dembowski"] ] ]
208− """
209−
210− -- run examples
211− Test.Generic.main
212− Test.EnumSumGeneric.main
213− Test.Inferred.main
214− Test.Quickstart.main
test/QuickStart.pursdeleted−145
@@ -1,145 +0,0 @@
1−module Test.Quickstart where
2−
3−import Prelude
4−
5−import Data.Array as Array
6−import Data.Either (Either(..))
7−import Data.Maybe (Maybe(..))
8−import Data.Nullable (Nullable, toNullable)
9−import Effect (Effect)
10−import Effect.Class.Console (log)
11−import Foreign (ForeignError(..))
12−import Yoga.JSON as JSON
13−import Test.Assert (assertEqual)
14−
15−type MyRecordAlias =
16− { apple ∷ String
17− , banana ∷ Array Int
18− }
19−
20−testJSON1 ∷ String
21−testJSON1 =
22− """
23−{ "apple": "Hello"
24−, "banana": [ 1, 2, 3 ]
25−}
26−"""
27−
28−testJSON2 ∷ String
29−testJSON2 =
30− """
31−{ "apple": false
32−, "banana": [ 1, 2, 3 ]
33−}
34−"""
35−
36−type WithMaybe =
37− { cherry ∷ Maybe Boolean
38− }
39−
40−testJSON3 ∷ String
41−testJSON3 =
42− """
43−{ "cherry": true
44−}
45−"""
46−
47−testJSON4 ∷ String
48−testJSON4 =
49− """
50−{}
51−"""
52−
53−type WithNullable =
54− { cherry ∷ Nullable Boolean
55− }
56−
57−newtype FancyInt = FancyInt Int
58−
59−derive newtype instance eqFancyInt ∷ Eq FancyInt
60−derive newtype instance showFancyInt ∷ Show FancyInt
61−derive newtype instance readForeignFancyInt ∷ JSON.ReadForeign FancyInt
62−derive newtype instance writeForeignFancyInt ∷ JSON.WriteForeign FancyInt
63−
64−main ∷ Effect Unit
65−main = do
66− case JSON.readJSON testJSON1 of
67− Right (r ∷ MyRecordAlias) → do
68− assertEqual { expected: r.apple, actual: "Hello" }
69− assertEqual { expected: r.banana, actual: [ 1, 2, 3 ] }
70− Left e → do
71− assertEqual { expected: "failed", actual: show e }
72−
73− case JSON.readJSON testJSON2 of
74− Right (r ∷ MyRecordAlias) → do
75− assertEqual { expected: "failed", actual: show r }
76− Left e → do
77− let errors = Array.fromFoldable e
78− assertEqual
79− { expected:
80− [ ErrorAtProperty "apple" (TypeMismatch "String" "Boolean") ]
81− , actual: errors
82− }
83−
84− let
85− myValue =
86− { apple: "Hi"
87− , banana: [ 1, 2, 3 ]
88− } ∷ MyRecordAlias
89−
90− log (JSON.writeJSON myValue) -- {"banana":[1,2,3],"apple":"Hi"}
91−
92− case JSON.readJSON testJSON3 of
93− Right (r ∷ WithMaybe) → do
94− assertEqual { expected: Just true, actual: r.cherry }
95− Left e → do
96− assertEqual { expected: "failed", actual: show e }
97−
98− case JSON.readJSON testJSON4 of
99− Right (r ∷ WithMaybe) → do
100− assertEqual { expected: Nothing, actual: r.cherry }
101− Left e → do
102− assertEqual { expected: "failed", actual: show e }
103−
104− let
105− withJust =
106− { cherry: Just true
107− } ∷ WithMaybe
108− withNothing =
109− { cherry: Nothing
110− } ∷ WithMaybe
111−
112− log (JSON.writeJSON withJust) -- {"cherry":true}
113− log (JSON.writeJSON withNothing) -- {}
114−
115− case JSON.readJSON testJSON3 of
116− Right (r ∷ WithNullable) → do
117− assertEqual { expected: toNullable (Just true), actual: r.cherry }
118− Left e → do
119− assertEqual { expected: "failed", actual: show e }
120−
121− case JSON.readJSON testJSON4 of
122− Right (r ∷ WithNullable) → do
123− assertEqual { expected: "failed", actual: show r }
124− Left e → do
125− let errors = Array.fromFoldable e
126− assertEqual
127− { expected:
128− [ ErrorAtProperty "cherry"
129− (TypeMismatch "Nullable Boolean" "Undefined")
130− ]
131− , actual: errors
132− }
133−
134− let
135− withNullable =
136− { cherry: toNullable Nothing
137− } ∷ WithNullable
138− log (JSON.writeJSON withNullable) -- {"cherry":null}
139−
140− case JSON.readJSON "1" of
141− Right fancyInt@(FancyInt i) → do
142− assertEqual { expected: FancyInt 1, actual: fancyInt }
143− assertEqual { expected: 1, actual: i }
144− Left e → do
145− assertEqual { expected: "failed", actual: show e }
test/Util.purs+20−29
@@ -2,35 +2,26 @@ module Test.Util where
2
2
3import Prelude
3import Prelude
4
4
5−import Prim.Row as Row
5+import Data.Either (Either(..))
6−import Prim.RowList (class RowToList, Cons, Nil, RowList)
6+import Data.Semigroup.Foldable (intercalateMap)
7−import Record (get)
7+import Effect.Aff (Aff)
8−import Type.Prelude (class IsSymbol, Proxy(..))
8+import Foreign (Foreign)
9+import Test.Spec.Assertions (fail)
10+import Type.Proxy (Proxy(..))
11+import Yoga.JSON (class ReadForeign, class WriteForeign, read, readJSON, write, writeJSON)
12+import Yoga.JSON.Error (renderHumanError, toJSONPath)
9
13
10−-- | Check two records of the same type for equality.
14+roundtrips ∷ ∀ a. Show a ⇒ Eq a ⇒ ReadForeign a ⇒ WriteForeign a ⇒ a → Aff Unit
11−equal ∷
15+roundtrips x = do
12− ∀ r rs.
16+ x # write # shouldRead (Proxy ∷ _ a)
13− RowToList r rs ⇒
17+ x # writeJSON # shouldReadJSON (Proxy ∷ _ a)
14− EqualFields rs r ⇒
15− Record r →
16− Record r →
17− Boolean
18−equal a b = equalFields (Proxy ∷ Proxy rs) a b
19
18
20−class EqualFields (rs ∷ RowList Type) (row ∷ Row Type) | rs → row where
19+shouldRead ∷ ∀ a. ReadForeign a ⇒ Proxy a → Foreign → Aff Unit
21− equalFields ∷ Proxy rs → Record row → Record row → Boolean
20+shouldRead _ = read >>> case _ of
21+ Left e → fail (intercalateMap "\n" renderHumanError e <> "\n" <> intercalateMap "\n" toJSONPath e)
22+ Right (_ ∷ a) → pure unit
22
23
23−instance equalFieldsCons ∷
24+shouldReadJSON ∷ ∀ a. ReadForeign a ⇒ Proxy a → String → Aff Unit
24− ( IsSymbol name
25+shouldReadJSON _ = readJSON >>> case _ of
25− , Eq ty
26+ Left e → fail (intercalateMap "\n" renderHumanError e <> "\n" <> intercalateMap "\n" toJSONPath e)
26− , Row.Cons name ty tailRow row
27+ Right (_ ∷ a) → pure unit
27− , EqualFields tail row
28− ) ⇒
29− EqualFields (Cons name ty tail) row where
30− equalFields _ a b = get' a == get' b && rest
31− where
32− get' = get (Proxy ∷ Proxy name)
33− rest = equalFields (Proxy ∷ Proxy tail) a b
34−
35−instance equalFieldsNil ∷ EqualFields Nil row where
36− equalFields _ _ _ = true
test/WriteViaSpec.pursnew file+42
@@ -0,0 +1,42 @@
1+module Test.WriteViaSpec where
2+
3+import Prelude
4+
5+import Data.Either (Either(..))
6+import Test.Spec (Spec, describe, it)
7+import Test.Spec.Assertions (shouldEqual)
8+import Yoga.JSON (class ReadForeign, class WriteForeign)
9+import Yoga.JSON as JSON
10+import Yoga.JSON.Derive (readVia, writeVia)
11+
12+spec ∷ Spec Unit
13+spec = describe "En- and decoding with Coercibles" do
14+ let referenceJSON = """{"myString":"A","myInt":3}"""
15+ it "writing works" do
16+ let myRecord = MyRecord { myInt: MyInt 3, myString: MyString "A" }
17+ JSON.writeJSON myRecord `shouldEqual` referenceJSON
18+ it "reading works" do
19+ JSON.readJSON referenceJSON `shouldEqual` Right (MyRecord { myInt: MyInt 3, myString: MyString "A" })
20+
21+newtype MyInt = MyInt Int
22+newtype MyString = MyString String
23+
24+newtype MyRecord = MyRecord
25+ { myInt ∷ MyInt
26+ , myString ∷ MyString
27+ }
28+
29+instance WriteForeign MyRecord where
30+ writeImpl = writeVia @{ myInt ∷ Int, myString ∷ String }
31+
32+instance ReadForeign MyRecord where
33+ readImpl = readVia @{ myInt ∷ Int, myString ∷ String }
34+
35+-- Below instances are just necessary for the tests to compile
36+
37+instance Show MyRecord where
38+ show = JSON.writeJSON
39+
40+derive instance Eq MyRecord
41+derive instance Eq MyInt
42+derive instance Eq MyString