eslint-visitor-keys known bugs
npm13 known bugs in eslint-visitor-keys, with affected versions, fixes and workarounds. Sourced from upstream issue trackers.
13
bugs
Known bugs
| Severity | Affected | Fixed in | Title | Status | Source |
|---|---|---|---|---|---|
| medium | any | \u2014 | `Keyword` tokens output as `Identifier` Running this small example through astexplorer
```js
async function *foo() { // async === Identifier ################
// function === Keyword
var a; // var === Keyword
let b; // let === Keyword
const c = { // const === Keyword
get d() {}, // get === Identifier ################
set e(val) {}, // set === Identifier ################
}
await f; // await === Identifier ################
yield g; // yield === Keyword
typeof x; // typeof === Keyword
a in x; // in === Keyword
}
class H { // class === Keyword
static i() {} // static === Keyword
}
if (true) {} else {} // if === Keyword
// else === Keyword
try {} catch {} finally {} // try === Keyword
// catch === Keyword
// finally === Keyword
for (;;) {} // for === Keyword
do { } while (true); // do === Keyword
// while === Keyword
for (let x of y) {} // for === Keyword
// of === Identifier ################
```
[repl](https://astexplorer.net/#/gist/64a872691c918f615302c6f6735ff84e/9229e8f142352a7aba92132bc44a22535bb640cb)
It looks like there are a few keywords which are incorrectly parsed as identifiers instead of keywords. I found:
- `async`
- `await`
- `get`
- `set`
- `of` | fixed | github:428 |
| medium | any | \u2014 | Question: how come function references on the global scope are not closed https://github.com/eslint/eslint-scope/blob/dbddf14d5771b21b5da704213e4508c660ca1c64/tests/references.js#L211-L263
I'm working on trying to understand this codebase better.
But I can't understand why it works this way:
```js
function a() {}
a();
```
To me it seems clear that the reference that's created as part of the call should resolve directly to the function declaration, but it's not - it remains as an unresolved reference that's added to the global scope's `through` list.
This would cause the `no-unused-vars` ESLint rule to error on the function declaration, were it not for [this code](https://github.com/eslint/eslint/blob/015edf6467e33c67b904db037a674d71957a6865/lib/linter/linter.js#L172-L194) in the linter.
It looks like it works seemingly by chance? ESLint augments the global scope with more variables, and then forcefully resolves any `through` references against the global variable `set`, which includes the function declaration as well as the augmented variables.
Is anyone able to explain why this works this way?
Or a better question - when closing the global scope, why doesn't it attempt to resolve all `through` references against the variables defined in the global scope? | fixed | github:665 |
| medium | any | \u2014 | Should throw on invaid `(a = 1) = t` This should be invalid.
```text
require("espree").parse('(a = 1) = 2', {sourceType: 'module', ecmaVersion: 2019}).body[0].expression
Node {
type: 'AssignmentExpression',
start: 0,
end: 11,
operator: '=',
left: Node {
type: 'AssignmentPattern',
start: 1,
end: 6,
left: Node { type: 'Identifier', start: 1, end: 2, name: 'a' },
right: Node { type: 'Literal', start: 5, end: 6, value: 1, raw: '1' }
},
right: Node { type: 'Literal', start: 10, end: 11, value: 2, raw: '2' }
}
``` | fixed | github:470 |
| medium | any | \u2014 | Should throw on `async () => await 5 ** 6;` `espree` parse this as `await (5 ** 6)`
```text
require('espree').parse('async () => await 5 ** 6', {ecmaVersion: 2017}).body[0].expression.body
Node {
type: 'AwaitExpression',
start: 12,
end: 24,
argument: Node {
type: 'BinaryExpression',
start: 18,
end: 24,
left: Node { type: 'Literal', start: 18, end: 19, value: 5, raw: '5' },
operator: '**',
right: Node { type: 'Literal', start: 23, end: 24, value: 6, raw: '6' }
}
}
````
In chrome, this is a syntax error
```js
async () => await 5 ** 6
VM40:1 Uncaught SyntaxError: Unary operator used immediately before exponentiation expression. Parenthesis must be used to disambiguate operator precedence
```
Babel PR babel/babel#12441 | fixed | github:472 |
| medium | 7.3.1 | \u2014 | npm v7: peer mocha@">=1.18 <7" from [email protected] when running `npm install` with npm v7.
```bash
➜ espree git:(main) npm i
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: [email protected]
npm ERR! Found: [email protected]
npm ERR! node_modules/mocha
npm ERR! dev mocha@"^8.3.1" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer mocha@">=1.18 <7" from [email protected]
npm ERR! node_modules/leche
npm ERR! dev leche@"^2.3.0" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR!
npm ERR! See /home/weiran/.npm/eresolve-report.txt for a full report.
npm ERR! A complete log of this run can be found in:
npm ERR! /home/weiran/.npm/_logs/2021-04-13T03_23_03_200Z-debug.log
```
we have to remove leche(like in the eslint repo) - it has been unmaintained. | fixed | github:480 |
| medium | any | \u2014 | ChainExpression and others are missing in espree.Syntax According to #331, the `espree.Syntax` object is supposed to contain all node types supported by Espree. But comparing it with ` espree.VisitorKeys`, the following node types are missing:
* `ChainExpression`
* `ImportExpression`
* `JSXFragment`
* `JSXOpeningFragment`
* `JSXClosingFragment`
* `PrivateIdentifier`
* `PropertyDefinition`
* `StaticBlock`
`ExperimentalRestProperty` and `ExperimentalSpreadProperty` are also missing, but this might be intentional.
For sure one could derive a list of node types from the keys of `VisitorKeys`, but what's the purpose of the `Syntax` export then? Shouldn't it be used any longer?
| fixed | github:531 |
| medium | 9.5.0 | \u2014 | remove sourcemap url <img width="1440" alt="image" src="https://user-images.githubusercontent.com/41773861/226166008-f3396b2c-c725-4587-af90-123e0174f090.png">
version: [email protected] | fixed | github:566 |
| medium | any | \u2014 | Bug: `scope-manager` does not support the `ecmaVersion` option set to "latest." ### Which packages are affected?
- [ ] `espree`
- [X] `eslint-scope`
- [ ] `eslint-visitor-keys`
### Environment
Node version:
npm version:
ESLint version:
Operating System:
### What did you do?
Tried to set the ecmaVersion option to `lastest` in the `scope-manager`.
### What did you expect to happen?
Since we selected the "latest" option, it should recognize the most recent ECMAScript version and support import declarations.
### What actually happened?
Got the below error:

```
ImportDeclaration should appear when the mode is ES6 and in the module context.
```
https://github.com/eslint/js/blob/91d51d3da4273acaf2523a3b6d23a27a733c13cc/packages/eslint-scope/lib/scope-manager.js#L243
The above condition becomes false when the `ecmaVersion` option is set to `latest`.
### Link to Minimal Reproducible Example
https://deploy-preview-31--eslint-code-explorer.netlify.app/
### Participation
- [X] I am willing to submit a pull request for this issue.
### Additional comments
In [Espree](https://github.com/eslint/js/tree/main/packages/espree), the `ecmaVersion` option can be set to `"latest"` to support the most recent ECMAScript features.
https://github.com/eslint/js/blob/91d51d3da4273acaf2523a3b6d23a27a733c13cc/packages/espree/lib/options.js#L50
Should we maintain consistent handling and options for `ecmaVersion` in both `Espree` and `eslint-scope`? | fixed | github:622 |
| medium | 10.8.1 | \u2014 | Bug: `eslint-scope` requires `assert` ### Which packages are affected?
- [ ] `espree`
- [x] `eslint-scope`
- [ ] `eslint-visitor-keys`
### Environment
Node version: v20.16.0
npm version: 10.8.1
ESLint version: 8.57.0
Operating System: macOS
### What did you do?
In Code Explorer, I aimed to clean up the dependencies by removing unused development and runtime dependencies. I identified the dependencies that were not being used in the repository and then removed them.
### What did you expect to happen?
Code Explorer should work as expected since I removed only the unused dependencies.
### What actually happened?
code explorer scope view was breaking got the below error:

When I reviewed the scope-manager logic in response to the error, I found that it utilizes `assert`.
https://github.com/eslint/js/blob/79c6e93ba93b46186ebfac111c94f44ab3b4ee27/packages/eslint-scope/lib/scope-manager.js#L187
Also `assert` package was intentionally ignored in the config.
https://github.com/eslint/js/blob/79c6e93ba93b46186ebfac111c94f44ab3b4ee27/packages/eslint-scope/rollup.config.js#L3
This means the `assert` package was intentionally marked as external and is expected to be present in the environment where the package is used.
Do we have a specific reason for marking `assert` as external? There might be cases where `assert` is not available in the environment where the package (scope-manager) is being used.
### Link to Minimal Reproducible Example
https://deploy-preview-33--eslint-code-explorer.netlify.app
### Participation
- [x] I am willing to submit a pull request for this issue.
### Additional comments
_No response_ | fixed | github:625 |
| medium | 20.13.1 | \u2014 | Bug: Can't install monorepo ### Which packages are affected?
- [ ] `espree`
- [ ] `eslint-scope`
- [x] `eslint-visitor-keys`
### Environment
Node version: 20.13.1
npm version: 10.4.0
ESLint version: 9.4.0
Operating System: Windows
### What did you do?
Cloned the repository and ran `npm install`
### What did you expect to happen?
For the monorepo to install successfully.
### What actually happened?
I received this error message:
```
npm ERR! > [email protected] build:types
npm ERR! > tsc
npm ERR!
npm ERR! ../../node_modules/@types/node/stream/web.d.ts(469,56): error TS1005: '?' expected.
npm ERR! tsconfig.json(3,13): error TS6046: Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'es2021', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'webworker.iterable', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy',
'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asyncgenerator', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.object',
'es2019.string', 'es2019.symbol', 'es2020.bigint', 'es2020.promise', 'es2020.sharedmemory', 'es2020.string', 'es2020.symbol.wellknown', 'es2020.intl', 'es2021.promise', 'es2021.string', 'es2021.weakref', 'es2021.intl', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint', 'esnext.string', 'esnext.promise', 'esnext.weakref'.
```
### Link to Minimal Reproducible Example
https://github.com/eslint/js
### Participation
- [ ] I am willing to submit a pull request for this issue.
### Additional comments
_No response_ | fixed | github:630 |
| medium | 24.1.0 | \u2014 | Bug: Visitor keys for `ExportSpecifier` are not in source code order ### Which packages are affected?
- [ ] `espree`
- [ ] `eslint-scope`
- [x] `eslint-visitor-keys`
### Environment
Node version: 24.1.0
npm version: 11.3.0
ESLint version: 9.28.0
Operating System: Mac OS 15.4.1
### What did you do?
As far as I can see, it's not documented anywhere that visitor keys are always in source code order. However, in my opinion it's what a user would naturally expect, and this expectation seems to be confirmed because it's true for every single AST node type... With only one exception: `ExportSpecifier`.
```js
export { local as exported };
```
In this case, `exported` is visited before `local`:
https://github.com/eslint/js/blob/b847f35787d4bf2ec68163f45f3e4dc2d209eee8/packages/eslint-visitor-keys/lib/visitor-keys.js#L102-L105
I have opened this issue as a bug report as I *assume* that this deviation from "visit in source code order" rule is an oversight rather than intentional. But there may be some context I am missing.
### What did you expect to happen?
`local` to be visited before `exported`.
### What actually happened?
`exported` is visited before `local` (more like `ImportSpecifier`).
### Link to Minimal Reproducible Example
<skipped>
### Participation
- [x] I am willing to submit a pull request for this issue.
### Additional comments
_No response_ | fixed | github:655 |
| medium | 20.18.0 | \u2014 | Bug: New version of `acorn` v8.1.5 breaks build ### Which packages are affected?
- [x] `espree`
- [ ] `eslint-scope`
- [ ] `eslint-visitor-keys`
### Environment
Node version: 20.18.0
npm version: 10.9.2
ESLint version: HEAD
Operating System: Windows 11
### What did you do?
Hello,
Currently the [CI build is failing](https://github.com/eslint/js/actions/runs/15529797360/job/43716117138) due to the newly released [`acorn` v8.15.0](https://github.com/acornjs/acorn/releases/tag/8.15.0), which was published about 24 hours ago.
I’ve reviewed the changes between [`v8.14.1...v8.15.0`](https://github.com/acornjs/acorn/compare/8.14.1...8.15.0) and identified the source of the issue. Although this release introduces some ES2026 features, I think the bug is not related to those features.
The problem comes from this change:
https://github.com/acornjs/acorn/compare/8.14.1...8.15.0#diff-6a29ed00e92d69844ec35883ec62f4893f40687e70bcd87905757aeaa6fe0af5

```diff
- if (this.tok.type === tt.num && node.raw.charCodeAt(node.raw.length - 1) === 110)
- node.bigint = node.raw.slice(0, -1).replace(/_/g, "")
+ if (this.tok.type === tt.num && node.raw.charCodeAt(node.raw.length - 1) === 110)
+ node.bigint = node.value != null ? node.value.toString() : node.raw.slice(0, -1).replace(/_/g, "")
```
To reproduce the issue, you can simply reinstall packages (with the latest acorn) and run:
```sh
npm run test -w packages/espree
```
---
You can simply reproduce this bug by running `npm run test -w packages/espree` after reinstalling packages with latest `acorn`.
### What did you expect to happen?
Works as before.
### What actually happened?
Caused errors.
### Link to Minimal Reproducible Example
https://github.com/eslint/js/actions/runs/15529797360/job/43716117138
### Participation
- [x] I am willing to submit a pull request for this issue.
### Additional comments
I’m not sure whether this should be fixed in `acorn`, or if it would be better to adjust some test cases or logic in `espree` instead.
| fixed | github:659 |
| medium | 11.6.2 | \u2014 | Bug: ESLint types are incompatiable with `@types/eslint-scope` ### Which packages are affected?
- [ ] `espree`
- [x] `eslint-scope`
- [ ] `eslint-visitor-keys`
### Environment
Node version: 24
npm version: 11.6.2
ESLint version: 9.39.2
Operating System: Mac OS 15.5
### What did you do?
Used the return value of `eslintScope.analyze()` as a parameter of `eslint.Scope.ScopeManager` typed value.
### What did you expect to happen?
Types should be identical
### What actually happened?
Types are not identical
### Link to Minimal Reproducible Example
https://stackblitz.com/edit/node-isht7kjp?file=package.json,src%2Findex.ts
### Participation
- [ ] I am willing to submit a pull request for this issue.
### Additional comments
Coming from https://github.com/eslint-community/eslint-plugin-eslint-plugin/issues/575, seems like the type changes are actually a breaking change | fixed | github:719 |
API access
Get this data programmatically \u2014 free, no authentication.
curl https://depscope.dev/api/bugs/npm/eslint-visitor-keys