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

-- | 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 :: String
TypeScript.typeScriptFileName = VirtualObjectInfo -> String
Info.dashCaseName (ApiInfo -> VirtualObjectInfo
Info.mainObject ApiInfo
apiInfo) String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
".d.ts"
      , typeScriptFileContent :: [Declaration]
TypeScript.typeScriptFileContent =
          Bool
-> Map String VirtualObjectInfo
-> VirtualObjectInfo
-> [Declaration]
virtualObjectInfoToInterfaceDecs
            Bool
False
            Map String VirtualObjectInfo
voMap
            (ApiInfo -> VirtualObjectInfo
Info.mainObject ApiInfo
apiInfo)
            [Declaration] -> [Declaration] -> [Declaration]
forall a. [a] -> [a] -> [a]
++ [ [String] -> DeclarationType -> Declaration
TypeScript.Declaration
                   [ ApiInfo -> String
Info.initialiseFunctionDoc ApiInfo
apiInfo
                   , String
"@returns " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> ApiInfo -> String
Info.initialiseFunctionReturnDoc ApiInfo
apiInfo
                   ]
                   ( FunctionHeader -> DeclarationType
TypeScript.FunctionDec (FunctionHeader -> DeclarationType)
-> FunctionHeader -> DeclarationType
forall a b. (a -> b) -> a -> b
$
                       TypeScript.FunctionHeader
                         { functionName :: String
TypeScript.functionName = String
"initialise"
                         , functionParams :: [FunctionParam]
TypeScript.functionParams = []
                         , functionReturnType :: String
TypeScript.functionReturnType =
                             String
"Promise<" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> VirtualObjectInfo -> String
Info.virtualObjectName (ApiInfo -> VirtualObjectInfo
Info.mainObject ApiInfo
apiInfo) String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
">"
                         }
                   )
               , [String] -> DeclarationType -> Declaration
TypeScript.Declaration [] (Bool -> String -> DeclarationType
TypeScript.ExportDec Bool
True String
"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 (Map String VirtualObjectInfo -> VirtualObjectInfo -> TypeScriptFile
virtualObjectInfoToTypeScriptFile Map String VirtualObjectInfo
voMap) (ApiInfo -> [VirtualObjectInfo]
Info.virtualObjects ApiInfo
apiInfo)

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

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

importDeclarations
  :: Map String Info.VirtualObjectInfo -> Info.VirtualObjectInfo -> [TypeScript.Declaration]
importDeclarations :: Map String VirtualObjectInfo -> VirtualObjectInfo -> [Declaration]
importDeclarations Map String 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 String
returnType} <- [MethodHierarchy] -> [MethodInfo]
flattenMethods [MethodHierarchy]
methods
      , Just VirtualObjectInfo
vo <- [String -> Map String VirtualObjectInfo -> Maybe VirtualObjectInfo
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup String
returnType Map String 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
  :: Map String Info.VirtualObjectInfo -> Info.VirtualObjectInfo -> TypeScript.TypeScriptFile
virtualObjectInfoToTypeScriptFile :: Map String VirtualObjectInfo -> VirtualObjectInfo -> TypeScriptFile
virtualObjectInfoToTypeScriptFile Map String VirtualObjectInfo
voMap VirtualObjectInfo
vo =
  TypeScript.TypeScriptFile
    { typeScriptFileName :: String
TypeScript.typeScriptFileName = VirtualObjectInfo -> String
Info.dashCaseName VirtualObjectInfo
vo String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
".d.ts"
    , typeScriptFileContent :: [Declaration]
TypeScript.typeScriptFileContent = Bool
-> Map String VirtualObjectInfo
-> VirtualObjectInfo
-> [Declaration]
virtualObjectInfoToInterfaceDecs Bool
True Map String VirtualObjectInfo
voMap VirtualObjectInfo
vo
    }

virtualObjectInfoToInterfaceDecs
  :: Bool -> Map String Info.VirtualObjectInfo -> Info.VirtualObjectInfo -> [TypeScript.Declaration]
virtualObjectInfoToInterfaceDecs :: Bool
-> Map String VirtualObjectInfo
-> VirtualObjectInfo
-> [Declaration]
virtualObjectInfoToInterfaceDecs Bool
isDefaultExport Map String VirtualObjectInfo
voMap VirtualObjectInfo
vo =
  Map String VirtualObjectInfo -> VirtualObjectInfo -> [Declaration]
importDeclarations Map String VirtualObjectInfo
voMap VirtualObjectInfo
vo
    [Declaration] -> [Declaration] -> [Declaration]
forall a. [a] -> [a] -> [a]
++ [ [String] -> DeclarationType -> Declaration
TypeScript.Declaration
           [VirtualObjectInfo -> String
Info.virtualObjectDoc VirtualObjectInfo
vo]
           ( String -> [GroupedInterfaceContent] -> DeclarationType
TypeScript.InterfaceDec
               (VirtualObjectInfo -> String
Info.virtualObjectName VirtualObjectInfo
vo)
               ( [ InterfaceContent -> GroupedInterfaceContent
TypeScript.SingleInterfaceContent (InterfaceContent -> GroupedInterfaceContent)
-> InterfaceContent -> GroupedInterfaceContent
forall a b. (a -> b) -> a -> b
$
                     [String] -> InterfaceContentType -> InterfaceContent
TypeScript.InterfaceContent
                       [ String
"The type of the object, used for identification (the \""
                           String -> String -> String
forall a. Semigroup a => a -> a -> a
<> VirtualObjectInfo -> String
Info.virtualObjectName VirtualObjectInfo
vo
                           String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"\" string)."
                       ]
                       (String -> String -> InterfaceContentType
TypeScript.InterfaceProperty String
"objectType" String
"string")
                 ]
                   [GroupedInterfaceContent]
-> [GroupedInterfaceContent] -> [GroupedInterfaceContent]
forall a. Semigroup a => a -> a -> a
<> (MethodHierarchy -> GroupedInterfaceContent)
-> [MethodHierarchy] -> [GroupedInterfaceContent]
forall a b. (a -> b) -> [a] -> [b]
map
                     (String -> MethodHierarchy -> GroupedInterfaceContent
methodHierarchyToGroupedInterfaceContents (VirtualObjectInfo -> String
Info.virtualObjectName VirtualObjectInfo
vo))
                     (VirtualObjectInfo -> [MethodHierarchy]
Info.virtualObjectMethods VirtualObjectInfo
vo)
               )
           )
       ]
    [Declaration] -> [Declaration] -> [Declaration]
forall a. [a] -> [a] -> [a]
++ [ [String] -> DeclarationType -> Declaration
TypeScript.Declaration [] (Bool -> String -> DeclarationType
TypeScript.ExportDec Bool
True (String -> DeclarationType) -> String -> DeclarationType
forall a b. (a -> b) -> a -> b
$ VirtualObjectInfo -> String
Info.virtualObjectName VirtualObjectInfo
vo) | Bool
isDefaultExport
       ]

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

methodInfoToInterfaceContent :: String -> Info.MethodInfo -> TypeScript.InterfaceContent
methodInfoToInterfaceContent :: String -> MethodInfo -> InterfaceContent
methodInfoToInterfaceContent String
selfTypeName MethodInfo
method =
  [String] -> InterfaceContentType -> InterfaceContent
TypeScript.InterfaceContent
    ( [MethodInfo -> String
Info.methodDoc MethodInfo
method]
        [String] -> [String] -> [String]
forall a. Semigroup a => a -> a -> a
<> (ParamInfo -> String) -> [ParamInfo] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (\ParamInfo
p -> String
"@param " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> ParamInfo -> String
Info.paramName ParamInfo
p String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
" " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> ParamInfo -> String
Info.paramDoc ParamInfo
p) (MethodInfo -> [ParamInfo]
Info.methodParams MethodInfo
method)
        [String] -> [String] -> [String]
forall a. Semigroup a => a -> a -> a
<> [String
"@returns " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> MethodInfo -> String
Info.methodReturnDoc MethodInfo
method]
    )
    ( String -> [FunctionParam] -> String -> InterfaceContentType
TypeScript.InterfaceMethod
        (MethodInfo -> String
Info.methodName 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)
        (String -> MethodReturnTypeInfo -> String
methodReturnTypeToString String
selfTypeName (MethodReturnTypeInfo -> String) -> MethodReturnTypeInfo -> String
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 :: String
TypeScript.paramName = ParamInfo -> String
Info.paramName ParamInfo
p
    , paramType :: String
TypeScript.paramType = TSType -> String
tsTypeAsString (TSType -> String) -> TSType -> String
forall a b. (a -> b) -> a -> b
$ ParamInfo -> TSType
Info.paramType ParamInfo
p
    }

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