Bump packages to fix linter
This commit is contained in:
parent
ed9506bbaf
commit
0a11e3fdd9
6063 changed files with 378752 additions and 306784 deletions
6553
node_modules/eslint/CHANGELOG.md
generated
vendored
6553
node_modules/eslint/CHANGELOG.md
generated
vendored
File diff suppressed because it is too large
Load diff
2
node_modules/eslint/LICENSE
generated
vendored
2
node_modules/eslint/LICENSE
generated
vendored
|
|
@ -1,4 +1,4 @@
|
|||
Copyright JS Foundation and other contributors, https://js.foundation
|
||||
Copyright OpenJS Foundation and other contributors, <www.openjsf.org>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
166
node_modules/eslint/README.md
generated
vendored
166
node_modules/eslint/README.md
generated
vendored
|
|
@ -10,10 +10,10 @@
|
|||
# ESLint
|
||||
|
||||
[Website](https://eslint.org) |
|
||||
[Configuring](https://eslint.org/docs/user-guide/configuring) |
|
||||
[Configuring](https://eslint.org/docs/latest/use/configure) |
|
||||
[Rules](https://eslint.org/docs/rules/) |
|
||||
[Contributing](https://eslint.org/docs/developer-guide/contributing) |
|
||||
[Reporting Bugs](https://eslint.org/docs/developer-guide/contributing/reporting-bugs) |
|
||||
[Contributing](https://eslint.org/docs/latest/contribute) |
|
||||
[Reporting Bugs](https://eslint.org/docs/latest/contribute/report-bugs) |
|
||||
[Code of Conduct](https://eslint.org/conduct) |
|
||||
[Twitter](https://twitter.com/geteslint) |
|
||||
[Mailing List](https://groups.google.com/group/eslint) |
|
||||
|
|
@ -31,7 +31,7 @@ ESLint is a tool for identifying and reporting on patterns found in ECMAScript/J
|
|||
2. [Configuration](#configuration)
|
||||
3. [Code of Conduct](#code-of-conduct)
|
||||
4. [Filing Issues](#filing-issues)
|
||||
5. [Frequently Asked Questions](#faq)
|
||||
5. [Frequently Asked Questions](#frequently-asked-questions)
|
||||
6. [Releases](#releases)
|
||||
7. [Security Policy](#security-policy)
|
||||
8. [Semantic Versioning Policy](#semantic-versioning-policy)
|
||||
|
|
@ -41,31 +41,25 @@ ESLint is a tool for identifying and reporting on patterns found in ECMAScript/J
|
|||
12. [Sponsors](#sponsors)
|
||||
13. [Technology Sponsors](#technology-sponsors)
|
||||
|
||||
## <a name="installation-and-usage"></a>Installation and Usage
|
||||
## Installation and Usage
|
||||
|
||||
Prerequisites: [Node.js](https://nodejs.org/) (`^10.12.0`, or `>=12.0.0`) built with SSL support. (If you are using an official Node.js distribution, SSL is always built in.)
|
||||
Prerequisites: [Node.js](https://nodejs.org/) (`^12.22.0`, `^14.17.0`, or `>=16.0.0`) built with SSL support. (If you are using an official Node.js distribution, SSL is always built in.)
|
||||
|
||||
You can install ESLint using npm:
|
||||
You can install and configure ESLint using this command:
|
||||
|
||||
```
|
||||
$ npm install eslint --save-dev
|
||||
```
|
||||
|
||||
You should then set up a configuration file:
|
||||
|
||||
```
|
||||
$ ./node_modules/.bin/eslint --init
|
||||
```shell
|
||||
npm init @eslint/config
|
||||
```
|
||||
|
||||
After that, you can run ESLint on any file or directory like this:
|
||||
|
||||
```
|
||||
$ ./node_modules/.bin/eslint yourfile.js
|
||||
```shell
|
||||
./node_modules/.bin/eslint yourfile.js
|
||||
```
|
||||
|
||||
## <a name="configuration"></a>Configuration
|
||||
## Configuration
|
||||
|
||||
After running `eslint --init`, you'll have a `.eslintrc` file in your directory. In it, you'll see some rules configured like this:
|
||||
After running `npm init @eslint/config`, you'll have a `.eslintrc` file in your directory. In it, you'll see some rules configured like this:
|
||||
|
||||
```json
|
||||
{
|
||||
|
|
@ -82,28 +76,28 @@ The names `"semi"` and `"quotes"` are the names of [rules](https://eslint.org/do
|
|||
* `"warn"` or `1` - turn the rule on as a warning (doesn't affect exit code)
|
||||
* `"error"` or `2` - turn the rule on as an error (exit code will be 1)
|
||||
|
||||
The three error levels allow you fine-grained control over how ESLint applies rules (for more configuration options and details, see the [configuration docs](https://eslint.org/docs/user-guide/configuring)).
|
||||
The three error levels allow you fine-grained control over how ESLint applies rules (for more configuration options and details, see the [configuration docs](https://eslint.org/docs/latest/use/configure)).
|
||||
|
||||
## <a name="code-of-conduct"></a>Code of Conduct
|
||||
## Code of Conduct
|
||||
|
||||
ESLint adheres to the [JS Foundation Code of Conduct](https://eslint.org/conduct).
|
||||
|
||||
## <a name="filing-issues"></a>Filing Issues
|
||||
## Filing Issues
|
||||
|
||||
Before filing an issue, please be sure to read the guidelines for what you're reporting:
|
||||
|
||||
* [Bug Report](https://eslint.org/docs/developer-guide/contributing/reporting-bugs)
|
||||
* [Propose a New Rule](https://eslint.org/docs/developer-guide/contributing/new-rules)
|
||||
* [Proposing a Rule Change](https://eslint.org/docs/developer-guide/contributing/rule-changes)
|
||||
* [Request a Change](https://eslint.org/docs/developer-guide/contributing/changes)
|
||||
* [Bug Report](https://eslint.org/docs/latest/contribute/report-bugs)
|
||||
* [Propose a New Rule](https://eslint.org/docs/latest/contribute/propose-new-rule)
|
||||
* [Proposing a Rule Change](https://eslint.org/docs/latest/contribute/propose-rule-change)
|
||||
* [Request a Change](https://eslint.org/docs/latest/contribute/request-change)
|
||||
|
||||
## <a name="faq"></a>Frequently Asked Questions
|
||||
## Frequently Asked Questions
|
||||
|
||||
### I'm using JSCS, should I migrate to ESLint?
|
||||
|
||||
Yes. [JSCS has reached end of life](https://eslint.org/blog/2016/07/jscs-end-of-life) and is no longer supported.
|
||||
|
||||
We have prepared a [migration guide](https://eslint.org/docs/user-guide/migrating-from-jscs) to help you convert your JSCS settings to an ESLint configuration.
|
||||
We have prepared a [migration guide](https://eslint.org/docs/latest/use/migrating-from-jscs) to help you convert your JSCS settings to an ESLint configuration.
|
||||
|
||||
We are now at or near 100% compatibility with JSCS. If you try ESLint and believe we are not yet compatible with a JSCS rule/configuration, please create an issue (mentioning that it is a JSCS compatibility issue) and we will evaluate it as per our normal process.
|
||||
|
||||
|
|
@ -119,19 +113,19 @@ No, ESLint does both traditional linting (looking for problematic patterns) and
|
|||
|
||||
### Does ESLint support JSX?
|
||||
|
||||
Yes, ESLint natively supports parsing JSX syntax (this must be enabled in [configuration](https://eslint.org/docs/user-guide/configuring)). Please note that supporting JSX syntax *is not* the same as supporting React. React applies specific semantics to JSX syntax that ESLint doesn't recognize. We recommend using [eslint-plugin-react](https://www.npmjs.com/package/eslint-plugin-react) if you are using React and want React semantics.
|
||||
Yes, ESLint natively supports parsing JSX syntax (this must be enabled in [configuration](https://eslint.org/docs/latest/use/configure)). Please note that supporting JSX syntax *is not* the same as supporting React. React applies specific semantics to JSX syntax that ESLint doesn't recognize. We recommend using [eslint-plugin-react](https://www.npmjs.com/package/eslint-plugin-react) if you are using React and want React semantics.
|
||||
|
||||
### What ECMAScript versions does ESLint support?
|
||||
|
||||
ESLint has full support for ECMAScript 3, 5 (default), 2015, 2016, 2017, 2018, 2019, and 2020. You can set your desired ECMAScript syntax (and other settings, like global variables or your target environments) through [configuration](https://eslint.org/docs/user-guide/configuring).
|
||||
ESLint has full support for ECMAScript 3, 5 (default), 2015, 2016, 2017, 2018, 2019, 2020, 2021 and 2022. You can set your desired ECMAScript syntax (and other settings, like global variables or your target environments) through [configuration](https://eslint.org/docs/latest/use/configure).
|
||||
|
||||
### What about experimental features?
|
||||
|
||||
ESLint's parser only officially supports the latest final ECMAScript standard. We will make changes to core rules in order to avoid crashes on stage 3 ECMAScript syntax proposals (as long as they are implemented using the correct experimental ESTree syntax). We may make changes to core rules to better work with language extensions (such as JSX, Flow, and TypeScript) on a case-by-case basis.
|
||||
|
||||
In other cases (including if rules need to warn on more or fewer cases due to new syntax, rather than just not crashing), we recommend you use other parsers and/or rule plugins. If you are using Babel, you can use the [babel-eslint](https://github.com/babel/babel-eslint) parser and [eslint-plugin-babel](https://github.com/babel/eslint-plugin-babel) to use any option available in Babel.
|
||||
In other cases (including if rules need to warn on more or fewer cases due to new syntax, rather than just not crashing), we recommend you use other parsers and/or rule plugins. If you are using Babel, you can use [@babel/eslint-parser](https://www.npmjs.com/package/@babel/eslint-parser) and [@babel/eslint-plugin](https://www.npmjs.com/package/@babel/eslint-plugin) to use any option available in Babel.
|
||||
|
||||
Once a language feature has been adopted into the ECMAScript standard (stage 4 according to the [TC39 process](https://tc39.github.io/process-document/)), we will accept issues and pull requests related to the new feature, subject to our [contributing guidelines](https://eslint.org/docs/developer-guide/contributing). Until then, please use the appropriate parser and plugin(s) for your experimental feature.
|
||||
Once a language feature has been adopted into the ECMAScript standard (stage 4 according to the [TC39 process](https://tc39.github.io/process-document/)), we will accept issues and pull requests related to the new feature, subject to our [contributing guidelines](https://eslint.org/docs/latest/contribute). Until then, please use the appropriate parser and plugin(s) for your experimental feature.
|
||||
|
||||
### Where to ask for help?
|
||||
|
||||
|
|
@ -147,15 +141,15 @@ We intentionally don't lock dependency versions so that we have the latest compa
|
|||
|
||||
The Twilio blog has a [deeper dive](https://www.twilio.com/blog/lockfiles-nodejs) to learn more.
|
||||
|
||||
## <a name="releases"></a>Releases
|
||||
## Releases
|
||||
|
||||
We have scheduled releases every two weeks on Friday or Saturday. You can follow a [release issue](https://github.com/eslint/eslint/issues?q=is%3Aopen+is%3Aissue+label%3Arelease) for updates about the scheduling of any particular release.
|
||||
|
||||
## <a name="security-policy"></a>Security Policy
|
||||
## Security Policy
|
||||
|
||||
ESLint takes security seriously. We work hard to ensure that ESLint is safe for everyone and that security issues are addressed quickly and responsibly. Read the full [security policy](https://github.com/eslint/.github/blob/master/SECURITY.md).
|
||||
|
||||
## <a name="semantic-versioning-policy"></a>Semantic Versioning Policy
|
||||
## Semantic Versioning Policy
|
||||
|
||||
ESLint follows [semantic versioning](https://semver.org). However, due to the nature of ESLint as a code quality tool, it's not always clear when a minor or major version bump occurs. To help clarify this for everyone, we've defined the following semantic versioning policy for ESLint:
|
||||
|
||||
|
|
@ -188,7 +182,7 @@ ESLint follows [semantic versioning](https://semver.org). However, due to the na
|
|||
|
||||
According to our policy, any minor update may report more linting errors than the previous release (ex: from a bug fix). As such, we recommend using the tilde (`~`) in `package.json` e.g. `"eslint": "~3.1.0"` to guarantee the results of your builds.
|
||||
|
||||
## <a name="stylistic-rule-updates"></a>Stylistic Rule Updates
|
||||
## Stylistic Rule Updates
|
||||
|
||||
Stylistic rules are frozen according to [our policy](https://eslint.org/blog/2020/05/changes-to-rules-policies) on how we evaluate new rules and rule changes.
|
||||
This means:
|
||||
|
|
@ -197,15 +191,16 @@ This means:
|
|||
* **New ECMAScript features**: We will also make sure stylistic rules are compatible with new ECMAScript features.
|
||||
* **New options**: We will **not** add any new options to stylistic rules unless an option is the only way to fix a bug or support a newly-added ECMAScript feature.
|
||||
|
||||
## <a name="license"></a>License
|
||||
## License
|
||||
|
||||
[](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Feslint%2Feslint?ref=badge_large)
|
||||
|
||||
## <a name="team"></a>Team
|
||||
## Team
|
||||
|
||||
These folks keep the project moving and are resources for help.
|
||||
|
||||
<!-- NOTE: This section is autogenerated. Do not manually edit.-->
|
||||
|
||||
<!--teamstart-->
|
||||
|
||||
### Technical Steering Committee (TSC)
|
||||
|
|
@ -229,54 +224,14 @@ Milos Djermanovic
|
|||
</a>
|
||||
</td></tr></tbody></table>
|
||||
|
||||
|
||||
### Reviewers
|
||||
|
||||
The people who review and implement new features.
|
||||
|
||||
<table><tbody><tr><td align="center" valign="top" width="11%">
|
||||
<a href="https://github.com/mysticatea">
|
||||
<img src="https://github.com/mysticatea.png?s=75" width="75" height="75"><br />
|
||||
Toru Nagashima
|
||||
</a>
|
||||
</td><td align="center" valign="top" width="11%">
|
||||
<a href="https://github.com/aladdin-add">
|
||||
<img src="https://github.com/aladdin-add.png?s=75" width="75" height="75"><br />
|
||||
薛定谔的猫
|
||||
</a>
|
||||
</td></tr></tbody></table>
|
||||
|
||||
|
||||
|
||||
|
||||
### Committers
|
||||
|
||||
The people who review and fix bugs and help triage issues.
|
||||
|
||||
<table><tbody><tr><td align="center" valign="top" width="11%">
|
||||
<a href="https://github.com/brettz9">
|
||||
<img src="https://github.com/brettz9.png?s=75" width="75" height="75"><br />
|
||||
Brett Zamir
|
||||
</a>
|
||||
</td><td align="center" valign="top" width="11%">
|
||||
<a href="https://github.com/bmish">
|
||||
<img src="https://github.com/bmish.png?s=75" width="75" height="75"><br />
|
||||
Bryan Mishkin
|
||||
</a>
|
||||
</td><td align="center" valign="top" width="11%">
|
||||
<a href="https://github.com/g-plane">
|
||||
<img src="https://github.com/g-plane.png?s=75" width="75" height="75"><br />
|
||||
Pig Fang
|
||||
</a>
|
||||
</td><td align="center" valign="top" width="11%">
|
||||
<a href="https://github.com/anikethsaha">
|
||||
<img src="https://github.com/anikethsaha.png?s=75" width="75" height="75"><br />
|
||||
Anix
|
||||
</a>
|
||||
</td><td align="center" valign="top" width="11%">
|
||||
<a href="https://github.com/yeonjuan">
|
||||
<img src="https://github.com/yeonjuan.png?s=75" width="75" height="75"><br />
|
||||
YeonJuan
|
||||
唯然
|
||||
</a>
|
||||
</td><td align="center" valign="top" width="11%">
|
||||
<a href="https://github.com/snitin315">
|
||||
|
|
@ -285,23 +240,64 @@ Nitin Kumar
|
|||
</a>
|
||||
</td></tr></tbody></table>
|
||||
|
||||
### Committers
|
||||
|
||||
The people who review and fix bugs and help triage issues.
|
||||
|
||||
<table><tbody><tr><td align="center" valign="top" width="11%">
|
||||
<a href="https://github.com/bmish">
|
||||
<img src="https://github.com/bmish.png?s=75" width="75" height="75"><br />
|
||||
Bryan Mishkin
|
||||
</a>
|
||||
</td><td align="center" valign="top" width="11%">
|
||||
<a href="https://github.com/SaraSoueidan">
|
||||
<img src="https://github.com/SaraSoueidan.png?s=75" width="75" height="75"><br />
|
||||
Sara Soueidan
|
||||
</a>
|
||||
</td><td align="center" valign="top" width="11%">
|
||||
<a href="https://github.com/yeonjuan">
|
||||
<img src="https://github.com/yeonjuan.png?s=75" width="75" height="75"><br />
|
||||
YeonJuan
|
||||
</a>
|
||||
</td></tr></tbody></table>
|
||||
|
||||
### Website Team
|
||||
|
||||
Team members who focus specifically on eslint.org
|
||||
|
||||
<table><tbody><tr><td align="center" valign="top" width="11%">
|
||||
<a href="https://github.com/amareshsm">
|
||||
<img src="https://github.com/amareshsm.png?s=75" width="75" height="75"><br />
|
||||
Amaresh S M
|
||||
</a>
|
||||
</td><td align="center" valign="top" width="11%">
|
||||
<a href="https://github.com/harish-sethuraman">
|
||||
<img src="https://github.com/harish-sethuraman.png?s=75" width="75" height="75"><br />
|
||||
Strek
|
||||
</a>
|
||||
</td><td align="center" valign="top" width="11%">
|
||||
<a href="https://github.com/kecrily">
|
||||
<img src="https://github.com/kecrily.png?s=75" width="75" height="75"><br />
|
||||
Percy Ma
|
||||
</a>
|
||||
</td></tr></tbody></table>
|
||||
|
||||
<!--teamend-->
|
||||
|
||||
## <a name="sponsors"></a>Sponsors
|
||||
## Sponsors
|
||||
|
||||
The following companies, organizations, and individuals support ESLint's ongoing maintenance and development. [Become a Sponsor](https://opencollective.com/eslint) to get your logo on our README and website.
|
||||
|
||||
<!-- NOTE: This section is autogenerated. Do not manually edit.-->
|
||||
<!--sponsorsstart-->
|
||||
<h3>Platinum Sponsors</h3>
|
||||
<p><a href="https://automattic.com"><img src="https://images.opencollective.com/photomatt/d0ef3e1/logo.png" alt="Automattic" height="undefined"></a></p><h3>Gold Sponsors</h3>
|
||||
<p><a href="https://nx.dev"><img src="https://images.opencollective.com/nx/0efbe42/logo.png" alt="Nx (by Nrwl)" height="96"></a> <a href="https://google.com/chrome"><img src="https://images.opencollective.com/chrome/dc55bd4/logo.png" alt="Chrome's Web Framework & Tools Performance Fund" height="96"></a> <a href="https://www.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a> <a href="https://coinbase.com"><img src="https://avatars.githubusercontent.com/u/1885080?v=4" alt="Coinbase" height="96"></a> <a href="https://substack.com/"><img src="https://avatars.githubusercontent.com/u/53023767?v=4" alt="Substack" height="96"></a></p><h3>Silver Sponsors</h3>
|
||||
<p><a href="https://retool.com/"><img src="https://images.opencollective.com/retool/98ea68e/logo.png" alt="Retool" height="64"></a> <a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a></p><h3>Bronze Sponsors</h3>
|
||||
<p><a href="https://www.crosswordsolver.org/anagram-solver/"><img src="https://images.opencollective.com/anagram-solver/2666271/logo.png" alt="Anagram Solver" height="32"></a> <a href="null"><img src="https://images.opencollective.com/bugsnag-stability-monitoring/c2cef36/logo.png" alt="Bugsnag Stability Monitoring" height="32"></a> <a href="https://mixpanel.com"><img src="https://images.opencollective.com/mixpanel/cd682f7/logo.png" alt="Mixpanel" height="32"></a> <a href="https://www.vpsserver.com"><img src="https://images.opencollective.com/vpsservercom/logo.png" alt="VPS Server" height="32"></a> <a href="https://icons8.com"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8: free icons, photos, illustrations, and music" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://www.firesticktricks.com"><img src="https://images.opencollective.com/fire-stick-tricks/b8fbe2c/logo.png" alt="Fire Stick Tricks" height="32"></a> <a href="https://www.practiceignition.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Practice Ignition" height="32"></a></p>
|
||||
<p><a href="#"><img src="https://images.opencollective.com/2021-frameworks-fund/logo.png" alt="Chrome Frameworks Fund" height="undefined"></a> <a href="https://automattic.com"><img src="https://images.opencollective.com/automattic/d0ef3e1/logo.png" alt="Automattic" height="undefined"></a></p><h3>Gold Sponsors</h3>
|
||||
<p><a href="https://ridicorp.com/career/"><img src="https://images.opencollective.com/ridi-corporation/175dcf3/logo.png" alt="RIDI" height="96"></a> <a href="https://engineering.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a></p><h3>Silver Sponsors</h3>
|
||||
<p><a href="https://sentry.io"><img src="https://avatars.githubusercontent.com/u/1396951?v=4" alt="Sentry" height="64"></a> <a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a></p><h3>Bronze Sponsors</h3>
|
||||
<p><a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://nx.dev"><img src="https://images.opencollective.com/nx/0efbe42/logo.png" alt="Nx (by Nrwl)" height="32"></a> <a href="https://www.crosswordsolver.org/anagram-solver/"><img src="https://images.opencollective.com/anagram-solver/2666271/logo.png" alt="Anagram Solver" height="32"></a> <a href="https://icons8.com"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8: free icons, photos, illustrations, and music" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://www.ignitionapp.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Ignition" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774?v=4" alt="HeroCoders" height="32"></a> <a href="https://quickbookstoolhub.com"><img src="https://avatars.githubusercontent.com/u/95090305?u=e5bc398ef775c9ed19f955c675cdc1fb6abf01df&v=4" alt="QuickBooks Tool hub" height="32"></a></p>
|
||||
<!--sponsorsend-->
|
||||
|
||||
## <a name="technology-sponsors"></a>Technology Sponsors
|
||||
## Technology Sponsors
|
||||
|
||||
* Site search ([eslint.org](https://eslint.org)) is sponsored by [Algolia](https://www.algolia.com)
|
||||
* Hosting for ([eslint.org](https://eslint.org)) is sponsored by [Netlify](https://www.netlify.com)
|
||||
|
|
|
|||
18
node_modules/eslint/bin/eslint.js
generated
vendored
18
node_modules/eslint/bin/eslint.js
generated
vendored
|
|
@ -5,13 +5,10 @@
|
|||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
/* eslint no-console:off */
|
||||
/* eslint no-console:off -- CLI */
|
||||
|
||||
"use strict";
|
||||
|
||||
// to use V8's code cache to speed up instantiation time
|
||||
require("v8-compile-cache");
|
||||
|
||||
// must do this initialization *before* other requires in order to work
|
||||
if (process.argv.includes("--debug")) {
|
||||
require("debug").enable("eslint:*,-eslint:code-path,eslintrc:*");
|
||||
|
|
@ -69,7 +66,7 @@ function getErrorMessage(error) {
|
|||
// Lazy loading because this is used only if an error happened.
|
||||
const util = require("util");
|
||||
|
||||
// Foolproof -- thirdparty module might throw non-object.
|
||||
// Foolproof -- third-party module might throw non-object.
|
||||
if (typeof error !== "object" || error === null) {
|
||||
return String(error);
|
||||
}
|
||||
|
|
@ -124,13 +121,20 @@ ${message}`);
|
|||
|
||||
// Call the config initializer if `--init` is present.
|
||||
if (process.argv.includes("--init")) {
|
||||
await require("../lib/init/config-initializer").initializeConfig();
|
||||
|
||||
// `eslint --init` has been moved to `@eslint/create-config`
|
||||
console.warn("You can also run this command directly using 'npm init @eslint/config'.");
|
||||
|
||||
const spawn = require("cross-spawn");
|
||||
|
||||
spawn.sync("npm", ["init", "@eslint/config"], { encoding: "utf8", stdio: "inherit" });
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, call the CLI.
|
||||
process.exitCode = await require("../lib/cli").execute(
|
||||
process.argv,
|
||||
process.argv.includes("--stdin") ? await readStdin() : null
|
||||
process.argv.includes("--stdin") ? await readStdin() : null,
|
||||
true
|
||||
);
|
||||
}()).catch(onFatalError);
|
||||
|
|
|
|||
6
node_modules/eslint/conf/eslint-recommended.js
generated
vendored
6
node_modules/eslint/conf/eslint-recommended.js
generated
vendored
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
/* eslint sort-keys: ["error", "asc"] */
|
||||
/* eslint sort-keys: ["error", "asc"] -- Long, so make more readable */
|
||||
|
||||
/** @type {import("../lib/shared/types").ConfigData} */
|
||||
module.exports = {
|
||||
|
|
@ -42,9 +42,11 @@ module.exports = {
|
|||
"no-inner-declarations": "error",
|
||||
"no-invalid-regexp": "error",
|
||||
"no-irregular-whitespace": "error",
|
||||
"no-loss-of-precision": "error",
|
||||
"no-misleading-character-class": "error",
|
||||
"no-mixed-spaces-and-tabs": "error",
|
||||
"no-new-symbol": "error",
|
||||
"no-nonoctal-decimal-escape": "error",
|
||||
"no-obj-calls": "error",
|
||||
"no-octal": "error",
|
||||
"no-prototype-builtins": "error",
|
||||
|
|
@ -60,8 +62,10 @@ module.exports = {
|
|||
"no-unreachable": "error",
|
||||
"no-unsafe-finally": "error",
|
||||
"no-unsafe-negation": "error",
|
||||
"no-unsafe-optional-chaining": "error",
|
||||
"no-unused-labels": "error",
|
||||
"no-unused-vars": "error",
|
||||
"no-useless-backreference": "error",
|
||||
"no-useless-catch": "error",
|
||||
"no-useless-escape": "error",
|
||||
"no-with": "error",
|
||||
|
|
|
|||
149
node_modules/eslint/conf/globals.js
generated
vendored
Normal file
149
node_modules/eslint/conf/globals.js
generated
vendored
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
/**
|
||||
* @fileoverview Globals for ecmaVersion/sourceType
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Globals
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const commonjs = {
|
||||
exports: true,
|
||||
global: false,
|
||||
module: false,
|
||||
require: false
|
||||
};
|
||||
|
||||
const es3 = {
|
||||
Array: false,
|
||||
Boolean: false,
|
||||
constructor: false,
|
||||
Date: false,
|
||||
decodeURI: false,
|
||||
decodeURIComponent: false,
|
||||
encodeURI: false,
|
||||
encodeURIComponent: false,
|
||||
Error: false,
|
||||
escape: false,
|
||||
eval: false,
|
||||
EvalError: false,
|
||||
Function: false,
|
||||
hasOwnProperty: false,
|
||||
Infinity: false,
|
||||
isFinite: false,
|
||||
isNaN: false,
|
||||
isPrototypeOf: false,
|
||||
Math: false,
|
||||
NaN: false,
|
||||
Number: false,
|
||||
Object: false,
|
||||
parseFloat: false,
|
||||
parseInt: false,
|
||||
propertyIsEnumerable: false,
|
||||
RangeError: false,
|
||||
ReferenceError: false,
|
||||
RegExp: false,
|
||||
String: false,
|
||||
SyntaxError: false,
|
||||
toLocaleString: false,
|
||||
toString: false,
|
||||
TypeError: false,
|
||||
undefined: false,
|
||||
unescape: false,
|
||||
URIError: false,
|
||||
valueOf: false
|
||||
};
|
||||
|
||||
const es5 = {
|
||||
...es3,
|
||||
JSON: false
|
||||
};
|
||||
|
||||
const es2015 = {
|
||||
...es5,
|
||||
ArrayBuffer: false,
|
||||
DataView: false,
|
||||
Float32Array: false,
|
||||
Float64Array: false,
|
||||
Int16Array: false,
|
||||
Int32Array: false,
|
||||
Int8Array: false,
|
||||
Map: false,
|
||||
Promise: false,
|
||||
Proxy: false,
|
||||
Reflect: false,
|
||||
Set: false,
|
||||
Symbol: false,
|
||||
Uint16Array: false,
|
||||
Uint32Array: false,
|
||||
Uint8Array: false,
|
||||
Uint8ClampedArray: false,
|
||||
WeakMap: false,
|
||||
WeakSet: false
|
||||
};
|
||||
|
||||
// no new globals in ES2016
|
||||
const es2016 = {
|
||||
...es2015
|
||||
};
|
||||
|
||||
const es2017 = {
|
||||
...es2016,
|
||||
Atomics: false,
|
||||
SharedArrayBuffer: false
|
||||
};
|
||||
|
||||
// no new globals in ES2018
|
||||
const es2018 = {
|
||||
...es2017
|
||||
};
|
||||
|
||||
// no new globals in ES2019
|
||||
const es2019 = {
|
||||
...es2018
|
||||
};
|
||||
|
||||
const es2020 = {
|
||||
...es2019,
|
||||
BigInt: false,
|
||||
BigInt64Array: false,
|
||||
BigUint64Array: false,
|
||||
globalThis: false
|
||||
};
|
||||
|
||||
const es2021 = {
|
||||
...es2020,
|
||||
AggregateError: false,
|
||||
FinalizationRegistry: false,
|
||||
WeakRef: false
|
||||
};
|
||||
|
||||
const es2022 = {
|
||||
...es2021
|
||||
};
|
||||
|
||||
const es2023 = {
|
||||
...es2022
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Exports
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
commonjs,
|
||||
es3,
|
||||
es5,
|
||||
es2015,
|
||||
es2016,
|
||||
es2017,
|
||||
es2018,
|
||||
es2019,
|
||||
es2020,
|
||||
es2021,
|
||||
es2022,
|
||||
es2023
|
||||
};
|
||||
|
|
@ -1,20 +1,17 @@
|
|||
{
|
||||
"categories": [
|
||||
{ "name": "Possible Errors", "description": "These rules relate to possible syntax or logic errors in JavaScript code:" },
|
||||
{ "name": "Best Practices", "description": "These rules relate to better ways of doing things to help you avoid problems:" },
|
||||
{ "name": "Strict Mode", "description": "These rules relate to strict mode directives:" },
|
||||
{ "name": "Variables", "description": "These rules relate to variable declarations:" },
|
||||
{ "name": "Stylistic Issues", "description": "These rules relate to style guidelines, and are therefore quite subjective:" },
|
||||
{ "name": "ECMAScript 6", "description": "These rules relate to ES6, also known as ES2015:" }
|
||||
"types": [
|
||||
{ "name": "problem", "displayName": "Possible Problems", "description": "These rules relate to possible logic errors in code:" },
|
||||
{ "name": "suggestion", "displayName": "Suggestions", "description": "These rules suggest alternate ways of doing things:" },
|
||||
{ "name": "layout", "displayName": "Layout & Formatting", "description": "These rules care about how the code looks rather than how it executes:" }
|
||||
],
|
||||
"deprecated": {
|
||||
"name": "Deprecated",
|
||||
"description": "These rules have been deprecated in accordance with the <a href=\"/docs/user-guide/rule-deprecation\">deprecation policy</a>, and replaced by newer rules:",
|
||||
"description": "These rules have been deprecated in accordance with the <a href=\"/docs/use/rule-deprecation\">deprecation policy</a>, and replaced by newer rules:",
|
||||
"rules": []
|
||||
},
|
||||
"removed": {
|
||||
"name": "Removed",
|
||||
"description": "These rules from older versions of ESLint (before the <a href=\"/docs/user-guide/rule-deprecation\">deprecation policy</a> existed) have been replaced by newer rules:",
|
||||
"description": "These rules from older versions of ESLint (before the <a href=\"/docs/use/rule-deprecation\">deprecation policy</a> existed) have been replaced by newer rules:",
|
||||
"rules": [
|
||||
{ "removed": "generator-star", "replacedBy": ["generator-star-spacing"] },
|
||||
{ "removed": "global-strict", "replacedBy": ["strict"] },
|
||||
24
node_modules/eslint/lib/api.js
generated
vendored
24
node_modules/eslint/lib/api.js
generated
vendored
|
|
@ -5,30 +5,22 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const { CLIEngine } = require("./cli-engine");
|
||||
//-----------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const { ESLint } = require("./eslint");
|
||||
const { Linter } = require("./linter");
|
||||
const { RuleTester } = require("./rule-tester");
|
||||
const { SourceCode } = require("./source-code");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Exports
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
Linter,
|
||||
CLIEngine,
|
||||
ESLint,
|
||||
RuleTester,
|
||||
SourceCode
|
||||
};
|
||||
|
||||
// DOTO: remove deprecated API.
|
||||
let deprecatedLinterInstance = null;
|
||||
|
||||
Object.defineProperty(module.exports, "linter", {
|
||||
enumerable: false,
|
||||
get() {
|
||||
if (!deprecatedLinterInstance) {
|
||||
deprecatedLinterInstance = new Linter();
|
||||
}
|
||||
|
||||
return deprecatedLinterInstance;
|
||||
}
|
||||
});
|
||||
|
|
|
|||
101
node_modules/eslint/lib/cli-engine/cli-engine.js
generated
vendored
101
node_modules/eslint/lib/cli-engine/cli-engine.js
generated
vendored
|
|
@ -41,7 +41,7 @@ const hash = require("./hash");
|
|||
const LintResultCache = require("./lint-result-cache");
|
||||
|
||||
const debug = require("debug")("eslint:cli-engine");
|
||||
const validFixTypes = new Set(["problem", "suggestion", "layout"]);
|
||||
const validFixTypes = new Set(["directive", "problem", "suggestion", "layout"]);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Typedefs
|
||||
|
|
@ -51,12 +51,14 @@ const validFixTypes = new Set(["problem", "suggestion", "layout"]);
|
|||
/** @typedef {import("../shared/types").ConfigData} ConfigData */
|
||||
/** @typedef {import("../shared/types").DeprecatedRuleInfo} DeprecatedRuleInfo */
|
||||
/** @typedef {import("../shared/types").LintMessage} LintMessage */
|
||||
/** @typedef {import("../shared/types").SuppressedLintMessage} SuppressedLintMessage */
|
||||
/** @typedef {import("../shared/types").ParserOptions} ParserOptions */
|
||||
/** @typedef {import("../shared/types").Plugin} Plugin */
|
||||
/** @typedef {import("../shared/types").RuleConf} RuleConf */
|
||||
/** @typedef {import("../shared/types").Rule} Rule */
|
||||
/** @typedef {ReturnType<CascadingConfigArrayFactory["getConfigArrayForFile"]>} ConfigArray */
|
||||
/** @typedef {ReturnType<ConfigArray["extractConfig"]>} ExtractedConfig */
|
||||
/** @typedef {import("../shared/types").FormatterFunction} FormatterFunction */
|
||||
/** @typedef {ReturnType<CascadingConfigArrayFactory.getConfigArrayForFile>} ConfigArray */
|
||||
/** @typedef {ReturnType<ConfigArray.extractConfig>} ExtractedConfig */
|
||||
|
||||
/**
|
||||
* The options to configure a CLI engine with.
|
||||
|
|
@ -91,7 +93,9 @@ const validFixTypes = new Set(["problem", "suggestion", "layout"]);
|
|||
* @typedef {Object} LintResult
|
||||
* @property {string} filePath The path to the file that was linted.
|
||||
* @property {LintMessage[]} messages All of the messages for the result.
|
||||
* @property {SuppressedLintMessage[]} suppressedMessages All of the suppressed messages for the result.
|
||||
* @property {number} errorCount Number of errors for the result.
|
||||
* @property {number} fatalErrorCount Number of fatal errors for the result.
|
||||
* @property {number} warningCount Number of warnings for the result.
|
||||
* @property {number} fixableErrorCount Number of fixable errors for the result.
|
||||
* @property {number} fixableWarningCount Number of fixable warnings for the result.
|
||||
|
|
@ -104,6 +108,7 @@ const validFixTypes = new Set(["problem", "suggestion", "layout"]);
|
|||
* @typedef {Object} LintReport
|
||||
* @property {LintResult[]} results All of the result.
|
||||
* @property {number} errorCount Number of errors for the result.
|
||||
* @property {number} fatalErrorCount Number of fatal errors for the result.
|
||||
* @property {number} warningCount Number of warnings for the result.
|
||||
* @property {number} fixableErrorCount Number of fixable errors for the result.
|
||||
* @property {number} fixableWarningCount Number of fixable warnings for the result.
|
||||
|
|
@ -261,6 +266,7 @@ function verifyText({
|
|||
const result = {
|
||||
filePath,
|
||||
messages,
|
||||
suppressedMessages: linter.getSuppressedMessages(),
|
||||
...calculateStatsPerFile(messages)
|
||||
};
|
||||
|
||||
|
|
@ -280,7 +286,7 @@ function verifyText({
|
|||
/**
|
||||
* Returns result with warning by ignore settings
|
||||
* @param {string} filePath File path of checked code
|
||||
* @param {string} baseDir Absolute path of base directory
|
||||
* @param {string} baseDir Absolute path of base directory
|
||||
* @returns {LintResult} Result with single warning
|
||||
* @private
|
||||
*/
|
||||
|
|
@ -307,7 +313,9 @@ function createIgnoreResult(filePath, baseDir) {
|
|||
message
|
||||
}
|
||||
],
|
||||
suppressedMessages: [],
|
||||
errorCount: 0,
|
||||
fatalErrorCount: 0,
|
||||
warningCount: 1,
|
||||
fixableErrorCount: 0,
|
||||
fixableWarningCount: 0
|
||||
|
|
@ -331,6 +339,23 @@ function getRule(ruleId, configArrays) {
|
|||
return builtInRules.get(ruleId) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a message's rule type should be fixed.
|
||||
* @param {LintMessage} message The message to check.
|
||||
* @param {ConfigArray[]} lastConfigArrays The list of config arrays that the last `executeOnFiles` or `executeOnText` used.
|
||||
* @param {string[]} fixTypes An array of fix types to check.
|
||||
* @returns {boolean} Whether the message should be fixed.
|
||||
*/
|
||||
function shouldMessageBeFixed(message, lastConfigArrays, fixTypes) {
|
||||
if (!message.ruleId) {
|
||||
return fixTypes.has("directive");
|
||||
}
|
||||
|
||||
const rule = message.ruleId && getRule(message.ruleId, lastConfigArrays);
|
||||
|
||||
return Boolean(rule && rule.meta && fixTypes.has(rule.meta.type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect used deprecated rules.
|
||||
* @param {ConfigArray[]} usedConfigArrays The config arrays which were used.
|
||||
|
|
@ -341,9 +366,7 @@ function *iterateRuleDeprecationWarnings(usedConfigArrays) {
|
|||
|
||||
// Flatten used configs.
|
||||
/** @type {ExtractedConfig[]} */
|
||||
const configs = [].concat(
|
||||
...usedConfigArrays.map(getUsedExtractedConfigs)
|
||||
);
|
||||
const configs = usedConfigArrays.flatMap(getUsedExtractedConfigs);
|
||||
|
||||
// Traverse rule configs.
|
||||
for (const config of configs) {
|
||||
|
|
@ -391,7 +414,7 @@ function isErrorMessage(message) {
|
|||
* a directory or looks like a directory (ends in `path.sep`), in which case the file
|
||||
* name will be the `cacheFile/.cache_hashOfCWD`
|
||||
*
|
||||
* if cacheFile points to a file or looks like a file then in will just use that file
|
||||
* if cacheFile points to a file or looks like a file then it will just use that file
|
||||
* @param {string} cacheFile The name of file to be used to store the cache
|
||||
* @param {string} cwd Current working directory
|
||||
* @returns {string} the resolved path to the cache file
|
||||
|
|
@ -463,6 +486,7 @@ function getCacheFile(cacheFile, cwd) {
|
|||
* @param {string[]|null} keys The keys to assign true.
|
||||
* @param {boolean} defaultValue The default value for each property.
|
||||
* @param {string} displayName The property name which is used in error message.
|
||||
* @throws {Error} Requires array.
|
||||
* @returns {Record<string,boolean>} The boolean map.
|
||||
*/
|
||||
function toBooleanMap(keys, defaultValue, displayName) {
|
||||
|
|
@ -526,6 +550,7 @@ function createConfigDataFromOptions(options) {
|
|||
/**
|
||||
* Checks whether a directory exists at the given location
|
||||
* @param {string} resolvedPath A path from the CWD
|
||||
* @throws {Error} As thrown by `fs.statSync` or `fs.isDirectory`.
|
||||
* @returns {boolean} `true` if a directory exists
|
||||
*/
|
||||
function directoryExists(resolvedPath) {
|
||||
|
|
@ -543,13 +568,18 @@ function directoryExists(resolvedPath) {
|
|||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Core CLI.
|
||||
*/
|
||||
class CLIEngine {
|
||||
|
||||
/**
|
||||
* Creates a new instance of the core CLI engine.
|
||||
* @param {CLIEngineOptions} providedOptions The options for this instance.
|
||||
* @param {Object} [additionalData] Additional settings that are not CLIEngineOptions.
|
||||
* @param {Record<string,Plugin>|null} [additionalData.preloadedPlugins] Preloaded plugins.
|
||||
*/
|
||||
constructor(providedOptions) {
|
||||
constructor(providedOptions, { preloadedPlugins } = {}) {
|
||||
const options = Object.assign(
|
||||
Object.create(null),
|
||||
defaultOptions,
|
||||
|
|
@ -562,6 +592,13 @@ class CLIEngine {
|
|||
}
|
||||
|
||||
const additionalPluginPool = new Map();
|
||||
|
||||
if (preloadedPlugins) {
|
||||
for (const [id, plugin] of Object.entries(preloadedPlugins)) {
|
||||
additionalPluginPool.set(id, plugin);
|
||||
}
|
||||
}
|
||||
|
||||
const cacheFilePath = getCacheFile(
|
||||
options.cacheLocation || options.cacheFile,
|
||||
options.cwd
|
||||
|
|
@ -578,8 +615,8 @@ class CLIEngine {
|
|||
useEslintrc: options.useEslintrc,
|
||||
builtInRules,
|
||||
loadRules,
|
||||
eslintRecommendedPath: path.resolve(__dirname, "../../conf/eslint-recommended.js"),
|
||||
eslintAllPath: path.resolve(__dirname, "../../conf/eslint-all.js")
|
||||
getEslintRecommendedConfig: () => require("../../conf/eslint-recommended.js"),
|
||||
getEslintAllConfig: () => require("../../conf/eslint-all.js")
|
||||
});
|
||||
const fileEnumerator = new FileEnumerator({
|
||||
configArrayFactory,
|
||||
|
|
@ -623,12 +660,7 @@ class CLIEngine {
|
|||
const originalFix = (typeof options.fix === "function")
|
||||
? options.fix : () => true;
|
||||
|
||||
options.fix = message => {
|
||||
const rule = message.ruleId && getRule(message.ruleId, lastConfigArrays);
|
||||
const matches = rule && rule.meta && fixTypes.has(rule.meta.type);
|
||||
|
||||
return matches && originalFix(message);
|
||||
};
|
||||
options.fix = message => shouldMessageBeFixed(message, lastConfigArrays, fixTypes) && originalFix(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -654,11 +686,13 @@ class CLIEngine {
|
|||
|
||||
results.forEach(result => {
|
||||
const filteredMessages = result.messages.filter(isErrorMessage);
|
||||
const filteredSuppressedMessages = result.suppressedMessages.filter(isErrorMessage);
|
||||
|
||||
if (filteredMessages.length > 0) {
|
||||
filtered.push({
|
||||
...result,
|
||||
messages: filteredMessages,
|
||||
suppressedMessages: filteredSuppressedMessages,
|
||||
errorCount: filteredMessages.length,
|
||||
warningCount: 0,
|
||||
fixableErrorCount: result.fixableErrorCount,
|
||||
|
|
@ -681,26 +715,6 @@ class CLIEngine {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a plugin by passing its configuration
|
||||
* @param {string} name Name of the plugin.
|
||||
* @param {Plugin} pluginObject Plugin configuration object.
|
||||
* @returns {void}
|
||||
*/
|
||||
addPlugin(name, pluginObject) {
|
||||
const {
|
||||
additionalPluginPool,
|
||||
configArrayFactory,
|
||||
lastConfigArrays
|
||||
} = internalSlotsMap.get(this);
|
||||
|
||||
additionalPluginPool.set(name, pluginObject);
|
||||
configArrayFactory.clearCache();
|
||||
lastConfigArrays.length = 1;
|
||||
lastConfigArrays[0] = configArrayFactory.getConfigArrayForFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the patterns passed into executeOnFiles() into glob-based patterns
|
||||
* for easier handling.
|
||||
|
|
@ -730,6 +744,7 @@ class CLIEngine {
|
|||
/**
|
||||
* Executes the current configuration on an array of file and directory names.
|
||||
* @param {string[]} patterns An array of file and directory names.
|
||||
* @throws {Error} As may be thrown by `fs.unlinkSync`.
|
||||
* @returns {LintReport} The results for all files that were linted.
|
||||
*/
|
||||
executeOnFiles(patterns) {
|
||||
|
|
@ -936,6 +951,7 @@ class CLIEngine {
|
|||
* This is the same logic used by the ESLint CLI executable to determine
|
||||
* configuration for each file it processes.
|
||||
* @param {string} filePath The path of the file to retrieve a config object for.
|
||||
* @throws {Error} If filepath a directory path.
|
||||
* @returns {ConfigData} A configuration object for the file.
|
||||
*/
|
||||
getConfigForFile(filePath) {
|
||||
|
|
@ -984,7 +1000,8 @@ class CLIEngine {
|
|||
* Returns the formatter representing the given format or null if the `format` is not a string.
|
||||
* @param {string} [format] The name of the format to load or the path to a
|
||||
* custom formatter.
|
||||
* @returns {(Function|null)} The formatter function or null if the `format` is not a string.
|
||||
* @throws {any} As may be thrown by requiring of formatter
|
||||
* @returns {(FormatterFunction|null)} The formatter function or null if the `format` is not a string.
|
||||
*/
|
||||
getFormatter(format) {
|
||||
|
||||
|
|
@ -1004,7 +1021,7 @@ class CLIEngine {
|
|||
let formatterPath;
|
||||
|
||||
// if there's a slash, then it's a file (TODO: this check seems dubious for scoped npm packages)
|
||||
if (!namespace && normalizedFormatName.indexOf("/") > -1) {
|
||||
if (!namespace && normalizedFormatName.includes("/")) {
|
||||
formatterPath = path.resolve(cwd, normalizedFormatName);
|
||||
} else {
|
||||
try {
|
||||
|
|
@ -1019,7 +1036,11 @@ class CLIEngine {
|
|||
try {
|
||||
return require(formatterPath);
|
||||
} catch (ex) {
|
||||
ex.message = `There was a problem loading formatter: ${formatterPath}\nError: ${ex.message}`;
|
||||
if (format === "table" || format === "codeframe") {
|
||||
ex.message = `The ${format} formatter is no longer part of core ESLint. Install it manually with \`npm install -D eslint-formatter-${format}\``;
|
||||
} else {
|
||||
ex.message = `There was a problem loading formatter: ${formatterPath}\nError: ${ex.message}`;
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
|
||||
|
|
|
|||
17
node_modules/eslint/lib/cli-engine/file-enumerator.js
generated
vendored
17
node_modules/eslint/lib/cli-engine/file-enumerator.js
generated
vendored
|
|
@ -60,7 +60,7 @@ const IGNORED_SILENTLY = 1;
|
|||
const IGNORED = 2;
|
||||
|
||||
// For VSCode intellisense
|
||||
/** @typedef {ReturnType<CascadingConfigArrayFactory["getConfigArrayForFile"]>} ConfigArray */
|
||||
/** @typedef {ReturnType<CascadingConfigArrayFactory.getConfigArrayForFile>} ConfigArray */
|
||||
|
||||
/**
|
||||
* @typedef {Object} FileEnumeratorOptions
|
||||
|
|
@ -114,6 +114,7 @@ function isGlobPattern(pattern) {
|
|||
/**
|
||||
* Get stats of a given path.
|
||||
* @param {string} filePath The path to target file.
|
||||
* @throws {Error} As may be thrown by `fs.statSync`.
|
||||
* @returns {fs.Stats|null} The stats.
|
||||
* @private
|
||||
*/
|
||||
|
|
@ -121,7 +122,8 @@ function statSafeSync(filePath) {
|
|||
try {
|
||||
return fs.statSync(filePath);
|
||||
} catch (error) {
|
||||
/* istanbul ignore next */
|
||||
|
||||
/* c8 ignore next */
|
||||
if (error.code !== "ENOENT") {
|
||||
throw error;
|
||||
}
|
||||
|
|
@ -132,6 +134,7 @@ function statSafeSync(filePath) {
|
|||
/**
|
||||
* Get filenames in a given path to a directory.
|
||||
* @param {string} directoryPath The path to target directory.
|
||||
* @throws {Error} As may be thrown by `fs.readdirSync`.
|
||||
* @returns {import("fs").Dirent[]} The filenames.
|
||||
* @private
|
||||
*/
|
||||
|
|
@ -139,7 +142,8 @@ function readdirSafeSync(directoryPath) {
|
|||
try {
|
||||
return fs.readdirSync(directoryPath, { withFileTypes: true });
|
||||
} catch (error) {
|
||||
/* istanbul ignore next */
|
||||
|
||||
/* c8 ignore next */
|
||||
if (error.code !== "ENOENT") {
|
||||
throw error;
|
||||
}
|
||||
|
|
@ -173,7 +177,6 @@ function createExtensionRegExp(extensions) {
|
|||
*/
|
||||
class NoFilesFoundError extends Error {
|
||||
|
||||
// eslint-disable-next-line jsdoc/require-description
|
||||
/**
|
||||
* @param {string} pattern The glob pattern which was not found.
|
||||
* @param {boolean} globDisabled If `true` then the pattern was a glob pattern, but glob was disabled.
|
||||
|
|
@ -190,7 +193,6 @@ class NoFilesFoundError extends Error {
|
|||
*/
|
||||
class AllFilesIgnoredError extends Error {
|
||||
|
||||
// eslint-disable-next-line jsdoc/require-description
|
||||
/**
|
||||
* @param {string} pattern The glob pattern which was not found.
|
||||
*/
|
||||
|
|
@ -215,8 +217,8 @@ class FileEnumerator {
|
|||
cwd = process.cwd(),
|
||||
configArrayFactory = new CascadingConfigArrayFactory({
|
||||
cwd,
|
||||
eslintRecommendedPath: path.resolve(__dirname, "../../conf/eslint-recommended.js"),
|
||||
eslintAllPath: path.resolve(__dirname, "../../conf/eslint-all.js")
|
||||
getEslintRecommendedConfig: () => require("../../conf/eslint-recommended.js"),
|
||||
getEslintAllConfig: () => require("../../conf/eslint-all.js")
|
||||
}),
|
||||
extensions = null,
|
||||
globInputPaths = true,
|
||||
|
|
@ -270,6 +272,7 @@ class FileEnumerator {
|
|||
/**
|
||||
* Iterate files which are matched by given glob patterns.
|
||||
* @param {string|string[]} patternOrPatterns The glob patterns to iterate files.
|
||||
* @throws {NoFilesFoundError|AllFilesIgnoredError} On an unmatched pattern.
|
||||
* @returns {IterableIterator<FileAndConfig>} The found files.
|
||||
*/
|
||||
*iterateFiles(patternOrPatterns) {
|
||||
|
|
|
|||
138
node_modules/eslint/lib/cli-engine/formatters/codeframe.js
generated
vendored
138
node_modules/eslint/lib/cli-engine/formatters/codeframe.js
generated
vendored
|
|
@ -1,138 +0,0 @@
|
|||
/**
|
||||
* @fileoverview Codeframe reporter
|
||||
* @author Vitor Balocco
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
const chalk = require("chalk");
|
||||
const { codeFrameColumns } = require("@babel/code-frame");
|
||||
const path = require("path");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Given a word and a count, append an s if count is not one.
|
||||
* @param {string} word A word in its singular form.
|
||||
* @param {number} count A number controlling whether word should be pluralized.
|
||||
* @returns {string} The original word with an s on the end if count is not one.
|
||||
*/
|
||||
function pluralize(word, count) {
|
||||
return (count === 1 ? word : `${word}s`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a formatted relative file path from an absolute path and a line/column in the file.
|
||||
* @param {string} filePath The absolute file path to format.
|
||||
* @param {number} line The line from the file to use for formatting.
|
||||
* @param {number} column The column from the file to use for formatting.
|
||||
* @returns {string} The formatted file path.
|
||||
*/
|
||||
function formatFilePath(filePath, line, column) {
|
||||
let relPath = path.relative(process.cwd(), filePath);
|
||||
|
||||
if (line && column) {
|
||||
relPath += `:${line}:${column}`;
|
||||
}
|
||||
|
||||
return chalk.green(relPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the formatted output for a given message.
|
||||
* @param {Object} message The object that represents this message.
|
||||
* @param {Object} parentResult The result object that this message belongs to.
|
||||
* @returns {string} The formatted output.
|
||||
*/
|
||||
function formatMessage(message, parentResult) {
|
||||
const type = (message.fatal || message.severity === 2) ? chalk.red("error") : chalk.yellow("warning");
|
||||
const msg = `${chalk.bold(message.message.replace(/([^ ])\.$/u, "$1"))}`;
|
||||
const ruleId = message.fatal ? "" : chalk.dim(`(${message.ruleId})`);
|
||||
const filePath = formatFilePath(parentResult.filePath, message.line, message.column);
|
||||
const sourceCode = parentResult.output ? parentResult.output : parentResult.source;
|
||||
|
||||
const firstLine = [
|
||||
`${type}:`,
|
||||
`${msg}`,
|
||||
ruleId ? `${ruleId}` : "",
|
||||
sourceCode ? `at ${filePath}:` : `at ${filePath}`
|
||||
].filter(String).join(" ");
|
||||
|
||||
const result = [firstLine];
|
||||
|
||||
if (sourceCode) {
|
||||
result.push(
|
||||
codeFrameColumns(sourceCode, { start: { line: message.line, column: message.column } }, { highlightCode: false })
|
||||
);
|
||||
}
|
||||
|
||||
return result.join("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the formatted output summary for a given number of errors and warnings.
|
||||
* @param {number} errors The number of errors.
|
||||
* @param {number} warnings The number of warnings.
|
||||
* @param {number} fixableErrors The number of fixable errors.
|
||||
* @param {number} fixableWarnings The number of fixable warnings.
|
||||
* @returns {string} The formatted output summary.
|
||||
*/
|
||||
function formatSummary(errors, warnings, fixableErrors, fixableWarnings) {
|
||||
const summaryColor = errors > 0 ? "red" : "yellow";
|
||||
const summary = [];
|
||||
const fixablesSummary = [];
|
||||
|
||||
if (errors > 0) {
|
||||
summary.push(`${errors} ${pluralize("error", errors)}`);
|
||||
}
|
||||
|
||||
if (warnings > 0) {
|
||||
summary.push(`${warnings} ${pluralize("warning", warnings)}`);
|
||||
}
|
||||
|
||||
if (fixableErrors > 0) {
|
||||
fixablesSummary.push(`${fixableErrors} ${pluralize("error", fixableErrors)}`);
|
||||
}
|
||||
|
||||
if (fixableWarnings > 0) {
|
||||
fixablesSummary.push(`${fixableWarnings} ${pluralize("warning", fixableWarnings)}`);
|
||||
}
|
||||
|
||||
let output = chalk[summaryColor].bold(`${summary.join(" and ")} found.`);
|
||||
|
||||
if (fixableErrors || fixableWarnings) {
|
||||
output += chalk[summaryColor].bold(`\n${fixablesSummary.join(" and ")} potentially fixable with the \`--fix\` option.`);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = function(results) {
|
||||
let errors = 0;
|
||||
let warnings = 0;
|
||||
let fixableErrors = 0;
|
||||
let fixableWarnings = 0;
|
||||
|
||||
const resultsWithMessages = results.filter(result => result.messages.length > 0);
|
||||
|
||||
let output = resultsWithMessages.reduce((resultsOutput, result) => {
|
||||
const messages = result.messages.map(message => `${formatMessage(message, result)}\n\n`);
|
||||
|
||||
errors += result.errorCount;
|
||||
warnings += result.warningCount;
|
||||
fixableErrors += result.fixableErrorCount;
|
||||
fixableWarnings += result.fixableWarningCount;
|
||||
|
||||
return resultsOutput.concat(messages);
|
||||
}, []).join("\n");
|
||||
|
||||
output += "\n";
|
||||
output += formatSummary(errors, warnings, fixableErrors, fixableWarnings);
|
||||
|
||||
return (errors + warnings) > 0 ? output : "";
|
||||
};
|
||||
46
node_modules/eslint/lib/cli-engine/formatters/formatters-meta.json
generated
vendored
Normal file
46
node_modules/eslint/lib/cli-engine/formatters/formatters-meta.json
generated
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
[
|
||||
{
|
||||
"name": "checkstyle",
|
||||
"description": "Outputs results to the [Checkstyle](https://checkstyle.sourceforge.io/) format."
|
||||
},
|
||||
{
|
||||
"name": "compact",
|
||||
"description": "Human-readable output format. Mimics the default output of JSHint."
|
||||
},
|
||||
{
|
||||
"name": "html",
|
||||
"description": "Outputs results to HTML. The `html` formatter is useful for visual presentation in the browser."
|
||||
},
|
||||
{
|
||||
"name": "jslint-xml",
|
||||
"description": "Outputs results to format compatible with the [JSLint Jenkins plugin](https://plugins.jenkins.io/jslint/)."
|
||||
},
|
||||
{
|
||||
"name": "json-with-metadata",
|
||||
"description": "Outputs JSON-serialized results. The `json-with-metadata` provides the same linting results as the [`json`](#json) formatter with additional metadata about the rules applied. The linting results are included in the `results` property and the rules metadata is included in the `metadata` property.\n\nAlternatively, you can use the [ESLint Node.js API](../../integrate/nodejs-api) to programmatically use ESLint."
|
||||
},
|
||||
{
|
||||
"name": "json",
|
||||
"description": "Outputs JSON-serialized results. The `json` formatter is useful when you want to programmatically work with the CLI's linting results.\n\nAlternatively, you can use the [ESLint Node.js API](../../integrate/nodejs-api) to programmatically use ESLint."
|
||||
},
|
||||
{
|
||||
"name": "junit",
|
||||
"description": "Outputs results to format compatible with the [JUnit Jenkins plugin](https://plugins.jenkins.io/junit/)."
|
||||
},
|
||||
{
|
||||
"name": "stylish",
|
||||
"description": "Human-readable output format. This is the default formatter."
|
||||
},
|
||||
{
|
||||
"name": "tap",
|
||||
"description": "Outputs results to the [Test Anything Protocol (TAP)](https://testanything.org/) specification format."
|
||||
},
|
||||
{
|
||||
"name": "unix",
|
||||
"description": "Outputs results to a format similar to many commands in UNIX-like systems. Parsable with tools such as [grep](https://www.gnu.org/software/grep/manual/grep.html), [sed](https://www.gnu.org/software/sed/manual/sed.html), and [awk](https://www.gnu.org/software/gawk/manual/gawk.html)."
|
||||
},
|
||||
{
|
||||
"name": "visualstudio",
|
||||
"description": "Outputs results to format compatible with the integrated terminal of the [Visual Studio](https://visualstudio.microsoft.com/) IDE. When using Visual Studio, you can click on the linting results in the integrated terminal to go to the issue in the source code."
|
||||
}
|
||||
]
|
||||
147
node_modules/eslint/lib/cli-engine/formatters/html.js
generated
vendored
147
node_modules/eslint/lib/cli-engine/formatters/html.js
generated
vendored
|
|
@ -39,87 +39,114 @@ function pageTemplate(it) {
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>ESLint Report</title>
|
||||
<link rel="icon" type="image/png" sizes="any" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAHaAAAB2gGFomX7AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAABD1JREFUWMPFl11sk2UUx3/nbYtjxS1MF7MLMTECMgSTtSSyrQkLhAj7UBPnDSEGoxegGzMwojhXVpmTAA5iYpSoMQa8GBhFOrMFk03buei6yRAlcmOM0SEmU9d90b19jxcM1o5+sGnsc/e+z/l6ztf/HFFVMnns6QieeOCHBePGsHM+wrOtvLG2C4WRVDSSygNV7sCjlspxwDnPB44aols/DXk+mbMBmx/6OseITF1CuOtfevkPh2Uu+/jbdX8lujSScRlT5r7/QDlAfsRmfzmpnkQ/H3H13gf6bBrBn1uqK8WylgEnU8eZmk1repbfchJG1TyKyIKEwuBHFd3lD3naY3O1siiwXsVoBV2VgM1ht/QQUJk2ByqKghsQziYQ8ifKgexIXmuyzC4r67Y7R+xPAfuB/Nn3Cpva+0s7khpQVtZtd4bt51BWxtBYAiciprG7c7D4SixzU9PYalDL6110Ifb/w8W9eY7JqFeFHbO8fPGyLHwwFHJNJTSgwtVTB9oaw9BlQ+tO93vOxypoaQnfEYlI43SeCHDC4TDq9+51/h5fxr33q0ZfV9g04wat9Q943rjJgCp3952W2i8Bi6eDvdsfKj0cK/DYMRyXL4/sUJUmIHd2zYMezsvLaamp4WpcWN3BXSiHpuMwbGbZlnZ8tXY4rgosy+G7oRwQ0cAsd28YGgqfU5UjCZQDLALxDg+Hv/P5Rqvj4hwrS8izXzWb4spwc1GgENFnkpWRzxeuB+ssUHgLdb9UVdt8vpGdKQpze7n7y1U3DBChNRUuqOo9c+0+qpKKxyZqtAIYla7gY4JszAAQri93BSsMRZoyBcUC+w3Q3AyOA4sNhAOZ0q7Iq0b2vUNvK5zPgP+/H8+Zetdoa6uOikhdGurxebwvJY8Iz3V1rTMNAH+opEuQj5KTT/qA1yC+wyUjBm12OidaUtCcPNNX2h0Hx2JG69VulANZAJZJwfU7rzd/FHixuXniTdM0m4GtSQT7bTartqEh9yfImUEzkwKZmTwmo5a5JwkYBfcDL01/RkR5y8iWhtPBknB8ZxwtU9UjwOrrKCeizzc25nTGg1F/turEHoU9wMLpDvWKf8DTmNCAKnd/tqUTF4ElMXJ+A5rWDJS+41WsGWzALhJ+ErBWrLj9g+pqojHxlXJX8HGUg0BsR/x1yhxf3jm4cSzpQFLp6tmi6PEE7g1ZhtZ91ufpSZUAFa6gC+UoQslNaSmypT1U8mHKiUgEKS8KfgF4EpYunFI16tsHin+OG0LcgQK7yj7g6cSzpva2D3hKVNG0Y3mVO1BkqfSlmJrHBQ4uvM12gJHc6ETW8HZVfMRmXvyxxNC1Z/o839zyXlDuCr4nsC11J+MXueaVJWn6yPv+/pJtc9oLTNN4AeTvNGByd3rlhE2x9s5pLwDoHCy+grDzWmOZ95lUtLYj5Bma126Y8eX0/zj/ADxGyViSg4BXAAAAAElFTkSuQmCC">
|
||||
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PScwIDAgMjk0LjgyNSAyNTguOTgyJyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnPg0KPHBhdGggZmlsbD0nIzgwODBGMicgZD0nTTk3LjAyMSw5OS4wMTZsNDguNDMyLTI3Ljk2MmMxLjIxMi0wLjcsMi43MDYtMC43LDMuOTE4LDBsNDguNDMzLDI3Ljk2MiBjMS4yMTEsMC43LDEuOTU5LDEuOTkzLDEuOTU5LDMuMzkzdjU1LjkyNGMwLDEuMzk5LTAuNzQ4LDIuNjkzLTEuOTU5LDMuMzk0bC00OC40MzMsMjcuOTYyYy0xLjIxMiwwLjctMi43MDYsMC43LTMuOTE4LDAgbC00OC40MzItMjcuOTYyYy0xLjIxMi0wLjctMS45NTktMS45OTQtMS45NTktMy4zOTR2LTU1LjkyNEM5NS4wNjMsMTAxLjAwOSw5NS44MSw5OS43MTYsOTcuMDIxLDk5LjAxNicvPg0KPHBhdGggZmlsbD0nIzRCMzJDMycgZD0nTTI3My4zMzYsMTI0LjQ4OEwyMTUuNDY5LDIzLjgxNmMtMi4xMDItMy42NC01Ljk4NS02LjMyNS0xMC4xODgtNi4zMjVIODkuNTQ1IGMtNC4yMDQsMC04LjA4OCwyLjY4NS0xMC4xOSw2LjMyNWwtNTcuODY3LDEwMC40NWMtMi4xMDIsMy42NDEtMi4xMDIsOC4yMzYsMCwxMS44NzdsNTcuODY3LDk5Ljg0NyBjMi4xMDIsMy42NCw1Ljk4Niw1LjUwMSwxMC4xOSw1LjUwMWgxMTUuNzM1YzQuMjAzLDAsOC4wODctMS44MDUsMTAuMTg4LTUuNDQ2bDU3Ljg2Ny0xMDAuMDEgQzI3NS40MzksMTMyLjM5NiwyNzUuNDM5LDEyOC4xMjgsMjczLjMzNiwxMjQuNDg4IE0yMjUuNDE5LDE3Mi44OThjMCwxLjQ4LTAuODkxLDIuODQ5LTIuMTc0LDMuNTlsLTczLjcxLDQyLjUyNyBjLTEuMjgyLDAuNzQtMi44ODgsMC43NC00LjE3LDBsLTczLjc2Ny00Mi41MjdjLTEuMjgyLTAuNzQxLTIuMTc5LTIuMTA5LTIuMTc5LTMuNTlWODcuODQzYzAtMS40ODEsMC44ODQtMi44NDksMi4xNjctMy41OSBsNzMuNzA3LTQyLjUyN2MxLjI4Mi0wLjc0MSwyLjg4Ni0wLjc0MSw0LjE2OCwwbDczLjc3Miw0Mi41MjdjMS4yODMsMC43NDEsMi4xODYsMi4xMDksMi4xODYsMy41OVYxNzIuODk4eicvPg0KPC9zdmc+">
|
||||
<style>
|
||||
body {
|
||||
font-family:Arial, "Helvetica Neue", Helvetica, sans-serif;
|
||||
font-size:16px;
|
||||
font-weight:normal;
|
||||
margin:0;
|
||||
padding:0;
|
||||
color:#333
|
||||
font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
#overview {
|
||||
padding:20px 30px
|
||||
}
|
||||
td, th {
|
||||
padding:5px 10px
|
||||
}
|
||||
h1 {
|
||||
margin:0
|
||||
}
|
||||
table {
|
||||
margin:30px;
|
||||
width:calc(100% - 60px);
|
||||
max-width:1000px;
|
||||
border-radius:5px;
|
||||
border:1px solid #ddd;
|
||||
border-spacing:0px;
|
||||
padding: 20px 30px;
|
||||
}
|
||||
|
||||
td,
|
||||
th {
|
||||
font-weight:400;
|
||||
font-size:medium;
|
||||
text-align:left;
|
||||
cursor:pointer
|
||||
padding: 5px 10px;
|
||||
}
|
||||
td.clr-1, td.clr-2, th span {
|
||||
font-weight:700
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
table {
|
||||
margin: 30px;
|
||||
width: calc(100% - 60px);
|
||||
max-width: 1000px;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #ddd;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
th {
|
||||
font-weight: 400;
|
||||
font-size: medium;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
td.clr-1,
|
||||
td.clr-2,
|
||||
th span {
|
||||
float:right;
|
||||
margin-left:20px
|
||||
font-weight: 700;
|
||||
}
|
||||
th span:after {
|
||||
content:"";
|
||||
clear:both;
|
||||
display:block
|
||||
|
||||
th span {
|
||||
float: right;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
th span::after {
|
||||
content: "";
|
||||
clear: both;
|
||||
display: block;
|
||||
}
|
||||
|
||||
tr:last-child td {
|
||||
border-bottom:none
|
||||
border-bottom: none;
|
||||
}
|
||||
tr td:first-child, tr td:last-child {
|
||||
color:#9da0a4
|
||||
|
||||
tr td:first-child,
|
||||
tr td:last-child {
|
||||
color: #9da0a4;
|
||||
}
|
||||
#overview.bg-0, tr.bg-0 th {
|
||||
color:#468847;
|
||||
background:#dff0d8;
|
||||
border-bottom:1px solid #d6e9c6
|
||||
|
||||
#overview.bg-0,
|
||||
tr.bg-0 th {
|
||||
color: #468847;
|
||||
background: #dff0d8;
|
||||
border-bottom: 1px solid #d6e9c6;
|
||||
}
|
||||
#overview.bg-1, tr.bg-1 th {
|
||||
color:#f0ad4e;
|
||||
background:#fcf8e3;
|
||||
border-bottom:1px solid #fbeed5
|
||||
|
||||
#overview.bg-1,
|
||||
tr.bg-1 th {
|
||||
color: #f0ad4e;
|
||||
background: #fcf8e3;
|
||||
border-bottom: 1px solid #fbeed5;
|
||||
}
|
||||
#overview.bg-2, tr.bg-2 th {
|
||||
color:#b94a48;
|
||||
background:#f2dede;
|
||||
border-bottom:1px solid #eed3d7
|
||||
|
||||
#overview.bg-2,
|
||||
tr.bg-2 th {
|
||||
color: #b94a48;
|
||||
background: #f2dede;
|
||||
border-bottom: 1px solid #eed3d7;
|
||||
}
|
||||
|
||||
td {
|
||||
border-bottom:1px solid #ddd
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
td.clr-1 {
|
||||
color:#f0ad4e
|
||||
color: #f0ad4e;
|
||||
}
|
||||
|
||||
td.clr-2 {
|
||||
color:#b94a48
|
||||
color: #b94a48;
|
||||
}
|
||||
|
||||
td a {
|
||||
color:#3a33d1;
|
||||
text-decoration:none
|
||||
color: #3a33d1;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
td a:hover {
|
||||
color:#272296;
|
||||
text-decoration:underline
|
||||
color: #272296;
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
|
@ -149,7 +176,7 @@ function pageTemplate(it) {
|
|||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`.trimLeft();
|
||||
`.trimStart();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -212,7 +239,7 @@ function messageTemplate(it) {
|
|||
} = it;
|
||||
|
||||
return `
|
||||
<tr style="display:none" class="f-${parentIndex}">
|
||||
<tr style="display: none;" class="f-${parentIndex}">
|
||||
<td>${lineNumber}:${columnNumber}</td>
|
||||
<td class="clr-${severityNumber}">${severityName}</td>
|
||||
<td>${encodeHTML(message)}</td>
|
||||
|
|
@ -220,7 +247,7 @@ function messageTemplate(it) {
|
|||
<a href="${ruleUrl ? ruleUrl : ""}" target="_blank" rel="noopener noreferrer">${ruleId ? ruleId : ""}</a>
|
||||
</td>
|
||||
</tr>
|
||||
`.trimLeft();
|
||||
`.trimStart();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -278,11 +305,11 @@ function resultTemplate(it) {
|
|||
<span>${encodeHTML(summary)}</span>
|
||||
</th>
|
||||
</tr>
|
||||
`.trimLeft();
|
||||
`.trimStart();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line jsdoc/require-description
|
||||
/**
|
||||
* Render the results.
|
||||
* @param {Array} results Test results.
|
||||
* @param {Object} rulesMeta Dictionary containing metadata for each rule executed by the analysis.
|
||||
* @returns {string} HTML string describing the results.
|
||||
|
|
|
|||
159
node_modules/eslint/lib/cli-engine/formatters/table.js
generated
vendored
159
node_modules/eslint/lib/cli-engine/formatters/table.js
generated
vendored
|
|
@ -1,159 +0,0 @@
|
|||
/**
|
||||
* @fileoverview "table reporter.
|
||||
* @author Gajus Kuizinas <gajus@gajus.com>
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const chalk = require("chalk"),
|
||||
table = require("table").table;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Given a word and a count, append an "s" if count is not one.
|
||||
* @param {string} word A word.
|
||||
* @param {number} count Quantity.
|
||||
* @returns {string} The original word with an s on the end if count is not one.
|
||||
*/
|
||||
function pluralize(word, count) {
|
||||
return (count === 1 ? word : `${word}s`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws text table.
|
||||
* @param {Array<Object>} messages Error messages relating to a specific file.
|
||||
* @returns {string} A text table.
|
||||
*/
|
||||
function drawTable(messages) {
|
||||
const rows = [];
|
||||
|
||||
if (messages.length === 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
rows.push([
|
||||
chalk.bold("Line"),
|
||||
chalk.bold("Column"),
|
||||
chalk.bold("Type"),
|
||||
chalk.bold("Message"),
|
||||
chalk.bold("Rule ID")
|
||||
]);
|
||||
|
||||
messages.forEach(message => {
|
||||
let messageType;
|
||||
|
||||
if (message.fatal || message.severity === 2) {
|
||||
messageType = chalk.red("error");
|
||||
} else {
|
||||
messageType = chalk.yellow("warning");
|
||||
}
|
||||
|
||||
rows.push([
|
||||
message.line || 0,
|
||||
message.column || 0,
|
||||
messageType,
|
||||
message.message,
|
||||
message.ruleId || ""
|
||||
]);
|
||||
});
|
||||
|
||||
return table(rows, {
|
||||
columns: {
|
||||
0: {
|
||||
width: 8,
|
||||
wrapWord: true
|
||||
},
|
||||
1: {
|
||||
width: 8,
|
||||
wrapWord: true
|
||||
},
|
||||
2: {
|
||||
width: 8,
|
||||
wrapWord: true
|
||||
},
|
||||
3: {
|
||||
paddingRight: 5,
|
||||
width: 50,
|
||||
wrapWord: true
|
||||
},
|
||||
4: {
|
||||
width: 20,
|
||||
wrapWord: true
|
||||
}
|
||||
},
|
||||
drawHorizontalLine(index) {
|
||||
return index === 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a report (multiple tables).
|
||||
* @param {Array} results Report results for every file.
|
||||
* @returns {string} A column of text tables.
|
||||
*/
|
||||
function drawReport(results) {
|
||||
let files;
|
||||
|
||||
files = results.map(result => {
|
||||
if (!result.messages.length) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return `\n${result.filePath}\n\n${drawTable(result.messages)}`;
|
||||
});
|
||||
|
||||
files = files.filter(content => content.trim());
|
||||
|
||||
return files.join("");
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = function(report) {
|
||||
let result,
|
||||
errorCount,
|
||||
warningCount;
|
||||
|
||||
result = "";
|
||||
errorCount = 0;
|
||||
warningCount = 0;
|
||||
|
||||
report.forEach(fileReport => {
|
||||
errorCount += fileReport.errorCount;
|
||||
warningCount += fileReport.warningCount;
|
||||
});
|
||||
|
||||
if (errorCount || warningCount) {
|
||||
result = drawReport(report);
|
||||
}
|
||||
|
||||
result += `\n${table([
|
||||
[
|
||||
chalk.red(pluralize(`${errorCount} Error`, errorCount))
|
||||
],
|
||||
[
|
||||
chalk.yellow(pluralize(`${warningCount} Warning`, warningCount))
|
||||
]
|
||||
], {
|
||||
columns: {
|
||||
0: {
|
||||
width: 110,
|
||||
wrapWord: true
|
||||
}
|
||||
},
|
||||
drawHorizontalLine() {
|
||||
return true;
|
||||
}
|
||||
})}`;
|
||||
|
||||
return result;
|
||||
};
|
||||
2
node_modules/eslint/lib/cli-engine/formatters/tap.js
generated
vendored
2
node_modules/eslint/lib/cli-engine/formatters/tap.js
generated
vendored
|
|
@ -31,7 +31,7 @@ function outputDiagnostics(diagnostic) {
|
|||
const prefix = " ";
|
||||
let output = `${prefix}---\n`;
|
||||
|
||||
output += prefix + yaml.safeDump(diagnostic).split("\n").join(`\n${prefix}`);
|
||||
output += prefix + yaml.dump(diagnostic).split("\n").join(`\n${prefix}`);
|
||||
output += "...\n";
|
||||
return output;
|
||||
}
|
||||
|
|
|
|||
4
node_modules/eslint/lib/cli-engine/hash.js
generated
vendored
4
node_modules/eslint/lib/cli-engine/hash.js
generated
vendored
|
|
@ -21,8 +21,8 @@ const murmur = require("imurmurhash");
|
|||
|
||||
/**
|
||||
* hash the given string
|
||||
* @param {string} str the string to hash
|
||||
* @returns {string} the hash
|
||||
* @param {string} str the string to hash
|
||||
* @returns {string} the hash
|
||||
*/
|
||||
function hash(str) {
|
||||
return murmur(str).result().toString(36);
|
||||
|
|
|
|||
2
node_modules/eslint/lib/cli-engine/lint-result-cache.js
generated
vendored
2
node_modules/eslint/lib/cli-engine/lint-result-cache.js
generated
vendored
|
|
@ -36,7 +36,7 @@ const invalidCacheStrategyErrorMessage = `Cache strategy must be one of: ${valid
|
|||
*/
|
||||
function isValidCacheStrategy(cacheStrategy) {
|
||||
return (
|
||||
validCacheStrategies.indexOf(cacheStrategy) !== -1
|
||||
validCacheStrategies.includes(cacheStrategy)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
2
node_modules/eslint/lib/cli-engine/xml-escape.js
generated
vendored
2
node_modules/eslint/lib/cli-engine/xml-escape.js
generated
vendored
|
|
@ -15,7 +15,7 @@
|
|||
* @private
|
||||
*/
|
||||
module.exports = function(s) {
|
||||
return (`${s}`).replace(/[<>&"'\x00-\x1F\x7F\u0080-\uFFFF]/gu, c => { // eslint-disable-line no-control-regex
|
||||
return (`${s}`).replace(/[<>&"'\x00-\x1F\x7F\u0080-\uFFFF]/gu, c => { // eslint-disable-line no-control-regex -- Converting controls to entities
|
||||
switch (c) {
|
||||
case "<":
|
||||
return "<";
|
||||
|
|
|
|||
203
node_modules/eslint/lib/cli.js
generated
vendored
203
node_modules/eslint/lib/cli.js
generated
vendored
|
|
@ -6,7 +6,7 @@
|
|||
"use strict";
|
||||
|
||||
/*
|
||||
* The CLI object should *not* call process.exit() directly. It should only return
|
||||
* NOTE: The CLI object should *not* call process.exit() directly. It should only return
|
||||
* exit codes. This allows other programs to use the CLI object and still control
|
||||
* when the program exits.
|
||||
*/
|
||||
|
|
@ -19,9 +19,13 @@ const fs = require("fs"),
|
|||
path = require("path"),
|
||||
{ promisify } = require("util"),
|
||||
{ ESLint } = require("./eslint"),
|
||||
CLIOptions = require("./options"),
|
||||
{ FlatESLint } = require("./eslint/flat-eslint"),
|
||||
createCLIOptions = require("./options"),
|
||||
log = require("./shared/logging"),
|
||||
RuntimeInfo = require("./shared/runtime-info");
|
||||
const { Legacy: { naming } } = require("@eslint/eslintrc");
|
||||
const { findFlatConfigFile } = require("./eslint/flat-eslint");
|
||||
const { ModuleImporter } = require("@humanwhocodes/module-importer");
|
||||
|
||||
const debug = require("debug")("eslint:cli");
|
||||
|
||||
|
|
@ -33,6 +37,7 @@ const debug = require("debug")("eslint:cli");
|
|||
/** @typedef {import("./eslint/eslint").LintMessage} LintMessage */
|
||||
/** @typedef {import("./eslint/eslint").LintResult} LintResult */
|
||||
/** @typedef {import("./options").ParsedCLIOptions} ParsedCLIOptions */
|
||||
/** @typedef {import("./shared/types").ResultsMeta} ResultsMeta */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
|
|
@ -54,17 +59,20 @@ function quietFixPredicate(message) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Translates the CLI options into the options expected by the CLIEngine.
|
||||
* Translates the CLI options into the options expected by the ESLint constructor.
|
||||
* @param {ParsedCLIOptions} cliOptions The CLI options to translate.
|
||||
* @returns {ESLintOptions} The options object for the CLIEngine.
|
||||
* @param {"flat"|"eslintrc"} [configType="eslintrc"] The format of the
|
||||
* config to generate.
|
||||
* @returns {Promise<ESLintOptions>} The options object for the ESLint constructor.
|
||||
* @private
|
||||
*/
|
||||
function translateOptions({
|
||||
async function translateOptions({
|
||||
cache,
|
||||
cacheFile,
|
||||
cacheLocation,
|
||||
cacheStrategy,
|
||||
config,
|
||||
configLookup,
|
||||
env,
|
||||
errorOnUnmatchedPattern,
|
||||
eslintrc,
|
||||
|
|
@ -85,19 +93,60 @@ function translateOptions({
|
|||
resolvePluginsRelativeTo,
|
||||
rule,
|
||||
rulesdir
|
||||
}) {
|
||||
return {
|
||||
allowInlineConfig: inlineConfig,
|
||||
cache,
|
||||
cacheLocation: cacheLocation || cacheFile,
|
||||
cacheStrategy,
|
||||
errorOnUnmatchedPattern,
|
||||
extensions: ext,
|
||||
fix: (fix || fixDryRun) && (quiet ? quietFixPredicate : true),
|
||||
fixTypes: fixType,
|
||||
ignore,
|
||||
ignorePath,
|
||||
overrideConfig: {
|
||||
}, configType) {
|
||||
|
||||
let overrideConfig, overrideConfigFile;
|
||||
const importer = new ModuleImporter();
|
||||
|
||||
if (configType === "flat") {
|
||||
overrideConfigFile = (typeof config === "string") ? config : !configLookup;
|
||||
if (overrideConfigFile === false) {
|
||||
overrideConfigFile = void 0;
|
||||
}
|
||||
|
||||
let globals = {};
|
||||
|
||||
if (global) {
|
||||
globals = global.reduce((obj, name) => {
|
||||
if (name.endsWith(":true")) {
|
||||
obj[name.slice(0, -5)] = "writable";
|
||||
} else {
|
||||
obj[name] = "readonly";
|
||||
}
|
||||
return obj;
|
||||
}, globals);
|
||||
}
|
||||
|
||||
overrideConfig = [{
|
||||
languageOptions: {
|
||||
globals,
|
||||
parserOptions: parserOptions || {}
|
||||
},
|
||||
rules: rule ? rule : {}
|
||||
}];
|
||||
|
||||
if (parser) {
|
||||
overrideConfig[0].languageOptions.parser = await importer.import(parser);
|
||||
}
|
||||
|
||||
if (plugin) {
|
||||
const plugins = {};
|
||||
|
||||
for (const pluginName of plugin) {
|
||||
|
||||
const shortName = naming.getShorthandName(pluginName, "eslint-plugin");
|
||||
const longName = naming.normalizePackageName(pluginName, "eslint-plugin");
|
||||
|
||||
plugins[shortName] = await importer.import(longName);
|
||||
}
|
||||
|
||||
overrideConfig[0].plugins = plugins;
|
||||
}
|
||||
|
||||
} else {
|
||||
overrideConfigFile = config;
|
||||
|
||||
overrideConfig = {
|
||||
env: env && env.reduce((obj, name) => {
|
||||
obj[name] = true;
|
||||
return obj;
|
||||
|
|
@ -115,19 +164,40 @@ function translateOptions({
|
|||
parserOptions,
|
||||
plugins: plugin,
|
||||
rules: rule
|
||||
},
|
||||
overrideConfigFile: config,
|
||||
reportUnusedDisableDirectives: reportUnusedDisableDirectives ? "error" : void 0,
|
||||
resolvePluginsRelativeTo,
|
||||
rulePaths: rulesdir,
|
||||
useEslintrc: eslintrc
|
||||
};
|
||||
}
|
||||
|
||||
const options = {
|
||||
allowInlineConfig: inlineConfig,
|
||||
cache,
|
||||
cacheLocation: cacheLocation || cacheFile,
|
||||
cacheStrategy,
|
||||
errorOnUnmatchedPattern,
|
||||
fix: (fix || fixDryRun) && (quiet ? quietFixPredicate : true),
|
||||
fixTypes: fixType,
|
||||
ignore,
|
||||
overrideConfig,
|
||||
overrideConfigFile,
|
||||
reportUnusedDisableDirectives: reportUnusedDisableDirectives ? "error" : void 0
|
||||
};
|
||||
|
||||
if (configType === "flat") {
|
||||
options.ignorePatterns = ignorePattern;
|
||||
} else {
|
||||
options.resolvePluginsRelativeTo = resolvePluginsRelativeTo;
|
||||
options.rulePaths = rulesdir;
|
||||
options.useEslintrc = eslintrc;
|
||||
options.extensions = ext;
|
||||
options.ignorePath = ignorePath;
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count error messages.
|
||||
* @param {LintResult[]} results The lint results.
|
||||
* @returns {{errorCount:number;warningCount:number}} The number of error messages.
|
||||
* @returns {{errorCount:number;fatalErrorCount:number,warningCount:number}} The number of error messages.
|
||||
*/
|
||||
function countErrors(results) {
|
||||
let errorCount = 0;
|
||||
|
|
@ -165,10 +235,11 @@ async function isDirectory(filePath) {
|
|||
* @param {LintResult[]} results The results to print.
|
||||
* @param {string} format The name of the formatter to use or the path to the formatter.
|
||||
* @param {string} outputFile The path for the output file.
|
||||
* @param {ResultsMeta} resultsMeta Warning count and max threshold.
|
||||
* @returns {Promise<boolean>} True if the printing succeeds, false if not.
|
||||
* @private
|
||||
*/
|
||||
async function printResults(engine, results, format, outputFile) {
|
||||
async function printResults(engine, results, format, outputFile, resultsMeta) {
|
||||
let formatter;
|
||||
|
||||
try {
|
||||
|
|
@ -178,7 +249,7 @@ async function printResults(engine, results, format, outputFile) {
|
|||
return false;
|
||||
}
|
||||
|
||||
const output = formatter.format(results);
|
||||
const output = await formatter.format(results, resultsMeta);
|
||||
|
||||
if (output) {
|
||||
if (outputFile) {
|
||||
|
|
@ -204,6 +275,31 @@ async function printResults(engine, results, format, outputFile) {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether flat config should be used.
|
||||
* @param {boolean} [allowFlatConfig] Whether or not to allow flat config.
|
||||
* @returns {Promise<boolean>} Where flat config should be used.
|
||||
*/
|
||||
async function shouldUseFlatConfig(allowFlatConfig) {
|
||||
if (!allowFlatConfig) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (process.env.ESLINT_USE_FLAT_CONFIG) {
|
||||
case "true":
|
||||
return true;
|
||||
case "false":
|
||||
return false;
|
||||
default:
|
||||
|
||||
/*
|
||||
* If neither explicitly enabled nor disabled, then use the presence
|
||||
* of a flat config file to determine enablement.
|
||||
*/
|
||||
return !!(await findFlatConfigFile(process.cwd()));
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -218,19 +314,34 @@ const cli = {
|
|||
* Executes the CLI based on an array of arguments that is passed in.
|
||||
* @param {string|Array|Object} args The arguments to process.
|
||||
* @param {string} [text] The text to lint (used for TTY).
|
||||
* @param {boolean} [allowFlatConfig] Whether or not to allow flat config.
|
||||
* @returns {Promise<number>} The exit code for the operation.
|
||||
*/
|
||||
async execute(args, text) {
|
||||
async execute(args, text, allowFlatConfig) {
|
||||
if (Array.isArray(args)) {
|
||||
debug("CLI args: %o", args.slice(2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Before doing anything, we need to see if we are using a
|
||||
* flat config file. If so, then we need to change the way command
|
||||
* line args are parsed. This is temporary, and when we fully
|
||||
* switch to flat config we can remove this logic.
|
||||
*/
|
||||
|
||||
const usingFlatConfig = await shouldUseFlatConfig(allowFlatConfig);
|
||||
|
||||
debug("Using flat config?", usingFlatConfig);
|
||||
|
||||
const CLIOptions = createCLIOptions(usingFlatConfig);
|
||||
|
||||
/** @type {ParsedCLIOptions} */
|
||||
let options;
|
||||
|
||||
try {
|
||||
options = CLIOptions.parse(args);
|
||||
} catch (error) {
|
||||
debug("Error parsing CLI options:", error.message);
|
||||
log.error(error.message);
|
||||
return 2;
|
||||
}
|
||||
|
|
@ -251,6 +362,7 @@ const cli = {
|
|||
log.info(RuntimeInfo.environment());
|
||||
return 0;
|
||||
} catch (err) {
|
||||
debug("Error retrieving environment info");
|
||||
log.error(err.message);
|
||||
return 2;
|
||||
}
|
||||
|
|
@ -266,7 +378,9 @@ const cli = {
|
|||
return 2;
|
||||
}
|
||||
|
||||
const engine = new ESLint(translateOptions(options));
|
||||
const engine = usingFlatConfig
|
||||
? new FlatESLint(await translateOptions(options, "flat"))
|
||||
: new ESLint(await translateOptions(options));
|
||||
const fileConfig =
|
||||
await engine.calculateConfigForFile(options.printConfig);
|
||||
|
||||
|
|
@ -289,7 +403,9 @@ const cli = {
|
|||
return 2;
|
||||
}
|
||||
|
||||
const engine = new ESLint(translateOptions(options));
|
||||
const ActiveESLint = usingFlatConfig ? FlatESLint : ESLint;
|
||||
|
||||
const engine = new ActiveESLint(await translateOptions(options, usingFlatConfig ? "flat" : "eslintrc"));
|
||||
let results;
|
||||
|
||||
if (useStdin) {
|
||||
|
|
@ -303,27 +419,34 @@ const cli = {
|
|||
|
||||
if (options.fix) {
|
||||
debug("Fix mode enabled - applying fixes");
|
||||
await ESLint.outputFixes(results);
|
||||
await ActiveESLint.outputFixes(results);
|
||||
}
|
||||
|
||||
let resultsToPrint = results;
|
||||
|
||||
if (options.quiet) {
|
||||
debug("Quiet mode enabled - filtering out warnings");
|
||||
resultsToPrint = ESLint.getErrorResults(resultsToPrint);
|
||||
resultsToPrint = ActiveESLint.getErrorResults(resultsToPrint);
|
||||
}
|
||||
|
||||
if (await printResults(engine, resultsToPrint, options.format, options.outputFile)) {
|
||||
const resultCounts = countErrors(results);
|
||||
const tooManyWarnings = options.maxWarnings >= 0 && resultCounts.warningCount > options.maxWarnings;
|
||||
const resultsMeta = tooManyWarnings
|
||||
? {
|
||||
maxWarningsExceeded: {
|
||||
maxWarnings: options.maxWarnings,
|
||||
foundWarnings: resultCounts.warningCount
|
||||
}
|
||||
}
|
||||
: {};
|
||||
|
||||
if (await printResults(engine, resultsToPrint, options.format, options.outputFile, resultsMeta)) {
|
||||
|
||||
// Errors and warnings from the original unfiltered results should determine the exit code
|
||||
const { errorCount, fatalErrorCount, warningCount } = countErrors(results);
|
||||
|
||||
const tooManyWarnings =
|
||||
options.maxWarnings >= 0 && warningCount > options.maxWarnings;
|
||||
const shouldExitForFatalErrors =
|
||||
options.exitOnFatalError && fatalErrorCount > 0;
|
||||
options.exitOnFatalError && resultCounts.fatalErrorCount > 0;
|
||||
|
||||
if (!errorCount && tooManyWarnings) {
|
||||
if (!resultCounts.errorCount && tooManyWarnings) {
|
||||
log.error(
|
||||
"ESLint found too many warnings (maximum: %s).",
|
||||
options.maxWarnings
|
||||
|
|
@ -334,7 +457,7 @@ const cli = {
|
|||
return 2;
|
||||
}
|
||||
|
||||
return (errorCount || tooManyWarnings) ? 1 : 0;
|
||||
return (resultCounts.errorCount || tooManyWarnings) ? 1 : 0;
|
||||
}
|
||||
|
||||
return 2;
|
||||
|
|
|
|||
32
node_modules/eslint/lib/config/default-config.js
generated
vendored
32
node_modules/eslint/lib/config/default-config.js
generated
vendored
|
|
@ -15,7 +15,6 @@ const Rules = require("../rules");
|
|||
// Helpers
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
exports.defaultConfig = [
|
||||
{
|
||||
plugins: {
|
||||
|
|
@ -26,7 +25,7 @@ exports.defaultConfig = [
|
|||
|
||||
/*
|
||||
* Because we try to delay loading rules until absolutely
|
||||
* necessary, a proxy allows us to hook into the lazy-loading
|
||||
* necessary, a proxy allows us to hook into the lazy-loading
|
||||
* aspect of the rules map while still keeping all of the
|
||||
* relevant configuration inside of the config array.
|
||||
*/
|
||||
|
|
@ -41,12 +40,31 @@ exports.defaultConfig = [
|
|||
})
|
||||
}
|
||||
},
|
||||
ignores: [
|
||||
"**/node_modules/**",
|
||||
".git/**"
|
||||
],
|
||||
languageOptions: {
|
||||
parser: "@/espree"
|
||||
sourceType: "module",
|
||||
ecmaVersion: "latest",
|
||||
parser: "@/espree",
|
||||
parserOptions: {}
|
||||
}
|
||||
},
|
||||
|
||||
// default ignores are listed here
|
||||
{
|
||||
ignores: [
|
||||
"**/node_modules/*",
|
||||
".git/"
|
||||
]
|
||||
},
|
||||
|
||||
// intentionally empty config to ensure these files are globbed by default
|
||||
{
|
||||
files: ["**/*.js", "**/*.mjs"]
|
||||
},
|
||||
{
|
||||
files: ["**/*.cjs"],
|
||||
languageOptions: {
|
||||
sourceType: "commonjs",
|
||||
ecmaVersion: "latest"
|
||||
}
|
||||
}
|
||||
];
|
||||
|
|
|
|||
127
node_modules/eslint/lib/config/flat-config-array.js
generated
vendored
127
node_modules/eslint/lib/config/flat-config-array.js
generated
vendored
|
|
@ -14,7 +14,6 @@ const { flatConfigSchema } = require("./flat-config-schema");
|
|||
const { RuleValidator } = require("./rule-validator");
|
||||
const { defaultConfig } = require("./default-config");
|
||||
const recommendedConfig = require("../../conf/eslint-recommended");
|
||||
const allConfig = require("../../conf/eslint-all");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helpers
|
||||
|
|
@ -37,6 +36,8 @@ function splitPluginIdentifier(identifier) {
|
|||
};
|
||||
}
|
||||
|
||||
const originalBaseConfig = Symbol("originalBaseConfig");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Exports
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -49,19 +50,43 @@ class FlatConfigArray extends ConfigArray {
|
|||
/**
|
||||
* Creates a new instance.
|
||||
* @param {*[]} configs An array of configuration information.
|
||||
* @param {{basePath: string, baseConfig: FlatConfig}} options The options
|
||||
* @param {{basePath: string, shouldIgnore: boolean, baseConfig: FlatConfig}} options The options
|
||||
* to use for the config array instance.
|
||||
*/
|
||||
constructor(configs, { basePath, baseConfig = defaultConfig }) {
|
||||
constructor(configs, {
|
||||
basePath,
|
||||
shouldIgnore = true,
|
||||
baseConfig = defaultConfig
|
||||
} = {}) {
|
||||
super(configs, {
|
||||
basePath,
|
||||
schema: flatConfigSchema
|
||||
});
|
||||
|
||||
this.unshift(baseConfig);
|
||||
if (baseConfig[Symbol.iterator]) {
|
||||
this.unshift(...baseConfig);
|
||||
} else {
|
||||
this.unshift(baseConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* The base config used to build the config array.
|
||||
* @type {Array<FlatConfig>}
|
||||
*/
|
||||
this[originalBaseConfig] = baseConfig;
|
||||
Object.defineProperty(this, originalBaseConfig, { writable: false });
|
||||
|
||||
/**
|
||||
* Determines if `ignores` fields should be honored.
|
||||
* If true, then all `ignores` fields are honored.
|
||||
* if false, then only `ignores` fields in the baseConfig are honored.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.shouldIgnore = shouldIgnore;
|
||||
Object.defineProperty(this, "shouldIgnore", { writable: false });
|
||||
}
|
||||
|
||||
/* eslint-disable class-methods-use-this */
|
||||
/* eslint-disable class-methods-use-this -- Desired as instance method */
|
||||
/**
|
||||
* Replaces a config with another config to allow us to put strings
|
||||
* in the config array that will be replaced by objects before
|
||||
|
|
@ -75,7 +100,30 @@ class FlatConfigArray extends ConfigArray {
|
|||
}
|
||||
|
||||
if (config === "eslint:all") {
|
||||
return allConfig;
|
||||
|
||||
/*
|
||||
* Load `eslint-all.js` here instead of at the top level to avoid loading all rule modules
|
||||
* when it isn't necessary. `eslint-all.js` reads `meta` of rule objects to filter out deprecated ones,
|
||||
* so requiring `eslint-all.js` module loads all rule modules as a consequence.
|
||||
*/
|
||||
return require("../../conf/eslint-all");
|
||||
}
|
||||
|
||||
/*
|
||||
* If `shouldIgnore` is false, we remove any ignore patterns specified
|
||||
* in the config so long as it's not a default config and it doesn't
|
||||
* have a `files` entry.
|
||||
*/
|
||||
if (
|
||||
!this.shouldIgnore &&
|
||||
!this[originalBaseConfig].includes(config) &&
|
||||
config.ignores &&
|
||||
!config.files
|
||||
) {
|
||||
/* eslint-disable-next-line no-unused-vars -- need to strip off other keys */
|
||||
const { ignores, ...otherKeys } = config;
|
||||
|
||||
return otherKeys;
|
||||
}
|
||||
|
||||
return config;
|
||||
|
|
@ -91,34 +139,75 @@ class FlatConfigArray extends ConfigArray {
|
|||
[ConfigArraySymbol.finalizeConfig](config) {
|
||||
|
||||
const { plugins, languageOptions, processor } = config;
|
||||
let parserName, processorName;
|
||||
let invalidParser = false,
|
||||
invalidProcessor = false;
|
||||
|
||||
// Check parser value
|
||||
if (languageOptions && languageOptions.parser && typeof languageOptions.parser === "string") {
|
||||
const { pluginName, objectName: parserName } = splitPluginIdentifier(languageOptions.parser);
|
||||
if (languageOptions && languageOptions.parser) {
|
||||
if (typeof languageOptions.parser === "string") {
|
||||
const { pluginName, objectName: localParserName } = splitPluginIdentifier(languageOptions.parser);
|
||||
|
||||
if (!plugins || !plugins[pluginName] || !plugins[pluginName].parsers || !plugins[pluginName].parsers[parserName]) {
|
||||
throw new TypeError(`Key "parser": Could not find "${parserName}" in plugin "${pluginName}".`);
|
||||
parserName = languageOptions.parser;
|
||||
|
||||
if (!plugins || !plugins[pluginName] || !plugins[pluginName].parsers || !plugins[pluginName].parsers[localParserName]) {
|
||||
throw new TypeError(`Key "parser": Could not find "${localParserName}" in plugin "${pluginName}".`);
|
||||
}
|
||||
|
||||
languageOptions.parser = plugins[pluginName].parsers[localParserName];
|
||||
} else {
|
||||
invalidParser = true;
|
||||
}
|
||||
|
||||
languageOptions.parser = plugins[pluginName].parsers[parserName];
|
||||
}
|
||||
|
||||
// Check processor value
|
||||
if (processor && typeof processor === "string") {
|
||||
const { pluginName, objectName: processorName } = splitPluginIdentifier(processor);
|
||||
if (processor) {
|
||||
if (typeof processor === "string") {
|
||||
const { pluginName, objectName: localProcessorName } = splitPluginIdentifier(processor);
|
||||
|
||||
if (!plugins || !plugins[pluginName] || !plugins[pluginName].processors || !plugins[pluginName].processors[processorName]) {
|
||||
throw new TypeError(`Key "processor": Could not find "${processorName}" in plugin "${pluginName}".`);
|
||||
processorName = processor;
|
||||
|
||||
if (!plugins || !plugins[pluginName] || !plugins[pluginName].processors || !plugins[pluginName].processors[localProcessorName]) {
|
||||
throw new TypeError(`Key "processor": Could not find "${localProcessorName}" in plugin "${pluginName}".`);
|
||||
}
|
||||
|
||||
config.processor = plugins[pluginName].processors[localProcessorName];
|
||||
} else {
|
||||
invalidProcessor = true;
|
||||
}
|
||||
|
||||
config.processor = plugins[pluginName].processors[processorName];
|
||||
}
|
||||
|
||||
ruleValidator.validate(config);
|
||||
|
||||
// apply special logic for serialization into JSON
|
||||
/* eslint-disable object-shorthand -- shorthand would change "this" value */
|
||||
Object.defineProperty(config, "toJSON", {
|
||||
value: function() {
|
||||
|
||||
if (invalidParser) {
|
||||
throw new Error("Caching is not supported when parser is an object.");
|
||||
}
|
||||
|
||||
if (invalidProcessor) {
|
||||
throw new Error("Caching is not supported when processor is an object.");
|
||||
}
|
||||
|
||||
return {
|
||||
...this,
|
||||
plugins: Object.keys(plugins),
|
||||
languageOptions: {
|
||||
...languageOptions,
|
||||
parser: parserName
|
||||
},
|
||||
processor: processorName
|
||||
};
|
||||
}
|
||||
});
|
||||
/* eslint-enable object-shorthand -- ok to enable now */
|
||||
|
||||
return config;
|
||||
}
|
||||
/* eslint-enable class-methods-use-this */
|
||||
/* eslint-enable class-methods-use-this -- Desired as instance method */
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
111
node_modules/eslint/lib/config/flat-config-helpers.js
generated
vendored
Normal file
111
node_modules/eslint/lib/config/flat-config-helpers.js
generated
vendored
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/**
|
||||
* @fileoverview Shared functions to work with configs.
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Parses a ruleId into its plugin and rule parts.
|
||||
* @param {string} ruleId The rule ID to parse.
|
||||
* @returns {{pluginName:string,ruleName:string}} The plugin and rule
|
||||
* parts of the ruleId;
|
||||
*/
|
||||
function parseRuleId(ruleId) {
|
||||
let pluginName, ruleName;
|
||||
|
||||
// distinguish between core rules and plugin rules
|
||||
if (ruleId.includes("/")) {
|
||||
|
||||
// mimic scoped npm packages
|
||||
if (ruleId.startsWith("@")) {
|
||||
pluginName = ruleId.slice(0, ruleId.lastIndexOf("/"));
|
||||
} else {
|
||||
pluginName = ruleId.slice(0, ruleId.indexOf("/"));
|
||||
}
|
||||
|
||||
ruleName = ruleId.slice(pluginName.length + 1);
|
||||
} else {
|
||||
pluginName = "@";
|
||||
ruleName = ruleId;
|
||||
}
|
||||
|
||||
return {
|
||||
pluginName,
|
||||
ruleName
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a rule instance from a given config based on the ruleId.
|
||||
* @param {string} ruleId The rule ID to look for.
|
||||
* @param {FlatConfig} config The config to search.
|
||||
* @returns {import("../shared/types").Rule|undefined} The rule if found
|
||||
* or undefined if not.
|
||||
*/
|
||||
function getRuleFromConfig(ruleId, config) {
|
||||
|
||||
const { pluginName, ruleName } = parseRuleId(ruleId);
|
||||
|
||||
const plugin = config.plugins && config.plugins[pluginName];
|
||||
let rule = plugin && plugin.rules && plugin.rules[ruleName];
|
||||
|
||||
|
||||
// normalize function rules into objects
|
||||
if (rule && typeof rule === "function") {
|
||||
rule = {
|
||||
create: rule
|
||||
};
|
||||
}
|
||||
|
||||
return rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a complete options schema for a rule.
|
||||
* @param {{create: Function, schema: (Array|null)}} rule A new-style rule object
|
||||
* @returns {Object} JSON Schema for the rule's options.
|
||||
*/
|
||||
function getRuleOptionsSchema(rule) {
|
||||
|
||||
if (!rule) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const schema = rule.schema || rule.meta && rule.meta.schema;
|
||||
|
||||
if (Array.isArray(schema)) {
|
||||
if (schema.length) {
|
||||
return {
|
||||
type: "array",
|
||||
items: schema,
|
||||
minItems: 0,
|
||||
maxItems: schema.length
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: "array",
|
||||
minItems: 0,
|
||||
maxItems: 0
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// Given a full schema, leave it alone
|
||||
return schema || null;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Exports
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
parseRuleId,
|
||||
getRuleFromConfig,
|
||||
getRuleOptionsSchema
|
||||
};
|
||||
23
node_modules/eslint/lib/config/flat-config-schema.js
generated
vendored
23
node_modules/eslint/lib/config/flat-config-schema.js
generated
vendored
|
|
@ -195,13 +195,6 @@ function assertIsObjectOrString(value) {
|
|||
// Low-Level Schemas
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
/** @type {ObjectPropertySchema} */
|
||||
const numberSchema = {
|
||||
merge: "replace",
|
||||
validate: "number"
|
||||
};
|
||||
|
||||
/** @type {ObjectPropertySchema} */
|
||||
const booleanSchema = {
|
||||
merge: "replace",
|
||||
|
|
@ -336,7 +329,7 @@ const rulesSchema = {
|
|||
// avoid hairy edge case
|
||||
if (ruleId === "__proto__") {
|
||||
|
||||
/* eslint-disable-next-line no-proto */
|
||||
/* eslint-disable-next-line no-proto -- Though deprecated, may still be present */
|
||||
delete result.__proto__;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -415,6 +408,18 @@ const rulesSchema = {
|
|||
}
|
||||
};
|
||||
|
||||
/** @type {ObjectPropertySchema} */
|
||||
const ecmaVersionSchema = {
|
||||
merge: "replace",
|
||||
validate(value) {
|
||||
if (typeof value === "number" || value === "latest") {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new TypeError("Expected a number or \"latest\".");
|
||||
}
|
||||
};
|
||||
|
||||
/** @type {ObjectPropertySchema} */
|
||||
const sourceTypeSchema = {
|
||||
merge: "replace",
|
||||
|
|
@ -439,7 +444,7 @@ exports.flatConfigSchema = {
|
|||
},
|
||||
languageOptions: {
|
||||
schema: {
|
||||
ecmaVersion: numberSchema,
|
||||
ecmaVersion: ecmaVersionSchema,
|
||||
sourceType: sourceTypeSchema,
|
||||
globals: globalsSchema,
|
||||
parser: parserSchema,
|
||||
|
|
|
|||
86
node_modules/eslint/lib/config/rule-validator.js
generated
vendored
86
node_modules/eslint/lib/config/rule-validator.js
generated
vendored
|
|
@ -10,74 +10,59 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
const ajv = require("../shared/ajv")();
|
||||
const {
|
||||
parseRuleId,
|
||||
getRuleFromConfig,
|
||||
getRuleOptionsSchema
|
||||
} = require("./flat-config-helpers");
|
||||
const ruleReplacements = require("../../conf/replacements.json");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Finds a rule with the given ID in the given config.
|
||||
* @param {string} ruleId The ID of the rule to find.
|
||||
* Throws a helpful error when a rule cannot be found.
|
||||
* @param {Object} ruleId The rule identifier.
|
||||
* @param {string} ruleId.pluginName The ID of the rule to find.
|
||||
* @param {string} ruleId.ruleName The ID of the rule to find.
|
||||
* @param {Object} config The config to search in.
|
||||
* @returns {{create: Function, schema: (Array|null)}} THe rule object.
|
||||
* @throws {TypeError} For missing plugin or rule.
|
||||
* @returns {void}
|
||||
*/
|
||||
function findRuleDefinition(ruleId, config) {
|
||||
const ruleIdParts = ruleId.split("/");
|
||||
let pluginName, ruleName;
|
||||
function throwRuleNotFoundError({ pluginName, ruleName }, config) {
|
||||
|
||||
// built-in rule
|
||||
if (ruleIdParts.length === 1) {
|
||||
pluginName = "@";
|
||||
ruleName = ruleIdParts[0];
|
||||
} else {
|
||||
ruleName = ruleIdParts.pop();
|
||||
pluginName = ruleIdParts.join("/");
|
||||
}
|
||||
const ruleId = pluginName === "@" ? ruleName : `${pluginName}/${ruleName}`;
|
||||
|
||||
if (!config.plugins || !config.plugins[pluginName]) {
|
||||
throw new TypeError(`Key "rules": Key "${ruleId}": Could not find plugin "${pluginName}".`);
|
||||
}
|
||||
const errorMessageHeader = `Key "rules": Key "${ruleId}"`;
|
||||
let errorMessage = `${errorMessageHeader}: Could not find plugin "${pluginName}".`;
|
||||
|
||||
if (!config.plugins[pluginName].rules || !config.plugins[pluginName].rules[ruleName]) {
|
||||
throw new TypeError(`Key "rules": Key "${ruleId}": Could not find "${ruleName}" in plugin "${pluginName}".`);
|
||||
}
|
||||
// if the plugin exists then we need to check if the rule exists
|
||||
if (config.plugins && config.plugins[pluginName]) {
|
||||
const replacementRuleName = ruleReplacements.rules[ruleName];
|
||||
|
||||
return config.plugins[pluginName].rules[ruleName];
|
||||
if (pluginName === "@" && replacementRuleName) {
|
||||
|
||||
}
|
||||
errorMessage = `${errorMessageHeader}: Rule "${ruleName}" was removed and replaced by "${replacementRuleName}".`;
|
||||
|
||||
/**
|
||||
* Gets a complete options schema for a rule.
|
||||
* @param {{create: Function, schema: (Array|null)}} rule A new-style rule object
|
||||
* @returns {Object} JSON Schema for the rule's options.
|
||||
*/
|
||||
function getRuleOptionsSchema(rule) {
|
||||
} else {
|
||||
|
||||
if (!rule) {
|
||||
return null;
|
||||
}
|
||||
errorMessage = `${errorMessageHeader}: Could not find "${ruleName}" in plugin "${pluginName}".`;
|
||||
|
||||
const schema = rule.schema || rule.meta && rule.meta.schema;
|
||||
// otherwise, let's see if we can find the rule name elsewhere
|
||||
for (const [otherPluginName, otherPlugin] of Object.entries(config.plugins)) {
|
||||
if (otherPlugin.rules && otherPlugin.rules[ruleName]) {
|
||||
errorMessage += ` Did you mean "${otherPluginName}/${ruleName}"?`;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Array.isArray(schema)) {
|
||||
if (schema.length) {
|
||||
return {
|
||||
type: "array",
|
||||
items: schema,
|
||||
minItems: 0,
|
||||
maxItems: schema.length
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: "array",
|
||||
minItems: 0,
|
||||
maxItems: 0
|
||||
};
|
||||
|
||||
// falls through to throw error
|
||||
}
|
||||
|
||||
// Given a full schema, leave it alone
|
||||
return schema || null;
|
||||
throw new TypeError(errorMessage);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -98,7 +83,6 @@ class RuleValidator {
|
|||
* A collection of compiled validators for rules that have already
|
||||
* been validated.
|
||||
* @type {WeakMap}
|
||||
* @property validators
|
||||
*/
|
||||
this.validators = new WeakMap();
|
||||
}
|
||||
|
|
@ -137,7 +121,11 @@ class RuleValidator {
|
|||
continue;
|
||||
}
|
||||
|
||||
const rule = findRuleDefinition(ruleId, config);
|
||||
const rule = getRuleFromConfig(ruleId, config);
|
||||
|
||||
if (!rule) {
|
||||
throwRuleNotFoundError(parseRuleId(ruleId), config);
|
||||
}
|
||||
|
||||
// Precompile and cache validator the first time
|
||||
if (!this.validators.has(rule)) {
|
||||
|
|
|
|||
940
node_modules/eslint/lib/eslint/eslint-helpers.js
generated
vendored
Normal file
940
node_modules/eslint/lib/eslint/eslint-helpers.js
generated
vendored
Normal file
|
|
@ -0,0 +1,940 @@
|
|||
/**
|
||||
* @fileoverview Helper functions for ESLint class
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const fsp = fs.promises;
|
||||
const isGlob = require("is-glob");
|
||||
const hash = require("../cli-engine/hash");
|
||||
const minimatch = require("minimatch");
|
||||
const util = require("util");
|
||||
const fswalk = require("@nodelib/fs.walk");
|
||||
const globParent = require("glob-parent");
|
||||
const isPathInside = require("is-path-inside");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Fixup references
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const doFsWalk = util.promisify(fswalk.walk);
|
||||
const Minimatch = minimatch.Minimatch;
|
||||
const MINIMATCH_OPTIONS = { dot: true };
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Types
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @typedef {Object} GlobSearch
|
||||
* @property {Array<string>} patterns The normalized patterns to use for a search.
|
||||
* @property {Array<string>} rawPatterns The patterns as entered by the user
|
||||
* before doing any normalization.
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Errors
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The error type when no files match a glob.
|
||||
*/
|
||||
class NoFilesFoundError extends Error {
|
||||
|
||||
/**
|
||||
* @param {string} pattern The glob pattern which was not found.
|
||||
* @param {boolean} globEnabled If `false` then the pattern was a glob pattern, but glob was disabled.
|
||||
*/
|
||||
constructor(pattern, globEnabled) {
|
||||
super(`No files matching '${pattern}' were found${!globEnabled ? " (glob was disabled)" : ""}.`);
|
||||
this.messageTemplate = "file-not-found";
|
||||
this.messageData = { pattern, globDisabled: !globEnabled };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The error type when a search fails to match multiple patterns.
|
||||
*/
|
||||
class UnmatchedSearchPatternsError extends Error {
|
||||
|
||||
/**
|
||||
* @param {Object} options The options for the error.
|
||||
* @param {string} options.basePath The directory that was searched.
|
||||
* @param {Array<string>} options.unmatchedPatterns The glob patterns
|
||||
* which were not found.
|
||||
* @param {Array<string>} options.patterns The glob patterns that were
|
||||
* searched.
|
||||
* @param {Array<string>} options.rawPatterns The raw glob patterns that
|
||||
* were searched.
|
||||
*/
|
||||
constructor({ basePath, unmatchedPatterns, patterns, rawPatterns }) {
|
||||
super(`No files matching '${rawPatterns}' in '${basePath}' were found.`);
|
||||
this.basePath = basePath;
|
||||
this.unmatchedPatterns = unmatchedPatterns;
|
||||
this.patterns = patterns;
|
||||
this.rawPatterns = rawPatterns;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The error type when there are files matched by a glob, but all of them have been ignored.
|
||||
*/
|
||||
class AllFilesIgnoredError extends Error {
|
||||
|
||||
/**
|
||||
* @param {string} pattern The glob pattern which was not found.
|
||||
*/
|
||||
constructor(pattern) {
|
||||
super(`All files matched by '${pattern}' are ignored.`);
|
||||
this.messageTemplate = "all-files-ignored";
|
||||
this.messageData = { pattern };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// General Helpers
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Check if a given value is a non-empty string or not.
|
||||
* @param {any} x The value to check.
|
||||
* @returns {boolean} `true` if `x` is a non-empty string.
|
||||
*/
|
||||
function isNonEmptyString(x) {
|
||||
return typeof x === "string" && x.trim() !== "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given value is an array of non-empty strings or not.
|
||||
* @param {any} x The value to check.
|
||||
* @returns {boolean} `true` if `x` is an array of non-empty strings.
|
||||
*/
|
||||
function isArrayOfNonEmptyString(x) {
|
||||
return Array.isArray(x) && x.every(isNonEmptyString);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// File-related Helpers
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Normalizes slashes in a file pattern to posix-style.
|
||||
* @param {string} pattern The pattern to replace slashes in.
|
||||
* @returns {string} The pattern with slashes normalized.
|
||||
*/
|
||||
function normalizeToPosix(pattern) {
|
||||
return pattern.replace(/\\/gu, "/");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a string is a glob pattern or not.
|
||||
* @param {string} pattern A glob pattern.
|
||||
* @returns {boolean} `true` if the string is a glob pattern.
|
||||
*/
|
||||
function isGlobPattern(pattern) {
|
||||
return isGlob(path.sep === "\\" ? normalizeToPosix(pattern) : pattern);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines if a given glob pattern will return any results.
|
||||
* Used primarily to help with useful error messages.
|
||||
* @param {Object} options The options for the function.
|
||||
* @param {string} options.basePath The directory to search.
|
||||
* @param {string} options.pattern A glob pattern to match.
|
||||
* @returns {Promise<boolean>} True if there is a glob match, false if not.
|
||||
*/
|
||||
function globMatch({ basePath, pattern }) {
|
||||
|
||||
let found = false;
|
||||
const patternToUse = path.isAbsolute(pattern)
|
||||
? normalizeToPosix(path.relative(basePath, pattern))
|
||||
: pattern;
|
||||
|
||||
const matcher = new Minimatch(patternToUse, MINIMATCH_OPTIONS);
|
||||
|
||||
const fsWalkSettings = {
|
||||
|
||||
deepFilter(entry) {
|
||||
const relativePath = normalizeToPosix(path.relative(basePath, entry.path));
|
||||
|
||||
return !found && matcher.match(relativePath, true);
|
||||
},
|
||||
|
||||
entryFilter(entry) {
|
||||
if (found || entry.dirent.isDirectory()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const relativePath = normalizeToPosix(path.relative(basePath, entry.path));
|
||||
|
||||
if (matcher.match(relativePath)) {
|
||||
found = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
return new Promise(resolve => {
|
||||
|
||||
// using a stream so we can exit early because we just need one match
|
||||
const globStream = fswalk.walkStream(basePath, fsWalkSettings);
|
||||
|
||||
globStream.on("data", () => {
|
||||
globStream.destroy();
|
||||
resolve(true);
|
||||
});
|
||||
|
||||
// swallow errors as they're not important here
|
||||
globStream.on("error", () => { });
|
||||
|
||||
globStream.on("end", () => {
|
||||
resolve(false);
|
||||
});
|
||||
globStream.read();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches a directory looking for matching glob patterns. This uses
|
||||
* the config array's logic to determine if a directory or file should
|
||||
* be ignored, so it is consistent with how ignoring works throughout
|
||||
* ESLint.
|
||||
* @param {Object} options The options for this function.
|
||||
* @param {string} options.basePath The directory to search.
|
||||
* @param {Array<string>} options.patterns An array of glob patterns
|
||||
* to match.
|
||||
* @param {Array<string>} options.rawPatterns An array of glob patterns
|
||||
* as the user inputted them. Used for errors.
|
||||
* @param {FlatConfigArray} options.configs The config array to use for
|
||||
* determining what to ignore.
|
||||
* @param {boolean} options.errorOnUnmatchedPattern Determines if an error
|
||||
* should be thrown when a pattern is unmatched.
|
||||
* @returns {Promise<Array<string>>} An array of matching file paths
|
||||
* or an empty array if there are no matches.
|
||||
* @throws {UnmatchedSearchPatternsErrror} If there is a pattern that doesn't
|
||||
* match any files.
|
||||
*/
|
||||
async function globSearch({
|
||||
basePath,
|
||||
patterns,
|
||||
rawPatterns,
|
||||
configs,
|
||||
errorOnUnmatchedPattern
|
||||
}) {
|
||||
|
||||
if (patterns.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
/*
|
||||
* In this section we are converting the patterns into Minimatch
|
||||
* instances for performance reasons. Because we are doing the same
|
||||
* matches repeatedly, it's best to compile those patterns once and
|
||||
* reuse them multiple times.
|
||||
*
|
||||
* To do that, we convert any patterns with an absolute path into a
|
||||
* relative path and normalize it to Posix-style slashes. We also keep
|
||||
* track of the relative patterns to map them back to the original
|
||||
* patterns, which we need in order to throw an error if there are any
|
||||
* unmatched patterns.
|
||||
*/
|
||||
const relativeToPatterns = new Map();
|
||||
const matchers = patterns.map((pattern, i) => {
|
||||
const patternToUse = path.isAbsolute(pattern)
|
||||
? normalizeToPosix(path.relative(basePath, pattern))
|
||||
: pattern;
|
||||
|
||||
relativeToPatterns.set(patternToUse, patterns[i]);
|
||||
|
||||
return new Minimatch(patternToUse, MINIMATCH_OPTIONS);
|
||||
});
|
||||
|
||||
/*
|
||||
* We track unmatched patterns because we may want to throw an error when
|
||||
* they occur. To start, this set is initialized with all of the patterns.
|
||||
* Every time a match occurs, the pattern is removed from the set, making
|
||||
* it easy to tell if we have any unmatched patterns left at the end of
|
||||
* search.
|
||||
*/
|
||||
const unmatchedPatterns = new Set([...relativeToPatterns.keys()]);
|
||||
|
||||
const filePaths = (await doFsWalk(basePath, {
|
||||
|
||||
deepFilter(entry) {
|
||||
const relativePath = normalizeToPosix(path.relative(basePath, entry.path));
|
||||
const matchesPattern = matchers.some(matcher => matcher.match(relativePath, true));
|
||||
|
||||
return matchesPattern && !configs.isDirectoryIgnored(entry.path);
|
||||
},
|
||||
entryFilter(entry) {
|
||||
const relativePath = normalizeToPosix(path.relative(basePath, entry.path));
|
||||
|
||||
// entries may be directories or files so filter out directories
|
||||
if (entry.dirent.isDirectory()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Optimization: We need to track when patterns are left unmatched
|
||||
* and so we use `unmatchedPatterns` to do that. There is a bit of
|
||||
* complexity here because the same file can be matched by more than
|
||||
* one pattern. So, when we start, we actually need to test every
|
||||
* pattern against every file. Once we know there are no remaining
|
||||
* unmatched patterns, then we can switch to just looking for the
|
||||
* first matching pattern for improved speed.
|
||||
*/
|
||||
const matchesPattern = unmatchedPatterns.size > 0
|
||||
? matchers.reduce((previousValue, matcher) => {
|
||||
const pathMatches = matcher.match(relativePath);
|
||||
|
||||
/*
|
||||
* We updated the unmatched patterns set only if the path
|
||||
* matches and the file isn't ignored. If the file is
|
||||
* ignored, that means there wasn't a match for the
|
||||
* pattern so it should not be removed.
|
||||
*
|
||||
* Performance note: isFileIgnored() aggressively caches
|
||||
* results so there is no performance penalty for calling
|
||||
* it twice with the same argument.
|
||||
*/
|
||||
if (pathMatches && !configs.isFileIgnored(entry.path)) {
|
||||
unmatchedPatterns.delete(matcher.pattern);
|
||||
}
|
||||
|
||||
return pathMatches || previousValue;
|
||||
}, false)
|
||||
: matchers.some(matcher => matcher.match(relativePath));
|
||||
|
||||
return matchesPattern && !configs.isFileIgnored(entry.path);
|
||||
}
|
||||
|
||||
})).map(entry => entry.path);
|
||||
|
||||
// now check to see if we have any unmatched patterns
|
||||
if (errorOnUnmatchedPattern && unmatchedPatterns.size > 0) {
|
||||
throw new UnmatchedSearchPatternsError({
|
||||
basePath,
|
||||
unmatchedPatterns: [...unmatchedPatterns].map(
|
||||
pattern => relativeToPatterns.get(pattern)
|
||||
),
|
||||
patterns,
|
||||
rawPatterns
|
||||
});
|
||||
}
|
||||
|
||||
return filePaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an error for unmatched patterns. The error will only contain information about the first one.
|
||||
* Checks to see if there are any ignored results for a given search.
|
||||
* @param {Object} options The options for this function.
|
||||
* @param {string} options.basePath The directory to search.
|
||||
* @param {Array<string>} options.patterns An array of glob patterns
|
||||
* that were used in the original search.
|
||||
* @param {Array<string>} options.rawPatterns An array of glob patterns
|
||||
* as the user inputted them. Used for errors.
|
||||
* @param {Array<string>} options.unmatchedPatterns A non-empty array of glob patterns
|
||||
* that were unmatched in the original search.
|
||||
* @returns {void} Always throws an error.
|
||||
* @throws {NoFilesFoundError} If the first unmatched pattern
|
||||
* doesn't match any files even when there are no ignores.
|
||||
* @throws {AllFilesIgnoredError} If the first unmatched pattern
|
||||
* matches some files when there are no ignores.
|
||||
*/
|
||||
async function throwErrorForUnmatchedPatterns({
|
||||
basePath,
|
||||
patterns,
|
||||
rawPatterns,
|
||||
unmatchedPatterns
|
||||
}) {
|
||||
|
||||
const pattern = unmatchedPatterns[0];
|
||||
const rawPattern = rawPatterns[patterns.indexOf(pattern)];
|
||||
|
||||
const patternHasMatch = await globMatch({
|
||||
basePath,
|
||||
pattern
|
||||
});
|
||||
|
||||
if (patternHasMatch) {
|
||||
throw new AllFilesIgnoredError(rawPattern);
|
||||
}
|
||||
|
||||
// if we get here there are truly no matches
|
||||
throw new NoFilesFoundError(rawPattern, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs multiple glob searches in parallel.
|
||||
* @param {Object} options The options for this function.
|
||||
* @param {Map<string,GlobSearch>} options.searches
|
||||
* An array of glob patterns to match.
|
||||
* @param {FlatConfigArray} options.configs The config array to use for
|
||||
* determining what to ignore.
|
||||
* @param {boolean} options.errorOnUnmatchedPattern Determines if an
|
||||
* unmatched glob pattern should throw an error.
|
||||
* @returns {Promise<Array<string>>} An array of matching file paths
|
||||
* or an empty array if there are no matches.
|
||||
*/
|
||||
async function globMultiSearch({ searches, configs, errorOnUnmatchedPattern }) {
|
||||
|
||||
/*
|
||||
* For convenience, we normalized the search map into an array of objects.
|
||||
* Next, we filter out all searches that have no patterns. This happens
|
||||
* primarily for the cwd, which is prepopulated in the searches map as an
|
||||
* optimization. However, if it has no patterns, it means all patterns
|
||||
* occur outside of the cwd and we can safely filter out that search.
|
||||
*/
|
||||
const normalizedSearches = [...searches].map(
|
||||
([basePath, { patterns, rawPatterns }]) => ({ basePath, patterns, rawPatterns })
|
||||
).filter(({ patterns }) => patterns.length > 0);
|
||||
|
||||
const results = await Promise.allSettled(
|
||||
normalizedSearches.map(
|
||||
({ basePath, patterns, rawPatterns }) => globSearch({
|
||||
basePath,
|
||||
patterns,
|
||||
rawPatterns,
|
||||
configs,
|
||||
errorOnUnmatchedPattern
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
const filePaths = [];
|
||||
|
||||
for (let i = 0; i < results.length; i++) {
|
||||
|
||||
const result = results[i];
|
||||
const currentSearch = normalizedSearches[i];
|
||||
|
||||
if (result.status === "fulfilled") {
|
||||
|
||||
// if the search was successful just add the results
|
||||
if (result.value.length > 0) {
|
||||
filePaths.push(...result.value);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// if we make it here then there was an error
|
||||
const error = result.reason;
|
||||
|
||||
// unexpected errors should be re-thrown
|
||||
if (!error.basePath) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (errorOnUnmatchedPattern) {
|
||||
|
||||
await throwErrorForUnmatchedPatterns({
|
||||
...currentSearch,
|
||||
unmatchedPatterns: error.unmatchedPatterns
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return [...new Set(filePaths)];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all files matching the options specified.
|
||||
* @param {Object} args The arguments objects.
|
||||
* @param {Array<string>} args.patterns An array of glob patterns.
|
||||
* @param {boolean} args.globInputPaths true to interpret glob patterns,
|
||||
* false to not interpret glob patterns.
|
||||
* @param {string} args.cwd The current working directory to find from.
|
||||
* @param {FlatConfigArray} args.configs The configs for the current run.
|
||||
* @param {boolean} args.errorOnUnmatchedPattern Determines if an unmatched pattern
|
||||
* should throw an error.
|
||||
* @returns {Promise<Array<string>>} The fully resolved file paths.
|
||||
* @throws {AllFilesIgnoredError} If there are no results due to an ignore pattern.
|
||||
* @throws {NoFilesFoundError} If no files matched the given patterns.
|
||||
*/
|
||||
async function findFiles({
|
||||
patterns,
|
||||
globInputPaths,
|
||||
cwd,
|
||||
configs,
|
||||
errorOnUnmatchedPattern
|
||||
}) {
|
||||
|
||||
const results = [];
|
||||
const missingPatterns = [];
|
||||
let globbyPatterns = [];
|
||||
let rawPatterns = [];
|
||||
const searches = new Map([[cwd, { patterns: globbyPatterns, rawPatterns: [] }]]);
|
||||
|
||||
// check to see if we have explicit files and directories
|
||||
const filePaths = patterns.map(filePath => path.resolve(cwd, filePath));
|
||||
const stats = await Promise.all(
|
||||
filePaths.map(
|
||||
filePath => fsp.stat(filePath).catch(() => { })
|
||||
)
|
||||
);
|
||||
|
||||
stats.forEach((stat, index) => {
|
||||
|
||||
const filePath = filePaths[index];
|
||||
const pattern = normalizeToPosix(patterns[index]);
|
||||
|
||||
if (stat) {
|
||||
|
||||
// files are added directly to the list
|
||||
if (stat.isFile()) {
|
||||
results.push({
|
||||
filePath,
|
||||
ignored: configs.isFileIgnored(filePath)
|
||||
});
|
||||
}
|
||||
|
||||
// directories need extensions attached
|
||||
if (stat.isDirectory()) {
|
||||
|
||||
// group everything in cwd together and split out others
|
||||
if (isPathInside(filePath, cwd)) {
|
||||
({ patterns: globbyPatterns, rawPatterns } = searches.get(cwd));
|
||||
} else {
|
||||
if (!searches.has(filePath)) {
|
||||
searches.set(filePath, { patterns: [], rawPatterns: [] });
|
||||
}
|
||||
({ patterns: globbyPatterns, rawPatterns } = searches.get(filePath));
|
||||
}
|
||||
|
||||
globbyPatterns.push(`${normalizeToPosix(filePath)}/**`);
|
||||
rawPatterns.push(pattern);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// save patterns for later use based on whether globs are enabled
|
||||
if (globInputPaths && isGlobPattern(filePath)) {
|
||||
|
||||
const basePath = globParent(filePath);
|
||||
|
||||
// group in cwd if possible and split out others
|
||||
if (isPathInside(basePath, cwd)) {
|
||||
({ patterns: globbyPatterns, rawPatterns } = searches.get(cwd));
|
||||
} else {
|
||||
if (!searches.has(basePath)) {
|
||||
searches.set(basePath, { patterns: [], rawPatterns: [] });
|
||||
}
|
||||
({ patterns: globbyPatterns, rawPatterns } = searches.get(basePath));
|
||||
}
|
||||
|
||||
globbyPatterns.push(filePath);
|
||||
rawPatterns.push(pattern);
|
||||
} else {
|
||||
missingPatterns.push(pattern);
|
||||
}
|
||||
});
|
||||
|
||||
// there were patterns that didn't match anything, tell the user
|
||||
if (errorOnUnmatchedPattern && missingPatterns.length) {
|
||||
throw new NoFilesFoundError(missingPatterns[0], globInputPaths);
|
||||
}
|
||||
|
||||
// now we are safe to do the search
|
||||
const globbyResults = await globMultiSearch({
|
||||
searches,
|
||||
configs,
|
||||
errorOnUnmatchedPattern
|
||||
});
|
||||
|
||||
return [
|
||||
...results,
|
||||
...globbyResults.map(filePath => ({
|
||||
filePath: path.resolve(filePath),
|
||||
ignored: false
|
||||
}))
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks whether a file exists at the given location
|
||||
* @param {string} resolvedPath A path from the CWD
|
||||
* @throws {Error} As thrown by `fs.statSync` or `fs.isFile`.
|
||||
* @returns {boolean} `true` if a file exists
|
||||
*/
|
||||
function fileExists(resolvedPath) {
|
||||
try {
|
||||
return fs.statSync(resolvedPath).isFile();
|
||||
} catch (error) {
|
||||
if (error && (error.code === "ENOENT" || error.code === "ENOTDIR")) {
|
||||
return false;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a directory exists at the given location
|
||||
* @param {string} resolvedPath A path from the CWD
|
||||
* @throws {Error} As thrown by `fs.statSync` or `fs.isDirectory`.
|
||||
* @returns {boolean} `true` if a directory exists
|
||||
*/
|
||||
function directoryExists(resolvedPath) {
|
||||
try {
|
||||
return fs.statSync(resolvedPath).isDirectory();
|
||||
} catch (error) {
|
||||
if (error && (error.code === "ENOENT" || error.code === "ENOTDIR")) {
|
||||
return false;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Results-related Helpers
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Checks if the given message is an error message.
|
||||
* @param {LintMessage} message The message to check.
|
||||
* @returns {boolean} Whether or not the message is an error message.
|
||||
* @private
|
||||
*/
|
||||
function isErrorMessage(message) {
|
||||
return message.severity === 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns result with warning by ignore settings
|
||||
* @param {string} filePath File path of checked code
|
||||
* @param {string} baseDir Absolute path of base directory
|
||||
* @returns {LintResult} Result with single warning
|
||||
* @private
|
||||
*/
|
||||
function createIgnoreResult(filePath, baseDir) {
|
||||
let message;
|
||||
const isHidden = filePath.split(path.sep)
|
||||
.find(segment => /^\./u.test(segment));
|
||||
const isInNodeModules = baseDir && path.relative(baseDir, filePath).startsWith("node_modules");
|
||||
|
||||
if (isHidden) {
|
||||
message = "File ignored by default. Use a negated ignore pattern (like \"--ignore-pattern '!<relative/path/to/filename>'\") to override.";
|
||||
} else if (isInNodeModules) {
|
||||
message = "File ignored by default. Use \"--ignore-pattern '!node_modules/*'\" to override.";
|
||||
} else {
|
||||
message = "File ignored because of a matching ignore pattern. Use \"--no-ignore\" to override.";
|
||||
}
|
||||
|
||||
return {
|
||||
filePath: path.resolve(filePath),
|
||||
messages: [
|
||||
{
|
||||
fatal: false,
|
||||
severity: 1,
|
||||
message
|
||||
}
|
||||
],
|
||||
suppressedMessages: [],
|
||||
errorCount: 0,
|
||||
warningCount: 1,
|
||||
fatalErrorCount: 0,
|
||||
fixableErrorCount: 0,
|
||||
fixableWarningCount: 0
|
||||
};
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Options-related Helpers
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* Check if a given value is a valid fix type or not.
|
||||
* @param {any} x The value to check.
|
||||
* @returns {boolean} `true` if `x` is valid fix type.
|
||||
*/
|
||||
function isFixType(x) {
|
||||
return x === "directive" || x === "problem" || x === "suggestion" || x === "layout";
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given value is an array of fix types or not.
|
||||
* @param {any} x The value to check.
|
||||
* @returns {boolean} `true` if `x` is an array of fix types.
|
||||
*/
|
||||
function isFixTypeArray(x) {
|
||||
return Array.isArray(x) && x.every(isFixType);
|
||||
}
|
||||
|
||||
/**
|
||||
* The error for invalid options.
|
||||
*/
|
||||
class ESLintInvalidOptionsError extends Error {
|
||||
constructor(messages) {
|
||||
super(`Invalid Options:\n- ${messages.join("\n- ")}`);
|
||||
this.code = "ESLINT_INVALID_OPTIONS";
|
||||
Error.captureStackTrace(this, ESLintInvalidOptionsError);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates and normalizes options for the wrapped CLIEngine instance.
|
||||
* @param {FlatESLintOptions} options The options to process.
|
||||
* @throws {ESLintInvalidOptionsError} If of any of a variety of type errors.
|
||||
* @returns {FlatESLintOptions} The normalized options.
|
||||
*/
|
||||
function processOptions({
|
||||
allowInlineConfig = true, // ← we cannot use `overrideConfig.noInlineConfig` instead because `allowInlineConfig` has side-effect that suppress warnings that show inline configs are ignored.
|
||||
baseConfig = null,
|
||||
cache = false,
|
||||
cacheLocation = ".eslintcache",
|
||||
cacheStrategy = "metadata",
|
||||
cwd = process.cwd(),
|
||||
errorOnUnmatchedPattern = true,
|
||||
fix = false,
|
||||
fixTypes = null, // ← should be null by default because if it's an array then it suppresses rules that don't have the `meta.type` property.
|
||||
globInputPaths = true,
|
||||
ignore = true,
|
||||
ignorePatterns = null,
|
||||
overrideConfig = null,
|
||||
overrideConfigFile = null,
|
||||
plugins = {},
|
||||
reportUnusedDisableDirectives = null, // ← should be null by default because if it's a string then it overrides the 'reportUnusedDisableDirectives' setting in config files. And we cannot use `overrideConfig.reportUnusedDisableDirectives` instead because we cannot configure the `error` severity with that.
|
||||
...unknownOptions
|
||||
}) {
|
||||
const errors = [];
|
||||
const unknownOptionKeys = Object.keys(unknownOptions);
|
||||
|
||||
if (unknownOptionKeys.length >= 1) {
|
||||
errors.push(`Unknown options: ${unknownOptionKeys.join(", ")}`);
|
||||
if (unknownOptionKeys.includes("cacheFile")) {
|
||||
errors.push("'cacheFile' has been removed. Please use the 'cacheLocation' option instead.");
|
||||
}
|
||||
if (unknownOptionKeys.includes("configFile")) {
|
||||
errors.push("'configFile' has been removed. Please use the 'overrideConfigFile' option instead.");
|
||||
}
|
||||
if (unknownOptionKeys.includes("envs")) {
|
||||
errors.push("'envs' has been removed.");
|
||||
}
|
||||
if (unknownOptionKeys.includes("extensions")) {
|
||||
errors.push("'extensions' has been removed.");
|
||||
}
|
||||
if (unknownOptionKeys.includes("resolvePluginsRelativeTo")) {
|
||||
errors.push("'resolvePluginsRelativeTo' has been removed.");
|
||||
}
|
||||
if (unknownOptionKeys.includes("globals")) {
|
||||
errors.push("'globals' has been removed. Please use the 'overrideConfig.languageOptions.globals' option instead.");
|
||||
}
|
||||
if (unknownOptionKeys.includes("ignorePath")) {
|
||||
errors.push("'ignorePath' has been removed.");
|
||||
}
|
||||
if (unknownOptionKeys.includes("ignorePattern")) {
|
||||
errors.push("'ignorePattern' has been removed. Please use the 'overrideConfig.ignorePatterns' option instead.");
|
||||
}
|
||||
if (unknownOptionKeys.includes("parser")) {
|
||||
errors.push("'parser' has been removed. Please use the 'overrideConfig.languageOptions.parser' option instead.");
|
||||
}
|
||||
if (unknownOptionKeys.includes("parserOptions")) {
|
||||
errors.push("'parserOptions' has been removed. Please use the 'overrideConfig.languageOptions.parserOptions' option instead.");
|
||||
}
|
||||
if (unknownOptionKeys.includes("rules")) {
|
||||
errors.push("'rules' has been removed. Please use the 'overrideConfig.rules' option instead.");
|
||||
}
|
||||
if (unknownOptionKeys.includes("rulePaths")) {
|
||||
errors.push("'rulePaths' has been removed. Please define your rules using plugins.");
|
||||
}
|
||||
}
|
||||
if (typeof allowInlineConfig !== "boolean") {
|
||||
errors.push("'allowInlineConfig' must be a boolean.");
|
||||
}
|
||||
if (typeof baseConfig !== "object") {
|
||||
errors.push("'baseConfig' must be an object or null.");
|
||||
}
|
||||
if (typeof cache !== "boolean") {
|
||||
errors.push("'cache' must be a boolean.");
|
||||
}
|
||||
if (!isNonEmptyString(cacheLocation)) {
|
||||
errors.push("'cacheLocation' must be a non-empty string.");
|
||||
}
|
||||
if (
|
||||
cacheStrategy !== "metadata" &&
|
||||
cacheStrategy !== "content"
|
||||
) {
|
||||
errors.push("'cacheStrategy' must be any of \"metadata\", \"content\".");
|
||||
}
|
||||
if (!isNonEmptyString(cwd) || !path.isAbsolute(cwd)) {
|
||||
errors.push("'cwd' must be an absolute path.");
|
||||
}
|
||||
if (typeof errorOnUnmatchedPattern !== "boolean") {
|
||||
errors.push("'errorOnUnmatchedPattern' must be a boolean.");
|
||||
}
|
||||
if (typeof fix !== "boolean" && typeof fix !== "function") {
|
||||
errors.push("'fix' must be a boolean or a function.");
|
||||
}
|
||||
if (fixTypes !== null && !isFixTypeArray(fixTypes)) {
|
||||
errors.push("'fixTypes' must be an array of any of \"directive\", \"problem\", \"suggestion\", and \"layout\".");
|
||||
}
|
||||
if (typeof globInputPaths !== "boolean") {
|
||||
errors.push("'globInputPaths' must be a boolean.");
|
||||
}
|
||||
if (typeof ignore !== "boolean") {
|
||||
errors.push("'ignore' must be a boolean.");
|
||||
}
|
||||
if (typeof overrideConfig !== "object") {
|
||||
errors.push("'overrideConfig' must be an object or null.");
|
||||
}
|
||||
if (!isNonEmptyString(overrideConfigFile) && overrideConfigFile !== null && overrideConfigFile !== true) {
|
||||
errors.push("'overrideConfigFile' must be a non-empty string, null, or true.");
|
||||
}
|
||||
if (typeof plugins !== "object") {
|
||||
errors.push("'plugins' must be an object or null.");
|
||||
} else if (plugins !== null && Object.keys(plugins).includes("")) {
|
||||
errors.push("'plugins' must not include an empty string.");
|
||||
}
|
||||
if (Array.isArray(plugins)) {
|
||||
errors.push("'plugins' doesn't add plugins to configuration to load. Please use the 'overrideConfig.plugins' option instead.");
|
||||
}
|
||||
if (
|
||||
reportUnusedDisableDirectives !== "error" &&
|
||||
reportUnusedDisableDirectives !== "warn" &&
|
||||
reportUnusedDisableDirectives !== "off" &&
|
||||
reportUnusedDisableDirectives !== null
|
||||
) {
|
||||
errors.push("'reportUnusedDisableDirectives' must be any of \"error\", \"warn\", \"off\", and null.");
|
||||
}
|
||||
if (errors.length > 0) {
|
||||
throw new ESLintInvalidOptionsError(errors);
|
||||
}
|
||||
|
||||
return {
|
||||
allowInlineConfig,
|
||||
baseConfig,
|
||||
cache,
|
||||
cacheLocation,
|
||||
cacheStrategy,
|
||||
|
||||
// when overrideConfigFile is true that means don't do config file lookup
|
||||
configFile: overrideConfigFile === true ? false : overrideConfigFile,
|
||||
overrideConfig,
|
||||
cwd,
|
||||
errorOnUnmatchedPattern,
|
||||
fix,
|
||||
fixTypes,
|
||||
globInputPaths,
|
||||
ignore,
|
||||
ignorePatterns,
|
||||
reportUnusedDisableDirectives
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Cache-related helpers
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* return the cacheFile to be used by eslint, based on whether the provided parameter is
|
||||
* a directory or looks like a directory (ends in `path.sep`), in which case the file
|
||||
* name will be the `cacheFile/.cache_hashOfCWD`
|
||||
*
|
||||
* if cacheFile points to a file or looks like a file then in will just use that file
|
||||
* @param {string} cacheFile The name of file to be used to store the cache
|
||||
* @param {string} cwd Current working directory
|
||||
* @returns {string} the resolved path to the cache file
|
||||
*/
|
||||
function getCacheFile(cacheFile, cwd) {
|
||||
|
||||
/*
|
||||
* make sure the path separators are normalized for the environment/os
|
||||
* keeping the trailing path separator if present
|
||||
*/
|
||||
const normalizedCacheFile = path.normalize(cacheFile);
|
||||
|
||||
const resolvedCacheFile = path.resolve(cwd, normalizedCacheFile);
|
||||
const looksLikeADirectory = normalizedCacheFile.slice(-1) === path.sep;
|
||||
|
||||
/**
|
||||
* return the name for the cache file in case the provided parameter is a directory
|
||||
* @returns {string} the resolved path to the cacheFile
|
||||
*/
|
||||
function getCacheFileForDirectory() {
|
||||
return path.join(resolvedCacheFile, `.cache_${hash(cwd)}`);
|
||||
}
|
||||
|
||||
let fileStats;
|
||||
|
||||
try {
|
||||
fileStats = fs.lstatSync(resolvedCacheFile);
|
||||
} catch {
|
||||
fileStats = null;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* in case the file exists we need to verify if the provided path
|
||||
* is a directory or a file. If it is a directory we want to create a file
|
||||
* inside that directory
|
||||
*/
|
||||
if (fileStats) {
|
||||
|
||||
/*
|
||||
* is a directory or is a file, but the original file the user provided
|
||||
* looks like a directory but `path.resolve` removed the `last path.sep`
|
||||
* so we need to still treat this like a directory
|
||||
*/
|
||||
if (fileStats.isDirectory() || looksLikeADirectory) {
|
||||
return getCacheFileForDirectory();
|
||||
}
|
||||
|
||||
// is file so just use that file
|
||||
return resolvedCacheFile;
|
||||
}
|
||||
|
||||
/*
|
||||
* here we known the file or directory doesn't exist,
|
||||
* so we will try to infer if its a directory if it looks like a directory
|
||||
* for the current operating system.
|
||||
*/
|
||||
|
||||
// if the last character passed is a path separator we assume is a directory
|
||||
if (looksLikeADirectory) {
|
||||
return getCacheFileForDirectory();
|
||||
}
|
||||
|
||||
return resolvedCacheFile;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Exports
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
isGlobPattern,
|
||||
directoryExists,
|
||||
fileExists,
|
||||
findFiles,
|
||||
|
||||
isNonEmptyString,
|
||||
isArrayOfNonEmptyString,
|
||||
|
||||
createIgnoreResult,
|
||||
isErrorMessage,
|
||||
|
||||
processOptions,
|
||||
|
||||
getCacheFile
|
||||
};
|
||||
73
node_modules/eslint/lib/eslint/eslint.js
generated
vendored
73
node_modules/eslint/lib/eslint/eslint.js
generated
vendored
|
|
@ -32,9 +32,17 @@ const { version } = require("../../package.json");
|
|||
/** @typedef {import("../shared/types").DeprecatedRuleInfo} DeprecatedRuleInfo */
|
||||
/** @typedef {import("../shared/types").ConfigData} ConfigData */
|
||||
/** @typedef {import("../shared/types").LintMessage} LintMessage */
|
||||
/** @typedef {import("../shared/types").SuppressedLintMessage} SuppressedLintMessage */
|
||||
/** @typedef {import("../shared/types").Plugin} Plugin */
|
||||
/** @typedef {import("../shared/types").Rule} Rule */
|
||||
/** @typedef {import("./load-formatter").Formatter} Formatter */
|
||||
/** @typedef {import("../shared/types").LintResult} LintResult */
|
||||
/** @typedef {import("../shared/types").ResultsMeta} ResultsMeta */
|
||||
|
||||
/**
|
||||
* The main formatter object.
|
||||
* @typedef LoadedFormatter
|
||||
* @property {(results: LintResult[], resultsMeta: ResultsMeta) => string | Promise<string>} format format function.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The options with which to configure the ESLint instance.
|
||||
|
|
@ -54,7 +62,7 @@ const { version } = require("../../package.json");
|
|||
* @property {string} [ignorePath] The ignore file to use instead of .eslintignore.
|
||||
* @property {ConfigData} [overrideConfig] Override config object, overrides all configs used with this instance
|
||||
* @property {string} [overrideConfigFile] The configuration file to use.
|
||||
* @property {Record<string,Plugin>} [plugins] An array of plugin implementations.
|
||||
* @property {Record<string,Plugin>|null} [plugins] Preloaded plugins. This is a map-like object, keys are plugin IDs and each value is implementation.
|
||||
* @property {"error" | "warn" | "off"} [reportUnusedDisableDirectives] the severity to report unused eslint-disable directives.
|
||||
* @property {string} [resolvePluginsRelativeTo] The folder where plugins should be resolved from, defaulting to the CWD.
|
||||
* @property {string[]} [rulePaths] An array of directories to load custom rules from.
|
||||
|
|
@ -68,20 +76,6 @@ const { version } = require("../../package.json");
|
|||
* @property {Object} definition The plugin definition.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A linting result.
|
||||
* @typedef {Object} LintResult
|
||||
* @property {string} filePath The path to the file that was linted.
|
||||
* @property {LintMessage[]} messages All of the messages for the result.
|
||||
* @property {number} errorCount Number of errors for the result.
|
||||
* @property {number} warningCount Number of warnings for the result.
|
||||
* @property {number} fixableErrorCount Number of fixable errors for the result.
|
||||
* @property {number} fixableWarningCount Number of fixable warnings for the result.
|
||||
* @property {string} [source] The source code of the file that was linted.
|
||||
* @property {string} [output] The source code of the file that was linted, with as many fixes applied as possible.
|
||||
* @property {DeprecatedRuleInfo[]} usedDeprecatedRules The list of used deprecated rules.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Private members for the `ESLint` instance.
|
||||
* @typedef {Object} ESLintPrivateMembers
|
||||
|
|
@ -111,9 +105,9 @@ function isNonEmptyString(x) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Check if a given value is an array of non-empty stringss or not.
|
||||
* Check if a given value is an array of non-empty strings or not.
|
||||
* @param {any} x The value to check.
|
||||
* @returns {boolean} `true` if `x` is an array of non-empty stringss.
|
||||
* @returns {boolean} `true` if `x` is an array of non-empty strings.
|
||||
*/
|
||||
function isArrayOfNonEmptyString(x) {
|
||||
return Array.isArray(x) && x.every(isNonEmptyString);
|
||||
|
|
@ -125,7 +119,7 @@ function isArrayOfNonEmptyString(x) {
|
|||
* @returns {boolean} `true` if `x` is valid fix type.
|
||||
*/
|
||||
function isFixType(x) {
|
||||
return x === "problem" || x === "suggestion" || x === "layout";
|
||||
return x === "directive" || x === "problem" || x === "suggestion" || x === "layout";
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -151,6 +145,7 @@ class ESLintInvalidOptionsError extends Error {
|
|||
/**
|
||||
* Validates and normalizes options for the wrapped CLIEngine instance.
|
||||
* @param {ESLintOptions} options The options to process.
|
||||
* @throws {ESLintInvalidOptionsError} If of any of a variety of type errors.
|
||||
* @returns {ESLintOptions} The normalized options.
|
||||
*/
|
||||
function processOptions({
|
||||
|
|
@ -237,7 +232,7 @@ function processOptions({
|
|||
errors.push("'fix' must be a boolean or a function.");
|
||||
}
|
||||
if (fixTypes !== null && !isFixTypeArray(fixTypes)) {
|
||||
errors.push("'fixTypes' must be an array of any of \"problem\", \"suggestion\", and \"layout\".");
|
||||
errors.push("'fixTypes' must be an array of any of \"directive\", \"problem\", \"suggestion\", and \"layout\".");
|
||||
}
|
||||
if (typeof globInputPaths !== "boolean") {
|
||||
errors.push("'globInputPaths' must be a boolean.");
|
||||
|
|
@ -421,6 +416,9 @@ function compareResultsByFilePath(a, b) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main API.
|
||||
*/
|
||||
class ESLint {
|
||||
|
||||
/**
|
||||
|
|
@ -429,26 +427,13 @@ class ESLint {
|
|||
*/
|
||||
constructor(options = {}) {
|
||||
const processedOptions = processOptions(options);
|
||||
const cliEngine = new CLIEngine(processedOptions);
|
||||
const cliEngine = new CLIEngine(processedOptions, { preloadedPlugins: options.plugins });
|
||||
const {
|
||||
additionalPluginPool,
|
||||
configArrayFactory,
|
||||
lastConfigArrays
|
||||
} = getCLIEngineInternalSlots(cliEngine);
|
||||
let updated = false;
|
||||
|
||||
/*
|
||||
* Address `plugins` to add plugin implementations.
|
||||
* Operate the `additionalPluginPool` internal slot directly to avoid
|
||||
* using `addPlugin(id, plugin)` method that resets cache everytime.
|
||||
*/
|
||||
if (options.plugins) {
|
||||
for (const [id, plugin] of Object.entries(options.plugins)) {
|
||||
additionalPluginPool.set(id, plugin);
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Address `overrideConfig` to set override config.
|
||||
* Operate the `configArrayFactory` internal slot directly because this
|
||||
|
|
@ -529,6 +514,9 @@ class ESLint {
|
|||
for (const { ruleId } of result.messages) {
|
||||
resultRuleIds.add(ruleId);
|
||||
}
|
||||
for (const { ruleId } of result.suppressedMessages) {
|
||||
resultRuleIds.add(ruleId);
|
||||
}
|
||||
}
|
||||
|
||||
// create a map of all rules in the results
|
||||
|
|
@ -612,12 +600,12 @@ class ESLint {
|
|||
* The following values are allowed:
|
||||
* - `undefined` ... Load `stylish` builtin formatter.
|
||||
* - A builtin formatter name ... Load the builtin formatter.
|
||||
* - A thirdparty formatter name:
|
||||
* - A third-party formatter name:
|
||||
* - `foo` → `eslint-formatter-foo`
|
||||
* - `@foo` → `@foo/eslint-formatter`
|
||||
* - `@foo/bar` → `@foo/eslint-formatter-bar`
|
||||
* - A file path ... Load the file.
|
||||
* @returns {Promise<Formatter>} A promise resolving to the formatter object.
|
||||
* @returns {Promise<LoadedFormatter>} A promise resolving to the formatter object.
|
||||
* This promise will be rejected if the given formatter was not found or not
|
||||
* a function.
|
||||
*/
|
||||
|
|
@ -626,7 +614,7 @@ class ESLint {
|
|||
throw new Error("'name' must be a string");
|
||||
}
|
||||
|
||||
const { cliEngine } = privateMembersMap.get(this);
|
||||
const { cliEngine, options } = privateMembersMap.get(this);
|
||||
const formatter = cliEngine.getFormatter(name);
|
||||
|
||||
if (typeof formatter !== "function") {
|
||||
|
|
@ -637,15 +625,20 @@ class ESLint {
|
|||
|
||||
/**
|
||||
* The main formatter method.
|
||||
* @param {LintResults[]} results The lint results to format.
|
||||
* @returns {string} The formatted lint results.
|
||||
* @param {LintResult[]} results The lint results to format.
|
||||
* @param {ResultsMeta} resultsMeta Warning count and max threshold.
|
||||
* @returns {string | Promise<string>} The formatted lint results.
|
||||
*/
|
||||
format(results) {
|
||||
format(results, resultsMeta) {
|
||||
let rulesMeta = null;
|
||||
|
||||
results.sort(compareResultsByFilePath);
|
||||
|
||||
return formatter(results, {
|
||||
...resultsMeta,
|
||||
get cwd() {
|
||||
return options.cwd;
|
||||
},
|
||||
get rulesMeta() {
|
||||
if (!rulesMeta) {
|
||||
rulesMeta = createRulesMeta(cliEngine.getRules());
|
||||
|
|
|
|||
1182
node_modules/eslint/lib/eslint/flat-eslint.js
generated
vendored
Normal file
1182
node_modules/eslint/lib/eslint/flat-eslint.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
4
node_modules/eslint/lib/eslint/index.js
generated
vendored
4
node_modules/eslint/lib/eslint/index.js
generated
vendored
|
|
@ -1,7 +1,9 @@
|
|||
"use strict";
|
||||
|
||||
const { ESLint } = require("./eslint");
|
||||
const { FlatESLint } = require("./flat-eslint");
|
||||
|
||||
module.exports = {
|
||||
ESLint
|
||||
ESLint,
|
||||
FlatESLint
|
||||
};
|
||||
|
|
|
|||
348
node_modules/eslint/lib/init/autoconfig.js
generated
vendored
348
node_modules/eslint/lib/init/autoconfig.js
generated
vendored
|
|
@ -1,348 +0,0 @@
|
|||
/**
|
||||
* @fileoverview Used for creating a suggested configuration based on project code.
|
||||
* @author Ian VanSchooten
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const equal = require("fast-deep-equal"),
|
||||
recConfig = require("../../conf/eslint-recommended"),
|
||||
ConfigOps = require("@eslint/eslintrc/lib/shared/config-ops"),
|
||||
{ Linter } = require("../linter"),
|
||||
configRule = require("./config-rule");
|
||||
|
||||
const debug = require("debug")("eslint:autoconfig");
|
||||
const linter = new Linter();
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Data
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const MAX_CONFIG_COMBINATIONS = 17, // 16 combinations + 1 for severity only
|
||||
RECOMMENDED_CONFIG_NAME = "eslint:recommended";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Private
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Information about a rule configuration, in the context of a Registry.
|
||||
* @typedef {Object} registryItem
|
||||
* @param {ruleConfig} config A valid configuration for the rule
|
||||
* @param {number} specificity The number of elements in the ruleConfig array
|
||||
* @param {number} errorCount The number of errors encountered when linting with the config
|
||||
*/
|
||||
|
||||
/**
|
||||
* This callback is used to measure execution status in a progress bar
|
||||
* @callback progressCallback
|
||||
* @param {number} The total number of times the callback will be called.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create registryItems for rules
|
||||
* @param {rulesConfig} rulesConfig Hash of rule names and arrays of ruleConfig items
|
||||
* @returns {Object} registryItems for each rule in provided rulesConfig
|
||||
*/
|
||||
function makeRegistryItems(rulesConfig) {
|
||||
return Object.keys(rulesConfig).reduce((accumulator, ruleId) => {
|
||||
accumulator[ruleId] = rulesConfig[ruleId].map(config => ({
|
||||
config,
|
||||
specificity: config.length || 1,
|
||||
errorCount: void 0
|
||||
}));
|
||||
return accumulator;
|
||||
}, {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an object in which to store rule configs and error counts
|
||||
*
|
||||
* Unless a rulesConfig is provided at construction, the registry will not contain
|
||||
* any rules, only methods. This will be useful for building up registries manually.
|
||||
*
|
||||
* Registry class
|
||||
*/
|
||||
class Registry {
|
||||
|
||||
// eslint-disable-next-line jsdoc/require-description
|
||||
/**
|
||||
* @param {rulesConfig} [rulesConfig] Hash of rule names and arrays of possible configurations
|
||||
*/
|
||||
constructor(rulesConfig) {
|
||||
this.rules = (rulesConfig) ? makeRegistryItems(rulesConfig) : {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the registry with core rule configs.
|
||||
*
|
||||
* It will set the registry's `rule` property to an object having rule names
|
||||
* as keys and an array of registryItems as values.
|
||||
* @returns {void}
|
||||
*/
|
||||
populateFromCoreRules() {
|
||||
const rulesConfig = configRule.createCoreRuleConfigs(/* noDeprecated = */ true);
|
||||
|
||||
this.rules = makeRegistryItems(rulesConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates sets of rule configurations which can be used for linting
|
||||
* and initializes registry errors to zero for those configurations (side effect).
|
||||
*
|
||||
* This combines as many rules together as possible, such that the first sets
|
||||
* in the array will have the highest number of rules configured, and later sets
|
||||
* will have fewer and fewer, as not all rules have the same number of possible
|
||||
* configurations.
|
||||
*
|
||||
* The length of the returned array will be <= MAX_CONFIG_COMBINATIONS.
|
||||
* @returns {Object[]} "rules" configurations to use for linting
|
||||
*/
|
||||
buildRuleSets() {
|
||||
let idx = 0;
|
||||
const ruleIds = Object.keys(this.rules),
|
||||
ruleSets = [];
|
||||
|
||||
/**
|
||||
* Add a rule configuration from the registry to the ruleSets
|
||||
*
|
||||
* This is broken out into its own function so that it doesn't need to be
|
||||
* created inside of the while loop.
|
||||
* @param {string} rule The ruleId to add.
|
||||
* @returns {void}
|
||||
*/
|
||||
const addRuleToRuleSet = function(rule) {
|
||||
|
||||
/*
|
||||
* This check ensures that there is a rule configuration and that
|
||||
* it has fewer than the max combinations allowed.
|
||||
* If it has too many configs, we will only use the most basic of
|
||||
* the possible configurations.
|
||||
*/
|
||||
const hasFewCombos = (this.rules[rule].length <= MAX_CONFIG_COMBINATIONS);
|
||||
|
||||
if (this.rules[rule][idx] && (hasFewCombos || this.rules[rule][idx].specificity <= 2)) {
|
||||
|
||||
/*
|
||||
* If the rule has too many possible combinations, only take
|
||||
* simple ones, avoiding objects.
|
||||
*/
|
||||
if (!hasFewCombos && typeof this.rules[rule][idx].config[1] === "object") {
|
||||
return;
|
||||
}
|
||||
|
||||
ruleSets[idx] = ruleSets[idx] || {};
|
||||
ruleSets[idx][rule] = this.rules[rule][idx].config;
|
||||
|
||||
/*
|
||||
* Initialize errorCount to zero, since this is a config which
|
||||
* will be linted.
|
||||
*/
|
||||
this.rules[rule][idx].errorCount = 0;
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
while (ruleSets.length === idx) {
|
||||
ruleIds.forEach(addRuleToRuleSet);
|
||||
idx += 1;
|
||||
}
|
||||
|
||||
return ruleSets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all items from the registry with a non-zero number of errors
|
||||
*
|
||||
* Note: this also removes rule configurations which were not linted
|
||||
* (meaning, they have an undefined errorCount).
|
||||
* @returns {void}
|
||||
*/
|
||||
stripFailingConfigs() {
|
||||
const ruleIds = Object.keys(this.rules),
|
||||
newRegistry = new Registry();
|
||||
|
||||
newRegistry.rules = Object.assign({}, this.rules);
|
||||
ruleIds.forEach(ruleId => {
|
||||
const errorFreeItems = newRegistry.rules[ruleId].filter(registryItem => (registryItem.errorCount === 0));
|
||||
|
||||
if (errorFreeItems.length > 0) {
|
||||
newRegistry.rules[ruleId] = errorFreeItems;
|
||||
} else {
|
||||
delete newRegistry.rules[ruleId];
|
||||
}
|
||||
});
|
||||
|
||||
return newRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes rule configurations which were not included in a ruleSet
|
||||
* @returns {void}
|
||||
*/
|
||||
stripExtraConfigs() {
|
||||
const ruleIds = Object.keys(this.rules),
|
||||
newRegistry = new Registry();
|
||||
|
||||
newRegistry.rules = Object.assign({}, this.rules);
|
||||
ruleIds.forEach(ruleId => {
|
||||
newRegistry.rules[ruleId] = newRegistry.rules[ruleId].filter(registryItem => (typeof registryItem.errorCount !== "undefined"));
|
||||
});
|
||||
|
||||
return newRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a registry of rules which had no error-free configs.
|
||||
* The new registry is intended to be analyzed to determine whether its rules
|
||||
* should be disabled or set to warning.
|
||||
* @returns {Registry} A registry of failing rules.
|
||||
*/
|
||||
getFailingRulesRegistry() {
|
||||
const ruleIds = Object.keys(this.rules),
|
||||
failingRegistry = new Registry();
|
||||
|
||||
ruleIds.forEach(ruleId => {
|
||||
const failingConfigs = this.rules[ruleId].filter(registryItem => (registryItem.errorCount > 0));
|
||||
|
||||
if (failingConfigs && failingConfigs.length === this.rules[ruleId].length) {
|
||||
failingRegistry.rules[ruleId] = failingConfigs;
|
||||
}
|
||||
});
|
||||
|
||||
return failingRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an eslint config for any rules which only have one configuration
|
||||
* in the registry.
|
||||
* @returns {Object} An eslint config with rules section populated
|
||||
*/
|
||||
createConfig() {
|
||||
const ruleIds = Object.keys(this.rules),
|
||||
config = { rules: {} };
|
||||
|
||||
ruleIds.forEach(ruleId => {
|
||||
if (this.rules[ruleId].length === 1) {
|
||||
config.rules[ruleId] = this.rules[ruleId][0].config;
|
||||
}
|
||||
});
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a cloned registry containing only configs with a desired specificity
|
||||
* @param {number} specificity Only keep configs with this specificity
|
||||
* @returns {Registry} A registry of rules
|
||||
*/
|
||||
filterBySpecificity(specificity) {
|
||||
const ruleIds = Object.keys(this.rules),
|
||||
newRegistry = new Registry();
|
||||
|
||||
newRegistry.rules = Object.assign({}, this.rules);
|
||||
ruleIds.forEach(ruleId => {
|
||||
newRegistry.rules[ruleId] = this.rules[ruleId].filter(registryItem => (registryItem.specificity === specificity));
|
||||
});
|
||||
|
||||
return newRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lint SourceCodes against all configurations in the registry, and record results
|
||||
* @param {Object[]} sourceCodes SourceCode objects for each filename
|
||||
* @param {Object} config ESLint config object
|
||||
* @param {progressCallback} [cb] Optional callback for reporting execution status
|
||||
* @returns {Registry} New registry with errorCount populated
|
||||
*/
|
||||
lintSourceCode(sourceCodes, config, cb) {
|
||||
let lintedRegistry = new Registry();
|
||||
|
||||
lintedRegistry.rules = Object.assign({}, this.rules);
|
||||
|
||||
const ruleSets = lintedRegistry.buildRuleSets();
|
||||
|
||||
lintedRegistry = lintedRegistry.stripExtraConfigs();
|
||||
|
||||
debug("Linting with all possible rule combinations");
|
||||
|
||||
const filenames = Object.keys(sourceCodes);
|
||||
const totalFilesLinting = filenames.length * ruleSets.length;
|
||||
|
||||
filenames.forEach(filename => {
|
||||
debug(`Linting file: ${filename}`);
|
||||
|
||||
let ruleSetIdx = 0;
|
||||
|
||||
ruleSets.forEach(ruleSet => {
|
||||
const lintConfig = Object.assign({}, config, { rules: ruleSet });
|
||||
const lintResults = linter.verify(sourceCodes[filename], lintConfig);
|
||||
|
||||
lintResults.forEach(result => {
|
||||
|
||||
/*
|
||||
* It is possible that the error is from a configuration comment
|
||||
* in a linted file, in which case there may not be a config
|
||||
* set in this ruleSetIdx.
|
||||
* (https://github.com/eslint/eslint/issues/5992)
|
||||
* (https://github.com/eslint/eslint/issues/7860)
|
||||
*/
|
||||
if (
|
||||
lintedRegistry.rules[result.ruleId] &&
|
||||
lintedRegistry.rules[result.ruleId][ruleSetIdx]
|
||||
) {
|
||||
lintedRegistry.rules[result.ruleId][ruleSetIdx].errorCount += 1;
|
||||
}
|
||||
});
|
||||
|
||||
ruleSetIdx += 1;
|
||||
|
||||
if (cb) {
|
||||
cb(totalFilesLinting); // eslint-disable-line node/callback-return
|
||||
}
|
||||
});
|
||||
|
||||
// Deallocate for GC
|
||||
sourceCodes[filename] = null;
|
||||
});
|
||||
|
||||
return lintedRegistry;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract rule configuration into eslint:recommended where possible.
|
||||
*
|
||||
* This will return a new config with `["extends": [ ..., "eslint:recommended"]` and
|
||||
* only the rules which have configurations different from the recommended config.
|
||||
* @param {Object} config config object
|
||||
* @returns {Object} config object using `"extends": ["eslint:recommended"]`
|
||||
*/
|
||||
function extendFromRecommended(config) {
|
||||
const newConfig = Object.assign({}, config);
|
||||
|
||||
ConfigOps.normalizeToStrings(newConfig);
|
||||
|
||||
const recRules = Object.keys(recConfig.rules).filter(ruleId => ConfigOps.isErrorSeverity(recConfig.rules[ruleId]));
|
||||
|
||||
recRules.forEach(ruleId => {
|
||||
if (equal(recConfig.rules[ruleId], newConfig.rules[ruleId])) {
|
||||
delete newConfig.rules[ruleId];
|
||||
}
|
||||
});
|
||||
newConfig.extends.unshift(RECOMMENDED_CONFIG_NAME);
|
||||
return newConfig;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
Registry,
|
||||
extendFromRecommended
|
||||
};
|
||||
144
node_modules/eslint/lib/init/config-file.js
generated
vendored
144
node_modules/eslint/lib/init/config-file.js
generated
vendored
|
|
@ -1,144 +0,0 @@
|
|||
/**
|
||||
* @fileoverview Helper to locate and load configuration files.
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const fs = require("fs"),
|
||||
path = require("path"),
|
||||
stringify = require("json-stable-stringify-without-jsonify");
|
||||
|
||||
const debug = require("debug")("eslint:config-file");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Determines sort order for object keys for json-stable-stringify
|
||||
*
|
||||
* see: https://github.com/samn/json-stable-stringify#cmp
|
||||
* @param {Object} a The first comparison object ({key: akey, value: avalue})
|
||||
* @param {Object} b The second comparison object ({key: bkey, value: bvalue})
|
||||
* @returns {number} 1 or -1, used in stringify cmp method
|
||||
*/
|
||||
function sortByKey(a, b) {
|
||||
return a.key > b.key ? 1 : -1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Private
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Writes a configuration file in JSON format.
|
||||
* @param {Object} config The configuration object to write.
|
||||
* @param {string} filePath The filename to write to.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function writeJSONConfigFile(config, filePath) {
|
||||
debug(`Writing JSON config file: ${filePath}`);
|
||||
|
||||
const content = `${stringify(config, { cmp: sortByKey, space: 4 })}\n`;
|
||||
|
||||
fs.writeFileSync(filePath, content, "utf8");
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a configuration file in YAML format.
|
||||
* @param {Object} config The configuration object to write.
|
||||
* @param {string} filePath The filename to write to.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function writeYAMLConfigFile(config, filePath) {
|
||||
debug(`Writing YAML config file: ${filePath}`);
|
||||
|
||||
// lazy load YAML to improve performance when not used
|
||||
const yaml = require("js-yaml");
|
||||
|
||||
const content = yaml.safeDump(config, { sortKeys: true });
|
||||
|
||||
fs.writeFileSync(filePath, content, "utf8");
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a configuration file in JavaScript format.
|
||||
* @param {Object} config The configuration object to write.
|
||||
* @param {string} filePath The filename to write to.
|
||||
* @throws {Error} If an error occurs linting the config file contents.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function writeJSConfigFile(config, filePath) {
|
||||
debug(`Writing JS config file: ${filePath}`);
|
||||
|
||||
let contentToWrite;
|
||||
const stringifiedContent = `module.exports = ${stringify(config, { cmp: sortByKey, space: 4 })};\n`;
|
||||
|
||||
try {
|
||||
const { CLIEngine } = require("../cli-engine");
|
||||
const linter = new CLIEngine({
|
||||
baseConfig: config,
|
||||
fix: true,
|
||||
useEslintrc: false
|
||||
});
|
||||
const report = linter.executeOnText(stringifiedContent);
|
||||
|
||||
contentToWrite = report.results[0].output || stringifiedContent;
|
||||
} catch (e) {
|
||||
debug("Error linting JavaScript config file, writing unlinted version");
|
||||
const errorMessage = e.message;
|
||||
|
||||
contentToWrite = stringifiedContent;
|
||||
e.message = "An error occurred while generating your JavaScript config file. ";
|
||||
e.message += "A config file was still generated, but the config file itself may not follow your linting rules.";
|
||||
e.message += `\nError: ${errorMessage}`;
|
||||
throw e;
|
||||
} finally {
|
||||
fs.writeFileSync(filePath, contentToWrite, "utf8");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a configuration file.
|
||||
* @param {Object} config The configuration object to write.
|
||||
* @param {string} filePath The filename to write to.
|
||||
* @returns {void}
|
||||
* @throws {Error} When an unknown file type is specified.
|
||||
* @private
|
||||
*/
|
||||
function write(config, filePath) {
|
||||
switch (path.extname(filePath)) {
|
||||
case ".js":
|
||||
case ".cjs":
|
||||
writeJSConfigFile(config, filePath);
|
||||
break;
|
||||
|
||||
case ".json":
|
||||
writeJSONConfigFile(config, filePath);
|
||||
break;
|
||||
|
||||
case ".yaml":
|
||||
case ".yml":
|
||||
writeYAMLConfigFile(config, filePath);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error("Can't write to unknown file type.");
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
write
|
||||
};
|
||||
704
node_modules/eslint/lib/init/config-initializer.js
generated
vendored
704
node_modules/eslint/lib/init/config-initializer.js
generated
vendored
|
|
@ -1,704 +0,0 @@
|
|||
/**
|
||||
* @fileoverview Config initialization wizard.
|
||||
* @author Ilya Volodin
|
||||
*/
|
||||
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const util = require("util"),
|
||||
path = require("path"),
|
||||
fs = require("fs"),
|
||||
enquirer = require("enquirer"),
|
||||
ProgressBar = require("progress"),
|
||||
semver = require("semver"),
|
||||
espree = require("espree"),
|
||||
recConfig = require("../../conf/eslint-recommended"),
|
||||
ConfigOps = require("@eslint/eslintrc/lib/shared/config-ops"),
|
||||
log = require("../shared/logging"),
|
||||
naming = require("@eslint/eslintrc/lib/shared/naming"),
|
||||
ModuleResolver = require("../shared/relative-module-resolver"),
|
||||
autoconfig = require("./autoconfig.js"),
|
||||
ConfigFile = require("./config-file"),
|
||||
npmUtils = require("./npm-utils"),
|
||||
{ getSourceCodeOfFiles } = require("./source-code-utils");
|
||||
|
||||
const debug = require("debug")("eslint:config-initializer");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Private
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/* istanbul ignore next: hard to test fs function */
|
||||
/**
|
||||
* Create .eslintrc file in the current working directory
|
||||
* @param {Object} config object that contains user's answers
|
||||
* @param {string} format The file format to write to.
|
||||
* @returns {void}
|
||||
*/
|
||||
function writeFile(config, format) {
|
||||
|
||||
// default is .js
|
||||
let extname = ".js";
|
||||
|
||||
if (format === "YAML") {
|
||||
extname = ".yml";
|
||||
} else if (format === "JSON") {
|
||||
extname = ".json";
|
||||
} else if (format === "JavaScript") {
|
||||
const pkgJSONPath = npmUtils.findPackageJson();
|
||||
|
||||
if (pkgJSONPath) {
|
||||
const pkgJSONContents = JSON.parse(fs.readFileSync(pkgJSONPath, "utf8"));
|
||||
|
||||
if (pkgJSONContents.type === "module") {
|
||||
extname = ".cjs";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const installedESLint = config.installedESLint;
|
||||
|
||||
delete config.installedESLint;
|
||||
|
||||
ConfigFile.write(config, `./.eslintrc${extname}`);
|
||||
log.info(`Successfully created .eslintrc${extname} file in ${process.cwd()}`);
|
||||
|
||||
if (installedESLint) {
|
||||
log.info("ESLint was installed locally. We recommend using this local copy instead of your globally-installed copy.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the peer dependencies of the given module.
|
||||
* This adds the gotten value to cache at the first time, then reuses it.
|
||||
* In a process, this function is called twice, but `npmUtils.fetchPeerDependencies` needs to access network which is relatively slow.
|
||||
* @param {string} moduleName The module name to get.
|
||||
* @returns {Object} The peer dependencies of the given module.
|
||||
* This object is the object of `peerDependencies` field of `package.json`.
|
||||
* Returns null if npm was not found.
|
||||
*/
|
||||
function getPeerDependencies(moduleName) {
|
||||
let result = getPeerDependencies.cache.get(moduleName);
|
||||
|
||||
if (!result) {
|
||||
log.info(`Checking peerDependencies of ${moduleName}`);
|
||||
|
||||
result = npmUtils.fetchPeerDependencies(moduleName);
|
||||
getPeerDependencies.cache.set(moduleName, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
getPeerDependencies.cache = new Map();
|
||||
|
||||
/**
|
||||
* Return necessary plugins, configs, parsers, etc. based on the config
|
||||
* @param {Object} config config object
|
||||
* @param {boolean} [installESLint=true] If `false` is given, it does not install eslint.
|
||||
* @returns {string[]} An array of modules to be installed.
|
||||
*/
|
||||
function getModulesList(config, installESLint) {
|
||||
const modules = {};
|
||||
|
||||
// Create a list of modules which should be installed based on config
|
||||
if (config.plugins) {
|
||||
for (const plugin of config.plugins) {
|
||||
const moduleName = naming.normalizePackageName(plugin, "eslint-plugin");
|
||||
|
||||
modules[moduleName] = "latest";
|
||||
}
|
||||
}
|
||||
if (config.extends) {
|
||||
const extendList = Array.isArray(config.extends) ? config.extends : [config.extends];
|
||||
|
||||
for (const extend of extendList) {
|
||||
if (extend.startsWith("eslint:") || extend.startsWith("plugin:")) {
|
||||
continue;
|
||||
}
|
||||
const moduleName = naming.normalizePackageName(extend, "eslint-config");
|
||||
|
||||
modules[moduleName] = "latest";
|
||||
Object.assign(
|
||||
modules,
|
||||
getPeerDependencies(`${moduleName}@latest`)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const parser = config.parser || (config.parserOptions && config.parserOptions.parser);
|
||||
|
||||
if (parser) {
|
||||
modules[parser] = "latest";
|
||||
}
|
||||
|
||||
if (installESLint === false) {
|
||||
delete modules.eslint;
|
||||
} else {
|
||||
const installStatus = npmUtils.checkDevDeps(["eslint"]);
|
||||
|
||||
// Mark to show messages if it's new installation of eslint.
|
||||
if (installStatus.eslint === false) {
|
||||
log.info("Local ESLint installation not found.");
|
||||
modules.eslint = modules.eslint || "latest";
|
||||
config.installedESLint = true;
|
||||
}
|
||||
}
|
||||
|
||||
return Object.keys(modules).map(name => `${name}@${modules[name]}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the `rules` of a config by examining a user's source code
|
||||
*
|
||||
* Note: This clones the config object and returns a new config to avoid mutating
|
||||
* the original config parameter.
|
||||
* @param {Object} answers answers received from enquirer
|
||||
* @param {Object} config config object
|
||||
* @returns {Object} config object with configured rules
|
||||
*/
|
||||
function configureRules(answers, config) {
|
||||
const BAR_TOTAL = 20,
|
||||
BAR_SOURCE_CODE_TOTAL = 4,
|
||||
newConfig = Object.assign({}, config),
|
||||
disabledConfigs = {};
|
||||
let sourceCodes,
|
||||
registry;
|
||||
|
||||
// Set up a progress bar, as this process can take a long time
|
||||
const bar = new ProgressBar("Determining Config: :percent [:bar] :elapseds elapsed, eta :etas ", {
|
||||
width: 30,
|
||||
total: BAR_TOTAL
|
||||
});
|
||||
|
||||
bar.tick(0); // Shows the progress bar
|
||||
|
||||
// Get the SourceCode of all chosen files
|
||||
const patterns = answers.patterns.split(/[\s]+/u);
|
||||
|
||||
try {
|
||||
sourceCodes = getSourceCodeOfFiles(patterns, { baseConfig: newConfig, useEslintrc: false }, total => {
|
||||
bar.tick((BAR_SOURCE_CODE_TOTAL / total));
|
||||
});
|
||||
} catch (e) {
|
||||
log.info("\n");
|
||||
throw e;
|
||||
}
|
||||
const fileQty = Object.keys(sourceCodes).length;
|
||||
|
||||
if (fileQty === 0) {
|
||||
log.info("\n");
|
||||
throw new Error("Automatic Configuration failed. No files were able to be parsed.");
|
||||
}
|
||||
|
||||
// Create a registry of rule configs
|
||||
registry = new autoconfig.Registry();
|
||||
registry.populateFromCoreRules();
|
||||
|
||||
// Lint all files with each rule config in the registry
|
||||
registry = registry.lintSourceCode(sourceCodes, newConfig, total => {
|
||||
bar.tick((BAR_TOTAL - BAR_SOURCE_CODE_TOTAL) / total); // Subtract out ticks used at beginning
|
||||
});
|
||||
debug(`\nRegistry: ${util.inspect(registry.rules, { depth: null })}`);
|
||||
|
||||
// Create a list of recommended rules, because we don't want to disable them
|
||||
const recRules = Object.keys(recConfig.rules).filter(ruleId => ConfigOps.isErrorSeverity(recConfig.rules[ruleId]));
|
||||
|
||||
// Find and disable rules which had no error-free configuration
|
||||
const failingRegistry = registry.getFailingRulesRegistry();
|
||||
|
||||
Object.keys(failingRegistry.rules).forEach(ruleId => {
|
||||
|
||||
// If the rule is recommended, set it to error, otherwise disable it
|
||||
disabledConfigs[ruleId] = (recRules.indexOf(ruleId) !== -1) ? 2 : 0;
|
||||
});
|
||||
|
||||
// Now that we know which rules to disable, strip out configs with errors
|
||||
registry = registry.stripFailingConfigs();
|
||||
|
||||
/*
|
||||
* If there is only one config that results in no errors for a rule, we should use it.
|
||||
* createConfig will only add rules that have one configuration in the registry.
|
||||
*/
|
||||
const singleConfigs = registry.createConfig().rules;
|
||||
|
||||
/*
|
||||
* The "sweet spot" for number of options in a config seems to be two (severity plus one option).
|
||||
* Very often, a third option (usually an object) is available to address
|
||||
* edge cases, exceptions, or unique situations. We will prefer to use a config with
|
||||
* specificity of two.
|
||||
*/
|
||||
const specTwoConfigs = registry.filterBySpecificity(2).createConfig().rules;
|
||||
|
||||
// Maybe a specific combination using all three options works
|
||||
const specThreeConfigs = registry.filterBySpecificity(3).createConfig().rules;
|
||||
|
||||
// If all else fails, try to use the default (severity only)
|
||||
const defaultConfigs = registry.filterBySpecificity(1).createConfig().rules;
|
||||
|
||||
// Combine configs in reverse priority order (later take precedence)
|
||||
newConfig.rules = Object.assign({}, disabledConfigs, defaultConfigs, specThreeConfigs, specTwoConfigs, singleConfigs);
|
||||
|
||||
// Make sure progress bar has finished (floating point rounding)
|
||||
bar.update(BAR_TOTAL);
|
||||
|
||||
// Log out some stats to let the user know what happened
|
||||
const finalRuleIds = Object.keys(newConfig.rules);
|
||||
const totalRules = finalRuleIds.length;
|
||||
const enabledRules = finalRuleIds.filter(ruleId => (newConfig.rules[ruleId] !== 0)).length;
|
||||
const resultMessage = [
|
||||
`\nEnabled ${enabledRules} out of ${totalRules}`,
|
||||
`rules based on ${fileQty}`,
|
||||
`file${(fileQty === 1) ? "." : "s."}`
|
||||
].join(" ");
|
||||
|
||||
log.info(resultMessage);
|
||||
|
||||
ConfigOps.normalizeToStrings(newConfig);
|
||||
return newConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* process user's answers and create config object
|
||||
* @param {Object} answers answers received from enquirer
|
||||
* @returns {Object} config object
|
||||
*/
|
||||
function processAnswers(answers) {
|
||||
let config = {
|
||||
rules: {},
|
||||
env: {},
|
||||
parserOptions: {},
|
||||
extends: []
|
||||
};
|
||||
|
||||
config.parserOptions.ecmaVersion = espree.latestEcmaVersion;
|
||||
config.env.es2021 = true;
|
||||
|
||||
// set the module type
|
||||
if (answers.moduleType === "esm") {
|
||||
config.parserOptions.sourceType = "module";
|
||||
} else if (answers.moduleType === "commonjs") {
|
||||
config.env.commonjs = true;
|
||||
}
|
||||
|
||||
// add in browser and node environments if necessary
|
||||
answers.env.forEach(env => {
|
||||
config.env[env] = true;
|
||||
});
|
||||
|
||||
// add in library information
|
||||
if (answers.framework === "react") {
|
||||
config.parserOptions.ecmaFeatures = {
|
||||
jsx: true
|
||||
};
|
||||
config.plugins = ["react"];
|
||||
config.extends.push("plugin:react/recommended");
|
||||
} else if (answers.framework === "vue") {
|
||||
config.plugins = ["vue"];
|
||||
config.extends.push("plugin:vue/essential");
|
||||
}
|
||||
|
||||
if (answers.typescript) {
|
||||
if (answers.framework === "vue") {
|
||||
config.parserOptions.parser = "@typescript-eslint/parser";
|
||||
} else {
|
||||
config.parser = "@typescript-eslint/parser";
|
||||
}
|
||||
|
||||
if (Array.isArray(config.plugins)) {
|
||||
config.plugins.push("@typescript-eslint");
|
||||
} else {
|
||||
config.plugins = ["@typescript-eslint"];
|
||||
}
|
||||
}
|
||||
|
||||
// setup rules based on problems/style enforcement preferences
|
||||
if (answers.purpose === "problems") {
|
||||
config.extends.unshift("eslint:recommended");
|
||||
} else if (answers.purpose === "style") {
|
||||
if (answers.source === "prompt") {
|
||||
config.extends.unshift("eslint:recommended");
|
||||
config.rules.indent = ["error", answers.indent];
|
||||
config.rules.quotes = ["error", answers.quotes];
|
||||
config.rules["linebreak-style"] = ["error", answers.linebreak];
|
||||
config.rules.semi = ["error", answers.semi ? "always" : "never"];
|
||||
} else if (answers.source === "auto") {
|
||||
config = configureRules(answers, config);
|
||||
config = autoconfig.extendFromRecommended(config);
|
||||
}
|
||||
}
|
||||
if (answers.typescript && config.extends.includes("eslint:recommended")) {
|
||||
config.extends.push("plugin:@typescript-eslint/recommended");
|
||||
}
|
||||
|
||||
// normalize extends
|
||||
if (config.extends.length === 0) {
|
||||
delete config.extends;
|
||||
} else if (config.extends.length === 1) {
|
||||
config.extends = config.extends[0];
|
||||
}
|
||||
|
||||
ConfigOps.normalizeToStrings(config);
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the version of the local ESLint.
|
||||
* @returns {string|null} The version. If the local ESLint was not found, returns null.
|
||||
*/
|
||||
function getLocalESLintVersion() {
|
||||
try {
|
||||
const eslintPath = ModuleResolver.resolve("eslint", path.join(process.cwd(), "__placeholder__.js"));
|
||||
const eslint = require(eslintPath);
|
||||
|
||||
return eslint.linter.version || null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the shareable config name of the chosen style guide.
|
||||
* @param {Object} answers The answers object.
|
||||
* @returns {string} The shareable config name.
|
||||
*/
|
||||
function getStyleGuideName(answers) {
|
||||
if (answers.styleguide === "airbnb" && answers.framework !== "react") {
|
||||
return "airbnb-base";
|
||||
}
|
||||
return answers.styleguide;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the local ESLint version conflicts with the required version of the chosen shareable config.
|
||||
* @param {Object} answers The answers object.
|
||||
* @returns {boolean} `true` if the local ESLint is found then it conflicts with the required version of the chosen shareable config.
|
||||
*/
|
||||
function hasESLintVersionConflict(answers) {
|
||||
|
||||
// Get the local ESLint version.
|
||||
const localESLintVersion = getLocalESLintVersion();
|
||||
|
||||
if (!localESLintVersion) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the required range of ESLint version.
|
||||
const configName = getStyleGuideName(answers);
|
||||
const moduleName = `eslint-config-${configName}@latest`;
|
||||
const peerDependencies = getPeerDependencies(moduleName) || {};
|
||||
const requiredESLintVersionRange = peerDependencies.eslint;
|
||||
|
||||
if (!requiredESLintVersionRange) {
|
||||
return false;
|
||||
}
|
||||
|
||||
answers.localESLintVersion = localESLintVersion;
|
||||
answers.requiredESLintVersionRange = requiredESLintVersionRange;
|
||||
|
||||
// Check the version.
|
||||
if (semver.satisfies(localESLintVersion, requiredESLintVersionRange)) {
|
||||
answers.installESLint = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Install modules.
|
||||
* @param {string[]} modules Modules to be installed.
|
||||
* @returns {void}
|
||||
*/
|
||||
function installModules(modules) {
|
||||
log.info(`Installing ${modules.join(", ")}`);
|
||||
npmUtils.installSyncSaveDev(modules);
|
||||
}
|
||||
|
||||
/* istanbul ignore next: no need to test enquirer */
|
||||
/**
|
||||
* Ask user to install modules.
|
||||
* @param {string[]} modules Array of modules to be installed.
|
||||
* @param {boolean} packageJsonExists Indicates if package.json is existed.
|
||||
* @returns {Promise} Answer that indicates if user wants to install.
|
||||
*/
|
||||
function askInstallModules(modules, packageJsonExists) {
|
||||
|
||||
// If no modules, do nothing.
|
||||
if (modules.length === 0) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
log.info("The config that you've selected requires the following dependencies:\n");
|
||||
log.info(modules.join(" "));
|
||||
return enquirer.prompt([
|
||||
{
|
||||
type: "toggle",
|
||||
name: "executeInstallation",
|
||||
message: "Would you like to install them now with npm?",
|
||||
enabled: "Yes",
|
||||
disabled: "No",
|
||||
initial: 1,
|
||||
skip() {
|
||||
return !(modules.length && packageJsonExists);
|
||||
},
|
||||
result(input) {
|
||||
return this.skipped ? null : input;
|
||||
}
|
||||
}
|
||||
]).then(({ executeInstallation }) => {
|
||||
if (executeInstallation) {
|
||||
installModules(modules);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* istanbul ignore next: no need to test enquirer */
|
||||
/**
|
||||
* Ask use a few questions on command prompt
|
||||
* @returns {Promise} The promise with the result of the prompt
|
||||
*/
|
||||
function promptUser() {
|
||||
|
||||
return enquirer.prompt([
|
||||
{
|
||||
type: "select",
|
||||
name: "purpose",
|
||||
message: "How would you like to use ESLint?",
|
||||
|
||||
// The returned number matches the name value of nth in the choices array.
|
||||
initial: 1,
|
||||
choices: [
|
||||
{ message: "To check syntax only", name: "syntax" },
|
||||
{ message: "To check syntax and find problems", name: "problems" },
|
||||
{ message: "To check syntax, find problems, and enforce code style", name: "style" }
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
name: "moduleType",
|
||||
message: "What type of modules does your project use?",
|
||||
initial: 0,
|
||||
choices: [
|
||||
{ message: "JavaScript modules (import/export)", name: "esm" },
|
||||
{ message: "CommonJS (require/exports)", name: "commonjs" },
|
||||
{ message: "None of these", name: "none" }
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
name: "framework",
|
||||
message: "Which framework does your project use?",
|
||||
initial: 0,
|
||||
choices: [
|
||||
{ message: "React", name: "react" },
|
||||
{ message: "Vue.js", name: "vue" },
|
||||
{ message: "None of these", name: "none" }
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "toggle",
|
||||
name: "typescript",
|
||||
message: "Does your project use TypeScript?",
|
||||
enabled: "Yes",
|
||||
disabled: "No",
|
||||
initial: 0
|
||||
},
|
||||
{
|
||||
type: "multiselect",
|
||||
name: "env",
|
||||
message: "Where does your code run?",
|
||||
hint: "(Press <space> to select, <a> to toggle all, <i> to invert selection)",
|
||||
initial: 0,
|
||||
choices: [
|
||||
{ message: "Browser", name: "browser" },
|
||||
{ message: "Node", name: "node" }
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
name: "source",
|
||||
message: "How would you like to define a style for your project?",
|
||||
choices: [
|
||||
{ message: "Use a popular style guide", name: "guide" },
|
||||
{ message: "Answer questions about your style", name: "prompt" },
|
||||
{ message: "Inspect your JavaScript file(s)", name: "auto" }
|
||||
],
|
||||
skip() {
|
||||
return this.state.answers.purpose !== "style";
|
||||
},
|
||||
result(input) {
|
||||
return this.skipped ? null : input;
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
name: "styleguide",
|
||||
message: "Which style guide do you want to follow?",
|
||||
choices: [
|
||||
{ message: "Airbnb: https://github.com/airbnb/javascript", name: "airbnb" },
|
||||
{ message: "Standard: https://github.com/standard/standard", name: "standard" },
|
||||
{ message: "Google: https://github.com/google/eslint-config-google", name: "google" },
|
||||
{ message: "XO: https://github.com/xojs/eslint-config-xo", name: "xo" }
|
||||
],
|
||||
skip() {
|
||||
this.state.answers.packageJsonExists = npmUtils.checkPackageJson();
|
||||
return !(this.state.answers.source === "guide" && this.state.answers.packageJsonExists);
|
||||
},
|
||||
result(input) {
|
||||
return this.skipped ? null : input;
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "input",
|
||||
name: "patterns",
|
||||
message: "Which file(s), path(s), or glob(s) should be examined?",
|
||||
skip() {
|
||||
return this.state.answers.source !== "auto";
|
||||
},
|
||||
validate(input) {
|
||||
if (!this.skipped && input.trim().length === 0 && input.trim() !== ",") {
|
||||
return "You must tell us what code to examine. Try again.";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
name: "format",
|
||||
message: "What format do you want your config file to be in?",
|
||||
initial: 0,
|
||||
choices: ["JavaScript", "YAML", "JSON"]
|
||||
},
|
||||
{
|
||||
type: "toggle",
|
||||
name: "installESLint",
|
||||
message() {
|
||||
const { answers } = this.state;
|
||||
const verb = semver.ltr(answers.localESLintVersion, answers.requiredESLintVersionRange)
|
||||
? "upgrade"
|
||||
: "downgrade";
|
||||
|
||||
return `The style guide "${answers.styleguide}" requires eslint@${answers.requiredESLintVersionRange}. You are currently using eslint@${answers.localESLintVersion}.\n Do you want to ${verb}?`;
|
||||
},
|
||||
enabled: "Yes",
|
||||
disabled: "No",
|
||||
initial: 1,
|
||||
skip() {
|
||||
return !(this.state.answers.source === "guide" && this.state.answers.packageJsonExists && hasESLintVersionConflict(this.state.answers));
|
||||
},
|
||||
result(input) {
|
||||
return this.skipped ? null : input;
|
||||
}
|
||||
}
|
||||
]).then(earlyAnswers => {
|
||||
|
||||
// early exit if no style guide is necessary
|
||||
if (earlyAnswers.purpose !== "style") {
|
||||
const config = processAnswers(earlyAnswers);
|
||||
const modules = getModulesList(config);
|
||||
|
||||
return askInstallModules(modules, earlyAnswers.packageJsonExists)
|
||||
.then(() => writeFile(config, earlyAnswers.format));
|
||||
}
|
||||
|
||||
// early exit if you are using a style guide
|
||||
if (earlyAnswers.source === "guide") {
|
||||
if (!earlyAnswers.packageJsonExists) {
|
||||
log.info("A package.json is necessary to install plugins such as style guides. Run `npm init` to create a package.json file and try again.");
|
||||
return void 0;
|
||||
}
|
||||
if (earlyAnswers.installESLint === false && !semver.satisfies(earlyAnswers.localESLintVersion, earlyAnswers.requiredESLintVersionRange)) {
|
||||
log.info(`Note: it might not work since ESLint's version is mismatched with the ${earlyAnswers.styleguide} config.`);
|
||||
}
|
||||
if (earlyAnswers.styleguide === "airbnb" && earlyAnswers.framework !== "react") {
|
||||
earlyAnswers.styleguide = "airbnb-base";
|
||||
}
|
||||
|
||||
const config = processAnswers(earlyAnswers);
|
||||
|
||||
if (Array.isArray(config.extends)) {
|
||||
config.extends.push(earlyAnswers.styleguide);
|
||||
} else if (config.extends) {
|
||||
config.extends = [config.extends, earlyAnswers.styleguide];
|
||||
} else {
|
||||
config.extends = [earlyAnswers.styleguide];
|
||||
}
|
||||
|
||||
const modules = getModulesList(config);
|
||||
|
||||
return askInstallModules(modules, earlyAnswers.packageJsonExists)
|
||||
.then(() => writeFile(config, earlyAnswers.format));
|
||||
|
||||
}
|
||||
|
||||
if (earlyAnswers.source === "auto") {
|
||||
const combinedAnswers = Object.assign({}, earlyAnswers);
|
||||
const config = processAnswers(combinedAnswers);
|
||||
const modules = getModulesList(config);
|
||||
|
||||
return askInstallModules(modules).then(() => writeFile(config, earlyAnswers.format));
|
||||
}
|
||||
|
||||
// continue with the style questions otherwise...
|
||||
return enquirer.prompt([
|
||||
{
|
||||
type: "select",
|
||||
name: "indent",
|
||||
message: "What style of indentation do you use?",
|
||||
initial: 0,
|
||||
choices: [{ message: "Tabs", name: "tab" }, { message: "Spaces", name: 4 }]
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
name: "quotes",
|
||||
message: "What quotes do you use for strings?",
|
||||
initial: 0,
|
||||
choices: [{ message: "Double", name: "double" }, { message: "Single", name: "single" }]
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
name: "linebreak",
|
||||
message: "What line endings do you use?",
|
||||
initial: 0,
|
||||
choices: [{ message: "Unix", name: "unix" }, { message: "Windows", name: "windows" }]
|
||||
},
|
||||
{
|
||||
type: "toggle",
|
||||
name: "semi",
|
||||
message: "Do you require semicolons?",
|
||||
enabled: "Yes",
|
||||
disabled: "No",
|
||||
initial: 1
|
||||
}
|
||||
]).then(answers => {
|
||||
const totalAnswers = Object.assign({}, earlyAnswers, answers);
|
||||
|
||||
const config = processAnswers(totalAnswers);
|
||||
const modules = getModulesList(config);
|
||||
|
||||
return askInstallModules(modules).then(() => writeFile(config, earlyAnswers.format));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const init = {
|
||||
getModulesList,
|
||||
hasESLintVersionConflict,
|
||||
installModules,
|
||||
processAnswers,
|
||||
writeFile,
|
||||
/* istanbul ignore next */initializeConfig() {
|
||||
return promptUser();
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = init;
|
||||
317
node_modules/eslint/lib/init/config-rule.js
generated
vendored
317
node_modules/eslint/lib/init/config-rule.js
generated
vendored
|
|
@ -1,317 +0,0 @@
|
|||
/**
|
||||
* @fileoverview Create configurations for a rule
|
||||
* @author Ian VanSchooten
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const builtInRules = require("../rules");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Wrap all of the elements of an array into arrays.
|
||||
* @param {*[]} xs Any array.
|
||||
* @returns {Array[]} An array of arrays.
|
||||
*/
|
||||
function explodeArray(xs) {
|
||||
return xs.reduce((accumulator, x) => {
|
||||
accumulator.push([x]);
|
||||
return accumulator;
|
||||
}, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mix two arrays such that each element of the second array is concatenated
|
||||
* onto each element of the first array.
|
||||
*
|
||||
* For example:
|
||||
* combineArrays([a, [b, c]], [x, y]); // -> [[a, x], [a, y], [b, c, x], [b, c, y]]
|
||||
* @param {Array} arr1 The first array to combine.
|
||||
* @param {Array} arr2 The second array to combine.
|
||||
* @returns {Array} A mixture of the elements of the first and second arrays.
|
||||
*/
|
||||
function combineArrays(arr1, arr2) {
|
||||
const res = [];
|
||||
|
||||
if (arr1.length === 0) {
|
||||
return explodeArray(arr2);
|
||||
}
|
||||
if (arr2.length === 0) {
|
||||
return explodeArray(arr1);
|
||||
}
|
||||
arr1.forEach(x1 => {
|
||||
arr2.forEach(x2 => {
|
||||
res.push([].concat(x1, x2));
|
||||
});
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Group together valid rule configurations based on object properties
|
||||
*
|
||||
* e.g.:
|
||||
* groupByProperty([
|
||||
* {before: true},
|
||||
* {before: false},
|
||||
* {after: true},
|
||||
* {after: false}
|
||||
* ]);
|
||||
*
|
||||
* will return:
|
||||
* [
|
||||
* [{before: true}, {before: false}],
|
||||
* [{after: true}, {after: false}]
|
||||
* ]
|
||||
* @param {Object[]} objects Array of objects, each with one property/value pair
|
||||
* @returns {Array[]} Array of arrays of objects grouped by property
|
||||
*/
|
||||
function groupByProperty(objects) {
|
||||
const groupedObj = objects.reduce((accumulator, obj) => {
|
||||
const prop = Object.keys(obj)[0];
|
||||
|
||||
accumulator[prop] = accumulator[prop] ? accumulator[prop].concat(obj) : [obj];
|
||||
return accumulator;
|
||||
}, {});
|
||||
|
||||
return Object.keys(groupedObj).map(prop => groupedObj[prop]);
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Private
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Configuration settings for a rule.
|
||||
*
|
||||
* A configuration can be a single number (severity), or an array where the first
|
||||
* element in the array is the severity, and is the only required element.
|
||||
* Configs may also have one or more additional elements to specify rule
|
||||
* configuration or options.
|
||||
* @typedef {Array|number} ruleConfig
|
||||
* @param {number} 0 The rule's severity (0, 1, 2).
|
||||
*/
|
||||
|
||||
/**
|
||||
* Object whose keys are rule names and values are arrays of valid ruleConfig items
|
||||
* which should be linted against the target source code to determine error counts.
|
||||
* (a ruleConfigSet.ruleConfigs).
|
||||
*
|
||||
* e.g. rulesConfig = {
|
||||
* "comma-dangle": [2, [2, "always"], [2, "always-multiline"], [2, "never"]],
|
||||
* "no-console": [2]
|
||||
* }
|
||||
* @typedef rulesConfig
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Create valid rule configurations by combining two arrays,
|
||||
* with each array containing multiple objects each with a
|
||||
* single property/value pair and matching properties.
|
||||
*
|
||||
* e.g.:
|
||||
* combinePropertyObjects(
|
||||
* [{before: true}, {before: false}],
|
||||
* [{after: true}, {after: false}]
|
||||
* );
|
||||
*
|
||||
* will return:
|
||||
* [
|
||||
* {before: true, after: true},
|
||||
* {before: true, after: false},
|
||||
* {before: false, after: true},
|
||||
* {before: false, after: false}
|
||||
* ]
|
||||
* @param {Object[]} objArr1 Single key/value objects, all with the same key
|
||||
* @param {Object[]} objArr2 Single key/value objects, all with another key
|
||||
* @returns {Object[]} Combined objects for each combination of input properties and values
|
||||
*/
|
||||
function combinePropertyObjects(objArr1, objArr2) {
|
||||
const res = [];
|
||||
|
||||
if (objArr1.length === 0) {
|
||||
return objArr2;
|
||||
}
|
||||
if (objArr2.length === 0) {
|
||||
return objArr1;
|
||||
}
|
||||
objArr1.forEach(obj1 => {
|
||||
objArr2.forEach(obj2 => {
|
||||
const combinedObj = {};
|
||||
const obj1Props = Object.keys(obj1);
|
||||
const obj2Props = Object.keys(obj2);
|
||||
|
||||
obj1Props.forEach(prop1 => {
|
||||
combinedObj[prop1] = obj1[prop1];
|
||||
});
|
||||
obj2Props.forEach(prop2 => {
|
||||
combinedObj[prop2] = obj2[prop2];
|
||||
});
|
||||
res.push(combinedObj);
|
||||
});
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of a rule configuration set
|
||||
*
|
||||
* A rule configuration set is an array of configurations that are valid for a
|
||||
* given rule. For example, the configuration set for the "semi" rule could be:
|
||||
*
|
||||
* ruleConfigSet.ruleConfigs // -> [[2], [2, "always"], [2, "never"]]
|
||||
*
|
||||
* Rule configuration set class
|
||||
*/
|
||||
class RuleConfigSet {
|
||||
|
||||
// eslint-disable-next-line jsdoc/require-description
|
||||
/**
|
||||
* @param {ruleConfig[]} configs Valid rule configurations
|
||||
*/
|
||||
constructor(configs) {
|
||||
|
||||
/**
|
||||
* Stored valid rule configurations for this instance
|
||||
* @type {Array}
|
||||
*/
|
||||
this.ruleConfigs = configs || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a severity level to the front of all configs in the instance.
|
||||
* This should only be called after all configs have been added to the instance.
|
||||
* @returns {void}
|
||||
*/
|
||||
addErrorSeverity() {
|
||||
const severity = 2;
|
||||
|
||||
this.ruleConfigs = this.ruleConfigs.map(config => {
|
||||
config.unshift(severity);
|
||||
return config;
|
||||
});
|
||||
|
||||
// Add a single config at the beginning consisting of only the severity
|
||||
this.ruleConfigs.unshift(severity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add rule configs from an array of strings (schema enums)
|
||||
* @param {string[]} enums Array of valid rule options (e.g. ["always", "never"])
|
||||
* @returns {void}
|
||||
*/
|
||||
addEnums(enums) {
|
||||
this.ruleConfigs = this.ruleConfigs.concat(combineArrays(this.ruleConfigs, enums));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add rule configurations from a schema object
|
||||
* @param {Object} obj Schema item with type === "object"
|
||||
* @returns {boolean} true if at least one schema for the object could be generated, false otherwise
|
||||
*/
|
||||
addObject(obj) {
|
||||
const objectConfigSet = {
|
||||
objectConfigs: [],
|
||||
add(property, values) {
|
||||
for (let idx = 0; idx < values.length; idx++) {
|
||||
const optionObj = {};
|
||||
|
||||
optionObj[property] = values[idx];
|
||||
this.objectConfigs.push(optionObj);
|
||||
}
|
||||
},
|
||||
|
||||
combine() {
|
||||
this.objectConfigs = groupByProperty(this.objectConfigs).reduce((accumulator, objArr) => combinePropertyObjects(accumulator, objArr), []);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* The object schema could have multiple independent properties.
|
||||
* If any contain enums or booleans, they can be added and then combined
|
||||
*/
|
||||
Object.keys(obj.properties).forEach(prop => {
|
||||
if (obj.properties[prop].enum) {
|
||||
objectConfigSet.add(prop, obj.properties[prop].enum);
|
||||
}
|
||||
if (obj.properties[prop].type && obj.properties[prop].type === "boolean") {
|
||||
objectConfigSet.add(prop, [true, false]);
|
||||
}
|
||||
});
|
||||
objectConfigSet.combine();
|
||||
|
||||
if (objectConfigSet.objectConfigs.length > 0) {
|
||||
this.ruleConfigs = this.ruleConfigs.concat(combineArrays(this.ruleConfigs, objectConfigSet.objectConfigs));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate valid rule configurations based on a schema object
|
||||
* @param {Object} schema A rule's schema object
|
||||
* @returns {Array[]} Valid rule configurations
|
||||
*/
|
||||
function generateConfigsFromSchema(schema) {
|
||||
const configSet = new RuleConfigSet();
|
||||
|
||||
if (Array.isArray(schema)) {
|
||||
for (const opt of schema) {
|
||||
if (opt.enum) {
|
||||
configSet.addEnums(opt.enum);
|
||||
} else if (opt.type && opt.type === "object") {
|
||||
if (!configSet.addObject(opt)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO (IanVS): support oneOf
|
||||
} else {
|
||||
|
||||
// If we don't know how to fill in this option, don't fill in any of the following options.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
configSet.addErrorSeverity();
|
||||
return configSet.ruleConfigs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate possible rule configurations for all of the core rules
|
||||
* @param {boolean} noDeprecated Indicates whether ignores deprecated rules or not.
|
||||
* @returns {rulesConfig} Hash of rule names and arrays of possible configurations
|
||||
*/
|
||||
function createCoreRuleConfigs(noDeprecated = false) {
|
||||
return Array.from(builtInRules).reduce((accumulator, [id, rule]) => {
|
||||
const schema = (typeof rule === "function") ? rule.schema : rule.meta.schema;
|
||||
const isDeprecated = (typeof rule === "function") ? rule.deprecated : rule.meta.deprecated;
|
||||
|
||||
if (noDeprecated && isDeprecated) {
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
accumulator[id] = generateConfigsFromSchema(schema);
|
||||
return accumulator;
|
||||
}, {});
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
generateConfigsFromSchema,
|
||||
createCoreRuleConfigs
|
||||
};
|
||||
178
node_modules/eslint/lib/init/npm-utils.js
generated
vendored
178
node_modules/eslint/lib/init/npm-utils.js
generated
vendored
|
|
@ -1,178 +0,0 @@
|
|||
/**
|
||||
* @fileoverview Utility for executing npm commands.
|
||||
* @author Ian VanSchooten
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const fs = require("fs"),
|
||||
spawn = require("cross-spawn"),
|
||||
path = require("path"),
|
||||
log = require("../shared/logging");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Find the closest package.json file, starting at process.cwd (by default),
|
||||
* and working up to root.
|
||||
* @param {string} [startDir=process.cwd()] Starting directory
|
||||
* @returns {string} Absolute path to closest package.json file
|
||||
*/
|
||||
function findPackageJson(startDir) {
|
||||
let dir = path.resolve(startDir || process.cwd());
|
||||
|
||||
do {
|
||||
const pkgFile = path.join(dir, "package.json");
|
||||
|
||||
if (!fs.existsSync(pkgFile) || !fs.statSync(pkgFile).isFile()) {
|
||||
dir = path.join(dir, "..");
|
||||
continue;
|
||||
}
|
||||
return pkgFile;
|
||||
} while (dir !== path.resolve(dir, ".."));
|
||||
return null;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Private
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Install node modules synchronously and save to devDependencies in package.json
|
||||
* @param {string|string[]} packages Node module or modules to install
|
||||
* @returns {void}
|
||||
*/
|
||||
function installSyncSaveDev(packages) {
|
||||
const packageList = Array.isArray(packages) ? packages : [packages];
|
||||
const npmProcess = spawn.sync("npm", ["i", "--save-dev"].concat(packageList), { stdio: "inherit" });
|
||||
const error = npmProcess.error;
|
||||
|
||||
if (error && error.code === "ENOENT") {
|
||||
const pluralS = packageList.length > 1 ? "s" : "";
|
||||
|
||||
log.error(`Could not execute npm. Please install the following package${pluralS} with a package manager of your choice: ${packageList.join(", ")}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch `peerDependencies` of the given package by `npm show` command.
|
||||
* @param {string} packageName The package name to fetch peerDependencies.
|
||||
* @returns {Object} Gotten peerDependencies. Returns null if npm was not found.
|
||||
*/
|
||||
function fetchPeerDependencies(packageName) {
|
||||
const npmProcess = spawn.sync(
|
||||
"npm",
|
||||
["show", "--json", packageName, "peerDependencies"],
|
||||
{ encoding: "utf8" }
|
||||
);
|
||||
|
||||
const error = npmProcess.error;
|
||||
|
||||
if (error && error.code === "ENOENT") {
|
||||
return null;
|
||||
}
|
||||
const fetchedText = npmProcess.stdout.trim();
|
||||
|
||||
return JSON.parse(fetchedText || "{}");
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether node modules are include in a project's package.json.
|
||||
* @param {string[]} packages Array of node module names
|
||||
* @param {Object} opt Options Object
|
||||
* @param {boolean} opt.dependencies Set to true to check for direct dependencies
|
||||
* @param {boolean} opt.devDependencies Set to true to check for development dependencies
|
||||
* @param {boolean} opt.startdir Directory to begin searching from
|
||||
* @returns {Object} An object whose keys are the module names
|
||||
* and values are booleans indicating installation.
|
||||
*/
|
||||
function check(packages, opt) {
|
||||
const deps = new Set();
|
||||
const pkgJson = (opt) ? findPackageJson(opt.startDir) : findPackageJson();
|
||||
let fileJson;
|
||||
|
||||
if (!pkgJson) {
|
||||
throw new Error("Could not find a package.json file. Run 'npm init' to create one.");
|
||||
}
|
||||
|
||||
try {
|
||||
fileJson = JSON.parse(fs.readFileSync(pkgJson, "utf8"));
|
||||
} catch (e) {
|
||||
const error = new Error(e);
|
||||
|
||||
error.messageTemplate = "failed-to-read-json";
|
||||
error.messageData = {
|
||||
path: pkgJson,
|
||||
message: e.message
|
||||
};
|
||||
throw error;
|
||||
}
|
||||
|
||||
["dependencies", "devDependencies"].forEach(key => {
|
||||
if (opt[key] && typeof fileJson[key] === "object") {
|
||||
Object.keys(fileJson[key]).forEach(dep => deps.add(dep));
|
||||
}
|
||||
});
|
||||
|
||||
return packages.reduce((status, pkg) => {
|
||||
status[pkg] = deps.has(pkg);
|
||||
return status;
|
||||
}, {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether node modules are included in the dependencies of a project's
|
||||
* package.json.
|
||||
*
|
||||
* Convenience wrapper around check().
|
||||
* @param {string[]} packages Array of node modules to check.
|
||||
* @param {string} rootDir The directory containing a package.json
|
||||
* @returns {Object} An object whose keys are the module names
|
||||
* and values are booleans indicating installation.
|
||||
*/
|
||||
function checkDeps(packages, rootDir) {
|
||||
return check(packages, { dependencies: true, startDir: rootDir });
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether node modules are included in the devDependencies of a project's
|
||||
* package.json.
|
||||
*
|
||||
* Convenience wrapper around check().
|
||||
* @param {string[]} packages Array of node modules to check.
|
||||
* @returns {Object} An object whose keys are the module names
|
||||
* and values are booleans indicating installation.
|
||||
*/
|
||||
function checkDevDeps(packages) {
|
||||
return check(packages, { devDependencies: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether package.json is found in current path.
|
||||
* @param {string} [startDir] Starting directory
|
||||
* @returns {boolean} Whether a package.json is found in current path.
|
||||
*/
|
||||
function checkPackageJson(startDir) {
|
||||
return !!findPackageJson(startDir);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
installSyncSaveDev,
|
||||
fetchPeerDependencies,
|
||||
findPackageJson,
|
||||
checkDeps,
|
||||
checkDevDeps,
|
||||
checkPackageJson
|
||||
};
|
||||
109
node_modules/eslint/lib/init/source-code-utils.js
generated
vendored
109
node_modules/eslint/lib/init/source-code-utils.js
generated
vendored
|
|
@ -1,109 +0,0 @@
|
|||
/**
|
||||
* @fileoverview Tools for obtaining SourceCode objects.
|
||||
* @author Ian VanSchooten
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const { CLIEngine } = require("../cli-engine");
|
||||
|
||||
/*
|
||||
* This is used for:
|
||||
*
|
||||
* 1. Enumerate target file because we have not expose such a API on `CLIEngine`
|
||||
* (https://github.com/eslint/eslint/issues/11222).
|
||||
* 2. Create `SourceCode` instances. Because we don't have any function which
|
||||
* instantiate `SourceCode` so it needs to take the created `SourceCode`
|
||||
* instance out after linting.
|
||||
*
|
||||
* TODO1: Expose the API that enumerates target files.
|
||||
* TODO2: Extract the creation logic of `SourceCode` from `Linter` class.
|
||||
*/
|
||||
const { getCLIEngineInternalSlots } = require("../cli-engine/cli-engine"); // eslint-disable-line node/no-restricted-require
|
||||
|
||||
const debug = require("debug")("eslint:source-code-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get the SourceCode object for a single file
|
||||
* @param {string} filename The fully resolved filename to get SourceCode from.
|
||||
* @param {Object} engine A CLIEngine.
|
||||
* @returns {Array} Array of the SourceCode object representing the file
|
||||
* and fatal error message.
|
||||
*/
|
||||
function getSourceCodeOfFile(filename, engine) {
|
||||
debug("getting sourceCode of", filename);
|
||||
const results = engine.executeOnFiles([filename]);
|
||||
|
||||
if (results && results.results[0] && results.results[0].messages[0] && results.results[0].messages[0].fatal) {
|
||||
const msg = results.results[0].messages[0];
|
||||
|
||||
throw new Error(`(${filename}:${msg.line}:${msg.column}) ${msg.message}`);
|
||||
}
|
||||
|
||||
// TODO: extract the logic that creates source code objects to `SourceCode#parse(text, options)` or something like.
|
||||
const { linter } = getCLIEngineInternalSlots(engine);
|
||||
const sourceCode = linter.getSourceCode();
|
||||
|
||||
return sourceCode;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* This callback is used to measure execution status in a progress bar
|
||||
* @callback progressCallback
|
||||
* @param {number} The total number of times the callback will be called.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the SourceCode of a single file, or set of files.
|
||||
* @param {string[]|string} patterns A filename, directory name, or glob, or an array of them
|
||||
* @param {Object} options A CLIEngine options object. If not provided, the default cli options will be used.
|
||||
* @param {progressCallback} callback Callback for reporting execution status
|
||||
* @returns {Object} The SourceCode of all processed files.
|
||||
*/
|
||||
function getSourceCodeOfFiles(patterns, options, callback) {
|
||||
const sourceCodes = {};
|
||||
const globPatternsList = typeof patterns === "string" ? [patterns] : patterns;
|
||||
const engine = new CLIEngine({ ...options, rules: {} });
|
||||
|
||||
// TODO: make file iteration as a public API and use it.
|
||||
const { fileEnumerator } = getCLIEngineInternalSlots(engine);
|
||||
const filenames =
|
||||
Array.from(fileEnumerator.iterateFiles(globPatternsList))
|
||||
.filter(entry => !entry.ignored)
|
||||
.map(entry => entry.filePath);
|
||||
|
||||
if (filenames.length === 0) {
|
||||
debug(`Did not find any files matching pattern(s): ${globPatternsList}`);
|
||||
}
|
||||
|
||||
filenames.forEach(filename => {
|
||||
const sourceCode = getSourceCodeOfFile(filename, engine);
|
||||
|
||||
if (sourceCode) {
|
||||
debug("got sourceCode of", filename);
|
||||
sourceCodes[filename] = sourceCode;
|
||||
}
|
||||
if (callback) {
|
||||
callback(filenames.length); // eslint-disable-line node/callback-return
|
||||
}
|
||||
});
|
||||
|
||||
return sourceCodes;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getSourceCodeOfFiles
|
||||
};
|
||||
302
node_modules/eslint/lib/linter/apply-disable-directives.js
generated
vendored
302
node_modules/eslint/lib/linter/apply-disable-directives.js
generated
vendored
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const escapeRegExp = require("escape-string-regexp");
|
||||
|
||||
/**
|
||||
* Compares the locations of two objects in a source file
|
||||
* @param {{line: number, column: number}} itemA The first object
|
||||
|
|
@ -16,6 +18,177 @@ function compareLocations(itemA, itemB) {
|
|||
return itemA.line - itemB.line || itemA.column - itemB.column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Groups a set of directives into sub-arrays by their parent comment.
|
||||
* @param {Directive[]} directives Unused directives to be removed.
|
||||
* @returns {Directive[][]} Directives grouped by their parent comment.
|
||||
*/
|
||||
function groupByParentComment(directives) {
|
||||
const groups = new Map();
|
||||
|
||||
for (const directive of directives) {
|
||||
const { unprocessedDirective: { parentComment } } = directive;
|
||||
|
||||
if (groups.has(parentComment)) {
|
||||
groups.get(parentComment).push(directive);
|
||||
} else {
|
||||
groups.set(parentComment, [directive]);
|
||||
}
|
||||
}
|
||||
|
||||
return [...groups.values()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates removal details for a set of directives within the same comment.
|
||||
* @param {Directive[]} directives Unused directives to be removed.
|
||||
* @param {Token} commentToken The backing Comment token.
|
||||
* @returns {{ description, fix, unprocessedDirective }[]} Details for later creation of output Problems.
|
||||
*/
|
||||
function createIndividualDirectivesRemoval(directives, commentToken) {
|
||||
|
||||
/*
|
||||
* `commentToken.value` starts right after `//` or `/*`.
|
||||
* All calculated offsets will be relative to this index.
|
||||
*/
|
||||
const commentValueStart = commentToken.range[0] + "//".length;
|
||||
|
||||
// Find where the list of rules starts. `\S+` matches with the directive name (e.g. `eslint-disable-line`)
|
||||
const listStartOffset = /^\s*\S+\s+/u.exec(commentToken.value)[0].length;
|
||||
|
||||
/*
|
||||
* Get the list text without any surrounding whitespace. In order to preserve the original
|
||||
* formatting, we don't want to change that whitespace.
|
||||
*
|
||||
* // eslint-disable-line rule-one , rule-two , rule-three -- comment
|
||||
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
*/
|
||||
const listText = commentToken.value
|
||||
.slice(listStartOffset) // remove directive name and all whitespace before the list
|
||||
.split(/\s-{2,}\s/u)[0] // remove `-- comment`, if it exists
|
||||
.trimEnd(); // remove all whitespace after the list
|
||||
|
||||
/*
|
||||
* We can assume that `listText` contains multiple elements.
|
||||
* Otherwise, this function wouldn't be called - if there is
|
||||
* only one rule in the list, then the whole comment must be removed.
|
||||
*/
|
||||
|
||||
return directives.map(directive => {
|
||||
const { ruleId } = directive;
|
||||
|
||||
const regex = new RegExp(String.raw`(?:^|\s*,\s*)${escapeRegExp(ruleId)}(?:\s*,\s*|$)`, "u");
|
||||
const match = regex.exec(listText);
|
||||
const matchedText = match[0];
|
||||
const matchStartOffset = listStartOffset + match.index;
|
||||
const matchEndOffset = matchStartOffset + matchedText.length;
|
||||
|
||||
const firstIndexOfComma = matchedText.indexOf(",");
|
||||
const lastIndexOfComma = matchedText.lastIndexOf(",");
|
||||
|
||||
let removalStartOffset, removalEndOffset;
|
||||
|
||||
if (firstIndexOfComma !== lastIndexOfComma) {
|
||||
|
||||
/*
|
||||
* Since there are two commas, this must one of the elements in the middle of the list.
|
||||
* Matched range starts where the previous rule name ends, and ends where the next rule name starts.
|
||||
*
|
||||
* // eslint-disable-line rule-one , rule-two , rule-three -- comment
|
||||
* ^^^^^^^^^^^^^^
|
||||
*
|
||||
* We want to remove only the content between the two commas, and also one of the commas.
|
||||
*
|
||||
* // eslint-disable-line rule-one , rule-two , rule-three -- comment
|
||||
* ^^^^^^^^^^^
|
||||
*/
|
||||
removalStartOffset = matchStartOffset + firstIndexOfComma;
|
||||
removalEndOffset = matchStartOffset + lastIndexOfComma;
|
||||
|
||||
} else {
|
||||
|
||||
/*
|
||||
* This is either the first element or the last element.
|
||||
*
|
||||
* If this is the first element, matched range starts where the first rule name starts
|
||||
* and ends where the second rule name starts. This is exactly the range we want
|
||||
* to remove so that the second rule name will start where the first one was starting
|
||||
* and thus preserve the original formatting.
|
||||
*
|
||||
* // eslint-disable-line rule-one , rule-two , rule-three -- comment
|
||||
* ^^^^^^^^^^^
|
||||
*
|
||||
* Similarly, if this is the last element, we've already matched the range we want to
|
||||
* remove. The previous rule name will end where the last one was ending, relative
|
||||
* to the content on the right side.
|
||||
*
|
||||
* // eslint-disable-line rule-one , rule-two , rule-three -- comment
|
||||
* ^^^^^^^^^^^^^
|
||||
*/
|
||||
removalStartOffset = matchStartOffset;
|
||||
removalEndOffset = matchEndOffset;
|
||||
}
|
||||
|
||||
return {
|
||||
description: `'${ruleId}'`,
|
||||
fix: {
|
||||
range: [
|
||||
commentValueStart + removalStartOffset,
|
||||
commentValueStart + removalEndOffset
|
||||
],
|
||||
text: ""
|
||||
},
|
||||
unprocessedDirective: directive.unprocessedDirective
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a description of deleting an entire unused disable comment.
|
||||
* @param {Directive[]} directives Unused directives to be removed.
|
||||
* @param {Token} commentToken The backing Comment token.
|
||||
* @returns {{ description, fix, unprocessedDirective }} Details for later creation of an output Problem.
|
||||
*/
|
||||
function createCommentRemoval(directives, commentToken) {
|
||||
const { range } = commentToken;
|
||||
const ruleIds = directives.filter(directive => directive.ruleId).map(directive => `'${directive.ruleId}'`);
|
||||
|
||||
return {
|
||||
description: ruleIds.length <= 2
|
||||
? ruleIds.join(" or ")
|
||||
: `${ruleIds.slice(0, ruleIds.length - 1).join(", ")}, or ${ruleIds[ruleIds.length - 1]}`,
|
||||
fix: {
|
||||
range,
|
||||
text: " "
|
||||
},
|
||||
unprocessedDirective: directives[0].unprocessedDirective
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses details from directives to create output Problems.
|
||||
* @param {Directive[]} allDirectives Unused directives to be removed.
|
||||
* @returns {{ description, fix, unprocessedDirective }[]} Details for later creation of output Problems.
|
||||
*/
|
||||
function processUnusedDisableDirectives(allDirectives) {
|
||||
const directiveGroups = groupByParentComment(allDirectives);
|
||||
|
||||
return directiveGroups.flatMap(
|
||||
directives => {
|
||||
const { parentComment } = directives[0].unprocessedDirective;
|
||||
const remainingRuleIds = new Set(parentComment.ruleIds);
|
||||
|
||||
for (const directive of directives) {
|
||||
remainingRuleIds.delete(directive.ruleId);
|
||||
}
|
||||
|
||||
return remainingRuleIds.size
|
||||
? createIndividualDirectivesRemoval(directives, parentComment.commentToken)
|
||||
: [createCommentRemoval(directives, parentComment.commentToken)];
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the same as the exported function, except that it
|
||||
* doesn't handle disable-line and disable-next-line directives, and it always reports unused
|
||||
|
|
@ -24,119 +197,106 @@ function compareLocations(itemA, itemB) {
|
|||
* for the exported function, except that `reportUnusedDisableDirectives` is not supported
|
||||
* (this function always reports unused disable directives).
|
||||
* @returns {{problems: Problem[], unusedDisableDirectives: Problem[]}} An object with a list
|
||||
* of filtered problems and unused eslint-disable directives
|
||||
* of problems (including suppressed ones) and unused eslint-disable directives
|
||||
*/
|
||||
function applyDirectives(options) {
|
||||
const problems = [];
|
||||
let nextDirectiveIndex = 0;
|
||||
let currentGlobalDisableDirective = null;
|
||||
const disabledRuleMap = new Map();
|
||||
|
||||
// enabledRules is only used when there is a current global disable directive.
|
||||
const enabledRules = new Set();
|
||||
const usedDisableDirectives = new Set();
|
||||
|
||||
for (const problem of options.problems) {
|
||||
let disableDirectivesForProblem = [];
|
||||
let nextDirectiveIndex = 0;
|
||||
|
||||
while (
|
||||
nextDirectiveIndex < options.directives.length &&
|
||||
compareLocations(options.directives[nextDirectiveIndex], problem) <= 0
|
||||
) {
|
||||
const directive = options.directives[nextDirectiveIndex++];
|
||||
|
||||
switch (directive.type) {
|
||||
case "disable":
|
||||
if (directive.ruleId === null) {
|
||||
currentGlobalDisableDirective = directive;
|
||||
disabledRuleMap.clear();
|
||||
enabledRules.clear();
|
||||
} else if (currentGlobalDisableDirective) {
|
||||
enabledRules.delete(directive.ruleId);
|
||||
disabledRuleMap.set(directive.ruleId, directive);
|
||||
} else {
|
||||
disabledRuleMap.set(directive.ruleId, directive);
|
||||
}
|
||||
break;
|
||||
if (directive.ruleId === null || directive.ruleId === problem.ruleId) {
|
||||
switch (directive.type) {
|
||||
case "disable":
|
||||
disableDirectivesForProblem.push(directive);
|
||||
break;
|
||||
|
||||
case "enable":
|
||||
if (directive.ruleId === null) {
|
||||
currentGlobalDisableDirective = null;
|
||||
disabledRuleMap.clear();
|
||||
} else if (currentGlobalDisableDirective) {
|
||||
enabledRules.add(directive.ruleId);
|
||||
disabledRuleMap.delete(directive.ruleId);
|
||||
} else {
|
||||
disabledRuleMap.delete(directive.ruleId);
|
||||
}
|
||||
break;
|
||||
case "enable":
|
||||
disableDirectivesForProblem = [];
|
||||
break;
|
||||
|
||||
// no default
|
||||
// no default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (disabledRuleMap.has(problem.ruleId)) {
|
||||
usedDisableDirectives.add(disabledRuleMap.get(problem.ruleId));
|
||||
} else if (currentGlobalDisableDirective && !enabledRules.has(problem.ruleId)) {
|
||||
usedDisableDirectives.add(currentGlobalDisableDirective);
|
||||
} else {
|
||||
problems.push(problem);
|
||||
if (disableDirectivesForProblem.length > 0) {
|
||||
const suppressions = disableDirectivesForProblem.map(directive => ({
|
||||
kind: "directive",
|
||||
justification: directive.unprocessedDirective.justification
|
||||
}));
|
||||
|
||||
if (problem.suppressions) {
|
||||
problem.suppressions = problem.suppressions.concat(suppressions);
|
||||
} else {
|
||||
problem.suppressions = suppressions;
|
||||
usedDisableDirectives.add(disableDirectivesForProblem[disableDirectivesForProblem.length - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
problems.push(problem);
|
||||
}
|
||||
|
||||
const unusedDisableDirectives = options.directives
|
||||
.filter(directive => directive.type === "disable" && !usedDisableDirectives.has(directive))
|
||||
.map(directive => ({
|
||||
ruleId: null,
|
||||
message: directive.ruleId
|
||||
? `Unused eslint-disable directive (no problems were reported from '${directive.ruleId}').`
|
||||
: "Unused eslint-disable directive (no problems were reported).",
|
||||
line: directive.unprocessedDirective.line,
|
||||
column: directive.unprocessedDirective.column,
|
||||
severity: options.reportUnusedDisableDirectives === "warn" ? 1 : 2,
|
||||
nodeType: null
|
||||
}));
|
||||
const unusedDisableDirectivesToReport = options.directives
|
||||
.filter(directive => directive.type === "disable" && !usedDisableDirectives.has(directive));
|
||||
|
||||
const processed = processUnusedDisableDirectives(unusedDisableDirectivesToReport);
|
||||
|
||||
const unusedDisableDirectives = processed
|
||||
.map(({ description, fix, unprocessedDirective }) => {
|
||||
const { parentComment, type, line, column } = unprocessedDirective;
|
||||
|
||||
return {
|
||||
ruleId: null,
|
||||
message: description
|
||||
? `Unused eslint-disable directive (no problems were reported from ${description}).`
|
||||
: "Unused eslint-disable directive (no problems were reported).",
|
||||
line: type === "disable-next-line" ? parentComment.commentToken.loc.start.line : line,
|
||||
column: type === "disable-next-line" ? parentComment.commentToken.loc.start.column + 1 : column,
|
||||
severity: options.reportUnusedDisableDirectives === "warn" ? 1 : 2,
|
||||
nodeType: null,
|
||||
...options.disableFixes ? {} : { fix }
|
||||
};
|
||||
});
|
||||
|
||||
return { problems, unusedDisableDirectives };
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list of directive comments (i.e. metadata about eslint-disable and eslint-enable comments) and a list
|
||||
* of reported problems, determines which problems should be reported.
|
||||
* of reported problems, adds the suppression information to the problems.
|
||||
* @param {Object} options Information about directives and problems
|
||||
* @param {{
|
||||
* type: ("disable"|"enable"|"disable-line"|"disable-next-line"),
|
||||
* ruleId: (string|null),
|
||||
* line: number,
|
||||
* column: number
|
||||
* column: number,
|
||||
* justification: string
|
||||
* }} options.directives Directive comments found in the file, with one-based columns.
|
||||
* Two directive comments can only have the same location if they also have the same type (e.g. a single eslint-disable
|
||||
* comment for two different rules is represented as two directives).
|
||||
* @param {{ruleId: (string|null), line: number, column: number}[]} options.problems
|
||||
* A list of problems reported by rules, sorted by increasing location in the file, with one-based columns.
|
||||
* @param {"off" | "warn" | "error"} options.reportUnusedDisableDirectives If `"warn"` or `"error"`, adds additional problems for unused directives
|
||||
* @returns {{ruleId: (string|null), line: number, column: number}[]}
|
||||
* A list of reported problems that were not disabled by the directive comments.
|
||||
* @param {boolean} options.disableFixes If true, it doesn't make `fix` properties.
|
||||
* @returns {{ruleId: (string|null), line: number, column: number, suppressions?: {kind: string, justification: string}}[]}
|
||||
* An object with a list of reported problems, the suppressed of which contain the suppression information.
|
||||
*/
|
||||
module.exports = ({ directives, problems, reportUnusedDisableDirectives = "off" }) => {
|
||||
module.exports = ({ directives, disableFixes, problems, reportUnusedDisableDirectives = "off" }) => {
|
||||
const blockDirectives = directives
|
||||
.filter(directive => directive.type === "disable" || directive.type === "enable")
|
||||
.map(directive => Object.assign({}, directive, { unprocessedDirective: directive }))
|
||||
.sort(compareLocations);
|
||||
|
||||
/**
|
||||
* Returns a new array formed by applying a given callback function to each element of the array, and then flattening the result by one level.
|
||||
* TODO(stephenwade): Replace this with array.flatMap when we drop support for Node v10
|
||||
* @param {any[]} array The array to process
|
||||
* @param {Function} fn The function to use
|
||||
* @returns {any[]} The result array
|
||||
*/
|
||||
function flatMap(array, fn) {
|
||||
const mapped = array.map(fn);
|
||||
const flattened = [].concat(...mapped);
|
||||
|
||||
return flattened;
|
||||
}
|
||||
|
||||
const lineDirectives = flatMap(directives, directive => {
|
||||
const lineDirectives = directives.flatMap(directive => {
|
||||
switch (directive.type) {
|
||||
case "disable":
|
||||
case "enable":
|
||||
|
|
@ -162,11 +322,13 @@ module.exports = ({ directives, problems, reportUnusedDisableDirectives = "off"
|
|||
const blockDirectivesResult = applyDirectives({
|
||||
problems,
|
||||
directives: blockDirectives,
|
||||
disableFixes,
|
||||
reportUnusedDisableDirectives
|
||||
});
|
||||
const lineDirectivesResult = applyDirectives({
|
||||
problems: blockDirectivesResult.problems,
|
||||
directives: lineDirectives,
|
||||
disableFixes,
|
||||
reportUnusedDisableDirectives
|
||||
});
|
||||
|
||||
|
|
|
|||
156
node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js
generated
vendored
156
node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js
generated
vendored
|
|
@ -29,6 +29,18 @@ function isCaseNode(node) {
|
|||
return Boolean(node.test);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given node appears as the value of a PropertyDefinition node.
|
||||
* @param {ASTNode} node THe node to check.
|
||||
* @returns {boolean} `true` if the node is a PropertyDefinition value,
|
||||
* false if not.
|
||||
*/
|
||||
function isPropertyDefinitionValue(node) {
|
||||
const parent = node.parent;
|
||||
|
||||
return parent && parent.type === "PropertyDefinition" && parent.value === node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given logical operator is taken into account for the code
|
||||
* path analysis.
|
||||
|
|
@ -138,6 +150,7 @@ function isIdentifierReference(node) {
|
|||
return parent.id !== node;
|
||||
|
||||
case "Property":
|
||||
case "PropertyDefinition":
|
||||
case "MethodDefinition":
|
||||
return (
|
||||
parent.key !== node ||
|
||||
|
|
@ -388,29 +401,68 @@ function processCodePathToEnter(analyzer, node) {
|
|||
let state = codePath && CodePath.getState(codePath);
|
||||
const parent = node.parent;
|
||||
|
||||
/**
|
||||
* Creates a new code path and trigger the onCodePathStart event
|
||||
* based on the currently selected node.
|
||||
* @param {string} origin The reason the code path was started.
|
||||
* @returns {void}
|
||||
*/
|
||||
function startCodePath(origin) {
|
||||
if (codePath) {
|
||||
|
||||
// Emits onCodePathSegmentStart events if updated.
|
||||
forwardCurrentToHead(analyzer, node);
|
||||
debug.dumpState(node, state, false);
|
||||
}
|
||||
|
||||
// Create the code path of this scope.
|
||||
codePath = analyzer.codePath = new CodePath({
|
||||
id: analyzer.idGenerator.next(),
|
||||
origin,
|
||||
upper: codePath,
|
||||
onLooped: analyzer.onLooped
|
||||
});
|
||||
state = CodePath.getState(codePath);
|
||||
|
||||
// Emits onCodePathStart events.
|
||||
debug.dump(`onCodePathStart ${codePath.id}`);
|
||||
analyzer.emitter.emit("onCodePathStart", codePath, node);
|
||||
}
|
||||
|
||||
/*
|
||||
* Special case: The right side of class field initializer is considered
|
||||
* to be its own function, so we need to start a new code path in this
|
||||
* case.
|
||||
*/
|
||||
if (isPropertyDefinitionValue(node)) {
|
||||
startCodePath("class-field-initializer");
|
||||
|
||||
/*
|
||||
* Intentional fall through because `node` needs to also be
|
||||
* processed by the code below. For example, if we have:
|
||||
*
|
||||
* class Foo {
|
||||
* a = () => {}
|
||||
* }
|
||||
*
|
||||
* In this case, we also need start a second code path.
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
switch (node.type) {
|
||||
case "Program":
|
||||
startCodePath("program");
|
||||
break;
|
||||
|
||||
case "FunctionDeclaration":
|
||||
case "FunctionExpression":
|
||||
case "ArrowFunctionExpression":
|
||||
if (codePath) {
|
||||
startCodePath("function");
|
||||
break;
|
||||
|
||||
// Emits onCodePathSegmentStart events if updated.
|
||||
forwardCurrentToHead(analyzer, node);
|
||||
debug.dumpState(node, state, false);
|
||||
}
|
||||
|
||||
// Create the code path of this scope.
|
||||
codePath = analyzer.codePath = new CodePath(
|
||||
analyzer.idGenerator.next(),
|
||||
codePath,
|
||||
analyzer.onLooped
|
||||
);
|
||||
state = CodePath.getState(codePath);
|
||||
|
||||
// Emits onCodePathStart events.
|
||||
debug.dump(`onCodePathStart ${codePath.id}`);
|
||||
analyzer.emitter.emit("onCodePathStart", codePath, node);
|
||||
case "StaticBlock":
|
||||
startCodePath("class-static-block");
|
||||
break;
|
||||
|
||||
case "ChainExpression":
|
||||
|
|
@ -503,6 +555,7 @@ function processCodePathToEnter(analyzer, node) {
|
|||
* @returns {void}
|
||||
*/
|
||||
function processCodePathToExit(analyzer, node) {
|
||||
|
||||
const codePath = analyzer.codePath;
|
||||
const state = CodePath.getState(codePath);
|
||||
let dontForward = false;
|
||||
|
|
@ -627,28 +680,39 @@ function processCodePathToExit(analyzer, node) {
|
|||
* @returns {void}
|
||||
*/
|
||||
function postprocess(analyzer, node) {
|
||||
|
||||
/**
|
||||
* Ends the code path for the current node.
|
||||
* @returns {void}
|
||||
*/
|
||||
function endCodePath() {
|
||||
let codePath = analyzer.codePath;
|
||||
|
||||
// Mark the current path as the final node.
|
||||
CodePath.getState(codePath).makeFinal();
|
||||
|
||||
// Emits onCodePathSegmentEnd event of the current segments.
|
||||
leaveFromCurrentSegment(analyzer, node);
|
||||
|
||||
// Emits onCodePathEnd event of this code path.
|
||||
debug.dump(`onCodePathEnd ${codePath.id}`);
|
||||
analyzer.emitter.emit("onCodePathEnd", codePath, node);
|
||||
debug.dumpDot(codePath);
|
||||
|
||||
codePath = analyzer.codePath = analyzer.codePath.upper;
|
||||
if (codePath) {
|
||||
debug.dumpState(node, CodePath.getState(codePath), true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
switch (node.type) {
|
||||
case "Program":
|
||||
case "FunctionDeclaration":
|
||||
case "FunctionExpression":
|
||||
case "ArrowFunctionExpression": {
|
||||
let codePath = analyzer.codePath;
|
||||
|
||||
// Mark the current path as the final node.
|
||||
CodePath.getState(codePath).makeFinal();
|
||||
|
||||
// Emits onCodePathSegmentEnd event of the current segments.
|
||||
leaveFromCurrentSegment(analyzer, node);
|
||||
|
||||
// Emits onCodePathEnd event of this code path.
|
||||
debug.dump(`onCodePathEnd ${codePath.id}`);
|
||||
analyzer.emitter.emit("onCodePathEnd", codePath, node);
|
||||
debug.dumpDot(codePath);
|
||||
|
||||
codePath = analyzer.codePath = analyzer.codePath.upper;
|
||||
if (codePath) {
|
||||
debug.dumpState(node, CodePath.getState(codePath), true);
|
||||
}
|
||||
case "ArrowFunctionExpression":
|
||||
case "StaticBlock": {
|
||||
endCodePath();
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -662,6 +726,27 @@ function postprocess(analyzer, node) {
|
|||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Special case: The right side of class field initializer is considered
|
||||
* to be its own function, so we need to end a code path in this
|
||||
* case.
|
||||
*
|
||||
* We need to check after the other checks in order to close the
|
||||
* code paths in the correct order for code like this:
|
||||
*
|
||||
*
|
||||
* class Foo {
|
||||
* a = () => {}
|
||||
* }
|
||||
*
|
||||
* In this case, The ArrowFunctionExpression code path is closed first
|
||||
* and then we need to close the code path for the PropertyDefinition
|
||||
* value.
|
||||
*/
|
||||
if (isPropertyDefinitionValue(node)) {
|
||||
endCodePath();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -674,7 +759,6 @@ function postprocess(analyzer, node) {
|
|||
*/
|
||||
class CodePathAnalyzer {
|
||||
|
||||
// eslint-disable-next-line jsdoc/require-description
|
||||
/**
|
||||
* @param {EventGenerator} eventGenerator An event generator to wrap.
|
||||
*/
|
||||
|
|
|
|||
7
node_modules/eslint/lib/linter/code-path-analysis/code-path-segment.js
generated
vendored
7
node_modules/eslint/lib/linter/code-path-analysis/code-path-segment.js
generated
vendored
|
|
@ -33,7 +33,6 @@ function isReachable(segment) {
|
|||
*/
|
||||
class CodePathSegment {
|
||||
|
||||
// eslint-disable-next-line jsdoc/require-description
|
||||
/**
|
||||
* @param {string} id An identifier.
|
||||
* @param {CodePathSegment[]} allPrevSegments An array of the previous segments.
|
||||
|
|
@ -89,10 +88,10 @@ class CodePathSegment {
|
|||
}
|
||||
});
|
||||
|
||||
/* istanbul ignore if */
|
||||
/* c8 ignore start */
|
||||
if (debug.enabled) {
|
||||
this.internal.nodes = [];
|
||||
}
|
||||
}/* c8 ignore stop */
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -101,7 +100,7 @@ class CodePathSegment {
|
|||
* @returns {boolean} `true` if the segment is coming from the end of a loop.
|
||||
*/
|
||||
isLoopedPrevSegment(segment) {
|
||||
return this.internal.loopedPrevSegments.indexOf(segment) !== -1;
|
||||
return this.internal.loopedPrevSegments.includes(segment);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
21
node_modules/eslint/lib/linter/code-path-analysis/code-path-state.js
generated
vendored
21
node_modules/eslint/lib/linter/code-path-analysis/code-path-state.js
generated
vendored
|
|
@ -33,7 +33,7 @@ function addToReturnedOrThrown(dest, others, all, segments) {
|
|||
const segment = segments[i];
|
||||
|
||||
dest.push(segment);
|
||||
if (others.indexOf(segment) === -1) {
|
||||
if (!others.includes(segment)) {
|
||||
all.push(segment);
|
||||
}
|
||||
}
|
||||
|
|
@ -59,7 +59,7 @@ function getContinueContext(state, label) {
|
|||
context = context.upper;
|
||||
}
|
||||
|
||||
/* istanbul ignore next: foolproof (syntax error) */
|
||||
/* c8 ignore next */
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ function getBreakContext(state, label) {
|
|||
context = context.upper;
|
||||
}
|
||||
|
||||
/* istanbul ignore next: foolproof (syntax error) */
|
||||
/* c8 ignore next */
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -219,7 +219,6 @@ function finalizeTestSegmentsOfFor(context, choiceContext, head) {
|
|||
*/
|
||||
class CodePathState {
|
||||
|
||||
// eslint-disable-next-line jsdoc/require-description
|
||||
/**
|
||||
* @param {IdGenerator} idGenerator An id generator to generate id for code
|
||||
* path segments.
|
||||
|
|
@ -360,6 +359,7 @@ class CodePathState {
|
|||
|
||||
/**
|
||||
* Pops the last choice context and finalizes it.
|
||||
* @throws {Error} (Unreachable.)
|
||||
* @returns {ChoiceContext} The popped context.
|
||||
*/
|
||||
popChoiceContext() {
|
||||
|
|
@ -433,7 +433,7 @@ class CodePathState {
|
|||
*/
|
||||
return context;
|
||||
|
||||
/* istanbul ignore next */
|
||||
/* c8 ignore next */
|
||||
default:
|
||||
throw new Error("unreachable");
|
||||
}
|
||||
|
|
@ -450,6 +450,7 @@ class CodePathState {
|
|||
/**
|
||||
* Makes a code path segment of the right-hand operand of a logical
|
||||
* expression.
|
||||
* @throws {Error} (Unreachable.)
|
||||
* @returns {void}
|
||||
*/
|
||||
makeLogicalRight() {
|
||||
|
|
@ -965,6 +966,7 @@ class CodePathState {
|
|||
* `WhileStatement`, `DoWhileStatement`, `ForStatement`, `ForInStatement`,
|
||||
* and `ForStatement`.
|
||||
* @param {string|null} label A label of the node which was triggered.
|
||||
* @throws {Error} (Unreachable - unknown type.)
|
||||
* @returns {void}
|
||||
*/
|
||||
pushLoopContext(type, label) {
|
||||
|
|
@ -1028,7 +1030,7 @@ class CodePathState {
|
|||
};
|
||||
break;
|
||||
|
||||
/* istanbul ignore next */
|
||||
/* c8 ignore next */
|
||||
default:
|
||||
throw new Error(`unknown type: "${type}"`);
|
||||
}
|
||||
|
|
@ -1036,6 +1038,7 @@ class CodePathState {
|
|||
|
||||
/**
|
||||
* Pops the last context of a loop statement and finalizes it.
|
||||
* @throws {Error} (Unreachable - unknown type.)
|
||||
* @returns {void}
|
||||
*/
|
||||
popLoopContext() {
|
||||
|
|
@ -1092,7 +1095,7 @@ class CodePathState {
|
|||
);
|
||||
break;
|
||||
|
||||
/* istanbul ignore next */
|
||||
/* c8 ignore next */
|
||||
default:
|
||||
throw new Error("unreachable");
|
||||
}
|
||||
|
|
@ -1389,11 +1392,12 @@ class CodePathState {
|
|||
|
||||
const context = getBreakContext(this, label);
|
||||
|
||||
/* istanbul ignore else: foolproof (syntax error) */
|
||||
|
||||
if (context) {
|
||||
context.brokenForkContext.add(forkContext.head);
|
||||
}
|
||||
|
||||
/* c8 ignore next */
|
||||
forkContext.replaceHead(forkContext.makeUnreachable(-1, -1));
|
||||
}
|
||||
|
||||
|
|
@ -1414,7 +1418,6 @@ class CodePathState {
|
|||
|
||||
const context = getContinueContext(this, label);
|
||||
|
||||
/* istanbul ignore else: foolproof (syntax error) */
|
||||
if (context) {
|
||||
if (context.continueDestSegments) {
|
||||
makeLooped(this, forkContext.head, context.continueDestSegments);
|
||||
|
|
|
|||
21
node_modules/eslint/lib/linter/code-path-analysis/code-path.js
generated
vendored
21
node_modules/eslint/lib/linter/code-path-analysis/code-path.js
generated
vendored
|
|
@ -21,13 +21,15 @@ const IdGenerator = require("./id-generator");
|
|||
*/
|
||||
class CodePath {
|
||||
|
||||
// eslint-disable-next-line jsdoc/require-description
|
||||
/**
|
||||
* @param {string} id An identifier.
|
||||
* @param {CodePath|null} upper The code path of the upper function scope.
|
||||
* @param {Function} onLooped A callback function to notify looping.
|
||||
* Creates a new instance.
|
||||
* @param {Object} options Options for the function (see below).
|
||||
* @param {string} options.id An identifier.
|
||||
* @param {string} options.origin The type of code path origin.
|
||||
* @param {CodePath|null} options.upper The code path of the upper function scope.
|
||||
* @param {Function} options.onLooped A callback function to notify looping.
|
||||
*/
|
||||
constructor(id, upper, onLooped) {
|
||||
constructor({ id, origin, upper, onLooped }) {
|
||||
|
||||
/**
|
||||
* The identifier of this code path.
|
||||
|
|
@ -36,6 +38,13 @@ class CodePath {
|
|||
*/
|
||||
this.id = id;
|
||||
|
||||
/**
|
||||
* The reason that this code path was started. May be "program",
|
||||
* "function", "class-field-initializer", or "class-static-block".
|
||||
* @type {string}
|
||||
*/
|
||||
this.origin = origin;
|
||||
|
||||
/**
|
||||
* The code path of the upper function scope.
|
||||
* @type {CodePath|null}
|
||||
|
|
@ -203,7 +212,7 @@ class CodePath {
|
|||
}
|
||||
|
||||
// Reset the flag of skipping if all branches have been skipped.
|
||||
if (skippedSegment && segment.prevSegments.indexOf(skippedSegment) !== -1) {
|
||||
if (skippedSegment && segment.prevSegments.includes(skippedSegment)) {
|
||||
skippedSegment = null;
|
||||
}
|
||||
visited[segment.id] = true;
|
||||
|
|
|
|||
10
node_modules/eslint/lib/linter/code-path-analysis/debug-helpers.js
generated
vendored
10
node_modules/eslint/lib/linter/code-path-analysis/debug-helpers.js
generated
vendored
|
|
@ -20,8 +20,8 @@ const debug = require("debug")("eslint:code-path");
|
|||
* @param {CodePathSegment} segment A segment to get.
|
||||
* @returns {string} Id of the segment.
|
||||
*/
|
||||
/* istanbul ignore next */
|
||||
function getId(segment) { // eslint-disable-line jsdoc/require-jsdoc
|
||||
/* c8 ignore next */
|
||||
function getId(segment) { // eslint-disable-line jsdoc/require-jsdoc -- Ignoring
|
||||
return segment.id + (segment.reachable ? "" : "!");
|
||||
}
|
||||
|
||||
|
|
@ -67,7 +67,7 @@ module.exports = {
|
|||
* @param {boolean} leaving A flag whether or not it's leaving
|
||||
* @returns {void}
|
||||
*/
|
||||
dumpState: !debug.enabled ? debug : /* istanbul ignore next */ function(node, state, leaving) {
|
||||
dumpState: !debug.enabled ? debug : /* c8 ignore next */ function(node, state, leaving) {
|
||||
for (let i = 0; i < state.currentSegments.length; ++i) {
|
||||
const segInternal = state.currentSegments[i].internal;
|
||||
|
||||
|
|
@ -98,7 +98,7 @@ module.exports = {
|
|||
* @see http://www.graphviz.org
|
||||
* @see http://www.webgraphviz.com
|
||||
*/
|
||||
dumpDot: !debug.enabled ? debug : /* istanbul ignore next */ function(codePath) {
|
||||
dumpDot: !debug.enabled ? debug : /* c8 ignore next */ function(codePath) {
|
||||
let text =
|
||||
"\n" +
|
||||
"digraph {\n" +
|
||||
|
|
@ -115,7 +115,7 @@ module.exports = {
|
|||
const traceMap = Object.create(null);
|
||||
const arrows = this.makeDotArrows(codePath, traceMap);
|
||||
|
||||
for (const id in traceMap) { // eslint-disable-line guard-for-in
|
||||
for (const id in traceMap) { // eslint-disable-line guard-for-in -- Want ability to traverse prototype
|
||||
const segment = traceMap[id];
|
||||
|
||||
text += `${id}[`;
|
||||
|
|
|
|||
1
node_modules/eslint/lib/linter/code-path-analysis/fork-context.js
generated
vendored
1
node_modules/eslint/lib/linter/code-path-analysis/fork-context.js
generated
vendored
|
|
@ -97,7 +97,6 @@ function mergeExtraSegments(context, segments) {
|
|||
*/
|
||||
class ForkContext {
|
||||
|
||||
// eslint-disable-next-line jsdoc/require-description
|
||||
/**
|
||||
* @param {IdGenerator} idGenerator An identifier generator for segments.
|
||||
* @param {ForkContext|null} upper An upper fork context.
|
||||
|
|
|
|||
5
node_modules/eslint/lib/linter/code-path-analysis/id-generator.js
generated
vendored
5
node_modules/eslint/lib/linter/code-path-analysis/id-generator.js
generated
vendored
|
|
@ -18,7 +18,6 @@
|
|||
*/
|
||||
class IdGenerator {
|
||||
|
||||
// eslint-disable-next-line jsdoc/require-description
|
||||
/**
|
||||
* @param {string} prefix Optional. A prefix of generated ids.
|
||||
*/
|
||||
|
|
@ -34,10 +33,10 @@ class IdGenerator {
|
|||
next() {
|
||||
this.n = 1 + this.n | 0;
|
||||
|
||||
/* istanbul ignore if */
|
||||
/* c8 ignore start */
|
||||
if (this.n < 0) {
|
||||
this.n = 1;
|
||||
}
|
||||
}/* c8 ignore stop */
|
||||
|
||||
return this.prefix + this.n;
|
||||
}
|
||||
|
|
|
|||
11
node_modules/eslint/lib/linter/config-comment-parser.js
generated
vendored
11
node_modules/eslint/lib/linter/config-comment-parser.js
generated
vendored
|
|
@ -3,7 +3,7 @@
|
|||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
/* eslint-disable class-methods-use-this*/
|
||||
/* eslint class-methods-use-this: off -- Methods desired on instance */
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -11,7 +11,11 @@
|
|||
//------------------------------------------------------------------------------
|
||||
|
||||
const levn = require("levn"),
|
||||
ConfigOps = require("@eslint/eslintrc/lib/shared/config-ops");
|
||||
{
|
||||
Legacy: {
|
||||
ConfigOps
|
||||
}
|
||||
} = require("@eslint/eslintrc/universal");
|
||||
|
||||
const debug = require("debug")("eslint:config-comment-parser");
|
||||
|
||||
|
|
@ -127,8 +131,7 @@ module.exports = class ConfigCommentParser {
|
|||
|
||||
const items = {};
|
||||
|
||||
// Collapse whitespace around commas
|
||||
string.replace(/\s*,\s*/gu, ",").split(/,+/u).forEach(name => {
|
||||
string.split(",").forEach(name => {
|
||||
const trimmedName = name.trim();
|
||||
|
||||
if (trimmedName) {
|
||||
|
|
|
|||
793
node_modules/eslint/lib/linter/linter.js
generated
vendored
793
node_modules/eslint/lib/linter/linter.js
generated
vendored
File diff suppressed because it is too large
Load diff
12
node_modules/eslint/lib/linter/node-event-generator.js
generated
vendored
12
node_modules/eslint/lib/linter/node-event-generator.js
generated
vendored
|
|
@ -37,9 +37,7 @@ const esquery = require("esquery");
|
|||
* @returns {any[]} The union of the input arrays
|
||||
*/
|
||||
function union(...arrays) {
|
||||
|
||||
// TODO(stephenwade): Replace this with arrays.flat() when we drop support for Node v10
|
||||
return [...new Set([].concat(...arrays))];
|
||||
return [...new Set(arrays.flat())];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -100,6 +98,13 @@ function getPossibleTypes(parsedSelector) {
|
|||
case "adjacent":
|
||||
return getPossibleTypes(parsedSelector.right);
|
||||
|
||||
case "class":
|
||||
if (parsedSelector.name === "function") {
|
||||
return ["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"];
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
default:
|
||||
return null;
|
||||
|
||||
|
|
@ -239,7 +244,6 @@ function parseSelector(rawSelector) {
|
|||
*/
|
||||
class NodeEventGenerator {
|
||||
|
||||
// eslint-disable-next-line jsdoc/require-description
|
||||
/**
|
||||
* @param {SafeEmitter} emitter
|
||||
* An SafeEmitter which is the destination of events. This emitter must already
|
||||
|
|
|
|||
24
node_modules/eslint/lib/linter/report-translator.js
generated
vendored
24
node_modules/eslint/lib/linter/report-translator.js
generated
vendored
|
|
@ -32,18 +32,18 @@ const interpolate = require("./interpolate");
|
|||
/**
|
||||
* Information about the report
|
||||
* @typedef {Object} ReportInfo
|
||||
* @property {string} ruleId
|
||||
* @property {(0|1|2)} severity
|
||||
* @property {(string|undefined)} message
|
||||
* @property {(string|undefined)} [messageId]
|
||||
* @property {number} line
|
||||
* @property {number} column
|
||||
* @property {(number|undefined)} [endLine]
|
||||
* @property {(number|undefined)} [endColumn]
|
||||
* @property {(string|null)} nodeType
|
||||
* @property {string} source
|
||||
* @property {({text: string, range: (number[]|null)}|null)} [fix]
|
||||
* @property {Array<{text: string, range: (number[]|null)}|null>} [suggestions]
|
||||
* @property {string} ruleId The rule ID
|
||||
* @property {(0|1|2)} severity Severity of the error
|
||||
* @property {(string|undefined)} message The message
|
||||
* @property {(string|undefined)} [messageId] The message ID
|
||||
* @property {number} line The line number
|
||||
* @property {number} column The column number
|
||||
* @property {(number|undefined)} [endLine] The ending line number
|
||||
* @property {(number|undefined)} [endColumn] The ending column number
|
||||
* @property {(string|null)} nodeType Type of node
|
||||
* @property {string} source Source text
|
||||
* @property {({text: string, range: (number[]|null)}|null)} [fix] The fix object
|
||||
* @property {Array<{text: string, range: (number[]|null)}|null>} [suggestions] Suggestion info
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
|
|||
3
node_modules/eslint/lib/linter/rules.js
generated
vendored
3
node_modules/eslint/lib/linter/rules.js
generated
vendored
|
|
@ -30,6 +30,9 @@ function normalizeRule(rule) {
|
|||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A storage for rules.
|
||||
*/
|
||||
class Rules {
|
||||
constructor() {
|
||||
this._rules = Object.create(null);
|
||||
|
|
|
|||
4
node_modules/eslint/lib/linter/safe-emitter.js
generated
vendored
4
node_modules/eslint/lib/linter/safe-emitter.js
generated
vendored
|
|
@ -12,8 +12,8 @@
|
|||
/**
|
||||
* An event emitter
|
||||
* @typedef {Object} SafeEmitter
|
||||
* @property {function(eventName: string, listenerFunc: Function): void} on Adds a listener for a given event name
|
||||
* @property {function(eventName: string, arg1?: any, arg2?: any, arg3?: any)} emit Emits an event with a given name.
|
||||
* @property {(eventName: string, listenerFunc: Function) => void} on Adds a listener for a given event name
|
||||
* @property {(eventName: string, arg1?: any, arg2?: any, arg3?: any) => void} emit Emits an event with a given name.
|
||||
* This calls all the listeners that were listening for that name, with `arg1`, `arg2`, and `arg3` as arguments.
|
||||
* @property {function(): string[]} eventNames Gets the list of event names that have registered listeners.
|
||||
*/
|
||||
|
|
|
|||
4
node_modules/eslint/lib/linter/source-code-fixer.js
generated
vendored
4
node_modules/eslint/lib/linter/source-code-fixer.js
generated
vendored
|
|
@ -80,8 +80,8 @@ SourceCodeFixer.applyFixes = function(sourceText, messages, shouldFix) {
|
|||
|
||||
/**
|
||||
* Try to use the 'fix' from a problem.
|
||||
* @param {Message} problem The message object to apply fixes from
|
||||
* @returns {boolean} Whether fix was successfully applied
|
||||
* @param {Message} problem The message object to apply fixes from
|
||||
* @returns {boolean} Whether fix was successfully applied
|
||||
*/
|
||||
function attemptFix(problem) {
|
||||
const fix = problem.fix;
|
||||
|
|
|
|||
15
node_modules/eslint/lib/linter/timing.js
generated
vendored
15
node_modules/eslint/lib/linter/timing.js
generated
vendored
|
|
@ -9,7 +9,7 @@
|
|||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/* istanbul ignore next */
|
||||
/* c8 ignore next */
|
||||
/**
|
||||
* Align the string to left
|
||||
* @param {string} str string to evaluate
|
||||
|
|
@ -22,7 +22,7 @@ function alignLeft(str, len, ch) {
|
|||
return str + new Array(len - str.length + 1).join(ch || " ");
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
/* c8 ignore next */
|
||||
/**
|
||||
* Align the string to right
|
||||
* @param {string} str string to evaluate
|
||||
|
|
@ -64,7 +64,7 @@ function getListSize() {
|
|||
return TIMING_ENV_VAR_AS_INTEGER > 10 ? TIMING_ENV_VAR_AS_INTEGER : MINIMUM_SIZE;
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
/* c8 ignore next */
|
||||
/**
|
||||
* display the data
|
||||
* @param {Object} data Data object to be displayed
|
||||
|
|
@ -116,17 +116,17 @@ function display(data) {
|
|||
return ALIGN[index](":", width + extraAlignment, "-");
|
||||
}).join("|"));
|
||||
|
||||
console.log(table.join("\n")); // eslint-disable-line no-console
|
||||
console.log(table.join("\n")); // eslint-disable-line no-console -- Debugging function
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
/* c8 ignore next */
|
||||
module.exports = (function() {
|
||||
|
||||
const data = Object.create(null);
|
||||
|
||||
/**
|
||||
* Time the run
|
||||
* @param {*} key key from the data object
|
||||
* @param {any} key key from the data object
|
||||
* @param {Function} fn function to be called
|
||||
* @returns {Function} function to be executed
|
||||
* @private
|
||||
|
|
@ -138,10 +138,11 @@ module.exports = (function() {
|
|||
|
||||
return function(...args) {
|
||||
let t = process.hrtime();
|
||||
const result = fn(...args);
|
||||
|
||||
fn(...args);
|
||||
t = process.hrtime(t);
|
||||
data[key] += t[0] * 1e3 + t[1] / 1e6;
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
536
node_modules/eslint/lib/options.js
generated
vendored
536
node_modules/eslint/lib/options.js
generated
vendored
|
|
@ -32,7 +32,7 @@ const optionator = require("optionator");
|
|||
* @property {string[]} [ext] Specify JavaScript file extensions
|
||||
* @property {boolean} fix Automatically fix problems
|
||||
* @property {boolean} fixDryRun Automatically fix problems without saving the changes to the file system
|
||||
* @property {("problem" | "suggestion" | "layout")[]} [fixType] Specify the types of fixes to apply (problem, suggestion, layout)
|
||||
* @property {("directive" | "problem" | "suggestion" | "layout")[]} [fixType] Specify the types of fixes to apply (directive, problem, suggestion, layout)
|
||||
* @property {string} format Use a specific output format
|
||||
* @property {string[]} [global] Define global variables
|
||||
* @property {boolean} [help] Show help
|
||||
|
|
@ -50,7 +50,7 @@ const optionator = require("optionator");
|
|||
* @property {boolean | undefined} reportUnusedDisableDirectives Adds reported errors for unused eslint-disable directives
|
||||
* @property {string} [resolvePluginsRelativeTo] A folder where plugins should be resolved from, CWD by default
|
||||
* @property {Object} [rule] Specify rules
|
||||
* @property {string[]} [rulesdir] Use additional rules from this directory
|
||||
* @property {string[]} [rulesdir] Load additional rules from this directory. Deprecated: Use rules from plugins
|
||||
* @property {boolean} stdin Lint code provided on <STDIN>
|
||||
* @property {string} [stdinFilename] Specify filename to process STDIN as
|
||||
* @property {boolean} quiet Report errors only
|
||||
|
|
@ -63,261 +63,315 @@ const optionator = require("optionator");
|
|||
//------------------------------------------------------------------------------
|
||||
|
||||
// exports "parse(args)", "generateHelp()", and "generateHelpForOption(optionName)"
|
||||
module.exports = optionator({
|
||||
prepend: "eslint [options] file.js [file.js] [dir]",
|
||||
defaults: {
|
||||
concatRepeatedArrays: true,
|
||||
mergeRepeatedObjects: true
|
||||
},
|
||||
options: [
|
||||
{
|
||||
heading: "Basic configuration"
|
||||
},
|
||||
{
|
||||
|
||||
/**
|
||||
* Creates the CLI options for ESLint.
|
||||
* @param {boolean} usingFlatConfig Indicates if flat config is being used.
|
||||
* @returns {Object} The optionator instance.
|
||||
*/
|
||||
module.exports = function(usingFlatConfig) {
|
||||
|
||||
let lookupFlag;
|
||||
|
||||
if (usingFlatConfig) {
|
||||
lookupFlag = {
|
||||
option: "config-lookup",
|
||||
type: "Boolean",
|
||||
default: "true",
|
||||
description: "Disable look up for eslint.config.js"
|
||||
};
|
||||
} else {
|
||||
lookupFlag = {
|
||||
option: "eslintrc",
|
||||
type: "Boolean",
|
||||
default: "true",
|
||||
description: "Disable use of configuration from .eslintrc.*"
|
||||
},
|
||||
{
|
||||
option: "config",
|
||||
alias: "c",
|
||||
type: "path::String",
|
||||
description: "Use this configuration, overriding .eslintrc.* config options if present"
|
||||
},
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
let envFlag;
|
||||
|
||||
if (!usingFlatConfig) {
|
||||
envFlag = {
|
||||
option: "env",
|
||||
type: "[String]",
|
||||
description: "Specify environments"
|
||||
},
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
let extFlag;
|
||||
|
||||
if (!usingFlatConfig) {
|
||||
extFlag = {
|
||||
option: "ext",
|
||||
type: "[String]",
|
||||
description: "Specify JavaScript file extensions"
|
||||
},
|
||||
{
|
||||
option: "global",
|
||||
type: "[String]",
|
||||
description: "Define global variables"
|
||||
},
|
||||
{
|
||||
option: "parser",
|
||||
type: "String",
|
||||
description: "Specify the parser to be used"
|
||||
},
|
||||
{
|
||||
option: "parser-options",
|
||||
type: "Object",
|
||||
description: "Specify parser options"
|
||||
},
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
let resolvePluginsFlag;
|
||||
|
||||
if (!usingFlatConfig) {
|
||||
resolvePluginsFlag = {
|
||||
option: "resolve-plugins-relative-to",
|
||||
type: "path::String",
|
||||
description: "A folder where plugins should be resolved from, CWD by default"
|
||||
},
|
||||
{
|
||||
heading: "Specifying rules and plugins"
|
||||
},
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
let rulesDirFlag;
|
||||
|
||||
if (!usingFlatConfig) {
|
||||
rulesDirFlag = {
|
||||
option: "rulesdir",
|
||||
type: "[path::String]",
|
||||
description: "Use additional rules from this directory"
|
||||
},
|
||||
{
|
||||
option: "plugin",
|
||||
type: "[String]",
|
||||
description: "Specify plugins"
|
||||
},
|
||||
{
|
||||
option: "rule",
|
||||
type: "Object",
|
||||
description: "Specify rules"
|
||||
},
|
||||
{
|
||||
heading: "Fixing problems"
|
||||
},
|
||||
{
|
||||
option: "fix",
|
||||
type: "Boolean",
|
||||
default: false,
|
||||
description: "Automatically fix problems"
|
||||
},
|
||||
{
|
||||
option: "fix-dry-run",
|
||||
type: "Boolean",
|
||||
default: false,
|
||||
description: "Automatically fix problems without saving the changes to the file system"
|
||||
},
|
||||
{
|
||||
option: "fix-type",
|
||||
type: "Array",
|
||||
description: "Specify the types of fixes to apply (problem, suggestion, layout)"
|
||||
},
|
||||
{
|
||||
heading: "Ignoring files"
|
||||
},
|
||||
{
|
||||
description: "Load additional rules from this directory. Deprecated: Use rules from plugins"
|
||||
};
|
||||
}
|
||||
|
||||
let ignorePathFlag;
|
||||
|
||||
if (!usingFlatConfig) {
|
||||
ignorePathFlag = {
|
||||
option: "ignore-path",
|
||||
type: "path::String",
|
||||
description: "Specify path of ignore file"
|
||||
};
|
||||
}
|
||||
|
||||
return optionator({
|
||||
prepend: "eslint [options] file.js [file.js] [dir]",
|
||||
defaults: {
|
||||
concatRepeatedArrays: true,
|
||||
mergeRepeatedObjects: true
|
||||
},
|
||||
{
|
||||
option: "ignore",
|
||||
type: "Boolean",
|
||||
default: "true",
|
||||
description: "Disable use of ignore files and patterns"
|
||||
},
|
||||
{
|
||||
option: "ignore-pattern",
|
||||
type: "[String]",
|
||||
description: "Pattern of files to ignore (in addition to those in .eslintignore)",
|
||||
concatRepeatedArrays: [true, {
|
||||
oneValuePerFlag: true
|
||||
}]
|
||||
},
|
||||
{
|
||||
heading: "Using stdin"
|
||||
},
|
||||
{
|
||||
option: "stdin",
|
||||
type: "Boolean",
|
||||
default: "false",
|
||||
description: "Lint code provided on <STDIN>"
|
||||
},
|
||||
{
|
||||
option: "stdin-filename",
|
||||
type: "String",
|
||||
description: "Specify filename to process STDIN as"
|
||||
},
|
||||
{
|
||||
heading: "Handling warnings"
|
||||
},
|
||||
{
|
||||
option: "quiet",
|
||||
type: "Boolean",
|
||||
default: "false",
|
||||
description: "Report errors only"
|
||||
},
|
||||
{
|
||||
option: "max-warnings",
|
||||
type: "Int",
|
||||
default: "-1",
|
||||
description: "Number of warnings to trigger nonzero exit code"
|
||||
},
|
||||
{
|
||||
heading: "Output"
|
||||
},
|
||||
{
|
||||
option: "output-file",
|
||||
alias: "o",
|
||||
type: "path::String",
|
||||
description: "Specify file to write report to"
|
||||
},
|
||||
{
|
||||
option: "format",
|
||||
alias: "f",
|
||||
type: "String",
|
||||
default: "stylish",
|
||||
description: "Use a specific output format"
|
||||
},
|
||||
{
|
||||
option: "color",
|
||||
type: "Boolean",
|
||||
alias: "no-color",
|
||||
description: "Force enabling/disabling of color"
|
||||
},
|
||||
{
|
||||
heading: "Inline configuration comments"
|
||||
},
|
||||
{
|
||||
option: "inline-config",
|
||||
type: "Boolean",
|
||||
default: "true",
|
||||
description: "Prevent comments from changing config or rules"
|
||||
},
|
||||
{
|
||||
option: "report-unused-disable-directives",
|
||||
type: "Boolean",
|
||||
default: void 0,
|
||||
description: "Adds reported errors for unused eslint-disable directives"
|
||||
},
|
||||
{
|
||||
heading: "Caching"
|
||||
},
|
||||
{
|
||||
option: "cache",
|
||||
type: "Boolean",
|
||||
default: "false",
|
||||
description: "Only check changed files"
|
||||
},
|
||||
{
|
||||
option: "cache-file",
|
||||
type: "path::String",
|
||||
default: ".eslintcache",
|
||||
description: "Path to the cache file. Deprecated: use --cache-location"
|
||||
},
|
||||
{
|
||||
option: "cache-location",
|
||||
type: "path::String",
|
||||
description: "Path to the cache file or directory"
|
||||
},
|
||||
{
|
||||
option: "cache-strategy",
|
||||
dependsOn: ["cache"],
|
||||
type: "String",
|
||||
default: "metadata",
|
||||
enum: ["metadata", "content"],
|
||||
description: "Strategy to use for detecting changed files in the cache"
|
||||
},
|
||||
{
|
||||
heading: "Miscellaneous"
|
||||
},
|
||||
{
|
||||
option: "init",
|
||||
type: "Boolean",
|
||||
default: "false",
|
||||
description: "Run config initialization wizard"
|
||||
},
|
||||
{
|
||||
option: "env-info",
|
||||
type: "Boolean",
|
||||
default: "false",
|
||||
description: "Output execution environment information"
|
||||
},
|
||||
{
|
||||
option: "error-on-unmatched-pattern",
|
||||
type: "Boolean",
|
||||
default: "true",
|
||||
description: "Prevent errors when pattern is unmatched"
|
||||
},
|
||||
{
|
||||
option: "exit-on-fatal-error",
|
||||
type: "Boolean",
|
||||
default: "false",
|
||||
description: "Exit with exit code 2 in case of fatal error"
|
||||
},
|
||||
{
|
||||
option: "debug",
|
||||
type: "Boolean",
|
||||
default: false,
|
||||
description: "Output debugging information"
|
||||
},
|
||||
{
|
||||
option: "help",
|
||||
alias: "h",
|
||||
type: "Boolean",
|
||||
description: "Show help"
|
||||
},
|
||||
{
|
||||
option: "version",
|
||||
alias: "v",
|
||||
type: "Boolean",
|
||||
description: "Output the version number"
|
||||
},
|
||||
{
|
||||
option: "print-config",
|
||||
type: "path::String",
|
||||
description: "Print the configuration for the given file"
|
||||
}
|
||||
]
|
||||
});
|
||||
options: [
|
||||
{
|
||||
heading: "Basic configuration"
|
||||
},
|
||||
lookupFlag,
|
||||
{
|
||||
option: "config",
|
||||
alias: "c",
|
||||
type: "path::String",
|
||||
description: usingFlatConfig
|
||||
? "Use this configuration instead of eslint.config.js"
|
||||
: "Use this configuration, overriding .eslintrc.* config options if present"
|
||||
},
|
||||
envFlag,
|
||||
extFlag,
|
||||
{
|
||||
option: "global",
|
||||
type: "[String]",
|
||||
description: "Define global variables"
|
||||
},
|
||||
{
|
||||
option: "parser",
|
||||
type: "String",
|
||||
description: "Specify the parser to be used"
|
||||
},
|
||||
{
|
||||
option: "parser-options",
|
||||
type: "Object",
|
||||
description: "Specify parser options"
|
||||
},
|
||||
resolvePluginsFlag,
|
||||
{
|
||||
heading: "Specify Rules and Plugins"
|
||||
},
|
||||
{
|
||||
option: "plugin",
|
||||
type: "[String]",
|
||||
description: "Specify plugins"
|
||||
},
|
||||
{
|
||||
option: "rule",
|
||||
type: "Object",
|
||||
description: "Specify rules"
|
||||
},
|
||||
rulesDirFlag,
|
||||
{
|
||||
heading: "Fix Problems"
|
||||
},
|
||||
{
|
||||
option: "fix",
|
||||
type: "Boolean",
|
||||
default: false,
|
||||
description: "Automatically fix problems"
|
||||
},
|
||||
{
|
||||
option: "fix-dry-run",
|
||||
type: "Boolean",
|
||||
default: false,
|
||||
description: "Automatically fix problems without saving the changes to the file system"
|
||||
},
|
||||
{
|
||||
option: "fix-type",
|
||||
type: "Array",
|
||||
description: "Specify the types of fixes to apply (directive, problem, suggestion, layout)"
|
||||
},
|
||||
{
|
||||
heading: "Ignore Files"
|
||||
},
|
||||
ignorePathFlag,
|
||||
{
|
||||
option: "ignore",
|
||||
type: "Boolean",
|
||||
default: "true",
|
||||
description: "Disable use of ignore files and patterns"
|
||||
},
|
||||
{
|
||||
option: "ignore-pattern",
|
||||
type: "[String]",
|
||||
description: "Pattern of files to ignore (in addition to those in .eslintignore)",
|
||||
concatRepeatedArrays: [true, {
|
||||
oneValuePerFlag: true
|
||||
}]
|
||||
},
|
||||
{
|
||||
heading: "Use stdin"
|
||||
},
|
||||
{
|
||||
option: "stdin",
|
||||
type: "Boolean",
|
||||
default: "false",
|
||||
description: "Lint code provided on <STDIN>"
|
||||
},
|
||||
{
|
||||
option: "stdin-filename",
|
||||
type: "String",
|
||||
description: "Specify filename to process STDIN as"
|
||||
},
|
||||
{
|
||||
heading: "Handle Warnings"
|
||||
},
|
||||
{
|
||||
option: "quiet",
|
||||
type: "Boolean",
|
||||
default: "false",
|
||||
description: "Report errors only"
|
||||
},
|
||||
{
|
||||
option: "max-warnings",
|
||||
type: "Int",
|
||||
default: "-1",
|
||||
description: "Number of warnings to trigger nonzero exit code"
|
||||
},
|
||||
{
|
||||
heading: "Output"
|
||||
},
|
||||
{
|
||||
option: "output-file",
|
||||
alias: "o",
|
||||
type: "path::String",
|
||||
description: "Specify file to write report to"
|
||||
},
|
||||
{
|
||||
option: "format",
|
||||
alias: "f",
|
||||
type: "String",
|
||||
default: "stylish",
|
||||
description: "Use a specific output format"
|
||||
},
|
||||
{
|
||||
option: "color",
|
||||
type: "Boolean",
|
||||
alias: "no-color",
|
||||
description: "Force enabling/disabling of color"
|
||||
},
|
||||
{
|
||||
heading: "Inline configuration comments"
|
||||
},
|
||||
{
|
||||
option: "inline-config",
|
||||
type: "Boolean",
|
||||
default: "true",
|
||||
description: "Prevent comments from changing config or rules"
|
||||
},
|
||||
{
|
||||
option: "report-unused-disable-directives",
|
||||
type: "Boolean",
|
||||
default: void 0,
|
||||
description: "Adds reported errors for unused eslint-disable directives"
|
||||
},
|
||||
{
|
||||
heading: "Caching"
|
||||
},
|
||||
{
|
||||
option: "cache",
|
||||
type: "Boolean",
|
||||
default: "false",
|
||||
description: "Only check changed files"
|
||||
},
|
||||
{
|
||||
option: "cache-file",
|
||||
type: "path::String",
|
||||
default: ".eslintcache",
|
||||
description: "Path to the cache file. Deprecated: use --cache-location"
|
||||
},
|
||||
{
|
||||
option: "cache-location",
|
||||
type: "path::String",
|
||||
description: "Path to the cache file or directory"
|
||||
},
|
||||
{
|
||||
option: "cache-strategy",
|
||||
dependsOn: ["cache"],
|
||||
type: "String",
|
||||
default: "metadata",
|
||||
enum: ["metadata", "content"],
|
||||
description: "Strategy to use for detecting changed files in the cache"
|
||||
},
|
||||
{
|
||||
heading: "Miscellaneous"
|
||||
},
|
||||
{
|
||||
option: "init",
|
||||
type: "Boolean",
|
||||
default: "false",
|
||||
description: "Run config initialization wizard"
|
||||
},
|
||||
{
|
||||
option: "env-info",
|
||||
type: "Boolean",
|
||||
default: "false",
|
||||
description: "Output execution environment information"
|
||||
},
|
||||
{
|
||||
option: "error-on-unmatched-pattern",
|
||||
type: "Boolean",
|
||||
default: "true",
|
||||
description: "Prevent errors when pattern is unmatched"
|
||||
},
|
||||
{
|
||||
option: "exit-on-fatal-error",
|
||||
type: "Boolean",
|
||||
default: "false",
|
||||
description: "Exit with exit code 2 in case of fatal error"
|
||||
},
|
||||
{
|
||||
option: "debug",
|
||||
type: "Boolean",
|
||||
default: false,
|
||||
description: "Output debugging information"
|
||||
},
|
||||
{
|
||||
option: "help",
|
||||
alias: "h",
|
||||
type: "Boolean",
|
||||
description: "Show help"
|
||||
},
|
||||
{
|
||||
option: "version",
|
||||
alias: "v",
|
||||
type: "Boolean",
|
||||
description: "Output the version number"
|
||||
},
|
||||
{
|
||||
option: "print-config",
|
||||
type: "path::String",
|
||||
description: "Print the configuration for the given file"
|
||||
}
|
||||
].filter(value => !!value)
|
||||
});
|
||||
};
|
||||
|
|
|
|||
1044
node_modules/eslint/lib/rule-tester/flat-rule-tester.js
generated
vendored
Normal file
1044
node_modules/eslint/lib/rule-tester/flat-rule-tester.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
141
node_modules/eslint/lib/rule-tester/rule-tester.js
generated
vendored
141
node_modules/eslint/lib/rule-tester/rule-tester.js
generated
vendored
|
|
@ -4,7 +4,7 @@
|
|||
*/
|
||||
"use strict";
|
||||
|
||||
/* global describe, it */
|
||||
/* globals describe, it -- Mocha globals */
|
||||
|
||||
/*
|
||||
* This is a wrapper around mocha to allow for DRY unittests for eslint
|
||||
|
|
@ -55,15 +55,19 @@ const ajv = require("../shared/ajv")({ strictDefaults: true });
|
|||
const espreePath = require.resolve("espree");
|
||||
const parserSymbol = Symbol.for("eslint.RuleTester.parser");
|
||||
|
||||
const { SourceCode } = require("../source-code");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Typedefs
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @typedef {import("../shared/types").Parser} Parser */
|
||||
|
||||
/* eslint-disable jsdoc/valid-types -- https://github.com/jsdoc-type-pratt-parser/jsdoc-type-pratt-parser/issues/4#issuecomment-778805577 */
|
||||
/**
|
||||
* A test case that is expected to pass lint.
|
||||
* @typedef {Object} ValidTestCase
|
||||
* @property {string} [name] Name for the test case.
|
||||
* @property {string} code Code for the test case.
|
||||
* @property {any[]} [options] Options for the test case.
|
||||
* @property {{ [name: string]: any }} [settings] Settings for the test case.
|
||||
|
|
@ -78,6 +82,7 @@ const parserSymbol = Symbol.for("eslint.RuleTester.parser");
|
|||
/**
|
||||
* A test case that is expected to fail lint.
|
||||
* @typedef {Object} InvalidTestCase
|
||||
* @property {string} [name] Name for the test case.
|
||||
* @property {string} code Code for the test case.
|
||||
* @property {number | Array<TestCaseError | string | RegExp>} errors Expected errors.
|
||||
* @property {string | null} [output] The expected code after autofixes are applied. If set to `null`, the test runner will assert that no autofix is suggested.
|
||||
|
|
@ -103,6 +108,7 @@ const parserSymbol = Symbol.for("eslint.RuleTester.parser");
|
|||
* @property {number} [endLine] The 1-based line number of the reported end location.
|
||||
* @property {number} [endColumn] The 1-based column number of the reported end location.
|
||||
*/
|
||||
/* eslint-enable jsdoc/valid-types -- https://github.com/jsdoc-type-pratt-parser/jsdoc-type-pratt-parser/issues/4#issuecomment-778805577 */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Private Members
|
||||
|
|
@ -120,6 +126,7 @@ let defaultConfig = { rules: {} };
|
|||
* configuration
|
||||
*/
|
||||
const RuleTesterParameters = [
|
||||
"name",
|
||||
"code",
|
||||
"filename",
|
||||
"options",
|
||||
|
|
@ -209,8 +216,11 @@ function freezeDeeply(x) {
|
|||
* @returns {string} The sanitized text.
|
||||
*/
|
||||
function sanitize(text) {
|
||||
if (typeof text !== "string") {
|
||||
return "";
|
||||
}
|
||||
return text.replace(
|
||||
/[\u0000-\u0009\u000b-\u001a]/gu, // eslint-disable-line no-control-regex
|
||||
/[\u0000-\u0009\u000b-\u001a]/gu, // eslint-disable-line no-control-regex -- Escaping controls
|
||||
c => `\\u${c.codePointAt(0).toString(16).padStart(4, "0")}`
|
||||
);
|
||||
}
|
||||
|
|
@ -284,6 +294,47 @@ function wrapParser(parser) {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to replace `SourceCode.prototype.getComments`.
|
||||
* @returns {void}
|
||||
* @throws {Error} Deprecation message.
|
||||
*/
|
||||
function getCommentsDeprecation() {
|
||||
throw new Error(
|
||||
"`SourceCode#getComments()` is deprecated and will be removed in a future major version. Use `getCommentsBefore()`, `getCommentsAfter()`, and `getCommentsInside()` instead."
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a deprecation warning if function-style format is being used.
|
||||
* @param {string} ruleName Name of the rule.
|
||||
* @returns {void}
|
||||
*/
|
||||
function emitLegacyRuleAPIWarning(ruleName) {
|
||||
if (!emitLegacyRuleAPIWarning[`warned-${ruleName}`]) {
|
||||
emitLegacyRuleAPIWarning[`warned-${ruleName}`] = true;
|
||||
process.emitWarning(
|
||||
`"${ruleName}" rule is using the deprecated function-style format and will stop working in ESLint v9. Please use object-style format: https://eslint.org/docs/latest/extend/custom-rules`,
|
||||
"DeprecationWarning"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a deprecation warning if rule has options but is missing the "meta.schema" property
|
||||
* @param {string} ruleName Name of the rule.
|
||||
* @returns {void}
|
||||
*/
|
||||
function emitMissingSchemaWarning(ruleName) {
|
||||
if (!emitMissingSchemaWarning[`warned-${ruleName}`]) {
|
||||
emitMissingSchemaWarning[`warned-${ruleName}`] = true;
|
||||
process.emitWarning(
|
||||
`"${ruleName}" rule has options but is missing the "meta.schema" property and will stop working in ESLint v9. Please add a schema: https://eslint.org/docs/latest/extend/custom-rules#options-schemas`,
|
||||
"DeprecationWarning"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -298,6 +349,7 @@ const IT_ONLY = Symbol("itOnly");
|
|||
* @this {Mocha}
|
||||
* @param {string} text The description of the test case.
|
||||
* @param {Function} method The logic of the test case.
|
||||
* @throws {Error} Any error upon execution of `method`.
|
||||
* @returns {any} Returned value of `method`.
|
||||
*/
|
||||
function itDefaultHandler(text, method) {
|
||||
|
|
@ -322,6 +374,9 @@ function describeDefaultHandler(text, method) {
|
|||
return method.call(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mocha test wrapper.
|
||||
*/
|
||||
class RuleTester {
|
||||
|
||||
/**
|
||||
|
|
@ -353,6 +408,7 @@ class RuleTester {
|
|||
/**
|
||||
* Set the configuration to use for all future tests
|
||||
* @param {Object} config the configuration to use.
|
||||
* @throws {TypeError} If non-object config.
|
||||
* @returns {void}
|
||||
*/
|
||||
static setDefaultConfig(config) {
|
||||
|
|
@ -437,7 +493,7 @@ class RuleTester {
|
|||
if (typeof this[DESCRIBE] === "function" || typeof this[IT] === "function") {
|
||||
throw new Error(
|
||||
"Set `RuleTester.itOnly` to use `only` with a custom test framework.\n" +
|
||||
"See https://eslint.org/docs/developer-guide/nodejs-api#customizing-ruletester for more."
|
||||
"See https://eslint.org/docs/latest/integrate/nodejs-api#customizing-ruletester for more."
|
||||
);
|
||||
}
|
||||
if (typeof it === "function") {
|
||||
|
|
@ -468,6 +524,8 @@ class RuleTester {
|
|||
* valid: (ValidTestCase | string)[],
|
||||
* invalid: InvalidTestCase[]
|
||||
* }} test The collection of tests to run.
|
||||
* @throws {TypeError|Error} If non-object `test`, or if a required
|
||||
* scenario of the given type is missing.
|
||||
* @returns {void}
|
||||
*/
|
||||
run(ruleName, rule, test) {
|
||||
|
|
@ -493,6 +551,9 @@ class RuleTester {
|
|||
].concat(scenarioErrors).join("\n"));
|
||||
}
|
||||
|
||||
if (typeof rule === "function") {
|
||||
emitLegacyRuleAPIWarning(ruleName);
|
||||
}
|
||||
|
||||
linter.defineRule(ruleName, Object.assign({}, rule, {
|
||||
|
||||
|
|
@ -511,6 +572,7 @@ class RuleTester {
|
|||
/**
|
||||
* Run the rule for the given item
|
||||
* @param {string|Object} item Item to run the rule against
|
||||
* @throws {Error} If an invalid schema.
|
||||
* @returns {Object} Eslint run result
|
||||
* @private
|
||||
*/
|
||||
|
|
@ -549,6 +611,15 @@ class RuleTester {
|
|||
|
||||
if (hasOwnProperty(item, "options")) {
|
||||
assert(Array.isArray(item.options), "options must be an array");
|
||||
if (
|
||||
item.options.length > 0 &&
|
||||
typeof rule === "object" &&
|
||||
(
|
||||
!rule.meta || (rule.meta && (typeof rule.meta.schema === "undefined" || rule.meta.schema === null))
|
||||
)
|
||||
) {
|
||||
emitMissingSchemaWarning(ruleName);
|
||||
}
|
||||
config.rules[ruleName] = [1].concat(item.options);
|
||||
} else {
|
||||
config.rules[ruleName] = 1;
|
||||
|
|
@ -561,14 +632,18 @@ class RuleTester {
|
|||
* The goal is to check whether or not AST was modified when
|
||||
* running the rule under test.
|
||||
*/
|
||||
linter.defineRule("rule-tester/validate-ast", () => ({
|
||||
Program(node) {
|
||||
beforeAST = cloneDeeplyExcludesParent(node);
|
||||
},
|
||||
"Program:exit"(node) {
|
||||
afterAST = node;
|
||||
linter.defineRule("rule-tester/validate-ast", {
|
||||
create() {
|
||||
return {
|
||||
Program(node) {
|
||||
beforeAST = cloneDeeplyExcludesParent(node);
|
||||
},
|
||||
"Program:exit"(node) {
|
||||
afterAST = node;
|
||||
}
|
||||
};
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
if (typeof config.parser === "string") {
|
||||
assert(path.isAbsolute(config.parser), "Parsers provided as strings to RuleTester must be absolute paths");
|
||||
|
|
@ -607,7 +682,16 @@ class RuleTester {
|
|||
validate(config, "rule-tester", id => (id === ruleName ? rule : null));
|
||||
|
||||
// Verify the code.
|
||||
const messages = linter.verify(code, config, filename);
|
||||
const { getComments } = SourceCode.prototype;
|
||||
let messages;
|
||||
|
||||
try {
|
||||
SourceCode.prototype.getComments = getCommentsDeprecation;
|
||||
messages = linter.verify(code, config, filename);
|
||||
} finally {
|
||||
SourceCode.prototype.getComments = getComments;
|
||||
}
|
||||
|
||||
const fatalErrorMessage = messages.find(m => m.fatal);
|
||||
|
||||
assert(!fatalErrorMessage, `A fatal parsing error occurred: ${fatalErrorMessage && fatalErrorMessage.message}`);
|
||||
|
|
@ -656,6 +740,13 @@ class RuleTester {
|
|||
* @private
|
||||
*/
|
||||
function testValidTemplate(item) {
|
||||
const code = typeof item === "object" ? item.code : item;
|
||||
|
||||
assert.ok(typeof code === "string", "Test case must specify a string value for 'code'");
|
||||
if (item.name) {
|
||||
assert.ok(typeof item.name === "string", "Optional test case property 'name' must be a string");
|
||||
}
|
||||
|
||||
const result = runRuleForItem(item);
|
||||
const messages = result.messages;
|
||||
|
||||
|
|
@ -696,6 +787,10 @@ class RuleTester {
|
|||
* @private
|
||||
*/
|
||||
function testInvalidTemplate(item) {
|
||||
assert.ok(typeof item.code === "string", "Test case must specify a string value for 'code'");
|
||||
if (item.name) {
|
||||
assert.ok(typeof item.name === "string", "Optional test case property 'name' must be a string");
|
||||
}
|
||||
assert.ok(item.errors || item.errors === 0,
|
||||
`Did not specify errors for an invalid test of ${ruleName}`);
|
||||
|
||||
|
|
@ -921,16 +1016,6 @@ class RuleTester {
|
|||
);
|
||||
}
|
||||
|
||||
// Rules that produce fixes must have `meta.fixable` property.
|
||||
if (result.output !== item.code) {
|
||||
assert.ok(
|
||||
hasOwnProperty(rule, "meta"),
|
||||
"Fixable rules should export a `meta.fixable` property."
|
||||
);
|
||||
|
||||
// Linter throws if a rule that produced a fix has `meta` but doesn't have `meta.fixable`.
|
||||
}
|
||||
|
||||
assertASTDidntChange(result.beforeAST, result.afterAST);
|
||||
}
|
||||
|
||||
|
|
@ -938,11 +1023,11 @@ class RuleTester {
|
|||
* This creates a mocha test suite and pipes all supplied info through
|
||||
* one of the templates above.
|
||||
*/
|
||||
RuleTester.describe(ruleName, () => {
|
||||
RuleTester.describe("valid", () => {
|
||||
this.constructor.describe(ruleName, () => {
|
||||
this.constructor.describe("valid", () => {
|
||||
test.valid.forEach(valid => {
|
||||
RuleTester[valid.only ? "itOnly" : "it"](
|
||||
sanitize(typeof valid === "object" ? valid.code : valid),
|
||||
this.constructor[valid.only ? "itOnly" : "it"](
|
||||
sanitize(typeof valid === "object" ? valid.name || valid.code : valid),
|
||||
() => {
|
||||
testValidTemplate(valid);
|
||||
}
|
||||
|
|
@ -950,10 +1035,10 @@ class RuleTester {
|
|||
});
|
||||
});
|
||||
|
||||
RuleTester.describe("invalid", () => {
|
||||
this.constructor.describe("invalid", () => {
|
||||
test.invalid.forEach(invalid => {
|
||||
RuleTester[invalid.only ? "itOnly" : "it"](
|
||||
sanitize(invalid.code),
|
||||
this.constructor[invalid.only ? "itOnly" : "it"](
|
||||
sanitize(invalid.name || invalid.code),
|
||||
() => {
|
||||
testInvalidTemplate(invalid);
|
||||
}
|
||||
|
|
|
|||
12
node_modules/eslint/lib/rules/accessor-pairs.js
generated
vendored
12
node_modules/eslint/lib/rules/accessor-pairs.js
generated
vendored
|
|
@ -134,13 +134,13 @@ function isPropertyDescriptor(node) {
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "enforce getter and setter pairs in objects and classes",
|
||||
category: "Best Practices",
|
||||
description: "Enforce getter and setter pairs in objects and classes",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/accessor-pairs"
|
||||
},
|
||||
|
|
@ -299,12 +299,12 @@ module.exports = {
|
|||
* @private
|
||||
*/
|
||||
function checkPropertyDescriptor(node) {
|
||||
const namesToCheck = node.properties
|
||||
const namesToCheck = new Set(node.properties
|
||||
.filter(p => p.type === "Property" && p.kind === "init" && !p.computed)
|
||||
.map(({ key }) => key.name);
|
||||
.map(({ key }) => key.name));
|
||||
|
||||
const hasGetter = namesToCheck.includes("get");
|
||||
const hasSetter = namesToCheck.includes("set");
|
||||
const hasGetter = namesToCheck.has("get");
|
||||
const hasSetter = namesToCheck.has("set");
|
||||
|
||||
if (checkSetWithoutGet && hasSetter && !hasGetter) {
|
||||
report(node, "missingGetter");
|
||||
|
|
|
|||
4
node_modules/eslint/lib/rules/array-bracket-newline.js
generated
vendored
4
node_modules/eslint/lib/rules/array-bracket-newline.js
generated
vendored
|
|
@ -11,13 +11,13 @@ const astUtils = require("./utils/ast-utils");
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "enforce linebreaks after opening and before closing array brackets",
|
||||
category: "Stylistic Issues",
|
||||
description: "Enforce linebreaks after opening and before closing array brackets",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/array-bracket-newline"
|
||||
},
|
||||
|
|
|
|||
4
node_modules/eslint/lib/rules/array-bracket-spacing.js
generated
vendored
4
node_modules/eslint/lib/rules/array-bracket-spacing.js
generated
vendored
|
|
@ -10,13 +10,13 @@ const astUtils = require("./utils/ast-utils");
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "enforce consistent spacing inside array brackets",
|
||||
category: "Stylistic Issues",
|
||||
description: "Enforce consistent spacing inside array brackets",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/array-bracket-spacing"
|
||||
},
|
||||
|
|
|
|||
8
node_modules/eslint/lib/rules/array-callback-return.js
generated
vendored
8
node_modules/eslint/lib/rules/array-callback-return.js
generated
vendored
|
|
@ -16,7 +16,7 @@ const astUtils = require("./utils/ast-utils");
|
|||
//------------------------------------------------------------------------------
|
||||
|
||||
const TARGET_NODE_TYPE = /^(?:Arrow)?FunctionExpression$/u;
|
||||
const TARGET_METHODS = /^(?:every|filter|find(?:Index)?|flatMap|forEach|map|reduce(?:Right)?|some|sort)$/u;
|
||||
const TARGET_METHODS = /^(?:every|filter|find(?:Last)?(?:Index)?|flatMap|forEach|map|reduce(?:Right)?|some|sort)$/u;
|
||||
|
||||
/**
|
||||
* Checks a given code path segment is reachable.
|
||||
|
|
@ -125,7 +125,7 @@ function getArrayMethodName(node) {
|
|||
}
|
||||
}
|
||||
|
||||
/* istanbul ignore next: unreachable */
|
||||
/* c8 ignore next */
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -133,13 +133,13 @@ function getArrayMethodName(node) {
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "problem",
|
||||
|
||||
docs: {
|
||||
description: "enforce `return` statements in callbacks of array methods",
|
||||
category: "Best Practices",
|
||||
description: "Enforce `return` statements in callbacks of array methods",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/array-callback-return"
|
||||
},
|
||||
|
|
|
|||
4
node_modules/eslint/lib/rules/array-element-newline.js
generated
vendored
4
node_modules/eslint/lib/rules/array-element-newline.js
generated
vendored
|
|
@ -11,13 +11,13 @@ const astUtils = require("./utils/ast-utils");
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "enforce line breaks after each array element",
|
||||
category: "Stylistic Issues",
|
||||
description: "Enforce line breaks after each array element",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/array-element-newline"
|
||||
},
|
||||
|
|
|
|||
4
node_modules/eslint/lib/rules/arrow-body-style.js
generated
vendored
4
node_modules/eslint/lib/rules/arrow-body-style.js
generated
vendored
|
|
@ -14,13 +14,13 @@ const astUtils = require("./utils/ast-utils");
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "require braces around arrow function bodies",
|
||||
category: "ECMAScript 6",
|
||||
description: "Require braces around arrow function bodies",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/arrow-body-style"
|
||||
},
|
||||
|
|
|
|||
4
node_modules/eslint/lib/rules/arrow-parens.js
generated
vendored
4
node_modules/eslint/lib/rules/arrow-parens.js
generated
vendored
|
|
@ -27,13 +27,13 @@ function hasBlockBody(node) {
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "require parentheses around arrow function arguments",
|
||||
category: "ECMAScript 6",
|
||||
description: "Require parentheses around arrow function arguments",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/arrow-parens"
|
||||
},
|
||||
|
|
|
|||
4
node_modules/eslint/lib/rules/arrow-spacing.js
generated
vendored
4
node_modules/eslint/lib/rules/arrow-spacing.js
generated
vendored
|
|
@ -14,13 +14,13 @@ const astUtils = require("./utils/ast-utils");
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "enforce consistent spacing before and after the arrow in arrow functions",
|
||||
category: "ECMAScript 6",
|
||||
description: "Enforce consistent spacing before and after the arrow in arrow functions",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/arrow-spacing"
|
||||
},
|
||||
|
|
|
|||
6
node_modules/eslint/lib/rules/block-scoped-var.js
generated
vendored
6
node_modules/eslint/lib/rules/block-scoped-var.js
generated
vendored
|
|
@ -8,13 +8,13 @@
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "enforce the use of variables within the scope they are defined",
|
||||
category: "Best Practices",
|
||||
description: "Enforce the use of variables within the scope they are defined",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/block-scoped-var"
|
||||
},
|
||||
|
|
@ -113,6 +113,8 @@ module.exports = {
|
|||
"SwitchStatement:exit": exitScope,
|
||||
CatchClause: enterScope,
|
||||
"CatchClause:exit": exitScope,
|
||||
StaticBlock: enterScope,
|
||||
"StaticBlock:exit": exitScope,
|
||||
|
||||
// Finds and reports references which are outside of valid scope.
|
||||
VariableDeclaration: checkForVariables
|
||||
|
|
|
|||
17
node_modules/eslint/lib/rules/block-spacing.js
generated
vendored
17
node_modules/eslint/lib/rules/block-spacing.js
generated
vendored
|
|
@ -11,13 +11,13 @@ const util = require("./utils/ast-utils");
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "disallow or enforce spaces inside of blocks after opening block and before closing block",
|
||||
category: "Stylistic Issues",
|
||||
description: "Disallow or enforce spaces inside of blocks after opening block and before closing block",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/block-spacing"
|
||||
},
|
||||
|
|
@ -41,7 +41,7 @@ module.exports = {
|
|||
|
||||
/**
|
||||
* Gets the open brace token from a given node.
|
||||
* @param {ASTNode} node A BlockStatement/SwitchStatement node to get.
|
||||
* @param {ASTNode} node A BlockStatement/StaticBlock/SwitchStatement node to get.
|
||||
* @returns {Token} The token of the open brace.
|
||||
*/
|
||||
function getOpenBrace(node) {
|
||||
|
|
@ -51,6 +51,12 @@ module.exports = {
|
|||
}
|
||||
return sourceCode.getLastToken(node, 1);
|
||||
}
|
||||
|
||||
if (node.type === "StaticBlock") {
|
||||
return sourceCode.getFirstToken(node, { skip: 1 }); // skip the `static` token
|
||||
}
|
||||
|
||||
// "BlockStatement"
|
||||
return sourceCode.getFirstToken(node);
|
||||
}
|
||||
|
||||
|
|
@ -73,8 +79,8 @@ module.exports = {
|
|||
}
|
||||
|
||||
/**
|
||||
* Reports invalid spacing style inside braces.
|
||||
* @param {ASTNode} node A BlockStatement/SwitchStatement node to get.
|
||||
* Checks and reports invalid spacing style inside braces.
|
||||
* @param {ASTNode} node A BlockStatement/StaticBlock/SwitchStatement node to check.
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkSpacingInsideBraces(node) {
|
||||
|
|
@ -158,6 +164,7 @@ module.exports = {
|
|||
|
||||
return {
|
||||
BlockStatement: checkSpacingInsideBraces,
|
||||
StaticBlock: checkSpacingInsideBraces,
|
||||
SwitchStatement: checkSpacingInsideBraces
|
||||
};
|
||||
}
|
||||
|
|
|
|||
10
node_modules/eslint/lib/rules/brace-style.js
generated
vendored
10
node_modules/eslint/lib/rules/brace-style.js
generated
vendored
|
|
@ -11,13 +11,13 @@ const astUtils = require("./utils/ast-utils");
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "enforce consistent brace style for blocks",
|
||||
category: "Stylistic Issues",
|
||||
description: "Enforce consistent brace style for blocks",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/brace-style"
|
||||
},
|
||||
|
|
@ -156,6 +156,12 @@ module.exports = {
|
|||
validateCurlyPair(sourceCode.getFirstToken(node), sourceCode.getLastToken(node));
|
||||
}
|
||||
},
|
||||
StaticBlock(node) {
|
||||
validateCurlyPair(
|
||||
sourceCode.getFirstToken(node, { skip: 1 }), // skip the `static` token
|
||||
sourceCode.getLastToken(node)
|
||||
);
|
||||
},
|
||||
ClassBody(node) {
|
||||
validateCurlyPair(sourceCode.getFirstToken(node), sourceCode.getLastToken(node));
|
||||
},
|
||||
|
|
|
|||
9
node_modules/eslint/lib/rules/callback-return.js
generated
vendored
9
node_modules/eslint/lib/rules/callback-return.js
generated
vendored
|
|
@ -1,6 +1,7 @@
|
|||
/**
|
||||
* @fileoverview Enforce return after a callback.
|
||||
* @author Jamund Ferguson
|
||||
* @deprecated in ESLint v7.0.0
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
|
|
@ -8,6 +9,7 @@
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
deprecated: true,
|
||||
|
|
@ -17,8 +19,7 @@ module.exports = {
|
|||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "require `return` statements after callbacks",
|
||||
category: "Node.js and CommonJS",
|
||||
description: "Require `return` statements after callbacks",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/callback-return"
|
||||
},
|
||||
|
|
@ -52,7 +53,7 @@ module.exports = {
|
|||
if (!node.parent) {
|
||||
return null;
|
||||
}
|
||||
if (types.indexOf(node.parent.type) === -1) {
|
||||
if (!types.includes(node.parent.type)) {
|
||||
return findClosestParentOfType(node.parent, types);
|
||||
}
|
||||
return node.parent;
|
||||
|
|
@ -86,7 +87,7 @@ module.exports = {
|
|||
* @returns {boolean} Whether or not this function matches our callback name.
|
||||
*/
|
||||
function isCallback(node) {
|
||||
return containsOnlyIdentifiers(node.callee) && callbacks.indexOf(sourceCode.getText(node.callee)) > -1;
|
||||
return containsOnlyIdentifiers(node.callee) && callbacks.includes(sourceCode.getText(node.callee));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
445
node_modules/eslint/lib/rules/camelcase.js
generated
vendored
445
node_modules/eslint/lib/rules/camelcase.js
generated
vendored
|
|
@ -5,17 +5,23 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "enforce camelcase naming convention",
|
||||
category: "Stylistic Issues",
|
||||
description: "Enforce camelcase naming convention",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/camelcase"
|
||||
},
|
||||
|
|
@ -55,32 +61,25 @@ module.exports = {
|
|||
],
|
||||
|
||||
messages: {
|
||||
notCamelCase: "Identifier '{{name}}' is not in camel case."
|
||||
notCamelCase: "Identifier '{{name}}' is not in camel case.",
|
||||
notCamelCasePrivate: "#{{name}} is not in camel case."
|
||||
}
|
||||
},
|
||||
|
||||
create(context) {
|
||||
|
||||
const options = context.options[0] || {};
|
||||
let properties = options.properties || "";
|
||||
const properties = options.properties === "never" ? "never" : "always";
|
||||
const ignoreDestructuring = options.ignoreDestructuring;
|
||||
const ignoreImports = options.ignoreImports;
|
||||
const ignoreGlobals = options.ignoreGlobals;
|
||||
const allow = options.allow || [];
|
||||
|
||||
let globalScope;
|
||||
|
||||
if (properties !== "always" && properties !== "never") {
|
||||
properties = "always";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// contains reported nodes to avoid reporting twice on destructuring with shorthand notation
|
||||
const reported = [];
|
||||
const ALLOWED_PARENT_TYPES = new Set(["CallExpression", "NewExpression"]);
|
||||
const reported = new Set();
|
||||
|
||||
/**
|
||||
* Checks if a string contains an underscore and isn't all upper-case
|
||||
|
|
@ -89,9 +88,10 @@ module.exports = {
|
|||
* @private
|
||||
*/
|
||||
function isUnderscored(name) {
|
||||
const nameBody = name.replace(/^_+|_+$/gu, "");
|
||||
|
||||
// if there's an underscore, it might be A_CONSTANT, which is okay
|
||||
return name.includes("_") && name !== name.toUpperCase();
|
||||
return nameBody.includes("_") && nameBody !== nameBody.toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -107,94 +107,76 @@ module.exports = {
|
|||
}
|
||||
|
||||
/**
|
||||
* Checks if a parent of a node is an ObjectPattern.
|
||||
* @param {ASTNode} node The node to check.
|
||||
* @returns {boolean} if the node is inside an ObjectPattern
|
||||
* Checks if a given name is good or not.
|
||||
* @param {string} name The name to check.
|
||||
* @returns {boolean} `true` if the name is good.
|
||||
* @private
|
||||
*/
|
||||
function isInsideObjectPattern(node) {
|
||||
let current = node;
|
||||
|
||||
while (current) {
|
||||
const parent = current.parent;
|
||||
|
||||
if (parent && parent.type === "Property" && parent.computed && parent.key === current) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (current.type === "ObjectPattern") {
|
||||
return true;
|
||||
}
|
||||
|
||||
current = parent;
|
||||
}
|
||||
|
||||
return false;
|
||||
function isGoodName(name) {
|
||||
return !isUnderscored(name) || isAllowed(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given node represents assignment target property in destructuring.
|
||||
*
|
||||
* For examples:
|
||||
* ({a: b.foo} = c); // => true for `foo`
|
||||
* ([a.foo] = b); // => true for `foo`
|
||||
* ([a.foo = 1] = b); // => true for `foo`
|
||||
* ({...a.foo} = b); // => true for `foo`
|
||||
* @param {ASTNode} node An Identifier node to check
|
||||
* @returns {boolean} True if the node is an assignment target property in destructuring.
|
||||
* Checks if a given identifier reference or member expression is an assignment
|
||||
* target.
|
||||
* @param {ASTNode} node The node to check.
|
||||
* @returns {boolean} `true` if the node is an assignment target.
|
||||
*/
|
||||
function isAssignmentTargetPropertyInDestructuring(node) {
|
||||
if (
|
||||
node.parent.type === "MemberExpression" &&
|
||||
node.parent.property === node &&
|
||||
!node.parent.computed
|
||||
) {
|
||||
const effectiveParent = node.parent.parent;
|
||||
|
||||
return (
|
||||
effectiveParent.type === "Property" &&
|
||||
effectiveParent.value === node.parent &&
|
||||
effectiveParent.parent.type === "ObjectPattern" ||
|
||||
effectiveParent.type === "ArrayPattern" ||
|
||||
effectiveParent.type === "RestElement" ||
|
||||
(
|
||||
effectiveParent.type === "AssignmentPattern" &&
|
||||
effectiveParent.left === node.parent
|
||||
)
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given node represents a reference to a global variable that is not declared in the source code.
|
||||
* These identifiers will be allowed, as it is assumed that user has no control over the names of external global variables.
|
||||
* @param {ASTNode} node `Identifier` node to check.
|
||||
* @returns {boolean} `true` if the node is a reference to a global variable.
|
||||
*/
|
||||
function isReferenceToGlobalVariable(node) {
|
||||
const variable = globalScope.set.get(node.name);
|
||||
|
||||
return variable && variable.defs.length === 0 &&
|
||||
variable.references.some(ref => ref.identifier === node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given node represents a reference to a property of an object in an object literal expression.
|
||||
* This allows to differentiate between a global variable that is allowed to be used as a reference, and the key
|
||||
* of the expressed object (which shouldn't be allowed).
|
||||
* @param {ASTNode} node `Identifier` node to check.
|
||||
* @returns {boolean} `true` if the node is a property name of an object literal expression
|
||||
*/
|
||||
function isPropertyNameInObjectLiteral(node) {
|
||||
function isAssignmentTarget(node) {
|
||||
const parent = node.parent;
|
||||
|
||||
return (
|
||||
parent.type === "Property" &&
|
||||
parent.parent.type === "ObjectExpression" &&
|
||||
!parent.computed &&
|
||||
parent.key === node
|
||||
);
|
||||
switch (parent.type) {
|
||||
case "AssignmentExpression":
|
||||
case "AssignmentPattern":
|
||||
return parent.left === node;
|
||||
|
||||
case "Property":
|
||||
return (
|
||||
parent.parent.type === "ObjectPattern" &&
|
||||
parent.value === node
|
||||
);
|
||||
case "ArrayPattern":
|
||||
case "RestElement":
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given binding identifier uses the original name as-is.
|
||||
* - If it's in object destructuring or object expression, the original name is its property name.
|
||||
* - If it's in import declaration, the original name is its exported name.
|
||||
* @param {ASTNode} node The `Identifier` node to check.
|
||||
* @returns {boolean} `true` if the identifier uses the original name as-is.
|
||||
*/
|
||||
function equalsToOriginalName(node) {
|
||||
const localName = node.name;
|
||||
const valueNode = node.parent.type === "AssignmentPattern"
|
||||
? node.parent
|
||||
: node;
|
||||
const parent = valueNode.parent;
|
||||
|
||||
switch (parent.type) {
|
||||
case "Property":
|
||||
return (
|
||||
(parent.parent.type === "ObjectPattern" || parent.parent.type === "ObjectExpression") &&
|
||||
parent.value === valueNode &&
|
||||
!parent.computed &&
|
||||
parent.key.type === "Identifier" &&
|
||||
parent.key.name === localName
|
||||
);
|
||||
|
||||
case "ImportSpecifier":
|
||||
return (
|
||||
parent.local === node &&
|
||||
astUtils.getModuleExportName(parent.imported) === localName
|
||||
);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -204,122 +186,213 @@ module.exports = {
|
|||
* @private
|
||||
*/
|
||||
function report(node) {
|
||||
if (!reported.includes(node)) {
|
||||
reported.push(node);
|
||||
context.report({ node, messageId: "notCamelCase", data: { name: node.name } });
|
||||
if (reported.has(node.range[0])) {
|
||||
return;
|
||||
}
|
||||
reported.add(node.range[0]);
|
||||
|
||||
// Report it.
|
||||
context.report({
|
||||
node,
|
||||
messageId: node.type === "PrivateIdentifier"
|
||||
? "notCamelCasePrivate"
|
||||
: "notCamelCase",
|
||||
data: { name: node.name }
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports an identifier reference or a binding identifier.
|
||||
* @param {ASTNode} node The `Identifier` node to report.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportReferenceId(node) {
|
||||
|
||||
/*
|
||||
* For backward compatibility, if it's in callings then ignore it.
|
||||
* Not sure why it is.
|
||||
*/
|
||||
if (
|
||||
node.parent.type === "CallExpression" ||
|
||||
node.parent.type === "NewExpression"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* For backward compatibility, if it's a default value of
|
||||
* destructuring/parameters then ignore it.
|
||||
* Not sure why it is.
|
||||
*/
|
||||
if (
|
||||
node.parent.type === "AssignmentPattern" &&
|
||||
node.parent.right === node
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The `ignoreDestructuring` flag skips the identifiers that uses
|
||||
* the property name as-is.
|
||||
*/
|
||||
if (ignoreDestructuring && equalsToOriginalName(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
report(node);
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
// Report camelcase of global variable references ------------------
|
||||
Program() {
|
||||
globalScope = context.getScope();
|
||||
const scope = context.getScope();
|
||||
|
||||
if (!ignoreGlobals) {
|
||||
|
||||
// Defined globals in config files or directive comments.
|
||||
for (const variable of scope.variables) {
|
||||
if (
|
||||
variable.identifiers.length > 0 ||
|
||||
isGoodName(variable.name)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
for (const reference of variable.references) {
|
||||
|
||||
/*
|
||||
* For backward compatibility, this rule reports read-only
|
||||
* references as well.
|
||||
*/
|
||||
reportReferenceId(reference.identifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Undefined globals.
|
||||
for (const reference of scope.through) {
|
||||
const id = reference.identifier;
|
||||
|
||||
if (isGoodName(id.name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* For backward compatibility, this rule reports read-only
|
||||
* references as well.
|
||||
*/
|
||||
reportReferenceId(id);
|
||||
}
|
||||
},
|
||||
|
||||
Identifier(node) {
|
||||
// Report camelcase of declared variables --------------------------
|
||||
[[
|
||||
"VariableDeclaration",
|
||||
"FunctionDeclaration",
|
||||
"FunctionExpression",
|
||||
"ArrowFunctionExpression",
|
||||
"ClassDeclaration",
|
||||
"ClassExpression",
|
||||
"CatchClause"
|
||||
]](node) {
|
||||
for (const variable of context.getDeclaredVariables(node)) {
|
||||
if (isGoodName(variable.name)) {
|
||||
continue;
|
||||
}
|
||||
const id = variable.identifiers[0];
|
||||
|
||||
/*
|
||||
* Leading and trailing underscores are commonly used to flag
|
||||
* private/protected identifiers, strip them before checking if underscored
|
||||
*/
|
||||
const name = node.name,
|
||||
nameIsUnderscored = isUnderscored(name.replace(/^_+|_+$/gu, "")),
|
||||
effectiveParent = (node.parent.type === "MemberExpression") ? node.parent.parent : node.parent;
|
||||
// Report declaration.
|
||||
if (!(ignoreDestructuring && equalsToOriginalName(id))) {
|
||||
report(id);
|
||||
}
|
||||
|
||||
// First, we ignore the node if it match the ignore list
|
||||
if (isAllowed(name)) {
|
||||
/*
|
||||
* For backward compatibility, report references as well.
|
||||
* It looks unnecessary because declarations are reported.
|
||||
*/
|
||||
for (const reference of variable.references) {
|
||||
if (reference.init) {
|
||||
continue; // Skip the write references of initializers.
|
||||
}
|
||||
reportReferenceId(reference.identifier);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Report camelcase in properties ----------------------------------
|
||||
[[
|
||||
"ObjectExpression > Property[computed!=true] > Identifier.key",
|
||||
"MethodDefinition[computed!=true] > Identifier.key",
|
||||
"PropertyDefinition[computed!=true] > Identifier.key",
|
||||
"MethodDefinition > PrivateIdentifier.key",
|
||||
"PropertyDefinition > PrivateIdentifier.key"
|
||||
]](node) {
|
||||
if (properties === "never" || isGoodName(node.name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if it's a global variable
|
||||
if (ignoreGlobals && isReferenceToGlobalVariable(node) && !isPropertyNameInObjectLiteral(node)) {
|
||||
report(node);
|
||||
},
|
||||
"MemberExpression[computed!=true] > Identifier.property"(node) {
|
||||
if (
|
||||
properties === "never" ||
|
||||
!isAssignmentTarget(node.parent) || // ← ignore read-only references.
|
||||
isGoodName(node.name)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
report(node);
|
||||
},
|
||||
|
||||
// MemberExpressions get special rules
|
||||
if (node.parent.type === "MemberExpression") {
|
||||
// Report camelcase in import --------------------------------------
|
||||
ImportDeclaration(node) {
|
||||
for (const variable of context.getDeclaredVariables(node)) {
|
||||
if (isGoodName(variable.name)) {
|
||||
continue;
|
||||
}
|
||||
const id = variable.identifiers[0];
|
||||
|
||||
// "never" check properties
|
||||
if (properties === "never") {
|
||||
return;
|
||||
// Report declaration.
|
||||
if (!(ignoreImports && equalsToOriginalName(id))) {
|
||||
report(id);
|
||||
}
|
||||
|
||||
// Always report underscored object names
|
||||
if (node.parent.object.type === "Identifier" && node.parent.object.name === node.name && nameIsUnderscored) {
|
||||
report(node);
|
||||
|
||||
// Report AssignmentExpressions only if they are the left side of the assignment
|
||||
} else if (effectiveParent.type === "AssignmentExpression" && nameIsUnderscored && (effectiveParent.right.type !== "MemberExpression" || effectiveParent.left.type === "MemberExpression" && effectiveParent.left.property.name === node.name)) {
|
||||
report(node);
|
||||
|
||||
} else if (isAssignmentTargetPropertyInDestructuring(node) && nameIsUnderscored) {
|
||||
report(node);
|
||||
/*
|
||||
* For backward compatibility, report references as well.
|
||||
* It looks unnecessary because declarations are reported.
|
||||
*/
|
||||
for (const reference of variable.references) {
|
||||
reportReferenceId(reference.identifier);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Report camelcase in re-export -----------------------------------
|
||||
[[
|
||||
"ExportAllDeclaration > Identifier.exported",
|
||||
"ExportSpecifier > Identifier.exported"
|
||||
]](node) {
|
||||
if (isGoodName(node.name)) {
|
||||
return;
|
||||
}
|
||||
report(node);
|
||||
},
|
||||
|
||||
// Report camelcase in labels --------------------------------------
|
||||
[[
|
||||
"LabeledStatement > Identifier.label",
|
||||
|
||||
/*
|
||||
* Properties have their own rules, and
|
||||
* AssignmentPattern nodes can be treated like Properties:
|
||||
* e.g.: const { no_camelcased = false } = bar;
|
||||
* For backward compatibility, report references as well.
|
||||
* It looks unnecessary because declarations are reported.
|
||||
*/
|
||||
} else if (node.parent.type === "Property" || node.parent.type === "AssignmentPattern") {
|
||||
|
||||
if (node.parent.parent && node.parent.parent.type === "ObjectPattern") {
|
||||
if (node.parent.shorthand && node.parent.value.left && nameIsUnderscored) {
|
||||
report(node);
|
||||
}
|
||||
|
||||
const assignmentKeyEqualsValue = node.parent.key.name === node.parent.value.name;
|
||||
|
||||
if (nameIsUnderscored && node.parent.computed) {
|
||||
report(node);
|
||||
}
|
||||
|
||||
// prevent checking righthand side of destructured object
|
||||
if (node.parent.key === node && node.parent.value !== node) {
|
||||
return;
|
||||
}
|
||||
|
||||
const valueIsUnderscored = node.parent.value.name && nameIsUnderscored;
|
||||
|
||||
// ignore destructuring if the option is set, unless a new identifier is created
|
||||
if (valueIsUnderscored && !(assignmentKeyEqualsValue && ignoreDestructuring)) {
|
||||
report(node);
|
||||
}
|
||||
}
|
||||
|
||||
// "never" check properties or always ignore destructuring
|
||||
if (properties === "never" || (ignoreDestructuring && isInsideObjectPattern(node))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// don't check right hand side of AssignmentExpression to prevent duplicate warnings
|
||||
if (nameIsUnderscored && !ALLOWED_PARENT_TYPES.has(effectiveParent.type) && !(node.parent.right === node)) {
|
||||
report(node);
|
||||
}
|
||||
|
||||
// Check if it's an import specifier
|
||||
} else if (["ImportSpecifier", "ImportNamespaceSpecifier", "ImportDefaultSpecifier"].includes(node.parent.type)) {
|
||||
|
||||
if (node.parent.type === "ImportSpecifier" && ignoreImports) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Report only if the local imported identifier is underscored
|
||||
if (
|
||||
node.parent.local &&
|
||||
node.parent.local.name === node.name &&
|
||||
nameIsUnderscored
|
||||
) {
|
||||
report(node);
|
||||
}
|
||||
|
||||
// Report anything that is underscored that isn't a CallExpression
|
||||
} else if (nameIsUnderscored && !ALLOWED_PARENT_TYPES.has(effectiveParent.type)) {
|
||||
report(node);
|
||||
"BreakStatement > Identifier.label",
|
||||
"ContinueStatement > Identifier.label"
|
||||
]](node) {
|
||||
if (isGoodName(node.name)) {
|
||||
return;
|
||||
}
|
||||
report(node);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
};
|
||||
|
|
|
|||
6
node_modules/eslint/lib/rules/capitalized-comments.js
generated
vendored
6
node_modules/eslint/lib/rules/capitalized-comments.js
generated
vendored
|
|
@ -99,13 +99,13 @@ function createRegExpForIgnorePatterns(normalizedOptions) {
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "enforce or disallow capitalization of the first letter of a comment",
|
||||
category: "Stylistic Issues",
|
||||
description: "Enforce or disallow capitalization of the first letter of a comment",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/capitalized-comments"
|
||||
},
|
||||
|
|
@ -185,7 +185,7 @@ module.exports = {
|
|||
|
||||
return Boolean(
|
||||
previousTokenOrComment &&
|
||||
["Block", "Line"].indexOf(previousTokenOrComment.type) !== -1
|
||||
["Block", "Line"].includes(previousTokenOrComment.type)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
78
node_modules/eslint/lib/rules/class-methods-use-this.js
generated
vendored
78
node_modules/eslint/lib/rules/class-methods-use-this.js
generated
vendored
|
|
@ -15,13 +15,13 @@ const astUtils = require("./utils/ast-utils");
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "enforce that class methods utilize `this`",
|
||||
category: "Best Practices",
|
||||
description: "Enforce that class methods utilize `this`",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/class-methods-use-this"
|
||||
},
|
||||
|
|
@ -34,6 +34,10 @@ module.exports = {
|
|||
items: {
|
||||
type: "string"
|
||||
}
|
||||
},
|
||||
enforceForClassFields: {
|
||||
type: "boolean",
|
||||
default: true
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
|
|
@ -45,10 +49,27 @@ module.exports = {
|
|||
},
|
||||
create(context) {
|
||||
const config = Object.assign({}, context.options[0]);
|
||||
const enforceForClassFields = config.enforceForClassFields !== false;
|
||||
const exceptMethods = new Set(config.exceptMethods || []);
|
||||
|
||||
const stack = [];
|
||||
|
||||
/**
|
||||
* Push `this` used flag initialized with `false` onto the stack.
|
||||
* @returns {void}
|
||||
*/
|
||||
function pushContext() {
|
||||
stack.push(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop `this` used flag from the stack.
|
||||
* @returns {boolean | undefined} `this` used flag
|
||||
*/
|
||||
function popContext() {
|
||||
return stack.pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the current context to false and pushes it onto the stack.
|
||||
* These booleans represent whether 'this' has been used in the context.
|
||||
|
|
@ -56,7 +77,7 @@ module.exports = {
|
|||
* @private
|
||||
*/
|
||||
function enterFunction() {
|
||||
stack.push(false);
|
||||
pushContext();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -66,7 +87,14 @@ module.exports = {
|
|||
* @private
|
||||
*/
|
||||
function isInstanceMethod(node) {
|
||||
return !node.static && node.kind !== "constructor" && node.type === "MethodDefinition";
|
||||
switch (node.type) {
|
||||
case "MethodDefinition":
|
||||
return !node.static && node.kind !== "constructor";
|
||||
case "PropertyDefinition":
|
||||
return !node.static && enforceForClassFields;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -76,8 +104,19 @@ module.exports = {
|
|||
* @private
|
||||
*/
|
||||
function isIncludedInstanceMethod(node) {
|
||||
return isInstanceMethod(node) &&
|
||||
(node.computed || !exceptMethods.has(node.key.name));
|
||||
if (isInstanceMethod(node)) {
|
||||
if (node.computed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const hashIfNeeded = node.key.type === "PrivateIdentifier" ? "#" : "";
|
||||
const name = node.key.type === "Literal"
|
||||
? astUtils.getStaticStringValue(node.key)
|
||||
: (node.key.name || "");
|
||||
|
||||
return !exceptMethods.has(hashIfNeeded + name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -89,11 +128,12 @@ module.exports = {
|
|||
* @private
|
||||
*/
|
||||
function exitFunction(node) {
|
||||
const methodUsesThis = stack.pop();
|
||||
const methodUsesThis = popContext();
|
||||
|
||||
if (isIncludedInstanceMethod(node.parent) && !methodUsesThis) {
|
||||
context.report({
|
||||
node,
|
||||
loc: astUtils.getFunctionHeadLoc(node, context.getSourceCode()),
|
||||
messageId: "missingThis",
|
||||
data: {
|
||||
name: astUtils.getFunctionNameWithKind(node)
|
||||
|
|
@ -118,8 +158,30 @@ module.exports = {
|
|||
"FunctionDeclaration:exit": exitFunction,
|
||||
FunctionExpression: enterFunction,
|
||||
"FunctionExpression:exit": exitFunction,
|
||||
|
||||
/*
|
||||
* Class field value are implicit functions.
|
||||
*/
|
||||
"PropertyDefinition > *.key:exit": pushContext,
|
||||
"PropertyDefinition:exit": popContext,
|
||||
|
||||
/*
|
||||
* Class static blocks are implicit functions. They aren't required to use `this`,
|
||||
* but we have to push context so that it captures any use of `this` in the static block
|
||||
* separately from enclosing contexts, because static blocks have their own `this` and it
|
||||
* shouldn't count as used `this` in enclosing contexts.
|
||||
*/
|
||||
StaticBlock: pushContext,
|
||||
"StaticBlock:exit": popContext,
|
||||
|
||||
ThisExpression: markThisUsed,
|
||||
Super: markThisUsed
|
||||
Super: markThisUsed,
|
||||
...(
|
||||
enforceForClassFields && {
|
||||
"PropertyDefinition > ArrowFunctionExpression.value": enterFunction,
|
||||
"PropertyDefinition > ArrowFunctionExpression.value:exit": exitFunction
|
||||
}
|
||||
)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
|||
41
node_modules/eslint/lib/rules/comma-dangle.js
generated
vendored
41
node_modules/eslint/lib/rules/comma-dangle.js
generated
vendored
|
|
@ -50,7 +50,7 @@ function normalizeOptions(optionValue, ecmaVersion) {
|
|||
objects: optionValue,
|
||||
imports: optionValue,
|
||||
exports: optionValue,
|
||||
functions: (!ecmaVersion || ecmaVersion < 8) ? "ignore" : optionValue
|
||||
functions: ecmaVersion < 2017 ? "ignore" : optionValue
|
||||
};
|
||||
}
|
||||
if (typeof optionValue === "object" && optionValue !== null) {
|
||||
|
|
@ -70,13 +70,13 @@ function normalizeOptions(optionValue, ecmaVersion) {
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "require or disallow trailing commas",
|
||||
category: "Stylistic Issues",
|
||||
description: "Require or disallow trailing commas",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/comma-dangle"
|
||||
},
|
||||
|
|
@ -123,7 +123,8 @@ module.exports = {
|
|||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
additionalItems: false
|
||||
},
|
||||
|
||||
messages: {
|
||||
|
|
@ -133,7 +134,7 @@ module.exports = {
|
|||
},
|
||||
|
||||
create(context) {
|
||||
const options = normalizeOptions(context.options[0], context.parserOptions.ecmaVersion);
|
||||
const options = normalizeOptions(context.options[0], context.languageOptions.ecmaVersion);
|
||||
|
||||
const sourceCode = context.getSourceCode();
|
||||
|
||||
|
|
@ -242,8 +243,18 @@ module.exports = {
|
|||
node: lastItem,
|
||||
loc: trailingToken.loc,
|
||||
messageId: "unexpected",
|
||||
fix(fixer) {
|
||||
return fixer.remove(trailingToken);
|
||||
*fix(fixer) {
|
||||
yield fixer.remove(trailingToken);
|
||||
|
||||
/*
|
||||
* Extend the range of the fix to include surrounding tokens to ensure
|
||||
* that the element after which the comma is removed stays _last_.
|
||||
* This intentionally makes conflicts in fix ranges with rules that may be
|
||||
* adding or removing elements in the same autofix pass.
|
||||
* https://github.com/eslint/eslint/issues/15660
|
||||
*/
|
||||
yield fixer.insertTextBefore(sourceCode.getTokenBefore(trailingToken), "");
|
||||
yield fixer.insertTextAfter(sourceCode.getTokenAfter(trailingToken), "");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -281,8 +292,18 @@ module.exports = {
|
|||
end: astUtils.getNextLocation(sourceCode, trailingToken.loc.end)
|
||||
},
|
||||
messageId: "missing",
|
||||
fix(fixer) {
|
||||
return fixer.insertTextAfter(trailingToken, ",");
|
||||
*fix(fixer) {
|
||||
yield fixer.insertTextAfter(trailingToken, ",");
|
||||
|
||||
/*
|
||||
* Extend the range of the fix to include surrounding tokens to ensure
|
||||
* that the element after which the comma is inserted stays _last_.
|
||||
* This intentionally makes conflicts in fix ranges with rules that may be
|
||||
* adding or removing elements in the same autofix pass.
|
||||
* https://github.com/eslint/eslint/issues/15660
|
||||
*/
|
||||
yield fixer.insertTextBefore(trailingToken, "");
|
||||
yield fixer.insertTextAfter(sourceCode.getTokenAfter(trailingToken), "");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -325,7 +346,7 @@ module.exports = {
|
|||
"always-multiline": forceTrailingCommaIfMultiline,
|
||||
"only-multiline": allowTrailingCommaIfMultiline,
|
||||
never: forbidTrailingComma,
|
||||
ignore: () => {}
|
||||
ignore() {}
|
||||
};
|
||||
|
||||
return {
|
||||
|
|
|
|||
80
node_modules/eslint/lib/rules/comma-spacing.js
generated
vendored
80
node_modules/eslint/lib/rules/comma-spacing.js
generated
vendored
|
|
@ -10,13 +10,13 @@ const astUtils = require("./utils/ast-utils");
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "enforce consistent spacing before and after commas",
|
||||
category: "Stylistic Issues",
|
||||
description: "Enforce consistent spacing before and after commas",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/comma-spacing"
|
||||
},
|
||||
|
|
@ -103,38 +103,6 @@ module.exports = {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the spacing around a comma token.
|
||||
* @param {Object} tokens The tokens to be validated.
|
||||
* @param {Token} tokens.comma The token representing the comma.
|
||||
* @param {Token} [tokens.left] The last token before the comma.
|
||||
* @param {Token} [tokens.right] The first token after the comma.
|
||||
* @param {Token|ASTNode} reportItem The item to use when reporting an error.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function validateCommaItemSpacing(tokens, reportItem) {
|
||||
if (tokens.left && astUtils.isTokenOnSameLine(tokens.left, tokens.comma) &&
|
||||
(options.before !== sourceCode.isSpaceBetweenTokens(tokens.left, tokens.comma))
|
||||
) {
|
||||
report(reportItem, "before", tokens.left);
|
||||
}
|
||||
|
||||
if (tokens.right && astUtils.isClosingParenToken(tokens.right)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tokens.right && !options.after && tokens.right.type === "Line") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tokens.right && astUtils.isTokenOnSameLine(tokens.comma, tokens.right) &&
|
||||
(options.after !== sourceCode.isSpaceBetweenTokens(tokens.comma, tokens.right))
|
||||
) {
|
||||
report(reportItem, "after", tokens.right);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds null elements of the given ArrayExpression or ArrayPattern node to the ignore list.
|
||||
* @param {ASTNode} node An ArrayExpression or ArrayPattern node.
|
||||
|
|
@ -172,18 +140,44 @@ module.exports = {
|
|||
return;
|
||||
}
|
||||
|
||||
if (token && token.type === "JSXText") {
|
||||
return;
|
||||
}
|
||||
|
||||
const previousToken = tokensAndComments[i - 1];
|
||||
const nextToken = tokensAndComments[i + 1];
|
||||
|
||||
validateCommaItemSpacing({
|
||||
comma: token,
|
||||
left: astUtils.isCommaToken(previousToken) || commaTokensToIgnore.includes(token) ? null : previousToken,
|
||||
right: astUtils.isCommaToken(nextToken) ? null : nextToken
|
||||
}, token);
|
||||
if (
|
||||
previousToken &&
|
||||
!astUtils.isCommaToken(previousToken) && // ignore spacing between two commas
|
||||
|
||||
/*
|
||||
* `commaTokensToIgnore` are ending commas of `null` elements (array holes/elisions).
|
||||
* In addition to spacing between two commas, this can also ignore:
|
||||
*
|
||||
* - Spacing after `[` (controlled by array-bracket-spacing)
|
||||
* Example: [ , ]
|
||||
* ^
|
||||
* - Spacing after a comment (for backwards compatibility, this was possibly unintentional)
|
||||
* Example: [a, /* * / ,]
|
||||
* ^
|
||||
*/
|
||||
!commaTokensToIgnore.includes(token) &&
|
||||
|
||||
astUtils.isTokenOnSameLine(previousToken, token) &&
|
||||
options.before !== sourceCode.isSpaceBetweenTokens(previousToken, token)
|
||||
) {
|
||||
report(token, "before", previousToken);
|
||||
}
|
||||
|
||||
if (
|
||||
nextToken &&
|
||||
!astUtils.isCommaToken(nextToken) && // ignore spacing between two commas
|
||||
!astUtils.isClosingParenToken(nextToken) && // controlled by space-in-parens
|
||||
!astUtils.isClosingBracketToken(nextToken) && // controlled by array-bracket-spacing
|
||||
!astUtils.isClosingBraceToken(nextToken) && // controlled by object-curly-spacing
|
||||
!(!options.after && nextToken.type === "Line") && // special case, allow space before line comment
|
||||
astUtils.isTokenOnSameLine(token, nextToken) &&
|
||||
options.after !== sourceCode.isSpaceBetweenTokens(token, nextToken)
|
||||
) {
|
||||
report(token, "after", nextToken);
|
||||
}
|
||||
});
|
||||
},
|
||||
ArrayExpression: addNullElementsToIgnoreList,
|
||||
|
|
|
|||
4
node_modules/eslint/lib/rules/comma-style.js
generated
vendored
4
node_modules/eslint/lib/rules/comma-style.js
generated
vendored
|
|
@ -11,13 +11,13 @@ const astUtils = require("./utils/ast-utils");
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "enforce consistent comma style",
|
||||
category: "Stylistic Issues",
|
||||
description: "Enforce consistent comma style",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/comma-style"
|
||||
},
|
||||
|
|
|
|||
114
node_modules/eslint/lib/rules/complexity.js
generated
vendored
114
node_modules/eslint/lib/rules/complexity.js
generated
vendored
|
|
@ -17,13 +17,13 @@ const { upperCaseFirst } = require("../shared/string-utils");
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "enforce a maximum cyclomatic complexity allowed in a program",
|
||||
category: "Best Practices",
|
||||
description: "Enforce a maximum cyclomatic complexity allowed in a program",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/complexity"
|
||||
},
|
||||
|
|
@ -75,60 +75,16 @@ module.exports = {
|
|||
// Helpers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// Using a stack to store complexity (handling nested functions)
|
||||
const fns = [];
|
||||
// Using a stack to store complexity per code path
|
||||
const complexities = [];
|
||||
|
||||
/**
|
||||
* When parsing a new function, store it in our function stack
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function startFunction() {
|
||||
fns.push(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the node at the end of function
|
||||
* @param {ASTNode} node node to evaluate
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function endFunction(node) {
|
||||
const name = upperCaseFirst(astUtils.getFunctionNameWithKind(node));
|
||||
const complexity = fns.pop();
|
||||
|
||||
if (complexity > THRESHOLD) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "complex",
|
||||
data: { name, complexity, max: THRESHOLD }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase the complexity of the function in context
|
||||
* Increase the complexity of the code path in context
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function increaseComplexity() {
|
||||
if (fns.length) {
|
||||
fns[fns.length - 1]++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase the switch complexity in context
|
||||
* @param {ASTNode} node node to evaluate
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function increaseSwitchComplexity(node) {
|
||||
|
||||
// Avoiding `default`
|
||||
if (node.test) {
|
||||
increaseComplexity();
|
||||
}
|
||||
complexities[complexities.length - 1]++;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
|
@ -136,13 +92,14 @@ module.exports = {
|
|||
//--------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
FunctionDeclaration: startFunction,
|
||||
FunctionExpression: startFunction,
|
||||
ArrowFunctionExpression: startFunction,
|
||||
"FunctionDeclaration:exit": endFunction,
|
||||
"FunctionExpression:exit": endFunction,
|
||||
"ArrowFunctionExpression:exit": endFunction,
|
||||
|
||||
onCodePathStart() {
|
||||
|
||||
// The initial complexity is 1, representing one execution path in the CodePath
|
||||
complexities.push(1);
|
||||
},
|
||||
|
||||
// Each branching in the code adds 1 to the complexity
|
||||
CatchClause: increaseComplexity,
|
||||
ConditionalExpression: increaseComplexity,
|
||||
LogicalExpression: increaseComplexity,
|
||||
|
|
@ -150,14 +107,57 @@ module.exports = {
|
|||
ForInStatement: increaseComplexity,
|
||||
ForOfStatement: increaseComplexity,
|
||||
IfStatement: increaseComplexity,
|
||||
SwitchCase: increaseSwitchComplexity,
|
||||
WhileStatement: increaseComplexity,
|
||||
DoWhileStatement: increaseComplexity,
|
||||
|
||||
// Avoid `default`
|
||||
"SwitchCase[test]": increaseComplexity,
|
||||
|
||||
// Logical assignment operators have short-circuiting behavior
|
||||
AssignmentExpression(node) {
|
||||
if (astUtils.isLogicalAssignmentOperator(node.operator)) {
|
||||
increaseComplexity();
|
||||
}
|
||||
},
|
||||
|
||||
onCodePathEnd(codePath, node) {
|
||||
const complexity = complexities.pop();
|
||||
|
||||
/*
|
||||
* This rule only evaluates complexity of functions, so "program" is excluded.
|
||||
* Class field initializers and class static blocks are implicit functions. Therefore,
|
||||
* they shouldn't contribute to the enclosing function's complexity, but their
|
||||
* own complexity should be evaluated.
|
||||
*/
|
||||
if (
|
||||
codePath.origin !== "function" &&
|
||||
codePath.origin !== "class-field-initializer" &&
|
||||
codePath.origin !== "class-static-block"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (complexity > THRESHOLD) {
|
||||
let name;
|
||||
|
||||
if (codePath.origin === "class-field-initializer") {
|
||||
name = "class field initializer";
|
||||
} else if (codePath.origin === "class-static-block") {
|
||||
name = "class static block";
|
||||
} else {
|
||||
name = astUtils.getFunctionNameWithKind(node);
|
||||
}
|
||||
|
||||
context.report({
|
||||
node,
|
||||
messageId: "complex",
|
||||
data: {
|
||||
name: upperCaseFirst(name),
|
||||
complexity,
|
||||
max: THRESHOLD
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
7
node_modules/eslint/lib/rules/computed-property-spacing.js
generated
vendored
7
node_modules/eslint/lib/rules/computed-property-spacing.js
generated
vendored
|
|
@ -10,13 +10,13 @@ const astUtils = require("./utils/ast-utils");
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "enforce consistent spacing inside computed property brackets",
|
||||
category: "Stylistic Issues",
|
||||
description: "Enforce consistent spacing inside computed property brackets",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/computed-property-spacing"
|
||||
},
|
||||
|
|
@ -195,7 +195,8 @@ module.exports = {
|
|||
};
|
||||
|
||||
if (enforceForClassMembers) {
|
||||
listeners.MethodDefinition = checkSpacing("key");
|
||||
listeners.MethodDefinition =
|
||||
listeners.PropertyDefinition = listeners.Property;
|
||||
}
|
||||
|
||||
return listeners;
|
||||
|
|
|
|||
4
node_modules/eslint/lib/rules/consistent-return.js
generated
vendored
4
node_modules/eslint/lib/rules/consistent-return.js
generated
vendored
|
|
@ -40,13 +40,13 @@ function isClassConstructor(node) {
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "require `return` statements to either always or never specify values",
|
||||
category: "Best Practices",
|
||||
description: "Require `return` statements to either always or never specify values",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/consistent-return"
|
||||
},
|
||||
|
|
|
|||
8
node_modules/eslint/lib/rules/consistent-this.js
generated
vendored
8
node_modules/eslint/lib/rules/consistent-this.js
generated
vendored
|
|
@ -8,13 +8,13 @@
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "enforce consistent naming when capturing the current execution context",
|
||||
category: "Stylistic Issues",
|
||||
description: "Enforce consistent naming when capturing the current execution context",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/consistent-this"
|
||||
},
|
||||
|
|
@ -47,7 +47,7 @@ module.exports = {
|
|||
* Reports that a variable declarator or assignment expression is assigning
|
||||
* a non-'this' value to the specified alias.
|
||||
* @param {ASTNode} node The assigning node.
|
||||
* @param {string} name the name of the alias that was incorrectly used.
|
||||
* @param {string} name the name of the alias that was incorrectly used.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportBadAssignment(node, name) {
|
||||
|
|
@ -65,7 +65,7 @@ module.exports = {
|
|||
function checkAssignment(node, name, value) {
|
||||
const isThis = value.type === "ThisExpression";
|
||||
|
||||
if (aliases.indexOf(name) !== -1) {
|
||||
if (aliases.includes(name)) {
|
||||
if (!isThis || node.operator && node.operator !== "=") {
|
||||
reportBadAssignment(node, name);
|
||||
}
|
||||
|
|
|
|||
4
node_modules/eslint/lib/rules/constructor-super.js
generated
vendored
4
node_modules/eslint/lib/rules/constructor-super.js
generated
vendored
|
|
@ -116,13 +116,13 @@ function isPossibleConstructor(node) {
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "problem",
|
||||
|
||||
docs: {
|
||||
description: "require `super()` calls in constructors",
|
||||
category: "ECMAScript 6",
|
||||
description: "Require `super()` calls in constructors",
|
||||
recommended: true,
|
||||
url: "https://eslint.org/docs/rules/constructor-super"
|
||||
},
|
||||
|
|
|
|||
4
node_modules/eslint/lib/rules/curly.js
generated
vendored
4
node_modules/eslint/lib/rules/curly.js
generated
vendored
|
|
@ -14,13 +14,13 @@ const astUtils = require("./utils/ast-utils");
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "enforce consistent brace style for all control statements",
|
||||
category: "Best Practices",
|
||||
description: "Enforce consistent brace style for all control statements",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/curly"
|
||||
},
|
||||
|
|
|
|||
4
node_modules/eslint/lib/rules/default-case-last.js
generated
vendored
4
node_modules/eslint/lib/rules/default-case-last.js
generated
vendored
|
|
@ -9,13 +9,13 @@
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "enforce default clauses in switch statements to be last",
|
||||
category: "Best Practices",
|
||||
description: "Enforce default clauses in switch statements to be last",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/default-case-last"
|
||||
},
|
||||
|
|
|
|||
8
node_modules/eslint/lib/rules/default-case.js
generated
vendored
8
node_modules/eslint/lib/rules/default-case.js
generated
vendored
|
|
@ -10,13 +10,13 @@ const DEFAULT_COMMENT_PATTERN = /^no default$/iu;
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "require `default` cases in `switch` statements",
|
||||
category: "Best Practices",
|
||||
description: "Require `default` cases in `switch` statements",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/default-case"
|
||||
},
|
||||
|
|
@ -50,8 +50,8 @@ module.exports = {
|
|||
|
||||
/**
|
||||
* Shortcut to get last element of array
|
||||
* @param {*[]} collection Array
|
||||
* @returns {*} Last element
|
||||
* @param {*[]} collection Array
|
||||
* @returns {any} Last element
|
||||
*/
|
||||
function last(collection) {
|
||||
return collection[collection.length - 1];
|
||||
|
|
|
|||
6
node_modules/eslint/lib/rules/default-param-last.js
generated
vendored
6
node_modules/eslint/lib/rules/default-param-last.js
generated
vendored
|
|
@ -5,13 +5,13 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "enforce default parameters to be last",
|
||||
category: "Best Practices",
|
||||
description: "Enforce default parameters to be last",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/default-param-last"
|
||||
},
|
||||
|
|
@ -25,8 +25,8 @@ module.exports = {
|
|||
|
||||
create(context) {
|
||||
|
||||
// eslint-disable-next-line jsdoc/require-description
|
||||
/**
|
||||
* Handler for function contexts.
|
||||
* @param {ASTNode} node function node
|
||||
* @returns {void}
|
||||
*/
|
||||
|
|
|
|||
4
node_modules/eslint/lib/rules/dot-location.js
generated
vendored
4
node_modules/eslint/lib/rules/dot-location.js
generated
vendored
|
|
@ -11,13 +11,13 @@ const astUtils = require("./utils/ast-utils");
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "enforce consistent newlines before and after dots",
|
||||
category: "Best Practices",
|
||||
description: "Enforce consistent newlines before and after dots",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/dot-location"
|
||||
},
|
||||
|
|
|
|||
9
node_modules/eslint/lib/rules/dot-notation.js
generated
vendored
9
node_modules/eslint/lib/rules/dot-notation.js
generated
vendored
|
|
@ -20,13 +20,13 @@ const validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/u;
|
|||
// `null` literal must be handled separately.
|
||||
const literalTypesToCheck = new Set(["string", "boolean"]);
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "enforce dot notation whenever possible",
|
||||
category: "Best Practices",
|
||||
description: "Enforce dot notation whenever possible",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/dot-notation"
|
||||
},
|
||||
|
|
@ -76,7 +76,7 @@ module.exports = {
|
|||
function checkComputedProperty(node, value) {
|
||||
if (
|
||||
validIdentifier.test(value) &&
|
||||
(allowKeywords || keywords.indexOf(String(value)) === -1) &&
|
||||
(allowKeywords || !keywords.includes(String(value))) &&
|
||||
!(allowPattern && allowPattern.test(value))
|
||||
) {
|
||||
const formattedValue = node.property.type === "Literal" ? JSON.stringify(value) : `\`${value}\``;
|
||||
|
|
@ -141,7 +141,8 @@ module.exports = {
|
|||
if (
|
||||
!allowKeywords &&
|
||||
!node.computed &&
|
||||
keywords.indexOf(String(node.property.name)) !== -1
|
||||
node.property.type === "Identifier" &&
|
||||
keywords.includes(String(node.property.name))
|
||||
) {
|
||||
context.report({
|
||||
node: node.property,
|
||||
|
|
|
|||
11
node_modules/eslint/lib/rules/eol-last.js
generated
vendored
11
node_modules/eslint/lib/rules/eol-last.js
generated
vendored
|
|
@ -8,13 +8,13 @@
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "require or disallow newline at the end of files",
|
||||
category: "Stylistic Issues",
|
||||
description: "Require or disallow newline at the end of files",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/eol-last"
|
||||
},
|
||||
|
|
@ -86,10 +86,15 @@ module.exports = {
|
|||
});
|
||||
} else if (mode === "never" && endsWithNewline) {
|
||||
|
||||
const secondLastLine = sourceCode.lines[sourceCode.lines.length - 2];
|
||||
|
||||
// File is newline-terminated, but shouldn't be
|
||||
context.report({
|
||||
node,
|
||||
loc: location,
|
||||
loc: {
|
||||
start: { line: sourceCode.lines.length - 1, column: secondLastLine.length },
|
||||
end: { line: sourceCode.lines.length, column: 0 }
|
||||
},
|
||||
messageId: "unexpected",
|
||||
fix(fixer) {
|
||||
const finalEOLs = /(?:\r?\n)+$/u,
|
||||
|
|
|
|||
6
node_modules/eslint/lib/rules/eqeqeq.js
generated
vendored
6
node_modules/eslint/lib/rules/eqeqeq.js
generated
vendored
|
|
@ -15,13 +15,13 @@ const astUtils = require("./utils/ast-utils");
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "require the use of `===` and `!==`",
|
||||
category: "Best Practices",
|
||||
description: "Require the use of `===` and `!==`",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/eqeqeq"
|
||||
},
|
||||
|
|
@ -78,7 +78,7 @@ module.exports = {
|
|||
|
||||
/**
|
||||
* Checks if an expression is a typeof expression
|
||||
* @param {ASTNode} node The node to check
|
||||
* @param {ASTNode} node The node to check
|
||||
* @returns {boolean} if the node is a typeof expression
|
||||
*/
|
||||
function isTypeOf(node) {
|
||||
|
|
|
|||
4
node_modules/eslint/lib/rules/for-direction.js
generated
vendored
4
node_modules/eslint/lib/rules/for-direction.js
generated
vendored
|
|
@ -9,13 +9,13 @@
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "problem",
|
||||
|
||||
docs: {
|
||||
description: "enforce \"for\" loop update clause moving the counter in the right direction.",
|
||||
category: "Possible Errors",
|
||||
description: "Enforce \"for\" loop update clause moving the counter in the right direction",
|
||||
recommended: true,
|
||||
url: "https://eslint.org/docs/rules/for-direction"
|
||||
},
|
||||
|
|
|
|||
4
node_modules/eslint/lib/rules/func-call-spacing.js
generated
vendored
4
node_modules/eslint/lib/rules/func-call-spacing.js
generated
vendored
|
|
@ -15,13 +15,13 @@ const astUtils = require("./utils/ast-utils");
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "require or disallow spacing between function identifiers and their invocations",
|
||||
category: "Stylistic Issues",
|
||||
description: "Require or disallow spacing between function identifiers and their invocations",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/func-call-spacing"
|
||||
},
|
||||
|
|
|
|||
22
node_modules/eslint/lib/rules/func-name-matching.js
generated
vendored
22
node_modules/eslint/lib/rules/func-name-matching.js
generated
vendored
|
|
@ -44,7 +44,7 @@ function isModuleExports(pattern) {
|
|||
* @returns {boolean} True if the string is a valid identifier
|
||||
*/
|
||||
function isIdentifier(name, ecmaVersion) {
|
||||
if (ecmaVersion >= 6) {
|
||||
if (ecmaVersion >= 2015) {
|
||||
return esutils.keyword.isIdentifierES6(name);
|
||||
}
|
||||
return esutils.keyword.isIdentifierES5(name);
|
||||
|
|
@ -68,13 +68,13 @@ const optionsObject = {
|
|||
additionalProperties: false
|
||||
};
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "require function names to match the name of the variable or property to which they are assigned",
|
||||
category: "Stylistic Issues",
|
||||
description: "Require function names to match the name of the variable or property to which they are assigned",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/func-name-matching"
|
||||
},
|
||||
|
|
@ -104,7 +104,7 @@ module.exports = {
|
|||
const nameMatches = typeof context.options[0] === "string" ? context.options[0] : "always";
|
||||
const considerPropertyDescriptor = options.considerPropertyDescriptor;
|
||||
const includeModuleExports = options.includeCommonJSModuleExports;
|
||||
const ecmaVersion = context.parserOptions && context.parserOptions.ecmaVersion ? context.parserOptions.ecmaVersion : 5;
|
||||
const ecmaVersion = context.languageOptions.ecmaVersion;
|
||||
|
||||
/**
|
||||
* Check whether node is a certain CallExpression.
|
||||
|
|
@ -196,21 +196,25 @@ module.exports = {
|
|||
const isProp = node.left.type === "MemberExpression";
|
||||
const name = isProp ? astUtils.getStaticPropertyName(node.left) : node.left.name;
|
||||
|
||||
if (node.right.id && isIdentifier(name) && shouldWarn(name, node.right.id.name)) {
|
||||
if (node.right.id && name && isIdentifier(name) && shouldWarn(name, node.right.id.name)) {
|
||||
report(node, name, node.right.id.name, isProp);
|
||||
}
|
||||
},
|
||||
|
||||
Property(node) {
|
||||
if (node.value.type !== "FunctionExpression" || !node.value.id || node.computed && !isStringLiteral(node.key)) {
|
||||
"Property, PropertyDefinition[value]"(node) {
|
||||
if (!(node.value.type === "FunctionExpression" && node.value.id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.key.type === "Identifier") {
|
||||
if (node.key.type === "Identifier" && !node.computed) {
|
||||
const functionName = node.value.id.name;
|
||||
let propertyName = node.key.name;
|
||||
|
||||
if (considerPropertyDescriptor && propertyName === "value") {
|
||||
if (
|
||||
considerPropertyDescriptor &&
|
||||
propertyName === "value" &&
|
||||
node.parent.type === "ObjectExpression"
|
||||
) {
|
||||
if (isPropertyCall("Object", "defineProperty", node.parent.parent) || isPropertyCall("Reflect", "defineProperty", node.parent.parent)) {
|
||||
const property = node.parent.parent.arguments[1];
|
||||
|
||||
|
|
|
|||
5
node_modules/eslint/lib/rules/func-names.js
generated
vendored
5
node_modules/eslint/lib/rules/func-names.js
generated
vendored
|
|
@ -24,13 +24,13 @@ function isFunctionName(variable) {
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "require or disallow named `function` expressions",
|
||||
category: "Stylistic Issues",
|
||||
description: "Require or disallow named `function` expressions",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/func-names"
|
||||
},
|
||||
|
|
@ -118,6 +118,7 @@ module.exports = {
|
|||
return isObjectOrClassMethod(node) ||
|
||||
(parent.type === "VariableDeclarator" && parent.id.type === "Identifier" && parent.init === node) ||
|
||||
(parent.type === "Property" && parent.value === node) ||
|
||||
(parent.type === "PropertyDefinition" && parent.value === node) ||
|
||||
(parent.type === "AssignmentExpression" && parent.left.type === "Identifier" && parent.right === node) ||
|
||||
(parent.type === "AssignmentPattern" && parent.left.type === "Identifier" && parent.right === node);
|
||||
}
|
||||
|
|
|
|||
4
node_modules/eslint/lib/rules/func-style.js
generated
vendored
4
node_modules/eslint/lib/rules/func-style.js
generated
vendored
|
|
@ -8,13 +8,13 @@
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "enforce the consistent use of either `function` declarations or expressions",
|
||||
category: "Stylistic Issues",
|
||||
description: "Enforce the consistent use of either `function` declarations or expressions",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/func-style"
|
||||
},
|
||||
|
|
|
|||
4
node_modules/eslint/lib/rules/function-call-argument-newline.js
generated
vendored
4
node_modules/eslint/lib/rules/function-call-argument-newline.js
generated
vendored
|
|
@ -9,13 +9,13 @@
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "enforce line breaks between arguments of a function call",
|
||||
category: "Stylistic Issues",
|
||||
description: "Enforce line breaks between arguments of a function call",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/function-call-argument-newline"
|
||||
},
|
||||
|
|
|
|||
22
node_modules/eslint/lib/rules/function-paren-newline.js
generated
vendored
22
node_modules/eslint/lib/rules/function-paren-newline.js
generated
vendored
|
|
@ -14,13 +14,13 @@ const astUtils = require("./utils/ast-utils");
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "enforce consistent line breaks inside function parentheses",
|
||||
category: "Stylistic Issues",
|
||||
description: "Enforce consistent line breaks inside function parentheses",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/function-paren-newline"
|
||||
},
|
||||
|
|
@ -183,6 +183,7 @@ module.exports = {
|
|||
/**
|
||||
* Gets the left paren and right paren tokens of a node.
|
||||
* @param {ASTNode} node The node with parens
|
||||
* @throws {TypeError} Unexpected node type.
|
||||
* @returns {Object} An object with keys `leftParen` for the left paren token, and `rightParen` for the right paren token.
|
||||
* Can also return `null` if an expression has no parens (e.g. a NewExpression with no arguments, or an ArrowFunctionExpression
|
||||
* with a single parameter)
|
||||
|
|
@ -190,10 +191,13 @@ module.exports = {
|
|||
function getParenTokens(node) {
|
||||
switch (node.type) {
|
||||
case "NewExpression":
|
||||
if (!node.arguments.length && !(
|
||||
astUtils.isOpeningParenToken(sourceCode.getLastToken(node, { skip: 1 })) &&
|
||||
astUtils.isClosingParenToken(sourceCode.getLastToken(node))
|
||||
)) {
|
||||
if (!node.arguments.length &&
|
||||
!(
|
||||
astUtils.isOpeningParenToken(sourceCode.getLastToken(node, { skip: 1 })) &&
|
||||
astUtils.isClosingParenToken(sourceCode.getLastToken(node)) &&
|
||||
node.callee.range[1] < node.range[1]
|
||||
)
|
||||
) {
|
||||
|
||||
// If the NewExpression does not have parens (e.g. `new Foo`), return null.
|
||||
return null;
|
||||
|
|
@ -226,9 +230,13 @@ module.exports = {
|
|||
return null;
|
||||
}
|
||||
|
||||
const rightParen = node.params.length
|
||||
? sourceCode.getTokenAfter(node.params[node.params.length - 1], astUtils.isClosingParenToken)
|
||||
: sourceCode.getTokenAfter(firstToken);
|
||||
|
||||
return {
|
||||
leftParen: firstToken,
|
||||
rightParen: sourceCode.getTokenBefore(node.body, astUtils.isClosingParenToken)
|
||||
rightParen
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
4
node_modules/eslint/lib/rules/generator-star-spacing.js
generated
vendored
4
node_modules/eslint/lib/rules/generator-star-spacing.js
generated
vendored
|
|
@ -25,13 +25,13 @@ const OVERRIDE_SCHEMA = {
|
|||
]
|
||||
};
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "enforce consistent spacing around `*` operators in generator functions",
|
||||
category: "ECMAScript 6",
|
||||
description: "Enforce consistent spacing around `*` operators in generator functions",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/generator-star-spacing"
|
||||
},
|
||||
|
|
|
|||
26
node_modules/eslint/lib/rules/getter-return.js
generated
vendored
26
node_modules/eslint/lib/rules/getter-return.js
generated
vendored
|
|
@ -29,13 +29,13 @@ function isReachable(segment) {
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "problem",
|
||||
|
||||
docs: {
|
||||
description: "enforce `return` statements in getters",
|
||||
category: "Possible Errors",
|
||||
description: "Enforce `return` statements in getters",
|
||||
recommended: true,
|
||||
url: "https://eslint.org/docs/rules/getter-return"
|
||||
},
|
||||
|
|
@ -112,18 +112,24 @@ module.exports = {
|
|||
}
|
||||
if (parent.type === "Property" && astUtils.getStaticPropertyName(parent) === "get" && parent.parent.type === "ObjectExpression") {
|
||||
|
||||
// Object.defineProperty()
|
||||
if (parent.parent.parent.type === "CallExpression" &&
|
||||
astUtils.getStaticPropertyName(parent.parent.parent.callee) === "defineProperty") {
|
||||
return true;
|
||||
// Object.defineProperty() or Reflect.defineProperty()
|
||||
if (parent.parent.parent.type === "CallExpression") {
|
||||
const callNode = parent.parent.parent.callee;
|
||||
|
||||
if (astUtils.isSpecificMemberAccess(callNode, "Object", "defineProperty") ||
|
||||
astUtils.isSpecificMemberAccess(callNode, "Reflect", "defineProperty")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Object.defineProperties()
|
||||
// Object.defineProperties() or Object.create()
|
||||
if (parent.parent.parent.type === "Property" &&
|
||||
parent.parent.parent.parent.type === "ObjectExpression" &&
|
||||
parent.parent.parent.parent.parent.type === "CallExpression" &&
|
||||
astUtils.getStaticPropertyName(parent.parent.parent.parent.parent.callee) === "defineProperties") {
|
||||
return true;
|
||||
parent.parent.parent.parent.parent.type === "CallExpression") {
|
||||
const callNode = parent.parent.parent.parent.parent.callee;
|
||||
|
||||
return astUtils.isSpecificMemberAccess(callNode, "Object", "defineProperties") ||
|
||||
astUtils.isSpecificMemberAccess(callNode, "Object", "create");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
14
node_modules/eslint/lib/rules/global-require.js
generated
vendored
14
node_modules/eslint/lib/rules/global-require.js
generated
vendored
|
|
@ -1,11 +1,12 @@
|
|||
/**
|
||||
* @fileoverview Rule for disallowing require() outside of the top-level module context
|
||||
* @author Jamund Ferguson
|
||||
* @deprecated in ESLint v7.0.0
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const ACCEPTABLE_PARENTS = [
|
||||
const ACCEPTABLE_PARENTS = new Set([
|
||||
"AssignmentExpression",
|
||||
"VariableDeclarator",
|
||||
"MemberExpression",
|
||||
|
|
@ -15,7 +16,7 @@ const ACCEPTABLE_PARENTS = [
|
|||
"Program",
|
||||
"VariableDeclaration",
|
||||
"ChainExpression"
|
||||
];
|
||||
]);
|
||||
|
||||
/**
|
||||
* Finds the eslint-scope reference in the given scope.
|
||||
|
|
@ -27,10 +28,11 @@ function findReference(scope, node) {
|
|||
const references = scope.references.filter(reference => reference.identifier.range[0] === node.range[0] &&
|
||||
reference.identifier.range[1] === node.range[1]);
|
||||
|
||||
/* istanbul ignore else: correctly returns null */
|
||||
if (references.length === 1) {
|
||||
return references[0];
|
||||
}
|
||||
|
||||
/* c8 ignore next */
|
||||
return null;
|
||||
|
||||
}
|
||||
|
|
@ -47,6 +49,7 @@ function isShadowed(scope, node) {
|
|||
return reference && reference.resolved && reference.resolved.defs.length > 0;
|
||||
}
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
deprecated: true,
|
||||
|
|
@ -56,8 +59,7 @@ module.exports = {
|
|||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "require `require()` calls to be placed at top-level module scope",
|
||||
category: "Node.js and CommonJS",
|
||||
description: "Require `require()` calls to be placed at top-level module scope",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/global-require"
|
||||
},
|
||||
|
|
@ -74,7 +76,7 @@ module.exports = {
|
|||
const currentScope = context.getScope();
|
||||
|
||||
if (node.callee.name === "require" && !isShadowed(currentScope, node.callee)) {
|
||||
const isGoodRequire = context.getAncestors().every(parent => ACCEPTABLE_PARENTS.indexOf(parent.type) > -1);
|
||||
const isGoodRequire = context.getAncestors().every(parent => ACCEPTABLE_PARENTS.has(parent.type));
|
||||
|
||||
if (!isGoodRequire) {
|
||||
context.report({ node, messageId: "unexpected" });
|
||||
|
|
|
|||
4
node_modules/eslint/lib/rules/grouped-accessor-pairs.js
generated
vendored
4
node_modules/eslint/lib/rules/grouped-accessor-pairs.js
generated
vendored
|
|
@ -90,13 +90,13 @@ function isAccessorKind(node) {
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "require grouped accessor pairs in object literals and classes",
|
||||
category: "Best Practices",
|
||||
description: "Require grouped accessor pairs in object literals and classes",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/grouped-accessor-pairs"
|
||||
},
|
||||
|
|
|
|||
4
node_modules/eslint/lib/rules/guard-for-in.js
generated
vendored
4
node_modules/eslint/lib/rules/guard-for-in.js
generated
vendored
|
|
@ -9,13 +9,13 @@
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "require `for-in` loops to include an `if` statement",
|
||||
category: "Best Practices",
|
||||
description: "Require `for-in` loops to include an `if` statement",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/guard-for-in"
|
||||
},
|
||||
|
|
|
|||
5
node_modules/eslint/lib/rules/handle-callback-err.js
generated
vendored
5
node_modules/eslint/lib/rules/handle-callback-err.js
generated
vendored
|
|
@ -1,6 +1,7 @@
|
|||
/**
|
||||
* @fileoverview Ensure handling of errors when we know they exist.
|
||||
* @author Jamund Ferguson
|
||||
* @deprecated in ESLint v7.0.0
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
|
@ -9,6 +10,7 @@
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
deprecated: true,
|
||||
|
|
@ -18,8 +20,7 @@ module.exports = {
|
|||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "require error handling in callbacks",
|
||||
category: "Node.js and CommonJS",
|
||||
description: "Require error handling in callbacks",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/handle-callback-err"
|
||||
},
|
||||
|
|
|
|||
20
node_modules/eslint/lib/rules/id-blacklist.js
generated
vendored
20
node_modules/eslint/lib/rules/id-blacklist.js
generated
vendored
|
|
@ -2,6 +2,7 @@
|
|||
* @fileoverview Rule that warns when identifier names that are
|
||||
* specified in the configuration are used.
|
||||
* @author Keith Cirkel (http://keithcirkel.co.uk)
|
||||
* @deprecated in ESLint v7.5.0
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
|
@ -109,6 +110,7 @@ function isShorthandPropertyDefinition(node) {
|
|||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
deprecated: true,
|
||||
|
|
@ -117,8 +119,7 @@ module.exports = {
|
|||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "disallow specified identifiers",
|
||||
category: "Stylistic Issues",
|
||||
description: "Disallow specified identifiers",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/id-blacklist"
|
||||
},
|
||||
|
|
@ -205,7 +206,17 @@ module.exports = {
|
|||
* @private
|
||||
*/
|
||||
function report(node) {
|
||||
if (!reportedNodes.has(node)) {
|
||||
|
||||
/*
|
||||
* We used the range instead of the node because it's possible
|
||||
* for the same identifier to be represented by two different
|
||||
* nodes, with the most clear example being shorthand properties:
|
||||
* { foo }
|
||||
* In this case, "foo" is represented by one node for the name
|
||||
* and one for the value. The only way to know they are the same
|
||||
* is to look at the range.
|
||||
*/
|
||||
if (!reportedNodes.has(node.range.toString())) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "restricted",
|
||||
|
|
@ -213,8 +224,9 @@ module.exports = {
|
|||
name: node.name
|
||||
}
|
||||
});
|
||||
reportedNodes.add(node);
|
||||
reportedNodes.add(node.range.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
|||
61
node_modules/eslint/lib/rules/id-denylist.js
generated
vendored
61
node_modules/eslint/lib/rules/id-denylist.js
generated
vendored
|
|
@ -69,14 +69,14 @@ function isRenamedImport(node) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given node is a renamed identifier node in an ObjectPattern destructuring.
|
||||
* Checks whether the given node is an ObjectPattern destructuring.
|
||||
*
|
||||
* Examples:
|
||||
* const { a : b } = foo; // node `a` is renamed node.
|
||||
* const { a : b } = foo;
|
||||
* @param {ASTNode} node `Identifier` node to check.
|
||||
* @returns {boolean} `true` if the node is a renamed node in an ObjectPattern destructuring.
|
||||
* @returns {boolean} `true` if the node is in an ObjectPattern destructuring.
|
||||
*/
|
||||
function isRenamedInDestructuring(node) {
|
||||
function isPropertyNameInDestructuring(node) {
|
||||
const parent = node.parent;
|
||||
|
||||
return (
|
||||
|
|
@ -84,38 +84,22 @@ function isRenamedInDestructuring(node) {
|
|||
!parent.computed &&
|
||||
parent.type === "Property" &&
|
||||
parent.parent.type === "ObjectPattern" &&
|
||||
parent.value !== node &&
|
||||
parent.key === node
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given node represents shorthand definition of a property in an object literal.
|
||||
* @param {ASTNode} node `Identifier` node to check.
|
||||
* @returns {boolean} `true` if the node is a shorthand property definition.
|
||||
*/
|
||||
function isShorthandPropertyDefinition(node) {
|
||||
const parent = node.parent;
|
||||
|
||||
return (
|
||||
parent.type === "Property" &&
|
||||
parent.parent.type === "ObjectExpression" &&
|
||||
parent.shorthand
|
||||
);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "disallow specified identifiers",
|
||||
category: "Stylistic Issues",
|
||||
description: "Disallow specified identifiers",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/id-denylist"
|
||||
},
|
||||
|
|
@ -128,7 +112,8 @@ module.exports = {
|
|||
uniqueItems: true
|
||||
},
|
||||
messages: {
|
||||
restricted: "Identifier '{{name}}' is restricted."
|
||||
restricted: "Identifier '{{name}}' is restricted.",
|
||||
restrictedPrivate: "Identifier '#{{name}}' is restricted."
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -187,11 +172,8 @@ module.exports = {
|
|||
parent.type !== "CallExpression" &&
|
||||
parent.type !== "NewExpression" &&
|
||||
!isRenamedImport(node) &&
|
||||
!isRenamedInDestructuring(node) &&
|
||||
!(
|
||||
isReferenceToGlobalVariable(node) &&
|
||||
!isShorthandPropertyDefinition(node)
|
||||
)
|
||||
!isPropertyNameInDestructuring(node) &&
|
||||
!isReferenceToGlobalVariable(node)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -202,15 +184,27 @@ module.exports = {
|
|||
* @private
|
||||
*/
|
||||
function report(node) {
|
||||
if (!reportedNodes.has(node)) {
|
||||
|
||||
/*
|
||||
* We used the range instead of the node because it's possible
|
||||
* for the same identifier to be represented by two different
|
||||
* nodes, with the most clear example being shorthand properties:
|
||||
* { foo }
|
||||
* In this case, "foo" is represented by one node for the name
|
||||
* and one for the value. The only way to know they are the same
|
||||
* is to look at the range.
|
||||
*/
|
||||
if (!reportedNodes.has(node.range.toString())) {
|
||||
const isPrivate = node.type === "PrivateIdentifier";
|
||||
|
||||
context.report({
|
||||
node,
|
||||
messageId: "restricted",
|
||||
messageId: isPrivate ? "restrictedPrivate" : "restricted",
|
||||
data: {
|
||||
name: node.name
|
||||
}
|
||||
});
|
||||
reportedNodes.add(node);
|
||||
reportedNodes.add(node.range.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -220,7 +214,10 @@ module.exports = {
|
|||
globalScope = context.getScope();
|
||||
},
|
||||
|
||||
Identifier(node) {
|
||||
[[
|
||||
"Identifier",
|
||||
"PrivateIdentifier"
|
||||
]](node) {
|
||||
if (isRestricted(node.name) && shouldCheck(node)) {
|
||||
report(node);
|
||||
}
|
||||
|
|
|
|||
91
node_modules/eslint/lib/rules/id-length.js
generated
vendored
91
node_modules/eslint/lib/rules/id-length.js
generated
vendored
|
|
@ -6,17 +6,56 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
const GraphemeSplitter = require("grapheme-splitter");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Checks if the string given as argument is ASCII or not.
|
||||
* @param {string} value A string that you want to know if it is ASCII or not.
|
||||
* @returns {boolean} `true` if `value` is ASCII string.
|
||||
*/
|
||||
function isASCII(value) {
|
||||
if (typeof value !== "string") {
|
||||
return false;
|
||||
}
|
||||
return /^[\u0020-\u007f]*$/u.test(value);
|
||||
}
|
||||
|
||||
/** @type {GraphemeSplitter | undefined} */
|
||||
let splitter;
|
||||
|
||||
/**
|
||||
* Gets the length of the string. If the string is not in ASCII, counts graphemes.
|
||||
* @param {string} value A string that you want to get the length.
|
||||
* @returns {number} The length of `value`.
|
||||
*/
|
||||
function getStringLength(value) {
|
||||
if (isASCII(value)) {
|
||||
return value.length;
|
||||
}
|
||||
if (!splitter) {
|
||||
splitter = new GraphemeSplitter();
|
||||
}
|
||||
return splitter.countGraphemes(value);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "enforce minimum and maximum identifier lengths",
|
||||
category: "Stylistic Issues",
|
||||
description: "Enforce minimum and maximum identifier lengths",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/rules/id-length"
|
||||
},
|
||||
|
|
@ -55,7 +94,9 @@ module.exports = {
|
|||
],
|
||||
messages: {
|
||||
tooShort: "Identifier name '{{name}}' is too short (< {{min}}).",
|
||||
tooLong: "Identifier name '{{name}}' is too long (> {{max}})."
|
||||
tooShortPrivate: "Identifier name '#{{name}}' is too short (< {{min}}).",
|
||||
tooLong: "Identifier name '{{name}}' is too long (> {{max}}).",
|
||||
tooLongPrivate: "Identifier name #'{{name}}' is too long (> {{max}})."
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -66,7 +107,7 @@ module.exports = {
|
|||
const properties = options.properties !== "never";
|
||||
const exceptions = new Set(options.exceptions);
|
||||
const exceptionPatterns = (options.exceptionPatterns || []).map(pattern => new RegExp(pattern, "u"));
|
||||
const reportedNode = new Set();
|
||||
const reportedNodes = new Set();
|
||||
|
||||
/**
|
||||
* Checks if a string matches the provided exception patterns
|
||||
|
|
@ -99,12 +140,14 @@ module.exports = {
|
|||
Property(parent, node) {
|
||||
|
||||
if (parent.parent.type === "ObjectPattern") {
|
||||
const isKeyAndValueSame = parent.value.name === parent.key.name;
|
||||
|
||||
return (
|
||||
parent.value !== parent.key && parent.value === node ||
|
||||
parent.value === parent.key && parent.key === node && properties
|
||||
!isKeyAndValueSame && parent.value === node ||
|
||||
isKeyAndValueSame && parent.key === node && properties
|
||||
);
|
||||
}
|
||||
return properties && !parent.computed && parent.key === node;
|
||||
return properties && !parent.computed && parent.key.name === node.name;
|
||||
},
|
||||
ImportDefaultSpecifier: true,
|
||||
RestElement: true,
|
||||
|
|
@ -113,17 +156,23 @@ module.exports = {
|
|||
ClassDeclaration: true,
|
||||
FunctionDeclaration: true,
|
||||
MethodDefinition: true,
|
||||
PropertyDefinition: true,
|
||||
CatchClause: true,
|
||||
ArrayPattern: true
|
||||
};
|
||||
|
||||
return {
|
||||
Identifier(node) {
|
||||
[[
|
||||
"Identifier",
|
||||
"PrivateIdentifier"
|
||||
]](node) {
|
||||
const name = node.name;
|
||||
const parent = node.parent;
|
||||
|
||||
const isShort = name.length < minLength;
|
||||
const isLong = name.length > maxLength;
|
||||
const nameLength = getStringLength(name);
|
||||
|
||||
const isShort = nameLength < minLength;
|
||||
const isLong = nameLength > maxLength;
|
||||
|
||||
if (!(isShort || isLong) || exceptions.has(name) || matchesExceptionPattern(name)) {
|
||||
return; // Nothing to report
|
||||
|
|
@ -131,11 +180,27 @@ module.exports = {
|
|||
|
||||
const isValidExpression = SUPPORTED_EXPRESSIONS[parent.type];
|
||||
|
||||
if (isValidExpression && !reportedNode.has(node) && (isValidExpression === true || isValidExpression(parent, node))) {
|
||||
reportedNode.add(node);
|
||||
/*
|
||||
* We used the range instead of the node because it's possible
|
||||
* for the same identifier to be represented by two different
|
||||
* nodes, with the most clear example being shorthand properties:
|
||||
* { foo }
|
||||
* In this case, "foo" is represented by one node for the name
|
||||
* and one for the value. The only way to know they are the same
|
||||
* is to look at the range.
|
||||
*/
|
||||
if (isValidExpression && !reportedNodes.has(node.range.toString()) && (isValidExpression === true || isValidExpression(parent, node))) {
|
||||
reportedNodes.add(node.range.toString());
|
||||
|
||||
let messageId = isShort ? "tooShort" : "tooLong";
|
||||
|
||||
if (node.type === "PrivateIdentifier") {
|
||||
messageId += "Private";
|
||||
}
|
||||
|
||||
context.report({
|
||||
node,
|
||||
messageId: isShort ? "tooShort" : "tooLong",
|
||||
messageId,
|
||||
data: { name, min: minLength, max: maxLength }
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue