Parse bound functions
mauriciomelo opened this issue · 8 comments
reproduce:
const parser = require('parse-function')();
const foo = function foo() { return this.message; };
parser.parse(foo.bind({ message: 'hello' }))
error:
SyntaxError: Unexpected token, expected , (1:22)
at Parser.raise (node_modules/parse-function/node_modules/babylon/lib/index.js:807:15)
at Parser.unexpected (node_modules/parse-function/node_modules/babylon/lib/index.js:2108:16)
at Parser.expect (node_modules/parse-function/node_modules/babylon/lib/index.js:2094:28)
at Parser.parseExprList (node_modules/parse-function/node_modules/babylon/lib/index.js:3884:14)
at Parser.parseExprAtom (node_modules/parse-function/node_modules/babylon/lib/index.js:3185:30)
at Parser.parseExprSubscripts (node_modules/parse-function/node_modules/babylon/lib/index.js:2864:21)
at Parser.parseMaybeUnary (node_modules/parse-function/node_modules/babylon/lib/index.js:2842:21)
at Parser.parseExprOps (node_modules/parse-function/node_modules/babylon/lib/index.js:2751:21)
at Parser.parseMaybeConditional (node_modules/parse-function/node_modules/babylon/lib/index.js:2721:21)
at Parser.parseMaybeAssign (node_modules/parse-function/node_modules/babylon/lib/index.js:2680:21)
at Parser.parseExpression (node_modules/parse-function/node_modules/babylon/lib/index.js:2634:21)
at Parser.parseStatementContent (node_modules/parse-function/node_modules/babylon/lib/index.js:4157:21)
at Parser.parseStatement (node_modules/parse-function/node_modules/babylon/lib/index.js:4045:17)
at Parser.parseBlockOrModuleBlockBody (node_modules/parse-function/node_modules/babylon/lib/index.js:4590:23)
at Parser.parseBlockBody (node_modules/parse-function/node_modules/babylon/lib/index.js:4576:10)
at Parser.parseBlock (node_modules/parse-function/node_modules/babylon/lib/index.js:4565:10)
at Parser.parseFunctionBody (node_modules/parse-function/node_modules/babylon/lib/index.js:3814:24)
at Parser.parseFunctionBodyAndFinish (node_modules/parse-function/node_modules/babylon/lib/index.js:3792:10)
at Parser.parseFunction (node_modules/parse-function/node_modules/babylon/lib/index.js:4717:10)
at Parser.parseFunctionExpression (node_modules/parse-function/node_modules/babylon/lib/index.js:3259:17)
at Parser.parseExprAtom (node_modules/parse-function/node_modules/babylon/lib/index.js:3193:21)
at Parser.parseExprSubscripts (node_modules/parse-function/node_modules/babylon/lib/index.js:2864:21)
at Parser.parseMaybeUnary (node_modules/parse-function/node_modules/babylon/lib/index.js:2842:21)
at Parser.parseExprOps (node_modules/parse-function/node_modules/babylon/lib/index.js:2751:21)
at Parser.parseMaybeConditional (node_modules/parse-function/node_modules/babylon/lib/index.js:2721:21)
at Parser.parseMaybeAssign (node_modules/parse-function/node_modules/babylon/lib/index.js:2680:21)
at Parser.parseExpression (node_modules/parse-function/node_modules/babylon/lib/index.js:2634:21)
at Parser.getExpression (node_modules/parse-function/node_modules/babylon/lib/index.js:2609:21)
at Object.parseExpression (node_modules/parse-function/node_modules/babylon/lib/index.js:10203:17)
at Object.getNode (node_modules/parse-function/dest/index.js:91:18)
at Object.parse (node_modules/parse-function/dest/index.js:367:24)
at Context.it.only (lib/rodar.spec.js:27:14)
bind is not preferred, this - too. I understand that there are cases such in react, but I dont think it is a problem here - the parser fail so I cant do much (looking in first glance).
that's the beauty of the plugins api, try handle it with plugin?
with "this" above I mean this
The example above is the simplest I could reproduce, the real scenario is bit more complex, I want to be able to parse a class (instance) method and preserve it's context. I don't have much control over what is passed to my lib's public api, that's why I can't refact it to not use this.
The interesting part is that when I use babylon.parse() directly it does not throw any error.
because we use parseExpression by default.
why not just pass that method instead of passing bound fn of it?
why not just pass that method instead of passing bound fn of it?
passing just the method seems to not preserve the context
But... I was wondering that even if the bound fn did parse I would lose the params (and defaults) because:
> ((a = 42) => {}).toString()
"(a = 42) => {}"
but
> ((a = 42) => {}).bind().toString()
"function () { [native code] }"
My options right now are:
- pass the entire instance (not only the method), for example
myLib.define(instance)instead ofmyLib.define(instance.method) - add an optional param to handle context, for example
myLib.define(instance.method, { context: instance })
Anyway, thank you for your support and quick reply
What context, what five dollars? Sorry, but absolutely seriously, I can't get for what you are talking about. ;/
You just pass a function and then work with its parsed parts - params, name and string body. Nothing to deal with context, we do nothing to your function too, its context is the same.
What are you trying to do? Can u share code?
the problem is that my lib didn't accept plain objects, so I had to pass an array of functions. the process of converting object methods into an array makes it "unbind" it's parent, for example
const { parse } = require('parse-function')();
class Foo {
constructor() {
this.bar = 42;
}
hello() {
return this.bar;
}
}
const foo = new Foo();
const hello = foo.hello; // unpacking makes it forget the parent context
myLibPublicFunction([hello])
function myLibPublicFunction (definitions) {
const fn = definitions[0];
parse(fn) // ok
// but I have to do some other stuff with fn
fn() // ops, no context
}
// because of that I had to bind
myLibPublicFunction([hello.bind(foo)]);
// it makes fn() happy but not parse(fn)
// so I simplified everything by making my public api accept an object instead of an array
myLibPublicFunction(foo);
function myLibPublicFunction (instance) {
parse(instance.hello) // happy
instance.hello() // happy
}
there are probably a bunch of typos there but hopefully it is understandable
oh yea, I got it. it was definitely an architecture/concept design mistake. so yea, always thinking twice is the best thing