-- Based off of [this gist for a JSON parser using Parsec](https://gist.github.com/fero23/51f63a33d733055d53b4)

{-# LANGUAGE ExistentialQuantification #-}

module Text.Parser.HOCON.Internal
  ( objectParser
  , stringParser
  , parseProps
  , parseLabel
  , arrayParser
  , numberParser
  , booleanParser
  , nullParser
  , preProcessing
  , hoconParser
  , postProcessing
  )
where

import Data.Bifunctor.Extra (mapValues)
import Data.HOCON (Config(..))
import Data.List.Split (splitOn)
import Data.Map (groupBy, sortByKey, Map)
import Data.String.Utils (replace, join, strip)
import Text.ParserCombinators.Parsec
  (char, Parser, alphaNum, digit, letter, noneOf, oneOf, space, string, between, sepBy, (<|>), many, many1, skipMany, try)

whitespace :: Parser ()
whitespace :: Parser ()
whitespace = ParsecT String () Identity Char -> Parser ()
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m ()
skipMany ParsecT String () Identity Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
space

objectParser :: Parser Config
objectParser :: Parser Config
objectParser = do
  Parser ()
whitespace Parser ()
-> ParsecT String () Identity Char
-> ParsecT String () Identity Char
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'{' ParsecT String () Identity Char -> Parser () -> Parser ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Parser ()
whitespace
  [(String, Config)]
props <- ParsecT String () Identity (String, Config)
-> Parser () -> ParsecT String () Identity [(String, Config)]
forall s (m :: * -> *) t u a sep.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m sep -> ParsecT s u m [a]
sepBy ParsecT String () Identity (String, Config)
parseProps (Parser ()
whitespace Parser ()
-> ParsecT String () Identity Char
-> ParsecT String () Identity Char
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
',' ParsecT String () Identity Char
-> ParsecT String () Identity Char
-> ParsecT String () Identity Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'\n') ParsecT String () Identity Char -> Parser () -> Parser ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Parser ()
whitespace)
  Parser ()
whitespace Parser ()
-> ParsecT String () Identity Char
-> ParsecT String () Identity Char
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'}' ParsecT String () Identity Char -> Parser () -> Parser ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Parser ()
whitespace
  Config -> Parser Config
forall (m :: * -> *) a. Monad m => a -> m a
return (Config -> Parser Config) -> Config -> Parser Config
forall a b. (a -> b) -> a -> b
$ [(String, Config)] -> Config
HOCONNode [(String, Config)]
props

parseString :: Parser String
parseString :: Parser String
parseString = Parser String
parseStr Parser String -> Parser String -> Parser String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> Parser String
parseOpenStr

parseStr :: Parser String
parseStr :: Parser String
parseStr = ParsecT String () Identity Char
-> ParsecT String () Identity Char
-> Parser String
-> Parser String
forall s (m :: * -> *) t u open close a.
Stream s m t =>
ParsecT s u m open
-> ParsecT s u m close -> ParsecT s u m a -> ParsecT s u m a
between (Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'\"') (Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'\"') (ParsecT String () Identity Char -> Parser String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many (ParsecT String () Identity Char -> Parser String)
-> ParsecT String () Identity Char -> Parser String
forall a b. (a -> b) -> a -> b
$ String -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
noneOf String
"\"" ParsecT String () Identity Char
-> ParsecT String () Identity Char
-> ParsecT String () Identity Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String () Identity Char -> ParsecT String () Identity Char
forall tok st a. GenParser tok st a -> GenParser tok st a
try (String -> Parser String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"\"\"" Parser String
-> ParsecT String () Identity Char
-> ParsecT String () Identity Char
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Char -> ParsecT String () Identity Char
forall (m :: * -> *) a. Monad m => a -> m a
return Char
'"'))

parseOpenStr :: Parser String
parseOpenStr :: Parser String
parseOpenStr = do
  Char
l   <- ParsecT String () Identity Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
letter
  String
str <- ParsecT String () Identity Char -> Parser String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many (ParsecT String () Identity Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
alphaNum ParsecT String () Identity Char
-> ParsecT String () Identity Char
-> ParsecT String () Identity Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> String -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf String
"._-")
  String -> Parser String
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Parser String) -> String -> Parser String
forall a b. (a -> b) -> a -> b
$ Char
l Char -> String -> String
forall a. a -> [a] -> [a]
: String
str

parseProps :: Parser (String, Config)
parseProps :: ParsecT String () Identity (String, Config)
parseProps = do
  String
label <- Parser String
parseString
  Config
value <- Parser ()
whitespace Parser () -> Parser Config -> Parser Config
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (Parser Config
parseJsonLikeValue Parser Config -> Parser Config -> Parser Config
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> Parser Config
parseObjectValue)
  (String, Config) -> ParsecT String () Identity (String, Config)
forall (m :: * -> *) a. Monad m => a -> m a
return ((String, Config) -> ParsecT String () Identity (String, Config))
-> (String, Config) -> ParsecT String () Identity (String, Config)
forall a b. (a -> b) -> a -> b
$ String -> Config -> (String, Config)
splitProp String
label Config
value
 where
  parseJsonLikeValue :: Parser Config
parseJsonLikeValue = do
    (Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
':' ParsecT String () Identity Char
-> ParsecT String () Identity Char
-> ParsecT String () Identity Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'=') ParsecT String () Identity Char -> Parser () -> Parser ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Parser ()
whitespace
    Parser Config
objectParser Parser Config -> Parser Config -> Parser Config
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> Parser Config
arrayParser Parser Config -> Parser Config -> Parser Config
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> Parser Config
booleanParser Parser Config -> Parser Config -> Parser Config
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> Parser Config
nullParser Parser Config -> Parser Config -> Parser Config
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> Parser Config
stringParser Parser Config -> Parser Config -> Parser Config
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> Parser Config
numberParser
  parseObjectValue :: Parser Config
parseObjectValue = Parser Config
objectParser

parseLabel :: Parser String
parseLabel :: Parser String
parseLabel = do
  Parser ()
whitespace
  String
label <- Parser String
parseString
  Parser ()
whitespace Parser ()
-> ParsecT String () Identity Char
-> ParsecT String () Identity Char
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
':' ParsecT String () Identity Char
-> ParsecT String () Identity Char
-> ParsecT String () Identity Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'=') ParsecT String () Identity Char -> Parser () -> Parser ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Parser ()
whitespace
  String -> Parser String
forall (m :: * -> *) a. Monad m => a -> m a
return String
label

numberParser :: Parser Config
numberParser :: Parser Config
numberParser = do
  Parser ()
whitespace
  String
digits <- ParsecT String () Identity Char -> Parser String
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
many1 (ParsecT String () Identity Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
digit ParsecT String () Identity Char
-> ParsecT String () Identity Char
-> ParsecT String () Identity Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> String -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf String
".-")
  Parser ()
whitespace
  Config -> Parser Config
forall (m :: * -> *) a. Monad m => a -> m a
return (Config -> Parser Config)
-> (Double -> Config) -> Double -> Parser Config
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> Config
HOCONNumber (Double -> Parser Config) -> Double -> Parser Config
forall a b. (a -> b) -> a -> b
$ String -> Double
forall a. Read a => String -> a
read String
digits

stringParser :: Parser Config
stringParser :: Parser Config
stringParser = do
  Parser ()
whitespace
  String
str <- Parser String
parseStr Parser String -> Parser String -> Parser String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> Parser String
parseOpenStr
  Parser ()
whitespace
  Config -> Parser Config
forall (m :: * -> *) a. Monad m => a -> m a
return (Config -> Parser Config) -> Config -> Parser Config
forall a b. (a -> b) -> a -> b
$ String -> Config
HOCONString String
str

booleanParser :: Parser Config
booleanParser :: Parser Config
booleanParser = do
  Parser ()
whitespace
  String
bool <- Parser String -> Parser String
forall tok st a. GenParser tok st a -> GenParser tok st a
try (String -> Parser String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"true" Parser String -> Parser String -> Parser String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> String -> Parser String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"false")
  Parser ()
whitespace
  Config -> Parser Config
forall (m :: * -> *) a. Monad m => a -> m a
return (Config -> Parser Config) -> Config -> Parser Config
forall a b. (a -> b) -> a -> b
$ if String
bool String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"true" then Bool -> Config
HOCONBool Bool
True else Bool -> Config
HOCONBool Bool
False

nullParser :: Parser Config
nullParser :: Parser Config
nullParser = do
  Parser ()
whitespace Parser () -> Parser String -> Parser String
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> String -> Parser String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"null" Parser String -> Parser () -> Parser ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Parser ()
whitespace
  Config -> Parser Config
forall (m :: * -> *) a. Monad m => a -> m a
return Config
HOCONNull

arrayParser :: Parser Config
arrayParser :: Parser Config
arrayParser = do
  Parser ()
whitespace Parser ()
-> ParsecT String () Identity Char
-> ParsecT String () Identity Char
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'[' ParsecT String () Identity Char -> Parser () -> Parser ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Parser ()
whitespace
  [Config]
array <- Parser Config -> Parser () -> ParsecT String () Identity [Config]
forall s (m :: * -> *) t u a sep.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m sep -> ParsecT s u m [a]
sepBy
    (Parser Config
objectParser Parser Config -> Parser Config -> Parser Config
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> Parser Config
arrayParser Parser Config -> Parser Config -> Parser Config
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> Parser Config
booleanParser Parser Config -> Parser Config -> Parser Config
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> Parser Config
nullParser Parser Config -> Parser Config -> Parser Config
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> Parser Config
stringParser Parser Config -> Parser Config -> Parser Config
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> Parser Config
numberParser)
    (Parser ()
whitespace Parser ()
-> ParsecT String () Identity Char
-> ParsecT String () Identity Char
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
',' ParsecT String () Identity Char -> Parser () -> Parser ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Parser ()
whitespace)
  Parser ()
whitespace Parser ()
-> ParsecT String () Identity Char
-> ParsecT String () Identity Char
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
']' ParsecT String () Identity Char -> Parser () -> Parser ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Parser ()
whitespace
  Config -> Parser Config
forall (m :: * -> *) a. Monad m => a -> m a
return (Config -> Parser Config) -> Config -> Parser Config
forall a b. (a -> b) -> a -> b
$ [Config] -> Config
HOCONList [Config]
array

splitProp :: String -> Config -> (String, Config)
splitProp :: String -> Config -> (String, Config)
splitProp String
label Config
value = case String -> String -> [String]
forall a. Eq a => [a] -> [a] -> [[a]]
splitOn String
"." String
label of
  [String
l         ] -> (String
l, Config
value)
  (String
l : [String]
nested) -> (String
l, [String] -> Config -> Config
join [String]
nested Config
value)
 where
  join :: [String] -> Config -> Config
join [String
l     ] Config
value = [(String, Config)] -> Config
HOCONNode [(String
l, Config
value)]
  join (String
l : [String]
ls) Config
value = [(String, Config)] -> Config
HOCONNode [(String
l, [String] -> Config -> Config
join [String]
ls Config
value)]


preProcessing :: String -> String
preProcessing :: String -> String
preProcessing =
  String -> String -> String -> String
forall a. Eq a => [a] -> [a] -> [a] -> [a]
replace String
"\n" String
","
    (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String -> String
forall a. Eq a => [a] -> [a] -> [a] -> [a]
replace String
"[\n" String
"["
    (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String -> String
forall a. Eq a => [a] -> [a] -> [a] -> [a]
replace String
"\n]" String
"]"
    (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String -> String
forall a. Eq a => [a] -> [a] -> [a] -> [a]
replace String
"{\n" String
"{"
    (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String -> String
forall a. Eq a => [a] -> [a] -> [a] -> [a]
replace String
"\n}" String
"}"
    (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String -> String
forall a. Eq a => [a] -> [a] -> [a] -> [a]
replace String
",\n" String
","
    (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
join String
"\n"
    ([String] -> String) -> (String -> [String]) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> Bool) -> [String] -> [String]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (String -> Bool) -> String -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null)
    ([String] -> [String])
-> (String -> [String]) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map String -> String
strip
    ([String] -> [String])
-> (String -> [String]) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> [String]
forall a. Eq a => [a] -> [a] -> [[a]]
splitOn String
"\n"

postProcessing :: Config -> Config
postProcessing :: Config -> Config
postProcessing (HOCONNode [(String, Config)]
nodes) = [(String, Config)] -> Config
HOCONNode ([(String, Config)] -> Config)
-> ([(String, Config)] -> [(String, Config)])
-> [(String, Config)]
-> Config
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(String, Config)] -> [(String, Config)]
sort ([(String, Config)] -> [(String, Config)])
-> ([(String, Config)] -> [(String, Config)])
-> [(String, Config)]
-> [(String, Config)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(String, Config)] -> [(String, Config)]
removeDuplicates ([(String, Config)] -> [(String, Config)])
-> ([(String, Config)] -> [(String, Config)])
-> [(String, Config)]
-> [(String, Config)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(String, Config)] -> [(String, Config)]
group ([(String, Config)] -> Config) -> [(String, Config)] -> Config
forall a b. (a -> b) -> a -> b
$ [(String, Config)]
nodes

group :: Map String Config -> Map String Config
group :: [(String, Config)] -> [(String, Config)]
group [(String, Config)]
nodes = do
  let grouped :: Map String [(String, Config)]
grouped = ((String, Config) -> String)
-> [(String, Config)] -> Map String [(String, Config)]
forall k v. (Ord k, Eq k) => (v -> k) -> [v] -> Map k [v]
groupBy (String, Config) -> String
forall a b. (a, b) -> a
fst [(String, Config)]
nodes
  (String
key, [Config]
configs) <- ([(String, Config)] -> [Config])
-> Map String [(String, Config)] -> Map String [Config]
forall b c a. (b -> c) -> Map a b -> Map a c
mapValues (((String, Config) -> Config) -> [(String, Config)] -> [Config]
forall a b. (a -> b) -> [a] -> [b]
map (String, Config) -> Config
forall a b. (a, b) -> b
snd) Map String [(String, Config)]
grouped
  (String, Config) -> [(String, Config)]
forall (m :: * -> *) a. Monad m => a -> m a
return (String
key, if (Config -> Bool) -> [Config] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Config -> Bool
isNode [Config]
configs then [Config] -> Config
mergeAll [Config]
configs else [Config] -> Config
forall a. [a] -> a
head [Config]
configs)
 where
  isNode :: Config -> Bool
isNode Config
n = case Config
n of
    HOCONNode [(String, Config)]
_ -> Bool
True
    Config
_           -> Bool
False

sort :: Map String Config -> Map String Config
sort :: [(String, Config)] -> [(String, Config)]
sort = [(String, Config)] -> [(String, Config)]
forall k v. Ord k => Map k v -> Map k v
sortByKey

hoconParser :: Parser Config
hoconParser :: Parser Config
hoconParser = Config -> Config
postProcessing (Config -> Config) -> Parser Config -> Parser Config
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser Config
parser
 where
  parser :: Parser Config
parser = Parser Config
objectParser Parser Config -> Parser Config -> Parser Config
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> do
    [(String, Config)]
values <- ParsecT String () Identity (String, Config)
-> ParsecT String () Identity Char
-> ParsecT String () Identity [(String, Config)]
forall s (m :: * -> *) t u a sep.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m sep -> ParsecT s u m [a]
sepBy ParsecT String () Identity (String, Config)
parseProps (Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
',')
    Config -> Parser Config
forall (m :: * -> *) a. Monad m => a -> m a
return (Config -> Parser Config) -> Config -> Parser Config
forall a b. (a -> b) -> a -> b
$ [(String, Config)] -> Config
HOCONNode [(String, Config)]
values

removeDuplicates :: Map String Config -> Map String Config
removeDuplicates :: [(String, Config)] -> [(String, Config)]
removeDuplicates = ([(String, Config)] -> (String, Config) -> [(String, Config)])
-> [(String, Config)] -> [(String, Config)] -> [(String, Config)]
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl (\[(String, Config)]
acc (String, Config)
e -> if ((String, Config) -> Bool) -> [(String, Config)] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any ((String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== (String, Config) -> String
forall a b. (a, b) -> a
fst (String, Config)
e) (String -> Bool)
-> ((String, Config) -> String) -> (String, Config) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String, Config) -> String
forall a b. (a, b) -> a
fst) [(String, Config)]
acc then [(String, Config)]
acc else (String, Config)
e (String, Config) -> [(String, Config)] -> [(String, Config)]
forall a. a -> [a] -> [a]
: [(String, Config)]
acc) []

mergeAll :: [Config] -> Config
mergeAll :: [Config] -> Config
mergeAll = (Config -> Config -> Config) -> [Config] -> Config
forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
foldl1 Config -> Config -> Config
merge

merge :: Config -> Config -> Config
merge :: Config -> Config -> Config
merge (HOCONNode [(String, Config)]
a) (HOCONNode [(String, Config)]
b) = [(String, Config)] -> Config
HOCONNode ([(String, Config)]
a [(String, Config)] -> [(String, Config)] -> [(String, Config)]
forall a. [a] -> [a] -> [a]
++ [(String, Config)]
b)