1{-# LANGUAGE OverloadedStrings #-}
2module Json.Decode.Error
9import Prelude hiding (userError)
10import qualified Data.Char as Char
11import qualified Data.List as List
12import qualified Data.Map as Map
13import qualified Data.Text as Text
15import qualified Json.Decode.Internals as Json
16import qualified Json.Encode as E
17import Reporting.Doc ((<+>), (<>))
18import qualified Reporting.Doc as D
19import qualified Reporting.Error.Syntax as Syntax
20import qualified Reporting.Render.Code as Code
21import qualified Reporting.Report as Report
29 = BadJson Syntax.Error
30 | BadContent (Json.Error e)
37toDoc :: String -> Code.Source -> (e -> [D.Doc]) -> Error e -> D.Doc
38toDoc rootName source userErrorToDocs err =
40 BadJson syntaxError ->
41 case Syntax.toReport source syntaxError of
42 Report.Report _ _ _ doc ->
45 BadContent jsonError ->
46 case flatten jsonError of
49 "I am not sure what is wrong with this JSON. Please create an <http://sscce.org>\
50 \ and share it at <https://github.com/elm/compiler/issues> so I can\
51 \ provide a helpful hint here!"
54 flatErrorToDoc rootName [] userErrorToDocs flatError
58 toNumberedDoc index flatErr =
59 D.dullcyan ("(" <> D.fromInt index <> ")") <+> flatErrorToDoc rootName [] userErrorToDocs flatErr
63 "I have " ++ show (length flatErrors) ++ " theories on what is going wrong:"
65 ++ zipWith toNumberedDoc [1..] flatErrors
72flatErrorToDoc :: String -> [D.Doc] -> (e -> [D.Doc]) -> FlatError e -> D.Doc
73flatErrorToDoc rootName starter userErrorToDocs (FlatError accesses json theory theories) =
80 userErrorToDocs userError
83 ["I","was","expecting"] ++ anExpectedThing tipe
87 D.fillSep (starter ++ explanation)
91 [ D.fillSep $ starter ++ ["The"] ++ actualThing json ++ ["at",accessToDoc rootName accesses,"is","causing","issues."]
92 , D.fillSep explanation
100 ["I","am","having","trouble","with","the"]
102 ++ ["here","because:"]
105 ["I","am","having","trouble","with","the"]
107 ++ ["at",accessToDoc rootName accesses,"because:"]
110 [ D.fillSep (starter ++ introduction)
111 , D.stack (toBullet [] userErrorToDocs theory : map (toBullet ["OR"] userErrorToDocs) theories)
112 , D.reflow "I accept any of these things."
116accessToDoc :: String -> [String] -> D.Doc
117accessToDoc rootName accesses =
118 D.dullyellow (D.fromString (rootName ++ concat accesses))
121actualThing :: E.Value -> [D.Doc]
124 E.Array _ -> [D.red "array"]
125 E.Object _ -> [D.red "object"]
126 E.String _ -> [D.red "string"]
127 E.Boolean b -> [D.red (if b then "true" else "false"),"value"]
128 E.Integer n -> ["number",D.red (D.fromInt n)]
129 E.Number _ -> [D.red "number"]
130 E.Null -> [D.red "null","value"]
133anExpectedThing :: Json.Type -> [D.Doc]
134anExpectedThing tipe =
136 Json.TObject -> ["an", D.green "OBJECT" <> "."]
137 Json.TArray -> ["an", D.green "ARRAY" <> "."]
138 Json.TString -> ["a", D.green "STRING" <> "."]
139 Json.TBool -> ["a", D.green "BOOLEAN" <> "."]
140 Json.TInt -> ["an", D.green "INT" <> "."]
141 Json.TObjectWith field -> ["an",D.green "OBJECT","with","a",D.green ("\"" <> D.fromString (Text.unpack field) <> "\""),"field."]
142 Json.TArrayPair len ->
143 ["an",D.green "ARRAY","with",D.green "TWO","entries."
144 ,"This","array","has",D.fromInt len, if len == 1 then "element." else "elements."
148toBullet :: [D.Doc] -> (e -> [D.Doc]) -> Theory e -> D.Doc
149toBullet intro userErrorToDocs theory =
150 D.indent 4 $ D.fillSep $ (++) intro $
153 userErrorToDocs userError
156 ["I","was","expecting"] ++ anExpectedThing tipe
164 FlatError [String] E.Value (Theory e) [Theory e]
169 | Expecting Json.Type
172flatten :: Json.Error e -> [FlatError e]
175 depth (FlatError accesses _ _ _) =
178 List.sortOn depth $ flattenTree (toErrorTree jsonError)
181flattenTree :: ErrorTree e -> [FlatError e]
182flattenTree (ErrorTree theories subTrees) =
184 addAccess access (FlatError accesses json t ts) =
185 FlatError (access:accesses) json t ts
187 toFlats (name, tree) =
188 map (addAccess name) (flattenTree tree)
191 concatMap toFlats (Map.toList subTrees)
197 (json, theory) : rest ->
198 FlatError [] json theory (map snd rest) : subErrors
207 { _theories :: [(E.Value, Theory e)]
208 , _subErrors :: Map.Map String (ErrorTree e)
212toErrorTree :: Json.Error e -> ErrorTree e
213toErrorTree jsonError =
219 ErrorTree [] Map.empty
222add :: Json.Error e -> ErrorTree e -> ErrorTree e
223add jsonError tree@(ErrorTree theories subErrors) =
225 Json.Field field subErr ->
226 ErrorTree theories (addName (fieldToName field) subErr subErrors)
228 Json.Index index subErr ->
229 ErrorTree theories (addName (indexToName index) subErr subErrors)
232 foldr add tree errors
234 Json.Expecting json tipe ->
235 ErrorTree ((json, Expecting tipe) : theories) subErrors
237 Json.Failure json err ->
238 ErrorTree ((json, Failure err) : theories) subErrors
241addName :: String -> Json.Error e -> Map.Map String (ErrorTree e) -> Map.Map String (ErrorTree e)
242addName name err subErrors =
245 Just (add err (maybe empty id maybeCrush))
247 Map.alter subAdd name subErrors
250fieldToName :: Text.Text -> String
252 case Text.unpack field of
256 string@(char : rest) ->
257 if Char.isAlpha char && all Char.isAlphaNum rest then
260 "['" ++ string ++ "']"
263indexToName :: Int -> String
265 "[" ++ show index ++ "]"
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list