0 | module Lana.JSON.Decoder
3 | import Data.List.Quantifiers as Bug
4 | import Data.SortedMap as Map
5 | import Data.Finite as Finite
6 | import Data.List.Elem as Bug
8 | import Lana.Name as LC
9 | import Lana.Class as LC
11 | import JSON.Simple.FromJSON as Simp
12 | import JSON.Parser as P
17 | Parser : Type -> Type
18 | Parser a = Either JSONErr a
21 | AObject = List (Pair String P.JSON)
24 | data JDecoder a = MkJDecoder LC.Name (P.JSON -> Parser a)
27 | decodeJSON : JDecoder a -> JSON -> Parser a
28 | decodeJSON (MkJDecoder unusedName f) json = f json
30 | record MyObject (a: Type) where
31 | constructor MkMyObject
33 | decoder: AObject -> Parser a
35 | record MyField (a: Type) where
36 | constructor MkMyField
38 | decoder: AObject -> Parser a
40 | record MyAdditionalFields (a: Type) where
41 | constructor MkMyAdditionalFields
42 | additionalFieldsDecoder: (List String -> AObject -> Parser a)
44 | record MyUnionMembers (allTypes: List Type) where
45 | constructor MkMyUnionMembers
46 | parseNameAndJSON: LC.Name -> JSON ->
47 | Parser (Union allTypes)
49 | mkField : {a: Type} ->
51 | MyObject (a -> b) ->
54 | mkField (MkMyObject fieldNames parseF) fieldVal =
58 | keys = fieldVal.name :: fieldNames
59 | dec : AObject -> Parser b
61 | let p : Parser (a -> b)
63 | in p <*> fieldVal.decoder aObject
65 | mkAdditional: {obj: Type} ->
67 | MyObject (a -> obj) ->
68 | MyAdditionalFields a ->
70 | mkAdditional (MkMyObject fieldNames parseF) fields =
71 | MkMyObject fieldNames dec
73 | dec : AObject -> Parser obj
76 | <*> additionalFieldsDecoder fields fieldNames aObject
78 | mkUnionCombine: {types: List Type} ->
79 | MyUnionMembers types ->
80 | MyUnionMembers types ->
81 | MyUnionMembers types
82 | mkUnionCombine left right =
84 | f : LC.Name -> JSON -> Parser (Union types)
86 | case left.parseNameAndJSON name value of
87 | Right suc => Right suc
89 | case right.parseNameAndJSON name value of
90 | Right suc => Right suc
91 | Left _ => Left . MkPair [] $
92 | "All union parsing options for "
93 | <+> name.nameUnqualified
101 | MyAdditionalFields (Map.SortedMap String a)
102 | mkAdditionalFields (MkJDecoder unusedName parseValue) =
104 | f: List String -> AObject ->
105 | Parser (Map.SortedMap String a)
106 | f definedFields object =
108 | additionalKeysMap : Map.SortedMap String JSON
109 | additionalKeysMap =
112 | (Map.fromList object)
115 | traverse parseValue additionalKeysMap
117 | MkMyAdditionalFields f
119 | mkUnionMemberWithIndex: {a: Type} ->
120 | {types: List Type} ->
122 | (JSON -> Parser a) ->
123 | MyUnionMembers types
124 | mkUnionMemberWithIndex elem parseMember =
125 | MkMyUnionMembers $
\name, json =>
127 | Data.List.Elem.Here =>
128 | map Data.List.Quantifiers.Any.Here $
130 | Data.List.Elem.There there =>
132 | inner = mkUnionMemberWithIndex there parseMember
134 | map Data.List.Quantifiers.Any.There $
135 | inner.parseNameAndJSON name json
138 | implementation LC.Lana JDecoder where
139 | Object = const MyObject
140 | Field = const MyField
141 | AdditionalFields = const MyAdditionalFields
142 | UnionMembers a b = MyUnionMembers a
144 | schemaName (MkJDecoder name unusedParser) = name
147 | MkJDecoder (LC.unqualifiedName "double") $
148 | withDouble "double" pure
151 | MkJDecoder (LC.unqualifiedName "text") $
152 | withString "text" pure
155 | MkJDecoder (LC.unqualifiedName "boolean") $
156 | withBoolean "boolean" pure
158 | array (MkJDecoder name itemForValue) =
159 | MkJDecoder (LC.annotateName name "array") $
160 | withArray "array" (traverse itemForValue)
163 | MkJDecoder (LC.unqualifiedName "null") $
\case
164 | JNull => pure LC.MkNull
165 | _ => Left (MkPair [] "Expected null")
167 | nullable (MkJDecoder name parseValue) =
168 | MkJDecoder (LC.annotateName name "nullable") $
\case
169 | JNull => pure (Left LC.MkNull)
170 | value => map Right (parseValue value)
172 | required key unusedAccessor (MkJDecoder unusedName parseValue) =
173 | MkMyField key $
\aObject =>
174 | explicitParseField parseValue aObject key
176 | optional key unusedAccessor (MkJDecoder unusedName parseValue) =
177 | MkMyField key $
\aObject =>
178 | explicitParseFieldMaybe parseValue aObject key
180 | additionalFields = const mkAdditionalFields
182 | mapField f (MkMyField name parseField) =
183 | MkMyField name (map f . parseField)
186 | MkMyObject [] (\unusedObject => pure f)
190 | additional = mkAdditional
192 | objectNamed name (MkMyObject unusedDefinedFields parseObject) =
194 | withObject (LC.nameToString name) parseObject
196 | finiteNamed name toText =
200 | . map (\e => (toText e, e))
204 | withString (LC.nameToString name) $
\textValue =>
205 | case SortedMap.lookup textValue decodingMap of
206 | Just enumValue => pure enumValue
209 | "Unrecognized value for "
210 | <+> LC.nameToString name
214 | validateNamed name unusedUncheck check (MkJDecoder unusedUnvalidatedName parseValue) =
215 | MkJDecoder name $
\jsonValue => do
216 | uncheckedValue <- parseValue jsonValue
217 | case check uncheckedValue of
218 | Right checkedValue => pure checkedValue
219 | Left err => Left . MkPair [] $
220 | "Error validating "
221 | <+> LC.nameToString name
224 | unionNamed name (MkMyUnionMembers parseMembers) =
225 | MkJDecoder name (parseMembers name)
227 | unionMemberWithIndex index (MkJDecoder unusedName parseMember) =
228 | mkUnionMemberWithIndex index parseMember
230 | unionCombine = mkUnionCombine
232 | jsonString (MkJDecoder name parseValue) =
234 | withString name.nameUnqualified $
\jsonText =>
235 | case parseJSON Virtual jsonText of
238 | "Error decoding nested json string: "
239 | <+> interpolate parseErr.error
240 | Right value => parseValue value