Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upFix eval functions, allow them to take args #21
Conversation
This comment has been minimized.
This comment has been minimized.
@jihchi @Khady This API is very important to the usability of these bindings. I would really appreciate your feedback. We may want to at least add a few more shortcut functions for calling eval functions that don't take arguments, and maybe make the ones that take extra arguments have Puppeteer API Docs: https://github.com/GoogleChrome/puppeteer/blob/v1.1.1/docs/api.md |
zploskey
reviewed
Mar 8, 2018
Looking at this with fresh eyes, this clearly needs some more work. |
/* TODO: Add support [, ...args] */ | ||
[@bs.splice] | ||
external selectOneEval : | ||
(string, 'a => 'b, array(jsonOrHandle)) => Js.Promise.t(serializable) = |
This comment has been minimized.
This comment has been minimized.
zploskey
Mar 8, 2018
Author
Owner
First argument of the eval function should be Dom.element
, then accept any number of other arguments as passed in the array(jsonOrHandle)
. Might be good to make this the WithArgs
version and drop the third argument for selectOneEval
.
[@bs.send.pipe : t] | ||
external selectAllEval : (string, unit => unit) => Js.Promise.t('a) = "$$eval"; | ||
external selectAllEval : | ||
(string, Dom.element => 'a) => Js.Promise.t(serializable) = |
This comment has been minimized.
This comment has been minimized.
zploskey
Mar 8, 2018
Author
Owner
Actually don't think this will work as is. The first argument of the function should be a nodeList(Dom.element)
. Need to figure out what to use for a nodeList
binding or if we need to write one.
https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll
This comment has been minimized.
This comment has been minimized.
yawaramin
Mar 8, 2018
You can use the type https://bucklescript.github.io/bucklescript/api/Dom.html#TYPEnodeList which was explicitly left as abstract so that different libraries could use the types interoperably.
This comment has been minimized.
This comment has been minimized.
zploskey
Mar 8, 2018
•
Author
Owner
Perfect, we should definitely use that here. We may want to recommend a library for working with these types--maybe put a link to bs-webapi
in the readme.
|
||
[@bs.send.pipe : t] [@bs.splice] | ||
external selectAllEvalWithArgs : | ||
(string, Dom.element => 'a, array(jsonOrHandle)) => |
This comment has been minimized.
This comment has been minimized.
zploskey
Mar 8, 2018
Author
Owner
As above, first arg to the eval function needs to be nodeList(Dom.element)
.
[@bs.send.pipe : t] [@bs.splice] | ||
external evaluate : | ||
(unit => Js.Promise.t(Js.Json.t), array({..})) => Js.Promise.t(Js.Json.t) = | ||
(Eval.Fn.t, array(Eval.Arg.t)) => Js.Promise.t(serializable) = |
This comment has been minimized.
This comment has been minimized.
zploskey
Mar 8, 2018
Author
Owner
Since I wound up splitting evaluate()
into evaluateString
and this function, we could maybe rethink whether we want to use Eval.Fn.t
as the first argument, or if Eval.Fn.t
needs to include string
. We need to somehow indicate how many args the function takes, or require the user to curry all the args before passing the function to evaluate
.
This comment has been minimized.
This comment has been minimized.
yawaramin
Mar 8, 2018
Having a separate function binding for the string argument seems like a good idea. It puts the user in an explicitly different context.
This comment has been minimized.
This comment has been minimized.
zploskey
Mar 8, 2018
Author
Owner
Probably best to have bindings for functions of each arity for evaluate
as well, so it is consistent. Then we can get rid of Eval.Fn
and we only need Eval.Arg
.
[@bs.send.pipe : t] [@bs.splice] | ||
external evaluateHandle : | ||
(unit => Js.Promise.t(JSHandle.t), array({..})) => Js.Promise.t(JSHandle.t) = | ||
('a => Js.Promise.t(JSHandle.t), array(Eval.Arg.t)) => |
This comment has been minimized.
This comment has been minimized.
zploskey
Mar 8, 2018
Author
Owner
The first arg to evaluateHandle
should be a function of any number of arguments (equal to the length of the array in the second arg to evaluateHandle, though I don't know if we can enforce that). Again, need to investigate whether we want/can require the user to curry the eval function with args so that we just take a function of type unit => Js.Promise.t(JSHandle.t)
.
This comment has been minimized.
This comment has been minimized.
yawaramin
Mar 8, 2018
It looks like, to correctly compile to uncurried callbacks for the pageFunction
, you'll need to use [@bs]
or [@bs.uncurry]
. This in turn means that you'll need to provide multiple external bindings by arity. E.g.,
[@bs.send.pipe: t] [@bs.splice] external evaluateHandle1: (
[@bs.uncurry] Eval.Arg.t => Js.Promise.t(JSHandle.t),
Eval.Arg.t) =>
Js.Promise.t(JSHandle.t) =
"evaluateHandle";
[@bs.send.pipe: t] [@bs.splice] external evaluateHandle2: (
[@bs.uncurry] (Eval.Arg.t, Eval.Arg.t) => Js.Promise.t(JSHandle.t),
Eval.Arg.t,
Eval.Arg.t) =>
Js.Promise.t(JSHandle.t) =
"evaluateHandle";
And so on.
This comment has been minimized.
This comment has been minimized.
zploskey
Mar 8, 2018
Author
Owner
Ah this is much better. Explicitly enumerating the the args means we constrain their number and we can get rid of [@bs.splice]
since they won't need to pass an array.
external fn1 : ('a => 'b) => t = "%identity"; | ||
external fn2 : (('a, 'b) => 'c) => t = "%identity"; | ||
external fn3 : (('a, 'b, 'c) => 'd) => t = "%identity"; | ||
external fn4 : (('a, 'b, 'c, 'd) => 'd) => t = "%identity"; |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Khady
Mar 8, 2018
external fn4 : (('a, 'b, 'c, 'd) => 'd) => t = "%identity";`
Should be
external fn4 : (('a, 'b, 'c, 'd) => 'e) => t = "%identity";
Khady
reviewed
Mar 8, 2018
external fn1 : ('a => 'b) => t = "%identity"; | ||
external fn2 : (('a, 'b) => 'c) => t = "%identity"; | ||
external fn3 : (('a, 'b, 'c) => 'd) => t = "%identity"; | ||
external fn4 : (('a, 'b, 'c, 'd) => 'd) => t = "%identity"; |
This comment has been minimized.
This comment has been minimized.
Khady
Mar 8, 2018
external fn4 : (('a, 'b, 'c, 'd) => 'd) => t = "%identity";`
Should be
external fn4 : (('a, 'b, 'c, 'd) => 'e) => t = "%identity";
This comment has been minimized.
This comment has been minimized.
Using the This also let us get rid of I'm pretty happy with this. Let me know if you have any concerns before I merge this. |
jihchi
reviewed
Mar 8, 2018
*/ | ||
[@bs.send.pipe : t] | ||
external selectOneEvalPromise : | ||
(string, Dom.element => Js.Promise.t('r)) => Js.Promise.t('r) = |
This comment has been minimized.
This comment has been minimized.
jihchi
Mar 8, 2018
Collaborator
Just curious, why need Promise
version (Dom.element => Js.Promise.t('r)
) here? Would Dom.element => 'r
not be enough?
This comment has been minimized.
This comment has been minimized.
zploskey
Mar 8, 2018
•
Author
Owner
Then the return type of the external is potentially Js.Promise.t(Js.Promise.t('r))
or 'r
which is not a promise, which are both incorrect. Javascript promises can't be nested like that and are flattened to one under the hood. The puppeteer docs also state it will always only return one promise. We need the return type from inside the promise returned from the evaled function, otherwise we can have a return type that is not a promise at all if they pass a function that does not return a promise. I know it seems odd but I'm not sure that there are any other straightforward ways of dealing with this.
This comment has been minimized.
This comment has been minimized.
zploskey
Mar 8, 2018
Author
Owner
If you need to eval a function that does not return a promise then use selectOneEval
instead of this function. The types will keep you honest as long as there is a known return type (i.e. not 'a
or the like). On a side note, we're going to want to write and generate API docs at some point since we are deviating a bit from the upstream API, and it's nice to see it in the editor. I've started to write some here.
zploskey
added some commits
Mar 8, 2018
This comment has been minimized.
This comment has been minimized.
Using |
zploskey
force-pushed the
betterEval
branch
from
802b166
to
c001d64
Mar 8, 2018
zploskey
merged commit b2a0781
into
master
Mar 8, 2018
This comment has been minimized.
This comment has been minimized.
If there are issues with these changes let's just do some bug fixes. |
zploskey commentedMar 6, 2018
•
edited
Fixes #6.