module Cardano.Wasm.Api.InfoToTypeScript where

import Cardano.Wasm.Api.Info (tsTypeAsString)
import Cardano.Wasm.Api.Info qualified as Info
import Cardano.Wasm.Api.TypeScriptDefs qualified as TypeScript

import Data.List (nub)
import Data.Map (Map)
import Data.Map qualified as Map
import Data.Maybe (fromMaybe)

-- | Converts the Cardano API information to a TypeScript declaration file AST.
apiInfoToTypeScriptFile :: Info.ApiInfo -> [TypeScript.TypeScriptFile]
apiInfoToTypeScriptFile :: ApiInfo -> [TypeScriptFile]
apiInfoToTypeScriptFile ApiInfo
apiInfo =
  ( TypeScript.TypeScriptFile
      { typeScriptFileName :: [Char]
TypeScript.typeScriptFileName = VirtualObjectInfo -> [Char]
Info.dashCaseName (ApiInfo -> VirtualObjectInfo
Info.mainObject ApiInfo
apiInfo) [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> [Char]
".d.ts"
      , typeScriptFileContent :: [Declaration]
TypeScript.typeScriptFileContent =
          [Char]
-> Bool
-> Map [Char] VirtualObjectInfo
-> VirtualObjectInfo
-> [Declaration]
virtualObjectInfoToInterfaceDecs
            [Char]
mainObjectName
            Bool
False
            Map [Char] VirtualObjectInfo
voMap
            (ApiInfo -> VirtualObjectInfo
Info.mainObject ApiInfo
apiInfo)
            [Declaration] -> [Declaration] -> [Declaration]
forall a. [a] -> [a] -> [a]
++ [ [[Char]] -> DeclarationType -> Declaration
TypeScript.Declaration
                   [ ApiInfo -> [Char]
Info.initialiseFunctionDoc ApiInfo
apiInfo
                   , [Char]
"@returns " [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> ApiInfo -> [Char]
Info.initialiseFunctionReturnDoc ApiInfo
apiInfo
                   ]
                   ( FunctionHeader -> DeclarationType
TypeScript.FunctionDec (FunctionHeader -> DeclarationType)
-> FunctionHeader -> DeclarationType
forall a b. (a -> b) -> a -> b
$
                       TypeScript.FunctionHeader
                         { functionName :: [Char]
TypeScript.functionName = [Char]
"initialise"
                         , functionParams :: [FunctionParam]
TypeScript.functionParams = []
                         , functionReturnType :: [Char]
TypeScript.functionReturnType =
                             [Char]
"Promise<" [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> VirtualObjectInfo -> [Char]
Info.virtualObjectName (ApiInfo -> VirtualObjectInfo
Info.mainObject ApiInfo
apiInfo) [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> [Char]
">"
                         }
                   )
               , [[Char]] -> DeclarationType -> Declaration
TypeScript.Declaration [] (Bool -> [Char] -> DeclarationType
TypeScript.ExportDec Bool
True [Char]
"initialise")
               ]
      }
  )
    TypeScriptFile -> [TypeScriptFile] -> [TypeScriptFile]
forall a. a -> [a] -> [a]
: [TypeScriptFile]
virtualObjectInterfaces
 where
  virtualObjectInterfaces :: [TypeScriptFile]
virtualObjectInterfaces =
    (VirtualObjectInfo -> TypeScriptFile)
-> [VirtualObjectInfo] -> [TypeScriptFile]
forall a b. (a -> b) -> [a] -> [b]
map ([Char]
-> Map [Char] VirtualObjectInfo
-> VirtualObjectInfo
-> TypeScriptFile
virtualObjectInfoToTypeScriptFile [Char]
mainObjectName Map [Char] VirtualObjectInfo
voMap) (ApiInfo -> [VirtualObjectInfo]
Info.virtualObjects ApiInfo
apiInfo)

  voMap :: Map [Char] VirtualObjectInfo
voMap = [([Char], VirtualObjectInfo)] -> Map [Char] VirtualObjectInfo
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [(VirtualObjectInfo -> [Char]
Info.virtualObjectName VirtualObjectInfo
vo, VirtualObjectInfo
vo) | VirtualObjectInfo
vo <- ApiInfo -> [VirtualObjectInfo]
Info.virtualObjects ApiInfo
apiInfo]

  mainObjectName :: [Char]
mainObjectName = VirtualObjectInfo -> [Char]
Info.virtualObjectName (VirtualObjectInfo -> [Char]) -> VirtualObjectInfo -> [Char]
forall a b. (a -> b) -> a -> b
$ ApiInfo -> VirtualObjectInfo
Info.mainObject ApiInfo
apiInfo

importDeclaration :: Info.VirtualObjectInfo -> TypeScript.Declaration
importDeclaration :: VirtualObjectInfo -> Declaration
importDeclaration VirtualObjectInfo
vo =
  TypeScript.Declaration
    { declarationComment :: [[Char]]
TypeScript.declarationComment = []
    , declarationContent :: DeclarationType
TypeScript.declarationContent =
        [Char] -> [Char] -> DeclarationType
TypeScript.ImportDec (VirtualObjectInfo -> [Char]
Info.virtualObjectName VirtualObjectInfo
vo) ([Char] -> DeclarationType) -> [Char] -> DeclarationType
forall a b. (a -> b) -> a -> b
$ VirtualObjectInfo -> [Char]
Info.dashCaseName VirtualObjectInfo
vo
    }

importDeclarations
  :: Map String Info.VirtualObjectInfo -> Info.VirtualObjectInfo -> [TypeScript.Declaration]
importDeclarations :: Map [Char] VirtualObjectInfo -> VirtualObjectInfo -> [Declaration]
importDeclarations Map [Char] VirtualObjectInfo
voMap (Info.VirtualObjectInfo{virtualObjectMethods :: VirtualObjectInfo -> [MethodHierarchy]
Info.virtualObjectMethods = [MethodHierarchy]
methods}) =
  (VirtualObjectInfo -> Declaration)
-> [VirtualObjectInfo] -> [Declaration]
forall a b. (a -> b) -> [a] -> [b]
map
    VirtualObjectInfo -> Declaration
importDeclaration
    ([VirtualObjectInfo] -> [Declaration])
-> [VirtualObjectInfo] -> [Declaration]
forall a b. (a -> b) -> a -> b
$ [VirtualObjectInfo] -> [VirtualObjectInfo]
forall a. Eq a => [a] -> [a]
nub
      [ VirtualObjectInfo
vo
      | Info.MethodInfo{methodReturnType :: MethodInfo -> MethodReturnTypeInfo
Info.methodReturnType = Info.NewObject [Char]
returnType} <- [MethodHierarchy] -> [MethodInfo]
flattenMethods [MethodHierarchy]
methods
      , Just VirtualObjectInfo
vo <- [[Char] -> Map [Char] VirtualObjectInfo -> Maybe VirtualObjectInfo
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup [Char]
returnType Map [Char] VirtualObjectInfo
voMap]
      ]

flattenMethods :: [Info.MethodHierarchy] -> [Info.MethodInfo]
flattenMethods :: [MethodHierarchy] -> [MethodInfo]
flattenMethods = (MethodHierarchy -> [MethodInfo])
-> [MethodHierarchy] -> [MethodInfo]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap MethodHierarchy -> [MethodInfo]
flattenMethods'
 where
  flattenMethods' :: Info.MethodHierarchy -> [Info.MethodInfo]
  flattenMethods' :: MethodHierarchy -> [MethodInfo]
flattenMethods' (Info.MethodInfoEntry MethodInfo
mi) = [MethodInfo
mi]
  flattenMethods' (Info.MethodGroupEntry (Info.MethodGroup{groupMethods :: MethodGroup -> [MethodHierarchy]
Info.groupMethods = [MethodHierarchy]
methods})) = [MethodHierarchy] -> [MethodInfo]
flattenMethods [MethodHierarchy]
methods

virtualObjectInfoToTypeScriptFile
  :: String -> Map String Info.VirtualObjectInfo -> Info.VirtualObjectInfo -> TypeScript.TypeScriptFile
virtualObjectInfoToTypeScriptFile :: [Char]
-> Map [Char] VirtualObjectInfo
-> VirtualObjectInfo
-> TypeScriptFile
virtualObjectInfoToTypeScriptFile [Char]
mainObjectName Map [Char] VirtualObjectInfo
voMap VirtualObjectInfo
vo =
  TypeScript.TypeScriptFile
    { typeScriptFileName :: [Char]
TypeScript.typeScriptFileName = VirtualObjectInfo -> [Char]
Info.dashCaseName VirtualObjectInfo
vo [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> [Char]
".d.ts"
    , typeScriptFileContent :: [Declaration]
TypeScript.typeScriptFileContent = [Char]
-> Bool
-> Map [Char] VirtualObjectInfo
-> VirtualObjectInfo
-> [Declaration]
virtualObjectInfoToInterfaceDecs [Char]
mainObjectName Bool
True Map [Char] VirtualObjectInfo
voMap VirtualObjectInfo
vo
    }

oxfordCommaSeparatedList :: [String] -> String
oxfordCommaSeparatedList :: [[Char]] -> [Char]
oxfordCommaSeparatedList [] = [Char]
""
oxfordCommaSeparatedList [[Char]
l] = [Char]
l
oxfordCommaSeparatedList [[Char]
p, [Char]
l] = [Char]
p [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> [Char]
" and " [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> [Char]
l
oxfordCommaSeparatedList [[Char]
a, [Char]
p, [Char]
l] = [Char]
a [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> [Char]
", " [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> [Char]
p [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> [Char]
", and " [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> [Char]
l
oxfordCommaSeparatedList ([Char]
h : [[Char]]
t) = [Char]
h [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> [Char]
", " [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> [[Char]] -> [Char]
oxfordCommaSeparatedList [[Char]]
t

virtualObjectInfoToInterfaceDecs
  :: String
  -> Bool
  -> Map String Info.VirtualObjectInfo
  -> Info.VirtualObjectInfo
  -> [TypeScript.Declaration]
virtualObjectInfoToInterfaceDecs :: [Char]
-> Bool
-> Map [Char] VirtualObjectInfo
-> VirtualObjectInfo
-> [Declaration]
virtualObjectInfoToInterfaceDecs [Char]
mainObjectName Bool
isDefaultExport Map [Char] VirtualObjectInfo
voMap VirtualObjectInfo
vo =
  Map [Char] VirtualObjectInfo -> VirtualObjectInfo -> [Declaration]
importDeclarations Map [Char] VirtualObjectInfo
voMap VirtualObjectInfo
vo
    [Declaration] -> [Declaration] -> [Declaration]
forall a. [a] -> [a] -> [a]
++ [ [[Char]] -> DeclarationType -> Declaration
TypeScript.Declaration
           [VirtualObjectInfo -> [Char]
Info.virtualObjectDoc VirtualObjectInfo
vo]
           ( [Char] -> [GroupedInterfaceContent] -> DeclarationType
TypeScript.InterfaceDec
               (VirtualObjectInfo -> [Char]
Info.virtualObjectName VirtualObjectInfo
vo)
               ( [ InterfaceContent -> GroupedInterfaceContent
TypeScript.SingleInterfaceContent (InterfaceContent -> GroupedInterfaceContent)
-> InterfaceContent -> GroupedInterfaceContent
forall a b. (a -> b) -> a -> b
$
                     [[Char]] -> InterfaceContentType -> InterfaceContent
TypeScript.InterfaceContent
                       [ [Char]
"The type of the object, used for identification (the \""
                           [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> VirtualObjectInfo -> [Char]
Info.virtualObjectName VirtualObjectInfo
vo
                           [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> [Char]
"\" string)."
                       , [Char]
"Other types of objects would be:"
                       , [[Char]] -> [Char]
oxfordCommaSeparatedList
                           ( ( if [Char]
mainObjectName [Char] -> [Char] -> Bool
forall a. Eq a => a -> a -> Bool
== VirtualObjectInfo -> [Char]
Info.virtualObjectName VirtualObjectInfo
vo
                                 then [[Char]] -> [[Char]]
forall a. a -> a
id
                                 else ([Char] -> [Char]
forall a. Show a => a -> [Char]
show [Char]
mainObjectName [Char] -> [[Char]] -> [[Char]]
forall a. a -> [a] -> [a]
:)
                             )
                               [ [Char] -> [Char]
forall a. Show a => a -> [Char]
show ([Char] -> [Char]) -> [Char] -> [Char]
forall a b. (a -> b) -> a -> b
$ VirtualObjectInfo -> [Char]
Info.virtualObjectName VirtualObjectInfo
v
                               | VirtualObjectInfo
v <- Map [Char] VirtualObjectInfo -> [VirtualObjectInfo]
forall k a. Map k a -> [a]
Map.elems Map [Char] VirtualObjectInfo
voMap
                               , VirtualObjectInfo -> [Char]
Info.virtualObjectName VirtualObjectInfo
v [Char] -> [Char] -> Bool
forall a. Eq a => a -> a -> Bool
/= VirtualObjectInfo -> [Char]
Info.virtualObjectName VirtualObjectInfo
vo
                               ]
                           )
                       ]
                       ([Char] -> [Char] -> InterfaceContentType
TypeScript.InterfaceProperty [Char]
"objectType" [Char]
"string")
                 ]
                   [GroupedInterfaceContent]
-> [GroupedInterfaceContent] -> [GroupedInterfaceContent]
forall a. Semigroup a => a -> a -> a
<> (MethodHierarchy -> GroupedInterfaceContent)
-> [MethodHierarchy] -> [GroupedInterfaceContent]
forall a b. (a -> b) -> [a] -> [b]
map
                     ([Char] -> MethodHierarchy -> GroupedInterfaceContent
methodHierarchyToGroupedInterfaceContents (VirtualObjectInfo -> [Char]
Info.virtualObjectName VirtualObjectInfo
vo))
                     (VirtualObjectInfo -> [MethodHierarchy]
Info.virtualObjectMethods VirtualObjectInfo
vo)
               )
           )
       ]
    [Declaration] -> [Declaration] -> [Declaration]
forall a. [a] -> [a] -> [a]
++ [ [[Char]] -> DeclarationType -> Declaration
TypeScript.Declaration [] (Bool -> [Char] -> DeclarationType
TypeScript.ExportDec Bool
True ([Char] -> DeclarationType) -> [Char] -> DeclarationType
forall a b. (a -> b) -> a -> b
$ VirtualObjectInfo -> [Char]
Info.virtualObjectName VirtualObjectInfo
vo) | Bool
isDefaultExport
       ]

methodHierarchyToGroupedInterfaceContents
  :: String -> Info.MethodHierarchy -> TypeScript.GroupedInterfaceContent
methodHierarchyToGroupedInterfaceContents :: [Char] -> MethodHierarchy -> GroupedInterfaceContent
methodHierarchyToGroupedInterfaceContents [Char]
selfTypeName (Info.MethodInfoEntry MethodInfo
method) =
  InterfaceContent -> GroupedInterfaceContent
TypeScript.SingleInterfaceContent (InterfaceContent -> GroupedInterfaceContent)
-> InterfaceContent -> GroupedInterfaceContent
forall a b. (a -> b) -> a -> b
$ [Char] -> MethodInfo -> InterfaceContent
methodInfoToInterfaceContent [Char]
selfTypeName MethodInfo
method
methodHierarchyToGroupedInterfaceContents [Char]
selfTypeName (Info.MethodGroupEntry MethodGroup
group) =
  InterfaceContentGroup -> GroupedInterfaceContent
TypeScript.GroupedInterfaceContent (InterfaceContentGroup -> GroupedInterfaceContent)
-> InterfaceContentGroup -> GroupedInterfaceContent
forall a b. (a -> b) -> a -> b
$
    [[Char]]
-> [Char] -> [GroupedInterfaceContent] -> InterfaceContentGroup
TypeScript.InterfaceContentGroup
      (MethodGroup -> [[Char]]
Info.groupDoc MethodGroup
group)
      (MethodGroup -> [Char]
Info.groupName MethodGroup
group)
      ( (MethodHierarchy -> GroupedInterfaceContent)
-> [MethodHierarchy] -> [GroupedInterfaceContent]
forall a b. (a -> b) -> [a] -> [b]
map
          ([Char] -> MethodHierarchy -> GroupedInterfaceContent
methodHierarchyToGroupedInterfaceContents [Char]
selfTypeName)
          (MethodGroup -> [MethodHierarchy]
Info.groupMethods MethodGroup
group)
      )

methodInfoToInterfaceContent :: String -> Info.MethodInfo -> TypeScript.InterfaceContent
methodInfoToInterfaceContent :: [Char] -> MethodInfo -> InterfaceContent
methodInfoToInterfaceContent [Char]
selfTypeName MethodInfo
method =
  [[Char]] -> InterfaceContentType -> InterfaceContent
TypeScript.InterfaceContent
    ( [MethodInfo -> [Char]
Info.methodDoc MethodInfo
method]
        [[Char]] -> [[Char]] -> [[Char]]
forall a. Semigroup a => a -> a -> a
<> (ParamInfo -> [Char]) -> [ParamInfo] -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
map (\ParamInfo
p -> [Char]
"@param " [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> ParamInfo -> [Char]
Info.paramName ParamInfo
p [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> [Char]
" " [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> ParamInfo -> [Char]
Info.paramDoc ParamInfo
p) (MethodInfo -> [ParamInfo]
Info.methodParams MethodInfo
method)
        [[Char]] -> [[Char]] -> [[Char]]
forall a. Semigroup a => a -> a -> a
<> [[Char]
"@returns " [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> MethodInfo -> [Char]
Info.methodReturnDoc MethodInfo
method]
    )
    ( [Char] -> [FunctionParam] -> [Char] -> InterfaceContentType
TypeScript.InterfaceMethod
        ([Char] -> Maybe [Char] -> [Char]
forall a. a -> Maybe a -> a
fromMaybe (MethodInfo -> [Char]
Info.methodName MethodInfo
method) (MethodInfo -> Maybe [Char]
Info.methodSimpleName MethodInfo
method))
        ((ParamInfo -> FunctionParam) -> [ParamInfo] -> [FunctionParam]
forall a b. (a -> b) -> [a] -> [b]
map ParamInfo -> FunctionParam
paramInfoToFunctionParam ([ParamInfo] -> [FunctionParam]) -> [ParamInfo] -> [FunctionParam]
forall a b. (a -> b) -> a -> b
$ MethodInfo -> [ParamInfo]
Info.methodParams MethodInfo
method)
        ([Char] -> MethodReturnTypeInfo -> [Char]
methodReturnTypeToString [Char]
selfTypeName (MethodReturnTypeInfo -> [Char]) -> MethodReturnTypeInfo -> [Char]
forall a b. (a -> b) -> a -> b
$ MethodInfo -> MethodReturnTypeInfo
Info.methodReturnType MethodInfo
method)
    )

paramInfoToFunctionParam :: Info.ParamInfo -> TypeScript.FunctionParam
paramInfoToFunctionParam :: ParamInfo -> FunctionParam
paramInfoToFunctionParam ParamInfo
p =
  TypeScript.FunctionParam
    { paramName :: [Char]
TypeScript.paramName = ParamInfo -> [Char]
Info.paramName ParamInfo
p
    , paramType :: [Char]
TypeScript.paramType = TSType -> [Char]
tsTypeAsString (TSType -> [Char]) -> TSType -> [Char]
forall a b. (a -> b) -> a -> b
$ ParamInfo -> TSType
Info.paramType ParamInfo
p
    }

methodReturnTypeToString :: String -> Info.MethodReturnTypeInfo -> String
methodReturnTypeToString :: [Char] -> MethodReturnTypeInfo -> [Char]
methodReturnTypeToString [Char]
selfTypeName MethodReturnTypeInfo
Info.Fluent = [Char]
selfTypeName
methodReturnTypeToString [Char]
_ (Info.NewObject [Char]
objTypeName) = [Char]
"Promise<" [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> [Char]
objTypeName [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> [Char]
">"
methodReturnTypeToString [Char]
_ (Info.OtherType TSType
typeName) = [Char]
"Promise<" [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> TSType -> [Char]
tsTypeAsString TSType
typeName [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> [Char]
">"