Created
May 16, 2018 19:56
-
-
Save gmmorris/2b132aaeafe2265dd8a2b95bafa0f3b4 to your computer and use it in GitHub Desktop.
Bucklescript bindings approaches for complex Object based arguments
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var CryptographyJs = require("./cryptography.js"); | |
CryptographyJs.hash({ algorithm: 'md5', length: 10 }, "asd"); | |
CryptographyJs.hash({ algorithm: 'md5' }, "asd"); | |
CryptographyJs.hash({ length: 10 }, "asd"); | |
CryptographyJs.hash({}, "asd"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Cryptography.hashWithOpts(hashOptions(~algorithm=`MD5, ~length=10, ()), "asd"); | |
Cryptography.hashWithOpts(hashOptions(~algorithm=`MD5, ()), "asd"); | |
Cryptography.hashWithOpts(hashOptions(~length=10, ()), "asd"); | |
Cryptography.hashWithOpts(hashOptions(), "111"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[@bs.deriving jsConverter] | |
type hash = [ | |
| [@bs.as "sha256"] `SHA256 | |
| [@bs.as "sha512"] `SHA512 | |
| [@bs.as "sha384"] `SHA384 | |
| [@bs.as "sha1"] `SHA1 | |
| [@bs.as "md5"] `MD5 | |
]; | |
[@bs.deriving abstract] | |
type hashConfig = { | |
[@bs.optional] | |
algorithm: string, | |
[@bs.optional] | |
length: int, | |
}; | |
module Crypt_ = { | |
[@bs.obj] | |
external hashOptions : | |
(~algorithm: Js.Nullable.t(string), ~length: Js.Nullable.t(int), unit) => | |
hashConfig = | |
""; | |
}; | |
let mapNullable = (opt: option('a), cb: 'a => 'b) => | |
switch (opt) { | |
| Some(a) => Js.Nullable.return(cb(a)) | |
| None => Js.Nullable.undefined | |
}; | |
let hashOptions = (~algorithm=?, ~length=?, ()) => | |
Crypt_.hashOptions( | |
~algorithm=mapNullable(algorithm, hashToJs), | |
~length=mapNullable(length, i => i), | |
(), | |
); | |
[@bs.module "./cryptography.js"] | |
external hashWithOpts : (hashConfig, string) => unit = "hash"; | |
hashWithOpts(hashOptions(~algorithm=`MD5, ~length=10, ()), "asd"); | |
hashWithOpts(hashOptions(~algorithm=`MD5, ()), "asd"); | |
hashWithOpts(hashOptions(~length=10, ()), "asd"); | |
hashWithOpts(hashOptions(), "asd"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ algorithm: 'md5', length: 10 } 'asd' | |
{ algorithm: 'md5', length: undefined } 'asd' | |
{ algorithm: undefined, length: 10 } 'asd' | |
{ algorithm: undefined, length: undefined } 'asd' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[@bs.deriving jsConverter] | |
type hash = [ | |
| [@bs.as "sha256"] `SHA256 | |
| [@bs.as "sha512"] `SHA512 | |
| [@bs.as "sha384"] `SHA384 | |
| [@bs.as "sha1"] `SHA1 | |
| [@bs.as "md5"] `MD5 | |
]; | |
[@bs.deriving abstract] | |
type hashConfig = { | |
[@bs.optional] | |
algorithm: string, | |
[@bs.optional] | |
length: int, | |
}; | |
module Crypt_ = { | |
[@bs.obj] | |
external hashOptions : | |
(~algorithm: string=?, ~length: int=?, unit) => hashConfig = | |
""; | |
}; | |
let mapNullable = (opt: option('a), cb: 'a => 'b) => | |
switch (opt) { | |
| Some(a) => Js.Nullable.return(cb(a)) | |
| None => Js.Nullable.undefined | |
}; | |
let hashOptions = (~algorithm=?, ~length=?, ()) => | |
switch (algorithm) { | |
| Some(algorithm_) => | |
switch (length) { | |
| Some(length_) => | |
Crypt_.hashOptions( | |
~algorithm=hashToJs(algorithm_), | |
~length=length_, | |
(), | |
) | |
| None => Crypt_.hashOptions(~algorithm=hashToJs(algorithm_), ()) | |
} | |
| None => | |
switch (length) { | |
| Some(length_) => Crypt_.hashOptions(~length=length_, ()) | |
| None => Crypt_.hashOptions() | |
} | |
}; | |
[@bs.module "./cryptography.js"] | |
external hashWithOpts : (hashConfig, string) => unit = "hash"; | |
hashWithOpts(hashOptions(~algorithm=`MD5, ~length=10, ()), "asd"); | |
hashWithOpts(hashOptions(~algorithm=`MD5, ()), "asd"); | |
hashWithOpts(hashOptions(~length=10, ()), "asd"); | |
hashWithOpts(hashOptions(), "asd"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ algorithm: 'md5', length: 10 } 'asd' | |
{ algorithm: 'md5' } 'asd' | |
{ length: 10 } 'asd' | |
{} 'asd' |
A...nd got there. Honestly don't get how that wasn't obvious to me. facepalm
type hashConfig;
[@bs.obj]
external hashOptions :
(~_Algorithm: string=?, ~length: int=?, unit) => hashConfig =
"";
let hashOptions = (~algorithm=?, ~length=?, ()) =>
hashOptions(
~_Algorithm=?Belt.Option.map(algorithm, hashToJs),
~length?,
(),
);
Cheers :D
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
OK, this has been very helpful but I'm hitting another wall.
And sorry for asking so many questions but I can't seem to find detailed documentation of these features beyond the Bucklescript manual (https://bucklescript.github.io/bucklescript/Manual.html) which while detailed in general, is quite sparse on the side effects of these annotations (gives many different examples, but each example is quite basic).
The one issue I'm still stuck on is that I actually got the TheAPIThatIWantToSupport.re a little wrong.
Sadly the API of the JS library isn't quite compatible with Reason's semantics, and some of the keys are actually capitalised.
If we apply this to our contrived example above, it would be something like:
See how the Algorithm field is capitalised?
I've tried explicitly mentioning the algorithm field with a [@bs.as] annotation on the hashConfig but that didn't work.
I tried using a deriving like this:
The _ seems to tell it to convert to a capitalised property, which is good, but I can't figure out how to pass that through to the hashWithOpts without explicitly changing the signature to {. "_Algorithm": string, "length": int} - and that had a weird result because the [bs.obj] seems to return an object rather than the array that the generated hashConfigToJs expects.
I seem to have made a mess of the whole thing . :p
Any ideas?