fix: Normalizing unions

This commit is contained in:
vegowotenks 2025-08-21 21:38:05 +02:00
parent 4f9cec2d51
commit 5655e621de

View file

@ -2,6 +2,7 @@
{-# LANGUAGE LambdaCase #-} {-# LANGUAGE LambdaCase #-}
{-# LANGUAGE DerivingVia #-} {-# LANGUAGE DerivingVia #-}
{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE PatternSynonyms #-}
module Language.Json.Type (infer, Type(..), isObject) where module Language.Json.Type (infer, Type(..), isObject) where
import Data.Map.Strict (Map) import Data.Map.Strict (Map)
import Data.Text (Text) import Data.Text (Text)
@ -21,11 +22,19 @@ data Type
| String | String
| Boolean | Boolean
| Array Type | Array Type
| Union (Set Type) -- multiple types are allowed here | Union' (Set Type) -- multiple types are allowed here
| Object (Map Text Type) | Object (Map Text Type)
deriving stock (Show, Ord, Eq, Generic) deriving stock (Show, Ord, Eq, Generic)
deriving PrettySerialize via Generically Type deriving PrettySerialize via Generically Type
pattern Union :: Set Type -> Type
pattern Union set <- Union' set where
Union set = let
merged = mergeUnionObjects set
in case Set.toList merged of
[t] -> t
_ -> Union' merged
instance Semigroup Type where instance Semigroup Type where
(<>) :: Type -> Type -> Type (<>) :: Type -> Type -> Type
(<>) a b = if a == b (<>) a b = if a == b
@ -38,10 +47,10 @@ instance Semigroup Type where
mergeMatched = (Map.zipWithMatched $ const (<>)) -- merge keys present in both maps mergeMatched = (Map.zipWithMatched $ const (<>)) -- merge keys present in both maps
unionNull = (Map.mapMissing $ const (<> Null)) -- mark keys missing in either map as nullable unionNull = (Map.mapMissing $ const (<> Null)) -- mark keys missing in either map as nullable
in Object $ Map.merge unionNull unionNull mergeMatched fieldsA fieldsB in Object $ Map.merge unionNull unionNull mergeMatched fieldsA fieldsB
(Union typesA, Union typesB) -> Union . mergeUnionObjects $ Set.union typesA typesB (Union typesA, Union typesB) -> Union $ Set.union typesA typesB
(Union typesA, _) -> Union . mergeUnionObjects $ Set.insert b typesA (Union typesA, _) -> Union $ Set.insert b typesA
(_, Union typesB) -> Union . mergeUnionObjects $ Set.insert a typesB (_, Union typesB) -> Union $ Set.insert a typesB
_ -> Union . mergeUnionObjects $ Set.fromList [a, b] _ -> Union $ Set.fromList [a, b]
instance Monoid Type where instance Monoid Type where
mempty :: Type mempty :: Type