-
Notifications
You must be signed in to change notification settings - Fork 214
/
Yaml.hs
127 lines (110 loc) · 3.91 KB
/
Yaml.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-| Convert Dhall to YAML via JSON
Since JSON is only a subset of YAML, the functionality offered here is more
limited than what the @dhall-yaml@ package can offer.
-}
module Dhall.JSON.Yaml
( Options(..)
, parseDocuments
, parseQuoted
, defaultOptions
, dhallToYaml
, jsonToYaml
, generatedCodeNotice
) where
import Data.ByteString (ByteString)
import Data.Text (Text)
import Dhall.JSON (Conversion (..), SpecialDoubleMode (..))
import Dhall.Parser (Header(..))
import Options.Applicative (Parser)
import qualified Data.Aeson
import qualified Data.Aeson.Yaml
import qualified Data.ByteString.Lazy
import qualified Data.Text.Encoding
import qualified Data.Vector
import qualified Dhall
import qualified Dhall.JSON
import qualified Options.Applicative
data Options = Options
{ explain :: Bool
, omission :: Data.Aeson.Value -> Data.Aeson.Value
, documents :: Bool
, quoted :: Bool
, conversion :: Conversion
, file :: Maybe FilePath
, output :: Maybe FilePath
, noEdit :: Bool
, preserveHeader :: Bool
}
defaultOptions :: Options
defaultOptions =
Options { explain = False
, omission = id
, documents = False
, quoted = False
, conversion = Dhall.JSON.defaultConversion
, file = Nothing
, output = Nothing
, noEdit = False
, preserveHeader = False
}
parseDocuments :: Parser Bool
parseDocuments =
Options.Applicative.switch
( Options.Applicative.long "documents"
<> Options.Applicative.help "If given a Dhall list, output a document for every element. Each document, including the first one, will be preceded by \"---\", even if there is only one document. If not given a list, output a single document (as if it were a list of one element)"
)
parseQuoted :: Parser Bool
parseQuoted =
Options.Applicative.switch
( Options.Applicative.long "quoted"
<> Options.Applicative.help "Prevent from generating not quoted scalars"
)
{-| The notice added to the top of a generated file when enabling the
@--generated-comment@
-}
generatedCodeNotice :: ByteString
generatedCodeNotice = "# Code generated by dhall-to-yaml. DO NOT EDIT.\n"
{-| Convert a piece of Text carrying a Dhall inscription to an equivalent YAML ByteString
-}
dhallToYaml
:: Options
-> Maybe FilePath -- ^ The source file path. If no path is given, imports
-- are resolved relative to the current directory.
-> Text -- ^ Input text.
-> IO ByteString
dhallToYaml Options{..} mFilePath code = do
let explaining = if explain then Dhall.detailed else id
let adapt (header, value) = (header, omission value)
(Header comment, json) <- adapt <$> explaining (Dhall.JSON.codeToHeaderAndValue conversion UseYAMLEncoding mFilePath code)
let suffix
| preserveHeader = Data.Text.Encoding.encodeUtf8 comment
| otherwise = mempty
let header =
if noEdit
then generatedCodeNotice <> suffix
else suffix
return $ header <> jsonToYaml json documents quoted
-- | Transform json representation into yaml
jsonToYaml
:: Data.Aeson.Value
-> Bool
-> Bool
-> ByteString
jsonToYaml json documents quoted =
Data.ByteString.Lazy.toStrict $ case (documents, json) of
(True, Data.Aeson.Array elems)
-> (if quoted
then Data.Aeson.Yaml.encodeQuotedDocuments
else Data.Aeson.Yaml.encodeDocuments
) (Data.Vector.toList elems)
(True, value)
-> (if quoted
then Data.Aeson.Yaml.encodeQuotedDocuments
else Data.Aeson.Yaml.encodeDocuments
) [ value ]
_ -> (if quoted
then Data.Aeson.Yaml.encodeQuoted
else Data.Aeson.Yaml.encode
) json