Allow trailing comma in sequence expression

I'm not saying we should encourage people to use sequence expression.

When I have something like,

const foo = doSomething(
  bar,
);

I decide to remove the function call, so I expect just remove the function name

const foo = (
  bar,
);

then tools to remove parentheses and the comma for me.

Unfortunately, ESlint and Prettier can't do anything, since it's a syntax error, but if we allow trailing comma in sequence expression, then an ESlint rule can unwrap the sequence expression since it's meaningless, and Prettier can do the rest work.

Maybe we can also use (eval,)(...) instead of (0, eval)(...) to make an indirect call?

Welcome @fisker !

Would it perhaps be better if these tools were able to offer some functionality even when the source has a syntax error? There are multiple JavaScript parsers which are able to produce ASTs even for inputs that contain errors.

In my experience of maintaining Prettier and ESLint rules, supporting invalid syntax causes much pain.

Prettier used to support invalid syntaxes in v2, then many unexpected cases were reported, so we only allow specific cases that don't affect print Whitelist recovered babel parse errors by fisker 路 Pull Request #10495 路 prettier/prettier 路 GitHub

I also added many checks to typescript-estree to prevent unexpected cases in Prettier and ESLint rules, eg Enhancement: Forbid catch clause with initializer 路 Issue #8182 路 typescript-eslint/typescript-eslint 路 GitHub.

While on one hand, it brings pretty much full consistency with comma separation elsewhere, this is probably the one case that wouldn't benefit from it.

In objects, arrays, function arguments, and so on, all values are important, and it's reasonable to expect diffs that append one more entry. In sequence expressions, all but the last value is ignored. Because of this, the last expression is always special. Most changes would occur before the last expression, not after.

If anything, a trailing comma could make the sequence expression misleading, making the last statement seem unimportant like the others.

All values are important in a parentheses/sequence expressions. They are all executed, left-to-right, and the value returned (which can only be used with parentheses ()) is just the last one.

This works identically to semicolon ;-separated sequences, except there you can't use the last value because there is no syntactically-valid way to do so (const result = (a;b;) is invalid, but if it were valid it would be equal to b, at least that is how eval() works)

In a way, parentheses could be equated to

function parentheses(...seq){
    return seq[seq.length - 1]
}

and in such a scenario, parentheses(1, 2, 3, ) would not return undefined or a syntax error but simply 3. I would agree that this is not the most intuitive semantic, but since we've already gone with it years ago I see no problem in (1, 2, 3, ) == 3 too

The return values of them are ignored. That's what I was referring to.