Add support for bigint (#5)

* Add support for bigint

Add multiple deserialisation options

* Add npm install
This commit is contained in:
sigma-andex 2022-07-04 18:08:04 +01:00 committed by GitHub
parent 353f5aa5aa
commit 0c1654c631
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 98 additions and 7 deletions

View File

@ -31,7 +31,7 @@ jobs:
path: |
.spago
output
- run: npm install
- run: spago build
- run: spago -x test.dhall test

27
package-lock.json generated Normal file
View File

@ -0,0 +1,27 @@
{
"name": "purescript-yoga-json",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"dependencies": {
"big-integer": "^1.6.51"
}
},
"node_modules/big-integer": {
"version": "1.6.51",
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
"integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==",
"engines": {
"node": ">=0.6"
}
}
},
"dependencies": {
"big-integer": {
"version": "1.6.51",
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
"integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg=="
}
}
}

6
package.json Normal file
View File

@ -0,0 +1,6 @@
{
"dependencies": {
"big-integer": "^1.6.51"
},
"type": "module"
}

View File

@ -4,6 +4,8 @@
, dependencies =
[ "arrays"
, "bifunctors"
, "bigints"
, "console"
, "control"
, "effect"
, "either"

View File

@ -1,5 +1,18 @@
export const _parseJSON = JSON.parse;
function reviver(key, value) {
if (key === 'big') {
return BigInt(value);
}
return value;
}
export const _parseJSON = (payload) => JSON.parse(payload, reviver);
export const _undefined = undefined;
export const _unsafeStringify = JSON.stringify;
function replacer(key, value) {
if (key === 'big') {
return value.toString();
}
return value;
}
export const _unsafeStringify = (data) => JSON.stringify(data, replacer);

View File

@ -39,11 +39,13 @@ import Control.Monad.Except (ExceptT(..), except, runExcept, throwError, withExc
import Data.Array as Array
import Data.Array.NonEmpty (NonEmptyArray, fromArray, toArray)
import Data.Bifunctor (lmap)
import Data.BigInt (BigInt)
import Data.BigInt as BigInt
import Data.Either (Either, hush, note)
import Data.FoldableWithIndex (foldrWithIndex)
import Data.Identity (Identity(..))
import Data.Int as Int
import Data.List.NonEmpty (singleton)
import Data.List.NonEmpty (NonEmptyList, singleton)
import Data.Map (Map)
import Data.Map as Map
import Data.Maybe (Maybe(..), fromMaybe, fromMaybe', maybe)
@ -57,7 +59,7 @@ import Data.Variant (Variant, inj, on)
import Effect.Exception (message, try)
import Effect.Uncurried as EU
import Effect.Unsafe (unsafePerformEffect)
import Foreign (F, Foreign, ForeignError(..), MultipleErrors, fail, isNull, isUndefined, readArray, readBoolean, readChar, readInt, readNull, readNumber, readString, tagOf, unsafeFromForeign, unsafeToForeign)
import Foreign (F, Foreign, ForeignError(..), MultipleErrors, fail, isNull, isUndefined, readArray, readBoolean, readChar, readInt, readNull, readNumber, readString, tagOf, unsafeFromForeign, unsafeReadTagged, unsafeToForeign)
import Foreign.Index (readProp)
import Foreign.Object (Object)
import Foreign.Object as Object
@ -177,6 +179,24 @@ instance ReadForeign Number where
instance ReadForeign Int where
readImpl = readInt
-- | Attempt to coerce a foreign value to a `BigInt`.
readBigInt ∷
∀ m. Monad m ⇒ Foreign → ExceptT (NonEmptyList ForeignError) m BigInt
readBigInt = unsafeReadTagged "BigInt"
instance ReadForeign BigInt where
readImpl fValue = tryInt fValue <|> readBigInt fValue <|> tryString fValue
where
tryInt f = readInt f <#> BigInt.fromInt
tryString f = do
bi ← readString f
BigInt.fromString bi
# note
( singleton $ ForeignError $ "String " <> bi <>
" could not be converted to BigInt"
)
# except
instance ReadForeign String where
readImpl = readString
@ -351,6 +371,9 @@ instance WriteForeign Char where
instance WriteForeign Number where
writeImpl = unsafeToForeign
instance WriteForeign BigInt where
writeImpl = unsafeToForeign
instance WriteForeign Boolean where
writeImpl = unsafeToForeign
@ -484,4 +507,4 @@ instance (Newtype nt key, ReadForeign (Map key value)) => ReadForeign (Map nt va
unsafeStringToInt :: String → Int
unsafeStringToInt = Int.fromString >>>
(fromMaybe' \_ -> unsafeCrashWith "impossible")
(fromMaybe' \_ -> unsafeCrashWith "impossible")

View File

@ -3,6 +3,7 @@ module Test.BasicsSpec where
import Prelude
import Data.Array.NonEmpty as NEA
import Data.BigInt (BigInt)
import Data.Either (Either(..))
import Data.Foldable (traverse_)
import Data.List as List
@ -51,7 +52,26 @@ spec = describe "En- and decoding" $ do
$ roundtrips (Map.fromFoldable [(Stringy "A" /\ "B"),(Stringy "C" /\ "D")])
it "roundtrips Map with Int newtype keys"
$ roundtrips (Map.fromFoldable [(Inty 4 /\ "B"),(Inty 8 /\ "D")])
it "roundtrips BigInt" do
let
inputStr = """{ "number":1, "big": 18014398509481982, "smallBig": 10 }"""
expected = """{"smallBig":"10","number":1,"big":"18014398509481982"}"""
parsed ∷ _ ({ number ∷ Int, big ∷ BigInt, smallBig ∷ BigInt })
parsed = readJSON inputStr
stringified = parsed <#> writeJSON
stringified `shouldEqual` (Right expected)
-- [TODO] Comment in as soon as bug in big-integers is fixed
-- it "roundtrips BigInt (2)" do
-- let
-- smallBig = BigInt.fromInt 10
-- big = unsafePartial $ fromJust $ BigInt.fromString "18014398509481982"
-- expected = { big, smallBig }
-- json = spy "json" $ writeJSON expected
-- parsed ∷ _ ({ big ∷ BigInt, smallBig ∷ BigInt })
-- parsed = readJSON json
-- (spy "parsed" parsed) `shouldEqual` (Right expected)
describe "works on record types" do
it "roundtrips" do
roundtrips { a: 12, b: "54" }
@ -111,4 +131,4 @@ derive newtype instance Show Inty
derive newtype instance Eq Inty
derive newtype instance Ord Inty
derive newtype instance WriteForeign Inty
derive newtype instance ReadForeign Inty
derive newtype instance ReadForeign Inty