Open kosich opened 3 years ago
Neeeat! I'm not quite sure how it handles brackets though. I think [1, 2, 3].map(_ + 1)
should become [1, 2, 3].map((_temp) => _temp + 1)
and not (_temp) => ([1, 2, 3].map(_temp + 1))
.
I think one thing you could do is to bubble up the _
to the nearest (not-function-calling) grouping, so that [1, 2, 3].map((_ + 1))
could become [1, 2, 3].map((_temp) => _temp + 1)
. It definitely feels a bit quirky at first, but at second glance, it's pretty robust. It would even work neatly with pipelines: const addOne = (_ |> (1 + _))
would become const addOne = (_temp) => 1 + _temp
(note that the mentioned code currently results in an error).
What do you think?
Heya, glad you liked it!
Yeah, I think constructs like [1, 2, 3].map(_ + 1)
should definitely be supported!
Though, with a nearest non-calling group bubbling there might be a problem, as [1, 2, 3].map( 2 * (20 + _) )
wont bubble high enough. One possible solution is to use explicit marking, where we want _
to bubble to (as you originally proposed).
Without changing the babel's syntax parsing (which I think is more troublesome), we could try the {}
marking (as discussed in #5 and if we won't find more issues with it).
Also, currently the plugin handles the pipes |>
as a special case. With explicit markings, we might or might not want continue doing that. E.g.:
// special case, implicit grouping
let a = 42 |> _ + 1; // ≈ 42 + 1;
typeof a; // 'number';
// no special case, explicitly placing bubble point:
let a = 42 |> { _ + 1 }; // ≈ 42 + 1;
typeof a; // 'number';
// no special case, bubbling to the top of the expression
let a = 42 |> _ + 1; // ≈ x => (x + 1)(42);
typeof a; // 'function';
a('param'); // runtime error
// no special case, no implicit bubbling
let a = 42 |> _ + 1; // parsing error
.
note that the mentioned code currently results in an error
Great catch! I'll have to check that out, thx! I was a bit lazy to add specs, but if we get serious, we should add proper tests.
.
Please, share your thoughts.
I think not having special cases is a better starting position. I think if something can be added later and it makes sense to add it later, it should be added later. So I believe that having no bubbling and implicit grouping would be the best at first.
I was wrong, let a = { _ + 1 }
is surely an invalid JS construct that fails at parse time (idk why I thought it would work).
So if we want a marker, seems like we'll need to alter babel's parser.
Since {}
turned me down, I needed some other valid syntax to mark partial expression's root. So, I had to apply a bit of magic. Bit magic, to be exact. I decided to try overriding bitwise not ~
unary operator:
let a = ~ _ + 1;
similar to your proposed ^
syntax, isn't it?
And after a while, I think it works:
a = ~ _;
assert(a(42) === 42);
a = ~ _ + 1;
assert(a(41) === 42);
a = ~ _(40) + 1;
assert(a(inc) === 42);
a = [1,2,3].map(~ _ + 1).join();
assert(a === '2,3,4');
a = [1,2,3].filter(~ _ % 2).map(~ _ + 1).join()
assert(a === '2,4');
~
mark is now required everywhere, except for pipe RHS:
// in pipe LHS, the ~ marker is required
a = ~ _ |> inc
assert(a(42) === 43)
// without a marker babel will throw
a = _ |> inc // INVALID: _ is unbound
// RHS can have explicit or implicit grouping
a = 40 |> ~ _ + 1 |> _ + 1
assert(a === 42)
Here is the babel playground with new syntax.
Please, note that I haven't covered or tested multiple placeholders, nested ~
groups, async/await, and ~
w/o a placeholder. Which might be ok for current stage and is probably better to implement with parser override.
Hey, great work on the proposal!
I created a babel plugin with simpler rules ("simpler", not "better"!), exploring no prefix partial expressions:
You can play with it in the babel playground.
And here's the plugin repository where I described some rules and how it integrates with the pipeline operator.
Maybe it can help pushing the proposal further.