1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Reporting.Error.Json
12import qualified Data.ByteString as BS
13import qualified Data.ByteString.UTF8 as BS_UTF8
14import qualified Data.NonEmptyList as NE
16import Json.Decode (Error(..), Problem(..), DecodeExpectation(..), ParseError(..), StringProblem(..))
17import qualified Reporting.Annotation as A
18import qualified Reporting.Doc as D
19import qualified Reporting.Exit.Help as Help
20import qualified Reporting.Render.Code as Code
27toReport :: FilePath -> FailureToReport x -> Error x -> Reason -> Help.Report
28toReport path ftr err reason =
30 DecodeProblem bytes problem ->
31 problemToReport path ftr (Code.toSource bytes) CRoot problem reason
33 ParseProblem bytes parseError ->
34 parseErrorToReport path (Code.toSource bytes) parseError reason
41because :: Reason -> String -> String
42because (ExplicitReason iNeedThings) problem =
43 iNeedThings ++ " " ++ problem
47-- PARSE ERROR TO REPORT
50parseErrorToReport :: FilePath -> Code.Source -> ParseError -> Reason -> Help.Report
51parseErrorToReport path source parseError reason =
53 toSnippet title row col (problem, details) =
54 let pos = A.Position row col in
55 Help.jsonReport title (Just path) $
56 Code.toSnippet source (A.Region pos pos) Nothing
57 ( D.reflow (because reason problem)
63 toSnippet "EXPECTING A VALUE" row col
65 "I was expecting to see a JSON value next:"
69 ["Try","something","like",D.dullyellow "\"this\"","or"
70 ,D.dullyellow "42","to","move","on","to","better","hints!"
73 "The JSON specification does not allow trailing commas, so you can sometimes\
74 \ get this error in arrays that have an extra comma at the end. In that case,\
75 \ remove that last comma or add another array entry after it!"
79 ObjectField row col ->
80 toSnippet "UNFINISHED OBJECT" row col
82 "I was partway through parsing a JSON object when I got stuck here:"
85 [ D.reflow $ "I was expecting to see a field name next."
90 ObjectColon row col ->
91 toSnippet "EXPECTING COLON" row col
93 "I was partway through parsing a JSON object when I got stuck here:"
96 [ D.reflow $ "I was expecting to see a colon next."
102 toSnippet "UNFINISHED OBJECT" row col
104 "I was partway through parsing a JSON object when I got stuck here:"
108 "I was expecting to see a comma or a closing curly brace next."
110 "Is a comma missing on the previous line? Is an array missing a closing square\
111 \ bracket? It is often something tricky like that!"
117 toSnippet "UNFINISHED ARRAY" row col
119 "I was partway through parsing a JSON array when I got stuck here:"
122 [ D.reflow $ "I was expecting to see a comma or a closing square bracket next."
124 "Is a comma missing on the previous line? It is often something like that!"
128 StringProblem stringProblem row col ->
129 case stringProblem of
131 toSnippet "ENDLESS STRING" row col
133 "I got to the end of the line without seeing the closing double quote:"
136 ["Strings","look","like",D.green "\"this\"","with","double"
137 ,"quotes","on","each","end.","Is","the","closing","double"
138 ,"quote","missing","in","your","code?"
142 BadStringControlChar ->
143 toSnippet "UNEXPECTED CONTROL CHARACTER" row col
145 "I ran into a control character unexpectedly:"
148 "These are characters that represent tabs, backspaces, newlines, and\
149 \ a bunch of other invisible characters. They all come before 20 in the\
150 \ ASCII range, and they are disallowed by the JSON specificaiton. Maybe\
151 \ a copy/paste added one of these invisible characters to your JSON?"
154 BadStringEscapeChar ->
155 toSnippet "UNKNOWN ESCAPE" row col
157 "Backslashes always start escaped characters, but I do not recognize this one:"
161 "Valid escape characters include:"
162 , D.dullyellow $ D.indent 4 $ D.vcat $
163 ["\\\"","\\\\","\\/","\\b","\\f","\\n","\\r","\\t","\\u003D"]
165 "Do you want one of those instead? Maybe you need \\\\ to escape a backslash?"
169 BadStringEscapeHex ->
170 toSnippet "BAD HEX ESCAPE" row col
172 "This is not a valid hex escape:"
175 ["Valid","hex","escapes","in","JSON","are","between"
176 ,D.green "\\u0000","and",D.green "\\uFFFF"
177 ,"and","always","have","exactly","four","digits."
181 NoLeadingZeros row col ->
182 toSnippet "BAD NUMBER" row col
184 "Numbers cannot start with zeros like this:"
186 D.reflow $ "Try deleting the leading zeros?"
190 toSnippet "UNEXPECTED NUMBER" row col
192 "I got stuck while trying to parse this number:"
195 "I do not accept floating point numbers like 3.1415 right now. That kind\
196 \ of JSON value is not needed for any of the uses that Elm has for now."
200 toSnippet "JSON PROBLEM" row col
202 "I was partway through parsing some JSON when I got stuck here:"
205 "I am not really sure what is wrong. This sometimes means there is extra\
206 \ stuff after a valid JSON value?"
213 [ D.toSimpleNote $ "Here is an example of a valid JSON object for reference:"
216 , D.indent 6 $ D.dullyellow "\"name\"" <> ": " <> D.dullyellow "\"Tom\"" <> ","
217 , D.indent 6 $ D.dullyellow "\"age\"" <> ": " <> D.dullyellow "42"
221 "Notice that (1) the field names are in double quotes and (2) there is no\
222 \ trailing comma after the last entry. Both are strict requirements in JSON!"
232 | CField BS.ByteString Context
236problemToReport :: FilePath -> FailureToReport x -> Code.Source -> Context -> Problem x -> Reason -> Help.Report
237problemToReport path ftr source context problem reason =
240 problemToReport path ftr source (CField field context) prob reason
243 problemToReport path ftr source (CIndex index context) prob reason
246 -- NOTE: only displays the deepest problem. This works well for the kind
247 -- of JSON used by Elm, but probably would not work well in general.
249 (NE.List prob _) = NE.sortBy (negate . getMaxDepth) (NE.List p ps)
251 problemToReport path ftr source context prob reason
254 _failureToReport ftr path source context region x
256 Expecting region expectation ->
257 expectationToReport path source context region expectation reason
260getMaxDepth :: Problem x -> Int
263 Field _ prob -> 1 + getMaxDepth prob
264 Index _ prob -> 1 + getMaxDepth prob
265 OneOf p ps -> maximum (getMaxDepth p : map getMaxDepth ps)
270newtype FailureToReport x =
271 FailureToReport { _failureToReport :: FilePath -> Code.Source -> Context -> A.Region -> x -> Help.Report }
274expectationToReport :: FilePath -> Code.Source -> Context -> A.Region -> DecodeExpectation -> Reason -> Help.Report
275expectationToReport path source context (A.Region start end) expectation reason =
277 (A.Position sr _) = start
278 (A.Position er _) = end
281 if sr == er then region else A.Region start start
286 "I ran into some trouble here:"
289 "I ran into trouble with the value of the \"" ++ BS_UTF8.toString field ++ "\" field:"
291 CIndex index (CField field _) ->
292 "When looking at the \"" ++ BS_UTF8.toString field ++ "\" field, I ran into trouble with the "
293 ++ D.intToOrdinal index ++ " entry:"
296 "I ran into trouble with the " ++ D.intToOrdinal index ++ " index of this array:"
298 toSnippet title aThing =
299 Help.jsonReport title (Just path) $
300 Code.toSnippet source region Nothing
301 ( D.reflow (because reason introduction)
302 , D.fillSep $ ["I","was","expecting","to","run","into"] ++ aThing
307 toSnippet "EXPECTING OBJECT" ["an", D.green "OBJECT" <> "."]
310 toSnippet "EXPECTING ARRAY" ["an", D.green "ARRAY" <> "."]
313 toSnippet "EXPECTING STRING" ["a", D.green "STRING" <> "."]
316 toSnippet "EXPECTING BOOL" ["a", D.green "BOOLEAN" <> "."]
319 toSnippet "EXPECTING INT" ["an", D.green "INT" <> "."]
322 toSnippet "MISSING FIELD"
323 ["an",D.green "OBJECT","with","a"
324 ,D.green ("\"" <> D.fromChars (BS_UTF8.toString field) <> "\"")
329 toSnippet "EXPECTING PAIR"
330 ["an",D.green "ARRAY","with",D.green "TWO","entries."
331 ,"This","array","has",D.fromInt len, if len == 1 then "element." else "elements."
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