Skip to content

Change Request: Program range cover whole program #648

Open
@overlookmotel

Description

@overlookmotel

Which packages would you like to change?

  • espree
  • eslint-scope
  • eslint-visitor-keys

What problem do you want to solve?

The source range for Program is surprising when source code starts or ends with comments.

e.g.:

// foo

x

// bar

Espree (like Esprima) produces an AST where range of Program node excludes whitespace and comments from start and end of file. In example above, the range of Program node is [ 8, 9 ] i.e. the range of the sole statement.

AST explorer - Espree

This differs from Acorn, which produces a range of [0, 17] i.e. the whole of the source code.

AST explorer - Acorn

What is particularly surprising is that with option comment: true you get comments which are outside the range of the program that contains them:

{
  type: 'Program',
  start: 8,
  end: 9,
  body: [
    {
      type: 'ExpressionStatement',
      start: 8,
      end: 9,
      expression: { type: 'Identifier', start: 8, end: 9, name: 'x' }
    }
  ],
  sourceType: 'script',
  comments: [
    { type: 'Line', value: ' foo', start: 0, end: 6, range: [ 0, 6 ] },
    { type: 'Line', value: ' bar', start: 11, end: 17, range: [ 11, 17 ] }
  ]
}

As a further surprise, if the file contains only comments, then the behavior changes:

// foo

This produces a range of [ 0, 8 ]. This does not align with Esprima, which produces range of [ 8, 8 ].

What do you think is the correct solution?

Espree's docs state that:

The primary goal is to produce the exact same AST structure and tokens as Esprima, and that takes precedence over anything else.

Given that Esprima has not received updates for 7 years, and is essentially defunct, I'm not sure whether the maintainers of Espree consider alignment with Esprima still to be the primary goal. I'm also not sure whether that aim, if it still holds, extends to source ranges, or just the AST shape.

What's the correct behavior?

This is arguable. But, in my opinion, it's unintuitive that comments which are part of a program exist in ranges outside of the Program.

The example where the program consists of only comments I think is illustrative. What's the logical range for Program to have in this case, if comments are excluded? [0, 0] or [8, 8]?

The fact that there isn't a clear answer I feel reveals there's a problem with the mental model.

[0, 8] (as Espree currently does) makes most sense to me. But this is inconsistent with Esprima, and also inconsistent with Espree's behavior when there are statements in the program.

Others may feel differently.

Why does this matter?

In addition to the difference from Acorn, @typescript-eslint/parser is also different again - for the first example, it gives a range of [8, 18]! Though the maintainers seem to think Acorn's behavior would be preferable.

AST explorer - TS-ESLint

Personally, I think it's unfortunate that the 3 most depended-on ESTree-compatible parsers Espree, Acorn, and TS-ESLint differ in this respect.

What to do?

One way or another, in my opinion Espree's current behavior is incorrect.

  • In the case which program is only comments, output differs from Esprima, violating Espree's stated goal.
  • Or, if alignment with Esprima is not an aim as far as ranges are concerned, it would make more sense to have a less surprising behavior.

Changing behavior to match Acorn (which personally I'd advocate for) would be a breaking change. Though, given that the 3 most popular ESTree-compatible parsers differ from each in this regard and I'm not aware of anyone complaining about it before, probably not a big one!

Participation

  • I am willing to submit a pull request for this change.

Additional comments

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    Feedback Needed

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions