{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.JsonSpec.OpenApi.Rename (
Rename
) where
import Data.JsonSpec
( FieldSpec(Optional, Required)
, Specification
( JsonArray, JsonBool, JsonDateTime, JsonEither, JsonInt, JsonLet
, JsonNullable, JsonNum, JsonObject, JsonRaw, JsonRef, JsonString, JsonTag
)
)
import GHC.TypeError (ErrorMessage((:$$:)))
import GHC.TypeLits (type (+), AppendSymbol, Nat, Symbol)
import qualified GHC.TypeError as TE
type family Rename (spec :: Specification) :: Specification where
Rename spec =
Fst (FoldRename (G '[]) (A '[]) spec)
type family
Fst
(a :: (Specification, Global))
:: Specification
where
Fst '(spec, global) = spec
type family
FoldRename
(global :: Global)
(active :: Active)
(spec :: Specification)
:: (Specification, Global)
where
FoldRename global active JsonString = '(JsonString, global)
FoldRename global active JsonNum = '(JsonNum, global)
FoldRename global active JsonInt = '(JsonInt, global)
FoldRename global active JsonBool = '(JsonBool, global)
FoldRename global active (JsonTag tag) = '(JsonTag tag, global)
FoldRename global active JsonDateTime = '(JsonDateTime, global)
FoldRename global active JsonRaw = '(JsonRaw, global)
FoldRename global active (JsonNullable spec) =
MapSpec
JsonNullable
(FoldRename global active spec)
FoldRename global active (JsonArray spec) =
MapSpec JsonArray (FoldRename global active spec)
FoldRename global active (JsonObject fields) =
RenameObject global active fields
FoldRename global active (JsonEither left right) =
RenameEither global active left right
FoldRename global active (JsonLet defs spec) =
RenameLet
(UpdateGlobals global defs)
active
defs
spec
FoldRename global (A active) (JsonRef name) =
'(JsonRef (LookupNewName name active), global)
type family
RenameObject
(global :: Global)
(active :: Active)
(fields :: [FieldSpec])
:: (Specification, Global)
where
RenameObject global active fields =
RenameObject2
(FoldReflectFields '( '[], global) active fields)
type family
RenameObject2
(acc :: ([FieldSpec], Global))
:: (Specification, Global)
where
RenameObject2 '(fields, global) =
'(JsonObject (Reverse '[] fields), global)
type family
FoldReflectFields
( acc :: ([FieldSpec], Global))
(active :: Active)
(fields :: [FieldSpec])
:: ([FieldSpec], Global)
where
FoldReflectFields '(acc, global) active '[] = '(acc, global)
FoldReflectFields '(acc, global) active (field : more) =
FoldReflectFields2
acc
active
(ReflectField global active field)
more
type family
FoldReflectFields2
( acc :: [FieldSpec])
(active :: Active)
( field :: (FieldSpec, Global))
( more :: [FieldSpec])
:: ([FieldSpec], Global)
where
FoldReflectFields2 acc active '(field, global) more =
FoldReflectFields
'(field : acc, global)
active
more
type family
ReflectField
(global :: Global)
(active :: Active)
(field :: FieldSpec)
:: (FieldSpec, Global)
where
ReflectField global active (Required name spec) =
ReflectRequiredField
name
(FoldRename global active spec)
ReflectField global active (Optional name spec) =
ReflectOptionalField
name
(FoldRename global active spec)
type family
ReflectRequiredField
(name :: Symbol)
(spec :: (Specification, Global))
:: (FieldSpec, Global)
where
ReflectRequiredField name '(spec, global) =
'(Required name spec, global)
type family
ReflectOptionalField
(name :: Symbol)
(spec :: (Specification, Global))
:: (FieldSpec, Global)
where
ReflectOptionalField name '(spec, global) =
'(Optional name spec, global)
type family
RenameEither
(global :: Global)
(active :: Active)
( left :: Specification)
( right :: Specification)
:: (Specification, Global)
where
RenameEither global active left right =
RenameEither2
active
(FoldRename global active left)
right
type family
RenameEither2
(active :: Active)
( left :: (Specification, Global))
( right :: Specification)
:: (Specification, Global)
where
RenameEither2 active '(left, global) right =
RenameEither3 left (FoldRename global active right)
type family
RenameEither3
(left :: Specification)
(right :: (Specification, Global))
:: (Specification, Global)
where
RenameEither3 left '(right, global) =
'(JsonEither left right, global)
type family
UpdateGlobals
(global :: Global)
( defs :: [(Symbol, Specification)])
:: Global
where
UpdateGlobals global '[] = global
UpdateGlobals (G global) ( '(name, spec) : more) =
UpdateGlobals
(G (IncrementName global name))
more
type family
IncrementName
(global :: [NameState])
( name :: Symbol)
:: [NameState]
where
IncrementName '[] name = '[N name 0]
IncrementName (N name ord : more) name =
N name (ord + 1) : more
IncrementName (N miss ord : more) name =
N miss ord : IncrementName more name
type family
RenameLet
(global :: Global)
(active :: Active)
(defs :: [(Symbol, Specification)])
(spec :: Specification)
:: (Specification, Global)
where
RenameLet global active defs spec =
RenameLet2
global
(UpdateActives global active defs)
defs
spec
type family
RenameLet2
(global :: Global)
(active :: Active)
(defs :: [(Symbol, Specification)])
(spec :: Specification)
where
RenameLet2 global active defs spec =
RenameLet3
global
active
(RenameDefs global defs)
spec
type family
RenameLet3
(global :: Global)
(active :: Active)
( defs :: [(Symbol, Specification)])
( spec :: Specification)
:: (Specification, Global)
where
RenameLet3 global active defs spec =
RenameLet4
(ReflectDefs global active defs)
active
spec
type family
RenameLet4
( r :: (Global, [(Symbol, Specification)]))
(active :: Active)
( spec :: Specification)
:: (Specification, Global)
where
RenameLet4 '(global, defs) active spec =
RenameLet5
(FoldRename global active spec)
defs
type family
RenameLet5
(r :: (Specification, Global))
(defs :: [(Symbol, Specification)])
:: (Specification, Global)
where
RenameLet5 '(spec, global) defs =
'(JsonLet defs spec, global)
type family
UpdateActives
(global :: Global)
(active :: Active)
( defs :: [(Symbol, Specification)])
:: Active
where
UpdateActives global active '[] = active
UpdateActives global (A active) ( '(name, spec) : more) =
UpdateActives
global
(A (SetActive global active name))
more
type family
SetActive
(global :: Global)
(active :: [NameState])
( name :: Symbol)
:: [NameState]
where
SetActive
(G (N name ord : moreG))
(N name x : moreA)
name
=
(N name ord : moreA)
SetActive
(G (N name ord : moreG))
(N miss x : moreA)
name
=
N miss x : SetActive (G (N name ord : moreG)) moreA name
SetActive
(G (N name ord : moreG))
'[]
name
=
'[N name ord]
SetActive
(G (N miss x : moreG))
active
name
=
SetActive (G moreG) active name
type family
ReflectDefs
(global :: Global)
(active :: Active)
( defs :: [(Symbol, Specification)])
:: (Global, [(Symbol, Specification)])
where
ReflectDefs global active defs =
FoldReflectDefs '(global, '[]) active defs
type family
FoldReflectDefs
(acc :: (Global, [(Symbol, Specification)]))
(active :: Active)
(defs :: [(Symbol, Specification)])
:: (Global, [(Symbol, Specification)])
where
FoldReflectDefs acc active '[] = acc
FoldReflectDefs
'(global, acc)
active
( '(name, spec) : more )
=
FoldReflectDefs2
(FoldRename global active spec)
active
name
acc
more
type family
FoldReflectDefs2
( spec :: (Specification, Global))
(active :: Active)
( name :: Symbol)
( acc :: [(Symbol, Specification)])
( more :: [(Symbol, Specification)])
:: (Global, [(Symbol, Specification)])
where
FoldReflectDefs2 '(spec, global) active name acc more =
FoldReflectDefs '(global, '(name, spec) : acc) active more
type family
RenameDefs
(global :: Global)
( defs :: [(Symbol, Specification)])
:: [(Symbol, Specification)]
where
RenameDefs globals '[] = '[]
RenameDefs (G globals) ( '(name, spec) : more) =
'(LookupNewName name globals, spec) : RenameDefs (G globals) more
type family
LookupNewName
(target :: Symbol)
( names :: [NameState])
:: Symbol
where
LookupNewName target (N target 0 : more) = target
LookupNewName target (N target ord : more) =
AppendSymbol target ( AppendSymbol "." ( ToSymbol ord))
LookupNewName target (N miss ord : more) =
LookupNewName target more
type family
ToSymbol
(o :: Nat)
:: Symbol
where
ToSymbol 1 = "1"
ToSymbol 2 = "2"
ToSymbol 3 = "3"
ToSymbol 4 = "4"
ToSymbol 5 = "5"
ToSymbol 6 = "6"
ToSymbol 7 = "7"
ToSymbol 8 = "8"
ToSymbol 9 = "9"
ToSymbol 10 = "10"
ToSymbol 11 = "11"
ToSymbol 12 = "12"
ToSymbol 13 = "13"
ToSymbol 14 = "14"
ToSymbol 15 = "15"
ToSymbol 16 = "16"
ToSymbol 17 = "17"
ToSymbol 18 = "18"
ToSymbol 19 = "19"
ToSymbol 20 = "20"
ToSymbol 21 = "21"
ToSymbol 22 = "22"
ToSymbol 23 = "23"
ToSymbol 24 = "24"
ToSymbol 25 = "25"
ToSymbol 26 = "26"
ToSymbol 27 = "27"
ToSymbol 28 = "28"
ToSymbol 29 = "29"
ToSymbol 30 = "30"
ToSymbol 31 = "31"
ToSymbol 32 = "32"
ToSymbol 33 = "33"
ToSymbol 34 = "34"
ToSymbol 35 = "35"
ToSymbol 36 = "36"
ToSymbol 37 = "37"
ToSymbol 38 = "38"
ToSymbol 39 = "39"
ToSymbol 40 = "40"
ToSymbol 41 = "41"
ToSymbol 42 = "42"
ToSymbol 43 = "43"
ToSymbol 44 = "44"
ToSymbol 45 = "45"
ToSymbol 46 = "46"
ToSymbol 47 = "47"
ToSymbol 48 = "48"
ToSymbol 49 = "49"
ToSymbol 50 = "50"
ToSymbol 51 = "51"
ToSymbol 52 = "52"
ToSymbol 53 = "53"
ToSymbol 54 = "54"
ToSymbol 55 = "55"
ToSymbol 56 = "56"
ToSymbol 57 = "57"
ToSymbol 58 = "58"
ToSymbol 59 = "59"
ToSymbol 60 = "60"
ToSymbol 61 = "61"
ToSymbol 62 = "62"
ToSymbol 63 = "63"
ToSymbol 64 = "64"
ToSymbol 65 = "65"
ToSymbol 66 = "66"
ToSymbol 67 = "67"
ToSymbol 68 = "68"
ToSymbol 69 = "69"
ToSymbol 70 = "70"
ToSymbol 71 = "71"
ToSymbol 72 = "72"
ToSymbol 73 = "73"
ToSymbol 74 = "74"
ToSymbol 75 = "75"
ToSymbol 76 = "76"
ToSymbol 77 = "77"
ToSymbol 78 = "78"
ToSymbol 79 = "79"
ToSymbol 80 = "80"
ToSymbol 81 = "81"
ToSymbol 82 = "82"
ToSymbol 83 = "83"
ToSymbol 84 = "84"
ToSymbol 85 = "85"
ToSymbol 86 = "86"
ToSymbol 87 = "87"
ToSymbol 88 = "88"
ToSymbol 89 = "89"
ToSymbol 90 = "90"
ToSymbol 91 = "91"
ToSymbol 92 = "92"
ToSymbol 93 = "93"
ToSymbol 94 = "94"
ToSymbol 95 = "95"
ToSymbol 96 = "96"
ToSymbol 97 = "97"
ToSymbol 98 = "98"
ToSymbol 99 = "99"
ToSymbol 100 = "100"
ToSymbol a =
TE.TypeError (
TE.Text "The author of json-spec-openapi was lazy and did"
:$$: TE.Text "not foresee that anyone would write a specification"
:$$: TE.Text "that would have to handle more than 100 collisions"
:$$: TE.Text "for a single name when converting to an OpenApi"
:$$: TE.Text "spec. Please submit a bug report on GitHub and"
:$$: TE.Text "I'll add a fix."
)
type family
MapSpec
(f :: Specification -> Specification)
(a :: (Specification, Global))
:: (Specification, Global)
where
MapSpec f '(a, b) = '(f a, b)
type family
Reverse
(acc :: [FieldSpec])
(list :: [FieldSpec])
:: [FieldSpec]
where
Reverse acc '[] = acc
Reverse acc (a : more) = Reverse (a : acc) more
data NameState = N
{ NameState -> Symbol
_name :: Symbol
, NameState -> Nat
_ord :: Nat
}
newtype Global = G [NameState]
newtype Active = A [NameState]