Skip to content

Commit c21e28a

Browse files
committed
Generate TypeScript definitions from ApiInfo
1 parent 1c7e8a8 commit c21e28a

File tree

7 files changed

+320
-34
lines changed

7 files changed

+320
-34
lines changed

cardano-wasm/app/Main.hs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
module Main (main) where
1+
module Main where
2+
3+
import Cardano.Wasm.Internal.Api.Info (apiInfo)
4+
import Cardano.Wasm.Internal.Api.InfoToTypeScript (apiInfoToTypeScriptFile)
5+
import Cardano.Wasm.Internal.Api.TypeScriptDefs (printTypeScriptFile)
26

37
main :: IO ()
4-
main = pure ()
8+
main = printTypeScriptFile (apiInfoToTypeScriptFile apiInfo)

cardano-wasm/cardano-wasm.cabal

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ executable cardano-wasm
4040
"-optl-Wl,--strip-all,--export=getApiInfo,--export=newConwayTx,--export=addTxInput,--export=addSimpleTxOut,--export=setFee,--export=estimateMinFee,--export=signWithPaymentKey,--export=alsoSignWithPaymentKey,--export=txToCbor"
4141
other-modules:
4242
Cardano.Wasm.Internal.Api.Info
43+
Cardano.Wasm.Internal.Api.InfoToTypeScript
4344
Cardano.Wasm.Internal.Api.Tx
45+
Cardano.Wasm.Internal.Api.TypeScriptDefs
4446
Cardano.Wasm.Internal.ExceptionHandling
4547
Cardano.Wasm.Internal.JavaScript.Bridge
4648

cardano-wasm/example/cardano-api.d.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,12 @@ declare interface UnsignedTx {
4343
/**
4444
* Estimates the minimum fee for the transaction.
4545
* @param protocolParams The protocol parameters.
46-
* @param numExtraKeyWitnesses The number of extra key witnesses (in addition to the ones already added).
47-
* @param numExtraByronKeyWitnesses The number of extra Byron key witnesses.
46+
* @param numKeyWitnesses The number of key witnesses.
47+
* @param numByronKeyWitnesses The number of Byron key witnesses.
4848
* @param totalRefScriptSize The total size of reference scripts in bytes.
4949
* @returns A promise that resolves to the estimated minimum fee in lovelace.
5050
*/
51-
estimateMinFee(protocolParams: any, numExtraKeyWitnesses: number, numExtraByronKeyWitnesses: number, totalRefScriptSize: number): Promise<bigint>;
51+
estimateMinFee(protocolParams: any, numKeyWitnesses: number, numByronKeyWitnesses: number, totalRefScriptSize: number): Promise<BigInt>;
5252

5353
/**
5454
* Signs the transaction with a payment key.
@@ -96,3 +96,4 @@ declare interface CardanoAPI {
9696
*/
9797
newConwayTx(): Promise<UnsignedTx>;
9898
}
99+

cardano-wasm/example/cardano-api.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ async function initialize() {
1414

1515
// Wrap a function with variable arguments to make the parameters inspectable
1616
function fixateArgs(params, func) {
17-
const paramString = params.join(',');
17+
const paramString = params.map(p => p.name).join(',');
1818
// Dynamically create a function that captures 'func' from the closure.
1919
// 'this' and 'arguments' are passed through from the wrapper to 'func'.
2020
// Using eval allows the returned function to have named parameters for inspectability.
@@ -28,7 +28,7 @@ async function initialize() {
2828

2929
// Same as fixateArgs but for async functions
3030
async function fixateArgsAsync(params, func) {
31-
const paramString = params.join(',');
31+
const paramString = params.map(p => p.name).join(',');
3232
// Dynamically create an async function.
3333
const wrapper = eval(`
3434
(async function(${paramString}) {
@@ -82,7 +82,7 @@ async function initialize() {
8282
});
8383

8484
// Populate the main API object with static methods
85-
apiInfo.staticMethods.forEach(method => {
85+
apiInfo.mainObject.methods.forEach(method => {
8686
cardanoAPI[method.name] = async function (...args) {
8787
const resultPromise = instance.exports[method.name](...args);
8888

Lines changed: 99 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
{-# LANGUAGE InstanceSigs #-}
22

3-
module Cardano.Wasm.Internal.Api.Info (apiInfo) where
3+
module Cardano.Wasm.Internal.Api.Info
4+
( apiInfo
5+
, ApiInfo (..)
6+
, VirtualObjectInfo (..)
7+
, MethodInfo (..)
8+
, ParamInfo (..)
9+
, MethodReturnTypeInfo (..)
10+
)
11+
where
412

513
import Data.Aeson qualified as Aeson
614
import Data.Text qualified as Text
@@ -18,56 +26,84 @@ data MethodReturnTypeInfo
1826
deriving (Show, Eq)
1927

2028
instance Aeson.ToJSON MethodReturnTypeInfo where
29+
toJSON :: MethodReturnTypeInfo -> Aeson.Value
2130
toJSON Fluent = Aeson.object ["type" Aeson..= Text.pack "fluent"]
2231
toJSON (NewObject objTypeName) = Aeson.object ["type" Aeson..= Text.pack "newObject", "objectType" Aeson..= objTypeName]
2332
toJSON (OtherType typeName) = Aeson.object ["type" Aeson..= Text.pack "other", "typeName" Aeson..= typeName]
2433

34+
-- | Information about a single parameter of a method.
35+
data ParamInfo = ParamInfo
36+
{ paramName :: String
37+
, paramType :: String
38+
, paramDoc :: String
39+
}
40+
deriving (Show, Eq)
41+
42+
instance Aeson.ToJSON ParamInfo where
43+
toJSON :: ParamInfo -> Aeson.Value
44+
toJSON (ParamInfo name pType doc) =
45+
Aeson.object
46+
[ "name" Aeson..= name
47+
, "type" Aeson..= pType
48+
, "doc" Aeson..= doc
49+
]
50+
2551
-- | Information about a single method of a virtual object.
2652
data MethodInfo = MethodInfo
2753
{ methodName :: String
28-
, methodParams :: [String]
54+
, methodDoc :: String
55+
, methodParams :: [ParamInfo]
2956
-- ^ Names of parameters, excluding 'this'.
3057
, methodReturnType :: MethodReturnTypeInfo
58+
, methodReturnDoc :: String
3159
}
3260
deriving (Show, Eq)
3361

3462
instance Aeson.ToJSON MethodInfo where
3563
toJSON :: MethodInfo -> Aeson.Value
36-
toJSON (MethodInfo name params retType) =
64+
toJSON (MethodInfo name doc params retType retDoc) =
3765
Aeson.object
3866
[ "name" Aeson..= name
67+
, "doc" Aeson..= doc
3968
, "params" Aeson..= params
4069
, "return" Aeson..= retType
70+
, "returnDoc" Aeson..= retDoc
4171
]
4272

4373
-- | Information about a virtual object and its methods.
4474
data VirtualObjectInfo = VirtualObjectInfo
4575
{ virtualObjectName :: String
76+
, virtualObjectDoc :: String
4677
, virtualObjectMethods :: [MethodInfo]
4778
}
4879
deriving (Show, Eq)
4980

5081
instance Aeson.ToJSON VirtualObjectInfo where
5182
toJSON :: VirtualObjectInfo -> Aeson.Value
52-
toJSON (VirtualObjectInfo name methods) =
83+
toJSON (VirtualObjectInfo name doc methods) =
5384
Aeson.object
5485
[ "objectName" Aeson..= name
86+
, "doc" Aeson..= doc
5587
, "methods" Aeson..= methods
5688
]
5789

5890
-- | Aggregate type for all API information.
5991
data ApiInfo = ApiInfo
60-
{ staticMethods :: [MethodInfo]
92+
{ mainObject :: VirtualObjectInfo
6193
, virtualObjects :: [VirtualObjectInfo]
94+
, initializeFunctionDoc :: String
95+
, initializeFunctionReturnDoc :: String
6296
}
6397
deriving (Show, Eq)
6498

6599
instance Aeson.ToJSON ApiInfo where
66100
toJSON :: ApiInfo -> Aeson.Value
67-
toJSON (ApiInfo staticObjs virtualObjs) =
101+
toJSON (ApiInfo mainObj virtualObjs initDoc initRetDoc) =
68102
Aeson.object
69-
[ "staticMethods" Aeson..= staticObjs
103+
[ "mainObject" Aeson..= mainObj
70104
, "virtualObjects" Aeson..= virtualObjs
105+
, "initializeFunctionDoc" Aeson..= initDoc
106+
, "initializeFunctionReturnDoc" Aeson..= initRetDoc
71107
]
72108

73109
-- | Provides metadata about the "virtual objects" and their methods.
@@ -77,64 +113,101 @@ apiInfo =
77113
let unsignedTxObjectName = "UnsignedTx"
78114
signedTxObjectName = "SignedTx"
79115

80-
staticApiMethods =
81-
[ MethodInfo
82-
{ methodName = "newConwayTx"
83-
, methodParams = []
84-
, methodReturnType = NewObject unsignedTxObjectName
85-
}
86-
]
87-
88116
unsignedTxObj =
89117
VirtualObjectInfo
90118
{ virtualObjectName = unsignedTxObjectName
119+
, virtualObjectDoc = "Represents an unsigned transaction."
91120
, virtualObjectMethods =
92121
[ MethodInfo
93122
{ methodName = "addTxInput"
94-
, methodParams = ["txId", "txIx"]
123+
, methodDoc = "Adds a simple transaction input to the transaction."
124+
, methodParams =
125+
[ ParamInfo "txId" "string" "The transaction ID of the input UTxO."
126+
, ParamInfo "txIx" "number" "The index of the input within the UTxO."
127+
]
95128
, methodReturnType = Fluent
129+
, methodReturnDoc = "The `UnsignedTx` object with the added input."
96130
}
97131
, MethodInfo
98132
{ methodName = "addSimpleTxOut"
99-
, methodParams = ["destAddr", "lovelaceAmount"]
133+
, methodDoc = "Adds a simple transaction output to the transaction."
134+
, methodParams =
135+
[ ParamInfo "destAddr" "string" "The destination address."
136+
, ParamInfo "lovelaceAmount" "bigint" "The amount in lovelace to output."
137+
]
100138
, methodReturnType = Fluent
139+
, methodReturnDoc = "The `UnsignedTx` object with the added output."
101140
}
102141
, MethodInfo
103142
{ methodName = "setFee"
104-
, methodParams = ["lovelaceAmount"]
143+
, methodDoc = "Sets the fee for the transaction."
144+
, methodParams = [ParamInfo "lovelaceAmount" "bigint" "The fee amount in lovelace."]
105145
, methodReturnType = Fluent
106-
}
107-
, MethodInfo
108-
{ methodName = "signWithPaymentKey"
109-
, methodParams = ["signingKey"]
110-
, methodReturnType = NewObject signedTxObjectName
146+
, methodReturnDoc = "The `UnsignedTx` object with the set fee."
111147
}
112148
, MethodInfo
113149
{ methodName = "estimateMinFee"
150+
, methodDoc = "Estimates the minimum fee for the transaction."
114151
, methodParams =
115-
["protocolParams", "numKeyWitnesses", "numByronKeyWitnesses", "totalRefScriptSize"]
152+
[ ParamInfo "protocolParams" "any" "The protocol parameters."
153+
, ParamInfo
154+
"numKeyWitnesses"
155+
"number"
156+
"The number of key witnesses."
157+
, ParamInfo "numByronKeyWitnesses" "number" "The number of Byron key witnesses."
158+
, ParamInfo "totalRefScriptSize" "number" "The total size of reference scripts in bytes."
159+
]
116160
, methodReturnType = OtherType "BigInt"
161+
, methodReturnDoc = "A promise that resolves to the estimated minimum fee in lovelace."
162+
}
163+
, MethodInfo
164+
{ methodName = "signWithPaymentKey"
165+
, methodDoc = "Signs the transaction with a payment key."
166+
, methodParams = [ParamInfo "signingKey" "string" "The signing key to witness the transaction."]
167+
, methodReturnType = NewObject signedTxObjectName
168+
, methodReturnDoc = "A promise that resolves to a `SignedTx` object."
117169
}
118170
]
119171
}
120172

121173
signedTxObj =
122174
VirtualObjectInfo
123175
{ virtualObjectName = signedTxObjectName
176+
, virtualObjectDoc = "Represents a signed transaction."
124177
, virtualObjectMethods =
125178
[ MethodInfo
126179
{ methodName = "alsoSignWithPaymentKey"
127-
, methodParams = ["signingKey"]
180+
, methodDoc = "Adds an extra signature to the transaction with a payment key."
181+
, methodParams = [ParamInfo "signingKey" "string" "The signing key to witness the transaction."]
128182
, methodReturnType = Fluent
183+
, methodReturnDoc = "The `SignedTx` object with the additional signature."
129184
}
130185
, MethodInfo
131186
{ methodName = "txToCbor"
187+
, methodDoc = "Converts the signed transaction to its CBOR representation."
132188
, methodParams = []
133189
, methodReturnType = OtherType "string"
190+
, methodReturnDoc =
191+
"A promise that resolves to the CBOR representation of the transaction as a hex string."
134192
}
135193
]
136194
}
137195
in ApiInfo
138-
{ staticMethods = staticApiMethods
196+
{ mainObject =
197+
VirtualObjectInfo
198+
{ virtualObjectName = "CardanoAPI"
199+
, virtualObjectDoc = "The main Cardano API object with static methods."
200+
, virtualObjectMethods =
201+
[ MethodInfo
202+
{ methodName = "newConwayTx"
203+
, methodDoc = "Creates a new Conway-era transaction."
204+
, methodParams = []
205+
, methodReturnType = NewObject unsignedTxObjectName
206+
, methodReturnDoc = "A promise that resolves to a new `UnsignedTx` object."
207+
}
208+
]
209+
}
139210
, virtualObjects = [unsignedTxObj, signedTxObj]
211+
, initializeFunctionDoc = "Initializes the Cardano API."
212+
, initializeFunctionReturnDoc = "A promise that resolves to the main `CardanoAPI` object."
140213
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
module Cardano.Wasm.Internal.Api.InfoToTypeScript where
2+
3+
import Cardano.Wasm.Internal.Api.Info qualified as Info
4+
import Cardano.Wasm.Internal.Api.TypeScriptDefs qualified as TypeScript
5+
6+
-- | Converts the Cardano API information to a TypeScript declaration file AST.
7+
apiInfoToTypeScriptFile :: Info.ApiInfo -> TypeScript.TypeScriptFile
8+
apiInfoToTypeScriptFile apiInfo =
9+
TypeScript.TypeScriptFile
10+
{ TypeScript.typeScriptFileName = "cardano-api.d.ts"
11+
, TypeScript.typeScriptFileContent =
12+
[ TypeScript.Declaration [] (TypeScript.ExportDec True "initialize")
13+
, TypeScript.Declaration
14+
[ Info.initializeFunctionDoc apiInfo
15+
, "@returns " <> Info.initializeFunctionReturnDoc apiInfo
16+
]
17+
( TypeScript.FunctionDec $
18+
TypeScript.FunctionHeader
19+
{ TypeScript.functionName = "initialize"
20+
, TypeScript.functionParams = []
21+
, TypeScript.functionReturnType =
22+
"Promise<" <> Info.virtualObjectName (Info.mainObject apiInfo) <> ">"
23+
}
24+
)
25+
]
26+
<> virtualObjectInterfaces
27+
}
28+
where
29+
virtualObjectInterfaces =
30+
map virtualObjectInfoToInterfaceDec (Info.virtualObjects apiInfo <> [Info.mainObject apiInfo])
31+
32+
virtualObjectInfoToInterfaceDec :: Info.VirtualObjectInfo -> TypeScript.Declaration
33+
virtualObjectInfoToInterfaceDec vo =
34+
TypeScript.Declaration
35+
[Info.virtualObjectDoc vo]
36+
( TypeScript.InterfaceDec
37+
(Info.virtualObjectName vo)
38+
( [ TypeScript.InterfaceContent
39+
[ "The type of the object, used for identification (the \""
40+
<> Info.virtualObjectName vo
41+
<> "\" string)."
42+
]
43+
(TypeScript.InterfaceProperty "objectType" "string")
44+
]
45+
<> map (methodInfoToInterfaceContent (Info.virtualObjectName vo)) (Info.virtualObjectMethods vo)
46+
)
47+
)
48+
49+
methodInfoToInterfaceContent :: String -> Info.MethodInfo -> TypeScript.InterfaceContent
50+
methodInfoToInterfaceContent selfTypeName method =
51+
TypeScript.InterfaceContent
52+
( [Info.methodDoc method]
53+
<> map (\p -> "@param " <> Info.paramName p <> " " <> Info.paramDoc p) (Info.methodParams method)
54+
<> ["@returns " <> Info.methodReturnDoc method]
55+
)
56+
( TypeScript.InterfaceMethod
57+
(Info.methodName method)
58+
(map paramInfoToFunctionParam $ Info.methodParams method)
59+
(methodReturnTypeToString selfTypeName $ Info.methodReturnType method)
60+
)
61+
62+
paramInfoToFunctionParam :: Info.ParamInfo -> TypeScript.FunctionParam
63+
paramInfoToFunctionParam p =
64+
TypeScript.FunctionParam
65+
{ TypeScript.paramName = Info.paramName p
66+
, TypeScript.paramType = Info.paramType p
67+
}
68+
69+
methodReturnTypeToString :: String -> Info.MethodReturnTypeInfo -> String
70+
methodReturnTypeToString selfTypeName Info.Fluent = selfTypeName
71+
methodReturnTypeToString _ (Info.NewObject objTypeName) = "Promise<" <> objTypeName <> ">"
72+
methodReturnTypeToString _ (Info.OtherType typeName) = "Promise<" <> typeName <> ">"

0 commit comments

Comments
 (0)