@@ -67,6 +67,13 @@ module Core.Encoding.Json (
67
67
prettyValue ,
68
68
) where
69
69
70
+ #if MIN_VERSION_aeson(2,0,1)
71
+ import qualified Data.Aeson.Key as Aeson
72
+ import qualified Data.Aeson.KeyMap as Aeson
73
+ #else
74
+ import qualified Data.HashMap.Strict as HashMap
75
+ #endif
76
+
70
77
import Core.Data.Structures (Key , Map , fromMap , intoMap )
71
78
import Core.Text.Bytes (Bytes , fromBytes , intoBytes )
72
79
import Core.Text.Colour (
@@ -86,21 +93,15 @@ import Core.Text.Rope (
86
93
fromRope ,
87
94
intoRope ,
88
95
singletonRope ,
96
+ unconsRope ,
89
97
)
90
98
import Core.Text.Utilities (
91
99
Render (Token , colourize , highlight ),
92
- breakPieces ,
100
+ breakRope ,
93
101
)
94
- import qualified Data.Aeson as Aeson
95
-
96
- #if MIN_VERSION_aeson(2,0,1)
97
- import qualified Data.Aeson.Key as Aeson
98
- import qualified Data.Aeson.KeyMap as Aeson
99
- #else
100
- import qualified Data.HashMap.Strict as HashMap
101
- #endif
102
-
103
102
import Data.Aeson (FromJSON , Value (String ))
103
+ import qualified Data.Aeson as Aeson
104
+ import Data.Char (intToDigit )
104
105
import Data.Coerce
105
106
import Data.Hashable (Hashable )
106
107
import qualified Data.List as List
@@ -178,26 +179,34 @@ encodeToRope value = case value of
178
179
closebracket = singletonRope ' ]'
179
180
180
181
{- |
181
- Escape any quotes or backslashes in a JsonString.
182
+ Escape any quotes, backslashes, or other possible rubbish in a ' JsonString' .
182
183
-}
183
184
escapeString :: Rope -> Rope
184
185
escapeString text =
185
- let text1 = escapeBackslashes text
186
- text2 = escapeQuotes text1
187
- in text2
186
+ let (before, after) = breakRope needsEscaping text
187
+ in case unconsRope after of
188
+ Nothing ->
189
+ text
190
+ Just (c, after') ->
191
+ before <> escapeCharacter c <> escapeString after'
192
+ where
193
+ needsEscaping c =
194
+ c == ' \" ' || c == ' \\ ' || c < ' \x20 '
188
195
{-# INLINEABLE escapeString #-}
189
196
190
- escapeBackslashes :: Rope -> Rope
191
- escapeBackslashes text =
192
- let pieces = breakPieces (== ' \\ ' ) text
193
- in mconcat (List. intersperse " \\\\ " pieces)
194
- {-# INLINEABLE escapeBackslashes #-}
195
-
196
- escapeQuotes :: Rope -> Rope
197
- escapeQuotes text =
198
- let pieces = breakPieces (== ' "' ) text
199
- in mconcat (List. intersperse " \\\" " pieces)
200
- {-# INLINEABLE escapeQuotes #-}
197
+ escapeCharacter :: Char -> Rope
198
+ escapeCharacter c =
199
+ case c of
200
+ ' \" ' -> " \\\" "
201
+ ' \\ ' -> " \\\\ "
202
+ ' \n ' -> " \\ n"
203
+ ' \r ' -> " \\ r"
204
+ ' \t ' -> " \\ t"
205
+ _ ->
206
+ if c < ' \x10 '
207
+ then " \\ u000" <> singletonRope (intToDigit (fromEnum c))
208
+ else " \\ u001" <> singletonRope (intToDigit ((fromEnum c) - 16 ))
209
+ {-# INLINEABLE escapeCharacter #-}
201
210
202
211
{- |
203
212
Given an array of bytes, attempt to decode it as a JSON value.
0 commit comments