@@ -1,112 +1,225 @@
11{-# OPTIONS_GHC -Wall #-}
22{-# LANGUAGE OverloadedStrings #-}
33module Reporting.Error.Json
4− ( Error(..)
5− , Problem(..)
6− , DecodeExpectation(..)
7− , ParseError(..)
8− , toReport
4+ ( toReport
95 )
106 where
117
128
13−import qualified Data.Utf8 as Utf8
14−import Data.Word (Word16)
9+import qualified Data.Char as Char
10+import qualified Data.Map as Map
1511
16−import qualified Reporting.Report as Report
12+import Json.Decode (Error(..), Problem(..), DecodeExpectation(..), ParseError(..), StringProblem(..))
13+import qualified Reporting.Annotation as A
14+import qualified Reporting.Doc as D
15+import qualified Reporting.Exit.Help as Help
16+import qualified Reporting.Render.Code as Code
1717
1818
1919
20−-- ERROR
21−
22−
23−data Error e
24− = DecodeProblem (Problem e)
25− | ParseProblem ParseError
26−
27−
28−
29−-- DECODE PROBLEMS
20+-- TO REPORT
3021
3122
32−data Problem e
33− = Field Utf8.String (Problem e)
34− | Index Int (Problem e)
35− | OneOf (Problem e) [Problem e]
36− | Failure e
37− | Expecting DecodeExpectation
23+toReport :: FilePath -> Error x -> Help.Report
24+toReport path err =
25+ case err of
26+ DecodeProblem bytes problem ->
27+ problemToReport (Code.toSource bytes) problem
3828
29+ ParseProblem bytes parseError ->
30+ parseErrorToReport path (Code.toSource bytes) parseError
3931
40−data DecodeExpectation
41− = TObject
42− | TArray
43− | TString
44− | TBool
45− | TInt
46− | TObjectWith Utf8.String
47− | TArrayPair Int
4832
4933
34+-- PARSE ERROR TO REPORT
5035
51−-- PARSE ERROR
5236
37+parseErrorToReport :: FilePath -> Code.Source -> ParseError -> Help.Report
38+parseErrorToReport path source parseError =
39+ let
40+ toSnippet title row col pair =
41+ let pos = A.Position row col in
42+ Help.jsonReport title (Just path) $
43+ Code.toSnippet source (A.Region pos pos) Nothing pair
44+ in
45+ case parseError of
46+ Start row col ->
47+ toSnippet "EXPECTING A VALUE" row col
48+ (
49+ D.reflow $ "I was expecting to see a JSON value next:"
50+ ,
51+ D.stack
52+ [ D.fillSep
53+ ["Try","something","like",D.dullyellow "\"this\"","or"
54+ ,D.dullyellow "42","to","move","on","to","better","hints!"
55+ ]
56+ , D.toSimpleNote $
57+ "The JSON specification does not allow trailing commas, so you can sometimes\
58+ \ get this error in arrays that have an extra comma at the end. In that case,\
59+ \ remove that last comma or add another array entry after it!"
60+ ]
61+ )
5362
54−data ParseError
55− = PIndex Int ParseError Row Col
56− | PField Utf8.String ParseError Row Col
57− | ObjectStart Row Col
58− | ObjectMore Row Col
59− | ObjectEnd Row Col
60− | ArrayStart Row Col
61− | ArrayMore Row Col
62− | ArrayEnd Row Col
63− | StringStart Row Col
64− | StringEnd Row Col
65− | IntStart Row Col
66− | NoLeadingZeros Row Col
67− | NoFloats Row Col
68− | Bool Row Col
69− | Null Row Col
70− | Value Row Col
71− | Colon Row Col
72− | EndOfFile Row Col
63+ ObjectField row col ->
64+ toSnippet "UNFINISHED OBJECT" row col
65+ (
66+ D.reflow $ "I was partway through parsing a JSON object when I got stuck here:"
67+ ,
68+ D.stack
69+ [ D.reflow $ "I was expecting to see a field name next."
70+ , objectNote
71+ ]
72+ )
7373
74+ ObjectColon row col ->
75+ toSnippet "EXPECTING COLON" row col
76+ (
77+ D.reflow $ "I was partway through parsing a JSON object when I got stuck here:"
78+ ,
79+ D.stack
80+ [ D.reflow $ "I was expecting to see a colon next."
81+ , objectNote
82+ ]
83+ )
7484
75−type Row = Word16
76−type Col = Word16
85+ ObjectEnd row col ->
86+ toSnippet "UNFINISHED OBJECT" row col
87+ (
88+ D.reflow $ "I was partway through parsing a JSON object when I got stuck here:"
89+ ,
90+ D.stack
91+ [ D.reflow $
92+ "I was expecting to see a comma or a closing curly brace next."
93+ , D.reflow $
94+ "Is a comma missing on the previous line? Is an array missing a closing square\
95+ \ bracket? It is often something tricky like that!"
96+ , objectNote
97+ ]
98+ )
7799
100+ ArrayEnd row col ->
101+ toSnippet "UNFINISHED ARRAY" row col
102+ (
103+ D.reflow $ "I was partway through parsing a JSON array when I got stuck here:"
104+ ,
105+ D.stack
106+ [ D.reflow $ "I was expecting to see a comma or a closing square bracket next."
107+ , D.reflow $
108+ "Is a comma missing on the previous line? It is often something like that!"
109+ ]
110+ )
111+
112+ StringProblem stringProblem row col ->
113+ case stringProblem of
114+ BadStringEnd ->
115+ toSnippet "ENDLESS STRING" row col
116+ (
117+ D.reflow $
118+ "I got to the end of the line without seeing the closing double quote:"
119+ ,
120+ D.fillSep $
121+ ["Strings","look","like",D.green "\"this\"","with","double"
122+ ,"quotes","on","each","end.","Is","the","closing","double"
123+ ,"quote","missing","in","your","code?"
124+ ]
125+ )
126+
127+ BadStringControlChar ->
128+ toSnippet "UNEXPECTED CONTROL CHARACTER" row col
129+ (
130+ D.reflow $
131+ "I ran into a control character unexpectedly:"
132+ ,
133+ D.reflow $
134+ "These are characters that represent tabs, backspaces, newlines, and\
135+ \ a bunch of other invisible characters. They all come before 20 in the\
136+ \ ASCII range, and they are disallowed by the JSON specificaiton. Maybe\
137+ \ a copy/paste added one of these invisible characters to your JSON?"
138+ )
139+
140+ BadStringEscapeChar ->
141+ toSnippet "UNKNOWN ESCAPE" row col
142+ (
143+ D.reflow $
144+ "Backslashes always start escaped characters, but I do not recognize this one:"
145+ ,
146+ D.stack
147+ [ D.reflow $
148+ "Valid escape characters include:"
149+ , D.dullyellow $ D.indent 4 $ D.vcat $
150+ ["\\\"","\\\\","\\/","\\b","\\f","\\n","\\r","\\t","\\u003D"]
151+ , D.reflow $
152+ "Do you want one of those instead? Maybe you need \\\\ to escape a backslash?"
153+ ]
154+ )
155+
156+ BadStringEscapeHex ->
157+ toSnippet "BAD HEX ESCAPE" row col
158+ (
159+ D.reflow $
160+ "This is not a valid hex escape:"
161+ ,
162+ D.fillSep $
163+ ["Valid","hex","escapes","in","JSON","are","between"
164+ ,D.green "\\u0000","and",D.green "\\uFFFF"
165+ ,"and","always","have","exactly","four","digits."
166+ ]
167+ )
168+
169+ NoLeadingZeros row col ->
170+ toSnippet "BAD NUMBER" row col
171+ (
172+ D.reflow $ "Numbers cannot start with zeros like this:"
173+ ,
174+ D.reflow $ "Try deleting the leading zeros?"
175+ )
176+
177+ NoFloats row col ->
178+ toSnippet "UNEXPECTED NUMBER" row col
179+ (
180+ D.reflow $ "I got stuck while trying to parse this number:"
181+ ,
182+ D.reflow $
183+ "I do not accept floating point numbers like 3.1415 right now. That kind\
184+ \ of JSON value is not needed for any of the uses that Elm has for now."
185+ )
186+
187+ BadEnd row col ->
188+ toSnippet "JSON PROBLEM" row col
189+ (
190+ D.reflow $ "I was partway through parsing some JSON when I got stuck here:"
191+ ,
192+ D.reflow $
193+ "I am not really sure what is wrong. This sometimes means there is extra\
194+ \ stuff after a valid JSON value?"
195+ )
196+
197+
198+objectNote :: D.Doc
199+objectNote =
200+ D.stack
201+ [ D.toSimpleNote $ "Here is an example of a valid JSON object for reference:"
202+ , D.vcat
203+ [ D.indent 4 $ "{"
204+ , D.indent 6 $ D.dullyellow "\"name\"" <> ": " <> D.dullyellow "\"Tom\"" <> ","
205+ , D.indent 6 $ D.dullyellow "\"age\"" <> ": " <> D.dullyellow "42"
206+ , D.indent 4 $ "}"
207+ ]
208+ , D.reflow $
209+ "Notice that (1) the field names are in double quotes and (2) there is no\
210+ \ trailing comma after the last entry. Both are strict requirements in JSON!"
211+ ]
78212
79213
80−-- TO REPORT
81214
215+-- PROBLEM TO REPORT
82216
83−toReport :: Error e -> Report.Report
84−toReport err =
85− error "TODO Reporting.Error.Json.toReport" err
86217
218+problemToReport :: Code.Source -> Problem x -> Help.Report
219+problemToReport source problem =
220+ error "TODO problemToReport" source problem
87221
88222{-
89−
90−-- ERROR
91−
92−
93−data Error e
94− = BadJson Syntax.Error
95− | BadContent (Json.Error e)
96−
97−
98−
99−-- TO DOC
100−
101−
102−toDoc :: String -> Code.Source -> (e -> [D.Doc]) -> Error e -> D.Doc
103−toDoc rootName source userErrorToDocs err =
104− case err of
105− BadJson syntaxError ->
106− case Syntax.toReport source syntaxError of
107− Report.Report _ _ _ doc ->
108− doc
109−
110223 BadContent jsonError ->
111224 case flatten jsonError of
112225 [] ->
@@ -312,9 +425,9 @@ addName name err subErrors =
312425 Map.alter subAdd name subErrors
313426
314427
315−fieldToName :: Text.Text -> String
428+fieldToName :: [Char] -> String
316429fieldToName field =
317− case Text.unpack field of
430+ case field of
318431 [] ->
319432 "['']"
320433
@@ -328,5 +441,4 @@ fieldToName field =
328441indexToName :: Int -> String
329442indexToName index =
330443 "[" ++ show index ++ "]"
331−
332444-}