Add part7

This commit is contained in:
Richard Feldman
2018-05-05 04:54:47 -04:00
parent f6bef58e3d
commit 825dea437b
575 changed files with 79140 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
# Ignore build or dist files
elm-stuff
node_modules

View File

@@ -0,0 +1,36 @@
sudo: false
language: node_js
node_js: "node"
os: linux
env: ELM_VERSION=0.18.0
cache:
directories:
- test/elm-stuff/build-artifacts
- sysconfcpus
before_install:
- echo -e "Host github.com\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
- | # epic build time improvement - see https://github.com/elm-lang/elm-compiler/issues/1473#issuecomment-245704142
if [ ! -d sysconfcpus/bin ];
then
git clone https://github.com/obmarg/libsysconfcpus.git;
cd libsysconfcpus;
./configure --prefix=$TRAVIS_BUILD_DIR/sysconfcpus;
make && make install;
cd ..;
fi
install:
- node --version
- npm --version
- cd tests
- npm install -g elm@$ELM_VERSION
- mv $(npm config get prefix)/bin/elm-make $(npm config get prefix)/bin/elm-make-old
- printf '%s\n\n' '#!/bin/bash' 'echo "Running elm-make with sysconfcpus -n 2"' '$TRAVIS_BUILD_DIR/sysconfcpus/bin/sysconfcpus -n 2 elm-make-old "$@"' > $(npm config get prefix)/bin/elm-make
- chmod +x $(npm config get prefix)/bin/elm-make
- npm install
- elm package install --yes
script:
- npm test

View File

@@ -0,0 +1,68 @@
### 2.6.0
**Additions:**
- `keys` allows extracting _only_ the keys from a JSON object
### 2.5.0
**Additions:**
- `dict` helps encoding `Dict`
### 2.4.0
**Additions:**
- `collection` helps with decoding array-like JavaScript structures such as `HTMLCollection`
- `combine` helps combining a `List` of decoders into a single `Decoder` for a `List` of such things
### 2.3.0
**Additions:**
- `indexedList` to get access to the current js array index while decoding
**Other Stuff:**
- `elm-doc-test` is now `elm-verify-examples`!
### 2.2.0
**Additions:**
- `parseInt` and `parseFloat` for weird api's that return numbers as strings
- `doubleEncoded` for a more generic _json as a string in json_ issues
**Fixes:**
- `optionalField` decodes the field, rather than the surrounding object now.
**Other Stuff:**
- Code Style conforms to elm-format@exp
- Doc tests!
- Travis integration
### 2.1.0
**Additions:**
- `optionalField : String -> Json.Decode.Decoder a -> Json.Decode.Decoder (Maybe.Maybe a)` - Decode an optional field, succeeding with `Nothing` if it is missing, but still giving an error if it is malformed.
### 2.0.0
**Breaking Changes:**
- Upgrade for Elm 0.18
- Removed `maybeNull` in favor of `Json.Decode.nullable`
- Removed `lazy` in favor of `Json.Decode.lazy`
- Renamed `apply` to `andMap` and reversed arguments to `Decoder a -> Decoder (a -> b) -> Decoder b` to make it work nicely with `(|>)`
**Additions:**
- `fromResult : Result String a -> Decoder a` - convert a `Result` to a `Decoder`, helpful in `andThen` callbacks following the removal of `Json.Decode.customDecoder`
- `Json.Encode.Extra.maybe : (a -> Value) -> Maybe a -> Value` - encode a `Maybe a` given an encoder for `a`. Thanks to @hendore for this addition.
**Other Stuff:**
- Code style conforms to elm-format
#### 1.1.0
**Additions:**
- `Json.Decode.Extra.sequence` - lets you generate a list of `Decoder a` and attempt to apply them to a JSON list. _Authored by @cobalamin_
#### 1.0.0
**Breaking Changes:**
- Upgrade for Elm 0.17

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 CircuitHub Inc., Elm Community members
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,9 @@
[![Build Status](https://travis-ci.org/elm-community/json-extra.svg?branch=master)](https://travis-ci.org/elm-community/json-extra)
# json-extra
```
elm-package install elm-community/json-extra
```
Convenience functions for working with JSON

View File

@@ -0,0 +1,61 @@
## Json.Decode.Extra.andMap
Imagine you have a data type for a user
```elm
import Date (Date)
type alias User =
{ id : Int
, createdAt : Date
, updatedAt : Date
, deletedAt : Maybe Date
, username : Maybe String
, email : Maybe String
, isAdmin : Bool
}
```
You can use `andMap` to incrementally apply decoders to your `User` type alias
by using that type alias as a function. Recall that record type aliases are
also functions which accept arguments in the order their fields are declared. In
this case, `User` looks like
```elm
User : Int -> Date -> Date -> Maybe Date -> Maybe String -> Maybe String -> Bool -> User
```
And also recall that Elm functions can be partially applied. We can use these
properties to apply each field of our JSON object to each field in our user one
field at a time. All we need to do is also wrap `User` in a decoder and step
through using `andMap`.
```elm
userDecoder : Decoder User
userDecoder =
succeed User
|> andMap (field "id" int)
|> andMap (field "createdAt" date)
|> andMap (field "updatedAt" date)
|> andMap (field "deletedAt" (maybe date))
|> andMap (field "username" (maybe string))
|> andMap (field "email" (maybe string))
|> andMap (field "isAdmin" bool)
```
This is a shortened form of
```elm
userDecoder : Decoder User
userDecoder =
succeed User
|> andThen (\f -> map f (field "id" int))
|> andThen (\f -> map f (field "createdAt" date))
|> andThen (\f -> map f (field "updatedAt" date))
|> andThen (\f -> map f (field "deletedAt" (maybe date)))
|> andThen (\f -> map f (field "username" (maybe string)))
|> andThen (\f -> map f (field "email" (maybe string)))
|> andThen (\f -> map f (field "isAdmin" bool))
```
See also: The [docs for `(|:)`](https://github.com/elm-community/json-extra/blob/master/docs/infixAndMap.md)

View File

@@ -0,0 +1,131 @@
## Json.Decode.Extra.(|:)
Infix version of `andMap` that makes for a nice DSL when decoding objects.
Consider the following type alias for a `Location`:
```elm
type alias Location =
{ id : Int
, name : String
, address : String
}
```
We can use `(|:)` to build up a decoder for `Location`:
```elm
locationDecoder : Decoder Location
locationDecoder =
succeed Location
|: (field "id" int)
|: (field "name" string)
|: (field "address" string)
```
If you're curious, here's how this works behind the scenes, read on.
`Location` is a type alias, and type aliases give you a convenience function
that returns an instance of the record in question. Try this out in `elm-repl`:
```elm
> type alias Location = { id : Int, name: String, address: String }
> Location
<function> : Int -> String -> String -> Repl.Location
> Location 1 "The White House" "1600 Pennsylvania Ave"
{ id = 1, name = "The White House", address = "1600 Pennsylvania Ave" }
```
In other words, if you call the `Location` function, passing three arguments,
it will return a new `Location` record by filling in each of its fields. (The
argument order is based on the order in which we listed the fields in the
type alias; the first argument sets `id`, the second argument sets `name`, etc.)
Now try running this through `elm-repl`:
```elm
> import Json.Decode exposing (succeed, int, string, field)
> succeed Location
<function>
: Json.Decode.Decoder
(Int -> String -> String -> Repl.Location)
```
So `succeed Location` gives us a `Decoder (Int -> String -> String -> Location)`.
That's not what we want! What we want is a `Decoder Location`. All we have so
far is a `Decoder` that wraps not a `Location`, but rather a function that
returns a `Location`.
What `|: (field "id" int)` does is to take that wrapped function and pass an
argument to it.
```elm
> import Json.Decode exposing (succeed, int, string, field)
> (field "id" int)
<function> : Json.Decode.Decoder Int
> succeed Location |: (field "id" int)
<function>
: Json.Decode.Decoder
(String -> String -> Repl.Location)
```
Notice how the wrapped function no longer takes an `Int` as its first argument.
That's because `(|:)` went ahead and supplied one: the `Int` wrapped by the decoder
`(field "id" int)` (which returns a `Decoder Int`).
Compare:
```elm
> succeed Location
Decoder (Int -> String -> String -> Location)
> succeed Location |: (field "id" int)
Decoder (String -> String -> Location)
```
We still want a `Decoder Location` and we still don't have it yet. Our decoder
still wraps a function instead of a plain `Location`. However, that function is
now smaller by one argument!
Let's repeat this pattern to provide the first `String` argument next.
```elm
> succeed Location
Decoder (Int -> String -> String -> Location)
> succeed Location |: (field "id" int)
Decoder (String -> String -> Location)
> succeed Location |: (field "id" int) |: (field "name" string)
Decoder (String -> Location)
```
Smaller and smaller! Now we're down from `(Int -> String -> String -> Location)`
to `(String -> Location)`. What happens if we repeat the pattern one more time?
```elm
> succeed Location
Decoder (Int -> String -> String -> Location)
> succeed Location |: (field "id" int)
Decoder (String -> String -> Location)
> succeed Location |: (field "id" int) |: (field "name" string)
Decoder (String -> Location)
> succeed Location |: (field "id" int) |: (field "name" string) |: (field "address" string)
Decoder Location
```
Having now supplied all three arguments to the wrapped function, it has ceased
to be a function. It's now just a plain old `Location`, like we wanted all along.
We win!

View File

@@ -0,0 +1,17 @@
{
"version": "2.7.0",
"summary": "Convenience functions for working with Json",
"repository": "https://github.com/elm-community/json-extra.git",
"license": "MIT",
"source-directories": [
"src"
],
"exposed-modules": [
"Json.Decode.Extra",
"Json.Encode.Extra"
],
"dependencies": {
"elm-lang/core": "5.0.0 <= v < 6.0.0"
},
"elm-version": "0.18.0 <= v < 0.19.0"
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
{
"scripts": {
"test": "elm-verify-examples && elm-format --validate src"
},
"dependencies": {
"elm-format": "^0.7.0-exp",
"elm-verify-examples": "^2.3.1"
}
}

View File

@@ -0,0 +1,565 @@
module Json.Decode.Extra
exposing
( (|:)
, andMap
, collection
, combine
, date
, dict2
, doubleEncoded
, fromResult
, indexedList
, keys
, optionalField
, parseFloat
, parseInt
, sequence
, set
, when
, withDefault
)
{-| Convenience functions for working with Json
# Date
@docs date
# Incremental Decoding
@docs andMap, (|:)
# Conditional Decoding
@docs when
# List
@docs collection, sequence, combine, indexedList, keys
# Set
@docs set
# Dict
@docs dict2
# Maybe
@docs withDefault, optionalField
# Result
@docs fromResult
# Encoded strings
@docs parseInt, parseFloat, doubleEncoded
-}
import Date
import Dict exposing (Dict)
import Json.Decode exposing (..)
import Set exposing (Set)
import String
{-| Can be helpful when decoding large objects incrementally.
See [the `andMap` docs](https://github.com/elm-community/json-extra/blob/2.0.0/docs/andMap.md)
for an explanation of how `andMap` works and how to use it.
-}
andMap : Decoder a -> Decoder (a -> b) -> Decoder b
andMap =
map2 (|>)
{-| Infix version of `andMap` that makes for a nice DSL when decoding objects.
See [the `(|:)` docs](https://github.com/elm-community/json-extra/blob/2.0.0/docs/infixAndMap.md)
for an explanation of how `(|:)` works and how to use it.
-}
(|:) : Decoder (a -> b) -> Decoder a -> Decoder b
(|:) =
flip andMap
{-| Extract a date using [`Date.fromString`](http://package.elm-lang.org/packages/elm-lang/core/latest/Date#fromString)
import Date
import Json.Decode exposing (..)
""" "2012-04-23T18:25:43.511Z" """
|> decodeString date
--> Date.fromString "2012-04-23T18:25:43.511Z"
""" "foo" """
|> decodeString date
--> Err "I ran into a `fail` decoder: Unable to parse 'foo' as a date. Dates must be in the ISO 8601 format."
-}
date : Decoder Date.Date
date =
string
|> andThen (Date.fromString >> fromResult)
{-| Extract a set.
import Json.Decode exposing (..)
import Set
"[ 1, 1, 5, 2 ]"
|> decodeString (set int)
--> Ok <| Set.fromList [ 1, 2, 5 ]
-}
set : Decoder comparable -> Decoder (Set comparable)
set decoder =
list decoder
|> map Set.fromList
{-| Extract a dict using separate decoders for keys and values.
import Json.Decode exposing (..)
import Dict
""" { "1": "foo", "2": "bar" } """
|> decodeString (dict2 int string)
--> Ok <| Dict.fromList [ ( 1, "foo" ), ( 2, "bar" ) ]
-}
dict2 : Decoder comparable -> Decoder v -> Decoder (Dict comparable v)
dict2 keyDecoder valueDecoder =
keyValuePairs valueDecoder
|> andThen (decodeDictFromTuples keyDecoder)
{-| Helper function for dict
-}
decodeDictFromTuples : Decoder comparable -> List ( String, v ) -> Decoder (Dict comparable v)
decodeDictFromTuples keyDecoder tuples =
case tuples of
[] ->
succeed Dict.empty
( strKey, value ) :: rest ->
case decodeString keyDecoder strKey of
Ok key ->
decodeDictFromTuples keyDecoder rest
|> andThen (Dict.insert key value >> succeed)
Err error ->
fail error
{-| Try running the given decoder; if that fails, then succeed with the given
fallback value.
import Json.Decode exposing (..)
""" { "children": "oops" } """
|> decodeString (field "children" (list string) |> withDefault [])
--> Ok []
""" null """
|> decodeString (field "children" (list string) |> withDefault [])
--> Ok []
""" 30 """
|> decodeString (int |> withDefault 42)
--> Ok 30
-}
withDefault : a -> Decoder a -> Decoder a
withDefault fallback decoder =
maybe decoder
|> map (Maybe.withDefault fallback)
{-| If a field is missing, succeed with `Nothing`. If it is present, decode it
as normal and wrap successes in a `Just`.
When decoding with
[`maybe`](http://package.elm-lang.org/packages/elm-lang/core/latest/Json-Decode#maybe),
if a field is present but malformed, you get a success and Nothing.
`optionalField` gives you a failed decoding in that case, so you know
you received malformed data.
Examples:
import Json.Decode exposing (..)
Let's define a `stuffDecoder` that extracts the `"stuff"` field, if it exists.
stuffDecoder : Decoder (Maybe String)
stuffDecoder =
optionalField "stuff" string
If the "stuff" field is missing, decode to Nothing.
""" { } """
|> decodeString stuffDecoder
--> Ok Nothing
If the "stuff" field is present but not a String, fail decoding.
""" { "stuff": [] } """
|> decodeString stuffDecoder
--> Err "Expecting a String at _.stuff but instead got: []"
If the "stuff" field is present and valid, decode to Just String.
""" { "stuff": "yay!" } """
|> decodeString stuffDecoder
--> Ok <| Just "yay!"
-}
optionalField : String -> Decoder a -> Decoder (Maybe a)
optionalField fieldName decoder =
let
finishDecoding json =
case decodeValue (field fieldName value) json of
Ok val ->
-- The field is present, so run the decoder on it.
map Just (field fieldName decoder)
Err _ ->
-- The field was missing, which is fine!
succeed Nothing
in
value
|> andThen finishDecoding
{-| This function turns a list of decoders into a decoder that returns a list.
The returned decoder will zip the list of decoders with a list of values,
matching each decoder with exactly one value at the same position. This is most
often useful in cases when you find yourself needing to dynamically generate a
list of decoders based on some data, and decode some other data with this list
of decoders.
Note that this function, unlike `List.map2`'s behaviour, expects the list of
decoders to have the same length as the list of values in the JSON.
import Json.Decode exposing (..)
sequence
[ map Just string
, succeed Nothing
, map Just string
]
|> flip decodeString """ [ "pick me", "ignore me", "and pick me" ] """
--> Ok [ Just "pick me", Nothing, Just "and pick me" ]
-}
sequence : List (Decoder a) -> Decoder (List a)
sequence decoders =
list value |> andThen (sequenceHelp decoders)
{-| Helper function for sequence
-}
sequenceHelp : List (Decoder a) -> List Value -> Decoder (List a)
sequenceHelp decoders jsonValues =
if List.length jsonValues /= List.length decoders then
fail "Number of decoders does not match number of values"
else
List.map2 decodeValue decoders jsonValues
|> List.foldr (Result.map2 (::)) (Ok [])
|> fromResult
{-| Get access to the current index while decoding a list element.
import Json.Decode exposing (..)
repeatedStringDecoder : Int -> Decoder String
repeatedStringDecoder times =
string |> map (String.repeat times)
""" [ "a", "b", "c", "d" ] """
|> decodeString (indexedList repeatedStringDecoder)
--> Ok [ "", "b", "cc", "ddd" ]
-}
indexedList : (Int -> Decoder a) -> Decoder (List a)
indexedList indexedDecoder =
list value
|> andThen
(\values ->
List.range 0 (List.length values - 1)
|> List.map indexedDecoder
|> sequence
)
{-| Get a list of the keys of a JSON object
import Json.Decode exposing (..)
""" { "alice": 42, "bob": 99 } """
|> decodeString keys
--> Ok [ "alice", "bob" ]
-}
keys : Decoder (List String)
keys =
keyValuePairs (succeed ())
|> map (List.foldl (\( key, _ ) acc -> key :: acc) [])
{-| Transform a result into a decoder
Sometimes it can be useful to use functions that primarily operate on
`Result` in decoders. An example of this is `Json.Decode.Extra.date`. It
uses the built-in `Date.fromString` to parse a `String` as a `Date`, and
then converts the `Result` from that conversion into a decoder which has
either already succeeded or failed based on the outcome.
import Json.Decode exposing (..)
validateString : String -> Result String String
validateString input =
case input of
"" ->
Err "Empty string is not allowed"
_ ->
Ok input
""" "something" """
|> decodeString (string |> andThen (fromResult << validateString))
--> Ok "something"
""" "" """
|> decodeString (string |> andThen (fromResult << validateString))
--> Err "I ran into a `fail` decoder: Empty string is not allowed"
-}
fromResult : Result String a -> Decoder a
fromResult result =
case result of
Ok successValue ->
succeed successValue
Err errorMessage ->
fail errorMessage
{-| Extract an int using [`String.toInt`](http://package.elm-lang.org/packages/elm-lang/core/latest/String#toInt)
import Json.Decode exposing (..)
""" { "field": "123" } """
|> decodeString (field "field" parseInt)
--> Ok 123
-}
parseInt : Decoder Int
parseInt =
string |> andThen (String.toInt >> fromResult)
{-| Extract a float using [`String.toFloat`](http://package.elm-lang.org/packages/elm-lang/core/latest/String#toFloat)
import Json.Decode exposing (..)
""" { "field": "50.5" } """
|> decodeString (field "field" parseFloat)
--> Ok 50.5
-}
parseFloat : Decoder Float
parseFloat =
string |> andThen (String.toFloat >> fromResult)
{-| Extract a JSON-encoded string field
"Yo dawg, I heard you like JSON..."
If someone has put JSON in your JSON (perhaps a JSON log entry, encoded
as a string) this is the function you're looking for. Give it a decoder
and it will return a new decoder that applies your decoder to a string
field and yields the result (or fails if your decoder fails).
import Json.Decode exposing (..)
logEntriesDecoder : Decoder (List String)
logEntriesDecoder =
doubleEncoded (list string)
logsDecoder : Decoder (List String)
logsDecoder =
field "logs" logEntriesDecoder
""" { "logs": "[\\"log1\\", \\"log2\\"]"} """
|> decodeString logsDecoder
--> Ok [ "log1", "log2" ]
-}
doubleEncoded : Decoder a -> Decoder a
doubleEncoded decoder =
string |> andThen (fromResult << decodeString decoder)
{-| Helps converting a list of decoders into a decoder for a list of that type.
import Json.Decode exposing (..)
decoders : List (Decoder String)
decoders =
[ field "foo" string
, field "bar" string
, field "another" string
]
""" { "foo": "hello", "another": "!", "bar": "world" } """
|> decodeString (combine decoders)
--> Ok [ "hello", "world", "!" ]
-}
combine : List (Decoder a) -> Decoder (List a)
combine =
List.foldr (map2 (::)) (succeed [])
{-| Some JavaScript structures look like arrays, but aren't really. Examples
include `HTMLCollection`, `NodeList` and everything else that has a `length`
property, has values indexed by an integer key between 0 and `length`, but yet
_is not_ a JavaScript Array.
This decoder can come to the rescue.
import Json.Decode exposing (..)
""" { "length": 3, "0": "foo", "1": "bar", "2": "baz" } """
|> decodeString (collection string)
--> Ok [ "foo", "bar", "baz" ]
-}
collection : Decoder a -> Decoder (List a)
collection decoder =
field "length" int
|> andThen
(\length ->
List.range 0 (length - 1)
|> List.map (\index -> field (toString index) decoder)
|> combine
)
{-| Helper for conditionally decoding values based on some discriminator
that needs to pass a certain check.
import Json.Decode exposing (..)
is : a -> a -> Bool
is a b =
a == b
enabledValue : Decoder Int
enabledValue =
(field "value" int)
|> when (field "enabled" bool) (is True)
""" { "enabled": true, "value": 123 } """
|> decodeString enabledValue
--> Ok 123
""" { "enabled": false, "value": 321 } """
|> decodeString enabledValue
--> Err "I ran into a `fail` decoder: Check failed with input `False`"
This can also be used to decode union types that are encoded with a discriminator field:
type Animal = Cat String | Dog String
dog : Decoder Animal
dog =
map Dog (field "name" string)
cat : Decoder Animal
cat =
map Cat (field "name" string)
animalType : Decoder String
animalType =
field "type" string
animal : Decoder Animal
animal =
oneOf
[ when animalType (is "dog") dog
, when animalType (is "cat") cat
]
"""
[
{ "type": "dog", "name": "Dawg" },
{ "type": "cat", "name": "Roxy" }
]
"""
|> decodeString (list animal)
--> Ok [ Dog "Dawg", Cat "Roxy" ]
-}
when : Decoder a -> (a -> Bool) -> Decoder b -> Decoder b
when checkDecoder check passDecoder =
checkDecoder
|> andThen
(\checkVal ->
if check checkVal then
passDecoder
else
fail <|
"Check failed with input `"
++ toString checkVal
++ "`"
)

View File

@@ -0,0 +1,47 @@
module Json.Encode.Extra exposing (dict, maybe)
{-| Convenience functions for turning Elm values into Json values.
@docs dict, maybe
-}
import Dict exposing (Dict)
import Json.Encode exposing (Value, encode, int, null, object)
{-| Encode a Maybe value. If the value is `Nothing` it will be encoded as `null`
import Json.Encode exposing (..)
maybe int (Just 50)
--> int 50
maybe int Nothing
--> null
-}
maybe : (a -> Value) -> Maybe a -> Value
maybe encoder =
Maybe.map encoder >> Maybe.withDefault null
{-| Turn a `Dict` into a JSON object.
import Json.Encode exposing (..)
import Dict
Dict.fromList [ ( "Sue", 38 ), ( "Tom", 42 ) ]
|> dict identity int
|> encode 0
--> """{"Sue":38,"Tom":42}"""
-}
dict : (comparable -> String) -> (v -> Value) -> Dict comparable v -> Value
dict toKey toValue dict =
Dict.toList dict
|> List.map (\( key, value ) -> ( toKey key, toValue value ))
|> object

View File

@@ -0,0 +1,16 @@
{
"version": "1.0.0",
"summary": "Test Suites",
"repository": "https://github.com/elm-community/json-extra.git",
"license": "MIT",
"source-directories": [
"../src",
"."
],
"exposed-modules": [],
"dependencies": {
"elm-lang/core": "5.0.0 <= v < 6.0.0",
"elm-community/elm-test": "4.0.0 <= v < 5.0.0"
},
"elm-version": "0.18.0 <= v < 0.19.0"
}

View File

@@ -0,0 +1,7 @@
{
"root": "../src",
"tests": [
"Json.Encode.Extra",
"Json.Decode.Extra"
]
}