Question about trailing comma handling in Arguments vs ImportCall

Hello, I've noticed proposal-import-attributes is just finished and included in ES2025. While examining the updated syntax, I came across an interesting difference in how trailing commas are handled between Arguments and ImportCall productions, and I'd like to understand the design rationale better.

In the Arguments production, trailing commas are handled by having separate production rules:

Arguments[Yield, Await] :
    ( )
    ( ArgumentList[?Yield, ?Await] )
    ( ArgumentList[?Yield, ?Await] , )

While in the ImportCall production (updated with import attributes in ES2025), trailing commas use an optional terminal:

ImportCall[Yield, Await] :
    import ( AssignmentExpression[+In, ?Yield, ?Await] ,opt )
    import ( AssignmentExpression[+In, ?Yield, ?Await] , AssignmentExpression[+In, ?Yield, ?Await] ,opt )

I understand that both terminals and nonterminals can be optional. I'm curious if there's a specific reason for choosing different approaches here - separate productions for Arguments vs. optional terminals for ImportCall.

Thank you!

My guess is, the person who modified the grammar to add trailing comma to Arguments either didn't know that terminals could be optional, or preferred not to do it that way. I'm pretty sure there's no technical reason not to do it that way.

1 Like

Thank you for the clarification! I was just curious if there was a specific design consideration behind the syntax, but it makes sense that it might just be a stylistic choice. AFAIK, ImportCall might be the first actual use of optional terminals in the spec - that's why it caught my attention.