Skip to content

Commit 5093e34

Browse files
jaceredapaf31
authored andcommitted
Add fieldTransform to Options (#32)
* Add fieldTransform to Options * Add comment about fieldTransform
1 parent df66706 commit 5093e34

File tree

4 files changed

+58
-30
lines changed

4 files changed

+58
-30
lines changed

src/Data/Foreign/Generic.purs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import Global.Unsafe (unsafeStringify)
2424
-- | - Unwrap single arguments
2525
-- | - Don't unwrap single constructors
2626
-- | - Use the constructor names as-is
27+
-- | - Use the field names as-is
2728
defaultOptions :: Options
2829
defaultOptions =
2930
{ sumEncoding:
@@ -34,6 +35,7 @@ defaultOptions =
3435
}
3536
, unwrapSingleConstructors: false
3637
, unwrapSingleArguments: true
38+
, fieldTransform: id
3739
}
3840

3941
-- | Read a value which has a `Generic` type.

src/Data/Foreign/Generic/Class.purs

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,19 @@ class GenericEncode a where
2525
encodeOpts :: Options -> a -> Foreign
2626

2727
class GenericDecodeArgs a where
28-
decodeArgs :: Int -> List Foreign -> F { result :: a
29-
, rest :: List Foreign
30-
, next :: Int
31-
}
28+
decodeArgs :: Options -> Int -> List Foreign -> F { result :: a
29+
, rest :: List Foreign
30+
, next :: Int
31+
}
3232

3333
class GenericEncodeArgs a where
34-
encodeArgs :: a -> List Foreign
34+
encodeArgs :: Options -> a -> List Foreign
3535

3636
class GenericDecodeFields a where
37-
decodeFields :: Foreign -> F a
37+
decodeFields :: Options -> Foreign -> F a
3838

3939
class GenericEncodeFields a where
40-
encodeFields :: a -> S.StrMap Foreign
40+
encodeFields :: Options -> a -> S.StrMap Foreign
4141

4242
class GenericCountArgs a where
4343
countArgs :: Proxy a -> Either a Int
@@ -74,13 +74,13 @@ instance genericDecodeConstructor
7474
case numArgs of
7575
Left a -> pure a
7676
Right 1 | opts.unwrapSingleArguments -> do
77-
{ result, rest } <- decodeArgs 0 (singleton args)
77+
{ result, rest } <- decodeArgs opts 0 (singleton args)
7878
unless (null rest) $
7979
fail (ForeignError "Expected a single argument")
8080
pure result
8181
Right n -> do
8282
vals <- readArray args
83-
{ result, rest } <- decodeArgs 0 (fromFoldable vals)
83+
{ result, rest } <- decodeArgs opts 0 (fromFoldable vals)
8484
unless (null rest) $
8585
fail (ForeignError ("Expected " <> show n <> " constructor arguments"))
8686
pure result
@@ -99,7 +99,7 @@ instance genericEncodeConstructor
9999
ctorName = reflectSymbol (SProxy :: SProxy name)
100100

101101
encodeArgsArray :: rep -> Maybe Foreign
102-
encodeArgsArray = unwrapArguments <<< toUnfoldable <<< encodeArgs
102+
encodeArgsArray = unwrapArguments <<< toUnfoldable <<< encodeArgs opts
103103

104104
unwrapArguments :: Array Foreign -> Maybe Foreign
105105
unwrapArguments [] = Nothing
@@ -122,75 +122,75 @@ instance genericEncodeSum
122122
encodeOpts opts (Inr b) = encodeOpts (opts { unwrapSingleConstructors = false }) b
123123

124124
instance genericDecodeArgsNoArguments :: GenericDecodeArgs NoArguments where
125-
decodeArgs i Nil = pure { result: NoArguments, rest: Nil, next: i }
126-
decodeArgs _ _ = fail (ForeignError "Too many constructor arguments")
125+
decodeArgs _ i Nil = pure { result: NoArguments, rest: Nil, next: i }
126+
decodeArgs _ _ _ = fail (ForeignError "Too many constructor arguments")
127127

128128
instance genericEncodeArgsNoArguments :: GenericEncodeArgs NoArguments where
129129
encodeArgs _ = mempty
130130

131131
instance genericDecodeArgsArgument
132132
:: Decode a
133133
=> GenericDecodeArgs (Argument a) where
134-
decodeArgs i (x : xs) = do
134+
decodeArgs _ i (x : xs) = do
135135
a <- mapExcept (lmap (map (ErrorAtIndex i))) (decode x)
136136
pure { result: Argument a, rest: xs, next: i + 1 }
137-
decodeArgs _ _ = fail (ForeignError "Not enough constructor arguments")
137+
decodeArgs _ _ _ = fail (ForeignError "Not enough constructor arguments")
138138

139139
instance genericEncodeArgsArgument
140140
:: Encode a
141141
=> GenericEncodeArgs (Argument a) where
142-
encodeArgs (Argument a) = singleton (encode a)
142+
encodeArgs _ (Argument a) = singleton (encode a)
143143

144144
instance genericDecodeArgsProduct
145145
:: (GenericDecodeArgs a, GenericDecodeArgs b)
146146
=> GenericDecodeArgs (Product a b) where
147-
decodeArgs i xs = do
148-
{ result: resA, rest: xs1, next: i1 } <- decodeArgs i xs
149-
{ result: resB, rest, next } <- decodeArgs i1 xs1
147+
decodeArgs opts i xs = do
148+
{ result: resA, rest: xs1, next: i1 } <- decodeArgs opts i xs
149+
{ result: resB, rest, next } <- decodeArgs opts i1 xs1
150150
pure { result: Product resA resB, rest, next }
151151

152152
instance genericEncodeArgsProduct
153153
:: (GenericEncodeArgs a, GenericEncodeArgs b)
154154
=> GenericEncodeArgs (Product a b) where
155-
encodeArgs (Product a b) = encodeArgs a <> encodeArgs b
155+
encodeArgs opts (Product a b) = encodeArgs opts a <> encodeArgs opts b
156156

157157
instance genericDecodeArgsRec
158158
:: GenericDecodeFields fields
159159
=> GenericDecodeArgs (Rec fields) where
160-
decodeArgs i (x : xs) = do
161-
fields <- mapExcept (lmap (map (ErrorAtIndex i))) (decodeFields x)
160+
decodeArgs opts i (x : xs) = do
161+
fields <- mapExcept (lmap (map (ErrorAtIndex i))) (decodeFields opts x)
162162
pure { result: Rec fields, rest: xs, next: i + 1 }
163-
decodeArgs _ _ = fail (ForeignError "Not enough constructor arguments")
163+
decodeArgs _ _ _ = fail (ForeignError "Not enough constructor arguments")
164164

165165
instance genericEncodeArgsRec
166166
:: GenericEncodeFields fields
167167
=> GenericEncodeArgs (Rec fields) where
168-
encodeArgs (Rec fs) = singleton (toForeign (encodeFields fs))
168+
encodeArgs opts (Rec fs) = singleton (toForeign (encodeFields opts fs))
169169

170170
instance genericDecodeFieldsField
171171
:: (IsSymbol name, Decode a)
172172
=> GenericDecodeFields (Field name a) where
173-
decodeFields x = do
174-
let name = reflectSymbol (SProxy :: SProxy name)
173+
decodeFields opts x = do
174+
let name = opts.fieldTransform $ reflectSymbol (SProxy :: SProxy name)
175175
-- If `name` field doesn't exist, then `y` will be `undefined`.
176176
Field <$> (index x name >>= mapExcept (lmap (map (ErrorAtProperty name))) <<< decode)
177177

178178
instance genericEncodeFieldsField
179179
:: (IsSymbol name, Encode a)
180180
=> GenericEncodeFields (Field name a) where
181-
encodeFields (Field a) =
182-
let name = reflectSymbol (SProxy :: SProxy name)
181+
encodeFields opts (Field a) =
182+
let name = opts.fieldTransform $ reflectSymbol (SProxy :: SProxy name)
183183
in S.singleton name (encode a)
184184

185185
instance genericDecodeFieldsProduct
186186
:: (GenericDecodeFields a, GenericDecodeFields b)
187187
=> GenericDecodeFields (Product a b) where
188-
decodeFields x = Product <$> decodeFields x <*> decodeFields x
188+
decodeFields opts x = Product <$> decodeFields opts x <*> decodeFields opts x
189189

190190
instance genericEncodeFieldsProduct
191191
:: (GenericEncodeFields a, GenericEncodeFields b)
192192
=> GenericEncodeFields (Product a b) where
193-
encodeFields (Product a b) = encodeFields a `S.union` encodeFields b
193+
encodeFields opts (Product a b) = encodeFields opts a `S.union` encodeFields opts b
194194

195195
instance genericCountArgsNoArguments :: GenericCountArgs NoArguments where
196196
countArgs _ = Left NoArguments

src/Data/Foreign/Generic/Types.purs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ type Options =
44
{ sumEncoding :: SumEncoding
55
, unwrapSingleConstructors :: Boolean
66
, unwrapSingleArguments :: Boolean
7+
, fieldTransform :: String -> String
78
}
89

910
-- | The encoding of sum types for your type.

test/Main.purs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ import Control.Monad.Except (runExcept)
88
import Data.Bifunctor (bimap)
99
import Data.Either (Either(..))
1010
import Data.Foreign.Class (class Encode, class Decode)
11-
import Data.Foreign.Generic (decodeJSON, encodeJSON)
11+
import Data.Foreign.Generic (decodeJSON, defaultOptions, encodeJSON, genericDecodeJSON, genericEncodeJSON)
12+
import Data.Foreign.Generic.Class (class GenericDecode, class GenericEncode, encodeFields)
1213
import Data.Foreign.Generic.EnumEncoding (class GenericDecodeEnum, class GenericEncodeEnum, GenericEnumOptions, genericDecodeEnum, genericEncodeEnum)
14+
import Data.Foreign.Generic.Types (Options, SumEncoding(..))
1315
import Data.Foreign.JSON (parseJSON)
1416
import Data.Foreign.NullOrUndefined (NullOrUndefined(..))
1517
import Data.Generic.Rep (class Generic)
@@ -49,6 +51,25 @@ testRoundTrip x = do
4951
Right y -> assert (x == y)
5052
Left err -> throw (show err)
5153

54+
testGenericRoundTrip
55+
:: a r eff
56+
. Eq a
57+
=> Generic a r
58+
=> GenericDecode r
59+
=> GenericEncode r
60+
=> Options
61+
-> a
62+
-> Eff ( console :: CONSOLE
63+
, assert :: ASSERT
64+
| eff
65+
) Unit
66+
testGenericRoundTrip opts x = do
67+
let json = genericEncodeJSON opts x
68+
log json
69+
case runExcept (genericDecodeJSON opts json) of
70+
Right y -> assert (x == y)
71+
Left err -> throw (show err)
72+
5273
testOption
5374
:: a rep eff
5475
. Eq a
@@ -99,3 +120,7 @@ main = do
99120
testRoundTrip (makeTree 5)
100121
testRoundTrip (StrMap.fromFoldable [Tuple "one" 1, Tuple "two" 2])
101122
testUnaryConstructorLiteral
123+
let opts = defaultOptions { fieldTransform = toUpper }
124+
testGenericRoundTrip opts (RecordTest { foo: 1, bar: "test", baz: 'a' })
125+
126+

0 commit comments

Comments
 (0)