Skip to content

Commit f6d6ccd

Browse files
authored
Add new --omitEmpty option (#842)
... as proposed in dhall-lang/dhall-kubernetes#46 (comment) `--omitEmpty` is the same as `--omitNull` except it also omits fields that are empty records. To be precise, it omits fields whose transitive fields are all `null` (and an empty record is a special case of a record whose transitive fields are all `null` since it is vacuously true when there are no fields). This allows Dhall configurations that target YAML to avoid having to nest sub-records inside of an `Optional` value. Omitting unnecessary `Optional` layers reduces the number of default values that the configuration format needs to thread around.
1 parent aa35981 commit f6d6ccd

File tree

4 files changed

+49
-24
lines changed

4 files changed

+49
-24
lines changed

dhall-json/dhall-json.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ Executable dhall-to-yaml
6363
Main-Is: Main.hs
6464
Build-Depends:
6565
base ,
66+
aeson ,
6667
bytestring < 0.11,
6768
dhall ,
6869
dhall-json ,

dhall-json/dhall-to-json/Main.hs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module Main where
66
import Control.Applicative ((<|>))
77
import Control.Exception (SomeException)
88
import Control.Monad (when)
9+
import Data.Aeson (Value)
910
import Data.Monoid ((<>))
1011
import Data.Version (showVersion)
1112
import Dhall.JSON (Conversion)
@@ -28,7 +29,7 @@ import qualified System.IO
2829
data Options = Options
2930
{ explain :: Bool
3031
, pretty :: Bool
31-
, omitNull :: Bool
32+
, omission :: Value -> Value
3233
, version :: Bool
3334
, conversion :: Conversion
3435
}
@@ -38,7 +39,7 @@ parseOptions =
3839
Options
3940
<$> parseExplain
4041
<*> parsePretty
41-
<*> parseOmitNull
42+
<*> Dhall.JSON.parseOmission
4243
<*> parseVersion
4344
<*> Dhall.JSON.parseConversion
4445
where
@@ -68,12 +69,6 @@ parseOptions =
6869
defaultBehavior =
6970
pure False
7071

71-
parseOmitNull =
72-
Options.Applicative.switch
73-
( Options.Applicative.long "omitNull"
74-
<> Options.Applicative.help "Omit record fields that are null"
75-
)
76-
7772
parseVersion =
7873
Options.Applicative.switch
7974
( Options.Applicative.long "version"
@@ -111,11 +106,9 @@ main = do
111106

112107
let explaining = if explain then Dhall.detailed else id
113108

114-
let omittingNull = if omitNull then Dhall.JSON.omitNull else id
115-
116109
stdin <- Data.Text.IO.getContents
117110

118-
json <- omittingNull <$> explaining (Dhall.JSON.codeToValue conversion "(stdin)" stdin)
111+
json <- omission <$> explaining (Dhall.JSON.codeToValue conversion "(stdin)" stdin)
119112

120113
Data.ByteString.Char8.putStrLn $ Data.ByteString.Lazy.toStrict $ encode json
121114

dhall-json/dhall-to-yaml/Main.hs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
module Main where
55

66
import Control.Exception (SomeException)
7+
import Data.Aeson (Value)
78
import Data.Monoid ((<>))
89
import Dhall.JSON (Conversion)
910
import Options.Applicative (Parser, ParserInfo)
@@ -22,7 +23,7 @@ import qualified System.IO
2223

2324
data Options = Options
2425
{ explain :: Bool
25-
, omitNull :: Bool
26+
, omission :: Value -> Value
2627
, documents :: Bool
2728
, conversion :: Conversion
2829
}
@@ -31,7 +32,7 @@ parseOptions :: Parser Options
3132
parseOptions =
3233
Options
3334
<$> parseExplain
34-
<*> parseOmitNull
35+
<*> Dhall.JSON.parseOmission
3536
<*> parseDocuments
3637
<*> Dhall.JSON.parseConversion
3738
where
@@ -41,12 +42,6 @@ parseOptions =
4142
<> Options.Applicative.help "Explain error messages in detail"
4243
)
4344

44-
parseOmitNull =
45-
Options.Applicative.switch
46-
( Options.Applicative.long "omitNull"
47-
<> Options.Applicative.help "Omit record fields that are null"
48-
)
49-
5045
parseDocuments =
5146
Options.Applicative.switch
5247
( Options.Applicative.long "documents"
@@ -70,11 +65,9 @@ main = do
7065
handle $ do
7166
let explaining = if explain then Dhall.detailed else id
7267

73-
let omittingNull = if omitNull then Dhall.JSON.omitNull else id
74-
7568
stdin <- Data.Text.IO.getContents
7669

77-
json <- omittingNull <$> explaining (Dhall.JSON.codeToValue conversion "(stdin)" stdin)
70+
json <- omission <$> explaining (Dhall.JSON.codeToValue conversion "(stdin)" stdin)
7871

7972
let yaml = case (documents, json) of
8073
(True, Data.Yaml.Array elems)

dhall-json/src/Dhall/JSON.hs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ module Dhall.JSON (
161161
-- * Dhall to JSON
162162
dhallToJSON
163163
, omitNull
164+
, omitEmpty
165+
, parseOmission
164166
, Conversion(..)
165167
, convertToHomogeneousMaps
166168
, parseConversion
@@ -329,8 +331,9 @@ toOrderedList =
329331

330332
-- | Omit record fields that are @null@
331333
omitNull :: Value -> Value
332-
omitNull (Object object) =
333-
Object (fmap omitNull (Data.HashMap.Strict.filter (/= Null) object))
334+
omitNull (Object object) = Object fields
335+
where
336+
fields =Data.HashMap.Strict.filter (/= Null) (fmap omitNull object)
334337
omitNull (Array array) =
335338
Array (fmap omitNull array)
336339
omitNull (String string) =
@@ -342,6 +345,40 @@ omitNull (Bool bool) =
342345
omitNull Null =
343346
Null
344347

348+
{-| Omit record fields that are @null@ or records whose transitive fields are
349+
all null
350+
-}
351+
omitEmpty :: Value -> Value
352+
omitEmpty (Object object) =
353+
if null fields then Null else Object fields
354+
where
355+
fields = Data.HashMap.Strict.filter (/= Null) (fmap omitEmpty object)
356+
omitEmpty (Array array) =
357+
Array (fmap omitEmpty array)
358+
omitEmpty (String string) =
359+
String string
360+
omitEmpty (Number number) =
361+
Number number
362+
omitEmpty (Bool bool) =
363+
Bool bool
364+
omitEmpty Null =
365+
Null
366+
367+
-- | Parser for command-line options related to omitting fields
368+
parseOmission :: Parser (Value -> Value)
369+
parseOmission =
370+
Options.Applicative.flag'
371+
omitNull
372+
( Options.Applicative.long "omitNull"
373+
<> Options.Applicative.help "Omit record fields that are null"
374+
)
375+
<|> Options.Applicative.flag'
376+
omitEmpty
377+
( Options.Applicative.long "omitEmpty"
378+
<> Options.Applicative.help "Omit record fields that are null or empty records"
379+
)
380+
<|> pure id
381+
345382
{-| Specify whether or not to convert association lists of type
346383
@List { mapKey: Text, mapValue : v }@ to records
347384
-}
@@ -691,6 +728,7 @@ convertToHomogeneousMaps (Conversion {..}) e0 = loop (Dhall.Core.normalize e0)
691728
Dhall.Core.Embed a ->
692729
Dhall.Core.Embed a
693730

731+
-- | Parser for command-line options related to homogeneous map support
694732
parseConversion :: Parser Conversion
695733
parseConversion =
696734
conversion

0 commit comments

Comments
 (0)