packages feed

spotify-0.1.0.0: types/Spotify/Types/Internal/CustomJSON.hs

{-# LANGUAGE UndecidableInstances #-}

module Spotify.Types.Internal.CustomJSON where

import Data.Aeson (
    FromJSON (parseJSON),
    GFromJSON,
    Options (constructorTagModifier, fieldLabelModifier),
    Zero,
    defaultOptions,
    genericParseJSON,
 )
import Data.Char (isUpper, toLower)
import Data.List (dropWhileEnd, stripPrefix)
import Data.Maybe (fromMaybe)
import GHC.Generics (Generic (Rep))
import Type.Reflection (Typeable, typeRep)

newtype CustomJSON a = CustomJSON a deriving (Generic)
instance (Generic a, GFromJSON Zero (Rep a), Typeable a) => FromJSON (CustomJSON a) where
    parseJSON = fmap CustomJSON . genericParseJSON defaultOptions{constructorTagModifier, fieldLabelModifier}
      where
        fieldLabelModifier = camelToSnake . dropWhileEnd (== '_')
        constructorTagModifier = camelToSnake . (fromMaybe <*> stripPrefix (show $ typeRep @a))
        camelToSnake = \case
            [] -> []
            x : xs -> toLower x : go xs
          where
            go = \case
                [] -> []
                x : xs ->
                    if isUpper x
                        then '_' : toLower x : go xs
                        else x : go xs