1
+ {-# LANGUAGE CPP #-}
1
2
{-# LANGUAGE DataKinds #-}
2
3
{-# LANGUAGE DeriveAnyClass #-}
3
4
{-# LANGUAGE DeriveGeneric #-}
@@ -21,12 +22,17 @@ module Language.LSP.Protocol.Types.Common (
21
22
, (.=?)
22
23
) where
23
24
24
- import Control.Applicative
25
25
import Control.DeepSeq
26
26
import Control.Lens
27
27
import Data.Aeson hiding (Null )
28
28
import qualified Data.Aeson as J
29
+ #if MIN_VERSION_aeson(2,0,0)
30
+ import qualified Data.Aeson.KeyMap as KM
31
+ #else
32
+ import qualified Data.HashMap.Strict as KM
33
+ #endif
29
34
import Data.Hashable
35
+ import Data.Set as Set
30
36
import Data.String (fromString )
31
37
import Data.Int (Int32 )
32
38
import Data.Mod.Word
@@ -93,11 +99,35 @@ instance (ToJSON a, ToJSON b) => ToJSON (a |? b) where
93
99
toJSON (InL x) = toJSON x
94
100
toJSON (InR x) = toJSON x
95
101
96
- instance (FromJSON a , FromJSON b ) => FromJSON (a |? b ) where
97
- -- Important: Try to parse the **rightmost** type first, as in the specification
98
- -- the more complex types tend to appear on the right of the |, e.g.
99
- -- @colorProvider?: boolean | DocumentColorOptions | DocumentColorRegistrationOptions;@
100
- parseJSON v = InR <$> parseJSON v <|> InL <$> parseJSON v
102
+ instance (FromJSON a , ToJSON a , FromJSON b , ToJSON b ) => FromJSON (a |? b ) where
103
+ -- Truly atrocious and abominable hack. The issue is tha we may have siutations
104
+ -- where some input JSON can parse correctly as both sides of the union, because
105
+ -- we have no tag. What do we do in this situation? It's very unclear, and the
106
+ -- spec is no help. The heuristic we adopt here is that it is better to take
107
+ -- the version with "more fields". How do we work that out? By converting back
108
+ -- to JSON and looking at the object fields.
109
+ --
110
+ -- Possibly we could do better by relying on Generic instances for a and b
111
+ -- in order to work out which has more fields on the Haskell side.
112
+ parseJSON v = do
113
+ let ra :: Result a = fromJSON v
114
+ rb :: Result b = fromJSON v
115
+ case (ra, rb) of
116
+ (Success a, Error _) -> pure $ InL a
117
+ (Error _, Success b) -> pure $ InR b
118
+ (Error e, Error _) -> fail e
119
+ (Success a, Success b) -> case (toJSON a, toJSON b) of
120
+ -- Both sides encode to the same thing, just pick one arbitrarily
121
+ (l, r) | l == r -> pure $ InL a
122
+ (Object oa, Object ob) ->
123
+ let ka = Set. fromList $ KM. keys oa
124
+ kb = Set. fromList $ KM. keys ob
125
+ in if kb `Set.isSubsetOf` ka
126
+ then pure $ InL a
127
+ else if ka `Set.isSubsetOf` kb
128
+ then pure $ InR b
129
+ else fail $ " Could not decide which type of value to produce, left encodes to an object with keys: " ++ show ka ++ " ; right has keys " ++ show kb
130
+ (l, r) -> fail $ " Could not decide which type of value to produce, left encodes to: " ++ show l ++ " ; right encodes to: " ++ show r
101
131
102
132
-- We could use 'Proxy' for this, as aeson also serializes it to/from null,
103
133
-- but this is more explicit.
0 commit comments