tunnckoCore/parse-function

ES6 default parameters

eush77 opened this issue · 10 comments

Default parameters are not currently supported:

> parseFunction('function (opts = { foo: { done: (x) => console.log({ value: x }) } }, cb) { /* ... */ }')
{ name: 'anonymous',
  body: ' foo: { done: (x) => console.log({ value: x }) } }, cb) { /* ... */ ',
  args: [ 'opts' ],
  params: 'opts' }

I would expect something like this:

{ name: 'anonymous',
  body: ' /* ... */ ',
  args: [ 'opts', 'cb' ],
  params: 'opts = { foo: { done: (x) => console.log({ value: x }) } }, cb' }

But perhaps it's even better to capture default params instead of throwing them away:

{ name: 'anonymous',
  body: '  /* ... */ ',
  args: [ 'opts', 'cb' ],
  params: 'opts = { foo: { done: (x) => console.log({ value: x }) } }, cb',
  defaults: {
    opts: '{ foo: { done: (x) => console.log({ value: x }) } }'
  } }

Yea, yea.. that's was in my mind, but I've just forgot it. lol.

@eush77 any help and ideas will be appreciated.

@eush77 what about if there's also parameter that dont have defaults? e.g. cb from below code?

function foo (a = 123, opts = { foo: { done: (x) => console.log({ value: x }) } }, cb) {
  cb(null, a, opts.foo || 'nope')
}

should that .defaults property in the result object, contain the cb ? What's your expectations?

I'm now playing with acorn.

@eush77 @cmtt, Is that okey? Lol, it's pretty fun to play with this things, haha.

{ name: 'anonymous',
  args: [ 'a', 'cb' ],
  params: 'a, cb',
  body: 'return a * 3',
  defaults: { a: '{foo: "ba)r", baz: 123}', cb: undefined },
  value: 'function (a = {foo: "ba)r", baz: 123}, cb) {return a * 3}' }
{ name: 'anonymous',
  args: [ 'a', 'cb' ],
  params: 'a, cb',
  body: 'return a * 3',
  defaults: { a: undefined, cb: undefined },
  value: 'function (a, cb) {return a * 3}' }
{ name: 'anonymous',
  args: [ 'a' ],
  params: 'a',
  body: 'return a * 3',
  defaults: { a: undefined },
  value: 'function (a) {return a * 3}' }
{ name: 'anonymous',
  args: [],
  params: '',
  body: 'return a * 3',
  defaults: {},
  value: 'function () {return a * 3}' }
{ name: 'anonymous',
  args: [],
  params: '',
  body: '',
  defaults: {},
  value: 'function () {}' }
{ name: 'anonymous',
  args: [ 'a', 'cb' ],
  params: 'a, cb',
  body: 'return a * 3',
  defaults: { a: '{foo: "ba)r", baz: 123}', cb: undefined },
  value: '(a = {foo: "ba)r", baz: 123}, cb) => {return a * 3}' }
{ name: 'anonymous',
  args: [ 'a', 'cb' ],
  params: 'a, cb',
  body: 'return a * 3',
  defaults: { a: undefined, cb: undefined },
  value: '(a, cb) => {return a * 3}' }
{ name: 'anonymous',
  args: [ 'a' ],
  params: 'a',
  body: 'return a * 3',
  defaults: { a: undefined },
  value: '(a) => {return a * 3}' }
{ name: 'anonymous',
  args: [],
  params: '',
  body: 'return a * 3',
  defaults: {},
  value: '() => {return a * 3}' }
{ name: 'anonymous',
  args: [],
  params: '',
  body: '',
  defaults: {},
  value: '() => {}' }
{ name: 'anonymous',
  args: [ 'a' ],
  params: 'a',
  body: 'a * 3 * a',
  defaults: { a: undefined },
  value: '(a) => a * 3 * a' }
{ name: 'anonymous',
  args: [ 'a', 'b' ],
  params: 'a, b',
  body: 'a * 3 * b',
  defaults: { a: undefined, b: undefined },
  value: '(a, b) => a * 3 * b' }
{ name: 'anonymous',
  args: [ 'x', 'y' ],
  params: 'x, y',
  body: 'console.log({ value: x * y })',
  defaults: { x: undefined, y: undefined },
  value: '(x, y) => console.log({ value: x * y })' }
{ name: 'anonymous',
  args: [ 'a' ],
  params: 'a',
  body: 'a * 3 * a',
  defaults: { a: undefined },
  value: 'a => a * 3 * a' }
{ name: 'anonymous',
  args: [ 'a' ],
  params: 'a',
  body: 'return a * 3 * a',
  defaults: { a: undefined },
  value: 'a => {return a * 3 * a}' }

Using acorn (acorn_loose) all test cases are passing + bonus more test cases...

It's sad that performance is 2-3-4x slower using acorn... ;/ but it is faster than string looping approach.
But I think there's no other way to handle all correctly.

closing as of v2.3.0

Again, very thanks! Hope this helps! Review the changelog.

@tunnckoCore Oh, that's great news! 👍 for correctness.

acorn is definitely too much, I will try to crank up performance and send a PR if I succeed. It's good the benchmarks are included.

Yea. It's lil' bit sadly, but I think we can't handle it without acorn or any low-level-awesome-parser. It's impossible, there are too much things. And if it can be done with string looping approach it 100% will be slower than using acorn directly - that's why i just used it.

I like the way that versions became. If you just dont need arrows, and at all es6 things, he can just stay to v2.0.x, otherwise ... yea. Pretty cool - there are 3 available and stable options.

But yea, if you can do something better and faster i'm here, just pr :)

And if it can be done with string looping approach it 100% will be slower than using acorn directly - that's why i just used it.

One thing about acorn is that it gives you not only function expression node and args, but also the function body, which means it takes some time to scan it and parse into AST which we absolutely don't need. String looping can stop early, just after function args.

👍 right

Will wait if you can do something sometime in the future, would be awesome!

That's works for me currently and it's no so big damage. :)

Cheers 🍻,
Charlike!