-
-
Save gmmorris/2b132aaeafe2265dd8a2b95bafa0f3b4 to your computer and use it in GitHub Desktop.
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"); |
Cryptography.hashWithOpts(hashOptions(~algorithm=`MD5, ~length=10, ()), "asd"); | |
Cryptography.hashWithOpts(hashOptions(~algorithm=`MD5, ()), "asd"); | |
Cryptography.hashWithOpts(hashOptions(~length=10, ()), "asd"); | |
Cryptography.hashWithOpts(hashOptions(), "111"); |
[@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"); |
{ algorithm: 'md5', length: 10 } 'asd' | |
{ algorithm: 'md5', length: undefined } 'asd' | |
{ algorithm: undefined, length: 10 } 'asd' | |
{ algorithm: undefined, length: undefined } 'asd' |
[@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"); |
{ algorithm: 'md5', length: 10 } 'asd' | |
{ algorithm: 'md5' } 'asd' | |
{ length: 10 } 'asd' | |
{} 'asd' |
Since the length
and ()
parameters are left as such I'd even suggest partial application, so we can focus only on the parameters that need some processing. Also I added the missing Crypt_
module qualifier.
[@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
];
type hashConfig;
[@bs.obj]
external hashOptions :
(~algorithm: string=?, ~length: int=?, unit) => hashConfig =
"";
let hashOptions = (~algorithm=?) =>
Crypt_.hashOptions(~algorithm=?Belt.Option.map(algorithm, hashToJs));
[@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");
Thanks guys, I'll play around with these ideas tomorrow. :)
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:
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");
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:
[@bs.deriving jsConverter]
type hashConfig = {
[@bs.optional]
_Algorithm: string,
[@bs.optional]
length: int,
};
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?
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
Removing the
switch
after the comment from Christophe in Discord, using the explicitly passed optional: