Skip to content

Commit a2c54da

Browse files
committed
Add functionality to group methods in JavaScript objects
1 parent 4cdb67f commit a2c54da

File tree

4 files changed

+463
-305
lines changed

4 files changed

+463
-305
lines changed

cardano-wasm/lib-wrapper/main.js

Lines changed: 58 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export function createInitializer(getWasi, loadWasmModule, createClient) {
2222
/**
2323
* Convert Base64 to Base16 encoding
2424
*/
25-
base64ToHex: function(base64) {
25+
base64ToHex: function (base64) {
2626
if (typeof atob === 'function') {
2727
const binary = atob(base64);
2828
return [...binary].reduce((hex, char) => {
@@ -88,48 +88,73 @@ export function createInitializer(getWasi, loadWasmModule, createClient) {
8888
const apiInfo = await instance.exports.getApiInfo();
8989
let makers = {};
9090
let cardanoApi = { objectType: "cardano-api" };
91+
9192
// Create maker functions for each virtual object type
93+
94+
function populateMethodOrGroup(methodPopulator, methodOrGroup, target) {
95+
if (methodOrGroup.type === "method") {
96+
methodPopulator(methodOrGroup.method, target);
97+
} else if (methodOrGroup.type === "group") {
98+
group = methodOrGroup.group;
99+
target = target[group.groupName] = {};
100+
group.groupMethods.forEach(methodOrGroup =>
101+
populateMethodOrGroup(methodPopulator, methodOrGroup, target)
102+
);
103+
}
104+
}
105+
106+
function populateDynamicMethod(method, target) {
107+
if (method.return.type === "fluent") {
108+
// Fluent methods are synchronous and update the provider
109+
// A fluent method is one that returns the same object type
110+
target[method.name] = fixateArgs(method.params, function (...args) {
111+
const previousProvider = currentHaskellValueProvider;
112+
// We update the provider so that it resolves the previous provider and chains the next call
113+
currentHaskellValueProvider = async () => {
114+
const prevHaskellValue = await previousProvider();
115+
return instance.exports[method.name](prevHaskellValue, ...args);
116+
};
117+
return jsObject; // Return current object for supporting chaining
118+
});
119+
} else {
120+
// Non-fluent methods (newObject or other) are async and apply the accumulated method calls
121+
target[method.name] = fixateArgs(method.params, async function (...args) {
122+
const haskellValue = await currentHaskellValueProvider(); // Resolve accumulated method calls
123+
const resultPromise = instance.exports[method.name](haskellValue, ...args); // Call the non-fluent method
124+
125+
if (method.return.type === "newObject") { // It returns a new object
126+
return makers[method.return.objectType](resultPromise);
127+
} else { // It returns some primitive or other JS type (not a virtual object)
128+
return resultPromise;
129+
}
130+
});
131+
}
132+
}
133+
92134
apiInfo.virtualObjects.forEach(vo => {
93-
makers[vo.objectName] = function(initialHaskellValuePromise) {
135+
makers[vo.objectName] = function (initialHaskellValuePromise) {
94136
// currentHaskellValueProvider is a function that returns a Promise for the Haskell value
95137
// It starts with the initial value promise and fluent methods accumulate transformations
96138
let currentHaskellValueProvider = () => initialHaskellValuePromise;
97139
let jsObject = { objectType: vo.objectName };
98140

99141
vo.methods.forEach(method => {
100-
if (method.return.type === "fluent") {
101-
// Fluent methods are synchronous and update the provider
102-
// A fluent method is one that returns the same object type
103-
jsObject[method.name] = fixateArgs(method.params, function(...args) {
104-
const previousProvider = currentHaskellValueProvider;
105-
// We update the provider so that it resolves the previous provider and chains the next call
106-
currentHaskellValueProvider = async () => {
107-
const prevHaskellValue = await previousProvider();
108-
return instance.exports[method.name](prevHaskellValue, ...args);
109-
};
110-
return jsObject; // Return current object for supporting chaining
111-
});
112-
} else {
113-
// Non-fluent methods (newObject or other) are async and apply the accumulated method calls
114-
jsObject[method.name] = fixateArgs(method.params, async function(...args) {
115-
const haskellValue = await currentHaskellValueProvider(); // Resolve accumulated method calls
116-
const resultPromise = instance.exports[method.name](haskellValue, ...args); // Call the non-fluent method
117-
118-
if (method.return.type === "newObject") { // It returns a new object
119-
return makers[method.return.objectType](resultPromise);
120-
} else { // It returns some primitive or other JS type (not a virtual object)
121-
return resultPromise;
122-
}
123-
});
124-
}
142+
populateMethodOrGroup(populateDynamicMethod, method, jsObject);
125143
});
126144
return jsObject;
127145
};
128146
});
129147

130148
// Populate the main API object with static methods
131-
apiInfo.mainObject.methods.forEach(method => {
132-
cardanoApi[method.name] = async function(...args) {
149+
150+
function populateStaticMethod(method, target) {
151+
target[method.name] = async function (...args) {
152+
if (method.group) {
153+
if (!target[method.group]) {
154+
target[method.group] = {};
155+
}
156+
target = target[method.group];
157+
}
133158
const resultPromise = instance.exports[method.name](...args);
134159

135160
if (method.return.type === "newObject") { // Create a new object
@@ -138,6 +163,10 @@ export function createInitializer(getWasi, loadWasmModule, createClient) {
138163
return resultPromise;
139164
}
140165
};
166+
}
167+
168+
apiInfo.mainObject.methods.forEach(methodOrGroup => {
169+
populateMethodOrGroup(populateStaticMethod, methodOrGroup, cardanoApi);
141170
});
142171

143172
return cardanoApi;

0 commit comments

Comments
 (0)