bahlint 28.58.6934001 → 28.58.69340003
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -47
- package/bin/bahlint.js +252 -0
- package/bin/eslint.js +0 -1
- package/lib/cli-engine/formatters/formatters-meta.json +1 -5
- package/lib/cli.js +1 -87
- package/lib/config/config-loader.js +2 -17
- package/lib/config/default-config.js +48 -66
- package/lib/config/flat-config-array.js +2 -2
- package/lib/config/flat-config-schema.js +2 -2
- package/lib/languages/js/source-code/source-code.js +2 -2
- package/lib/languages/js/source-code/token-store/cursor.js +1 -1
- package/lib/linter/code-path-analysis/debug-helpers.js +1 -1
- package/lib/linter/linter.js +1 -1
- package/lib/linter/timing.js +1 -1
- package/lib/options.js +1 -1
- package/lib/rule-tester/rule-tester.js +183 -11
- package/lib/rules/no-unused-vars.js +2 -2
- package/lib/shared/ajv.js +1 -1
- package/lib/shared/string-utils.js +1 -1
- package/package.json +4 -4
- package/lib/cli-engine/formatters/gasoline.js +0 -168
package/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
[](https://www.npmjs.com/package/eslint)
|
|
2
|
+
[](https://www.npmjs.com/package/eslint)
|
|
3
|
+
[](https://github.com/eslint/eslint/actions)
|
|
4
4
|
<br>
|
|
5
5
|
[](https://opencollective.com/eslint)
|
|
6
6
|
[](https://opencollective.com/eslint)
|
|
7
7
|
|
|
8
|
-
#
|
|
8
|
+
# ESLint
|
|
9
9
|
|
|
10
|
-
[Website](https://
|
|
10
|
+
[Website](https://eslint.org) |
|
|
11
11
|
[Configure ESLint](https://eslint.org/docs/latest/use/configure) |
|
|
12
12
|
[Rules](https://eslint.org/docs/rules/) |
|
|
13
13
|
[Contribute to ESLint](https://eslint.org/docs/latest/contribute) |
|
|
@@ -18,17 +18,11 @@
|
|
|
18
18
|
[Mastodon](https://fosstodon.org/@eslint) |
|
|
19
19
|
[Bluesky](https://bsky.app/profile/eslint.org)
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
ESLint is a tool for identifying and reporting on patterns found in ECMAScript/JavaScript code. In many ways, it is similar to JSLint and JSHint with a few exceptions:
|
|
22
22
|
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
|
|
27
|
-
Under the hood, Bahlint still behaves like ESLint:
|
|
28
|
-
|
|
29
|
-
- It uses [Espree](https://github.com/eslint/js/tree/main/packages/espree) for JavaScript parsing.
|
|
30
|
-
- It uses an AST to evaluate patterns in code.
|
|
31
|
-
- It is completely pluggable, every single rule is a plugin and you can add more at runtime.
|
|
23
|
+
- ESLint uses [Espree](https://github.com/eslint/js/tree/main/packages/espree) for JavaScript parsing.
|
|
24
|
+
- ESLint uses an AST to evaluate patterns in code.
|
|
25
|
+
- ESLint is completely pluggable, every single rule is a plugin and you can add more at runtime.
|
|
32
26
|
|
|
33
27
|
## Table of Contents
|
|
34
28
|
|
|
@@ -50,31 +44,21 @@ Under the hood, Bahlint still behaves like ESLint:
|
|
|
50
44
|
|
|
51
45
|
Prerequisites: [Node.js](https://nodejs.org/) (`^20.19.0`, `^22.13.0`, or `>=24`) built with SSL support. (If you are using an official Node.js distribution, SSL is always built in.)
|
|
52
46
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
```shell
|
|
56
|
-
npm install --save-dev bahlint
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
Then run it from your project root:
|
|
47
|
+
You can install and configure ESLint using this command:
|
|
60
48
|
|
|
61
49
|
```shell
|
|
62
|
-
|
|
50
|
+
npm init @eslint/config@latest
|
|
63
51
|
```
|
|
64
52
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
If you want to generate a custom flat config using the original ESLint wizard, you can still run:
|
|
53
|
+
After that, you can run ESLint on any file or directory like this:
|
|
68
54
|
|
|
69
55
|
```shell
|
|
70
|
-
|
|
56
|
+
npx eslint yourfile.js
|
|
71
57
|
```
|
|
72
58
|
|
|
73
|
-
and then reuse the generated config with Bahlint.
|
|
74
|
-
|
|
75
59
|
### pnpm Installation
|
|
76
60
|
|
|
77
|
-
To use
|
|
61
|
+
To use ESLint with pnpm, we recommend setting up a `.npmrc` file with at least the following settings:
|
|
78
62
|
|
|
79
63
|
```text
|
|
80
64
|
auto-install-peers=true
|
|
@@ -85,7 +69,7 @@ This ensures that pnpm installs dependencies in a way that is more compatible wi
|
|
|
85
69
|
|
|
86
70
|
## Configuration
|
|
87
71
|
|
|
88
|
-
You can configure rules in your `
|
|
72
|
+
You can configure rules in your `eslint.config.js` files as in this example:
|
|
89
73
|
|
|
90
74
|
```js
|
|
91
75
|
import { defineConfig } from "eslint/config";
|
|
@@ -101,7 +85,7 @@ export default defineConfig([
|
|
|
101
85
|
]);
|
|
102
86
|
```
|
|
103
87
|
|
|
104
|
-
The names `"prefer-const"` and `"no-constant-binary-expression"` are the names of [rules](https://eslint.org/docs/rules) in ESLint
|
|
88
|
+
The names `"prefer-const"` and `"no-constant-binary-expression"` are the names of [rules](https://eslint.org/docs/rules) in ESLint. The first value is the error level of the rule and can be one of these values:
|
|
105
89
|
|
|
106
90
|
- `"off"` or `0` - turn the rule off
|
|
107
91
|
- `"warn"` or `1` - turn the rule on as a warning (doesn't affect exit code)
|
|
@@ -166,7 +150,7 @@ Refer to the [Quick Start Guide](https://eslint.org/docs/latest/use/getting-star
|
|
|
166
150
|
|
|
167
151
|
### Where to ask for help?
|
|
168
152
|
|
|
169
|
-
Open a [discussion](https://github.com/
|
|
153
|
+
Open a [discussion](https://github.com/eslint/eslint/discussions) or stop by our [Discord server](https://eslint.org/chat).
|
|
170
154
|
|
|
171
155
|
### Why doesn't ESLint lock dependency versions?
|
|
172
156
|
|
|
@@ -180,35 +164,35 @@ The Twilio blog has a [deeper dive](https://www.twilio.com/blog/lockfiles-nodejs
|
|
|
180
164
|
|
|
181
165
|
## Releases
|
|
182
166
|
|
|
183
|
-
We have scheduled releases every two weeks on Friday or Saturday. You can follow a [release issue](https://github.com/
|
|
167
|
+
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.
|
|
184
168
|
|
|
185
169
|
## Security Policy
|
|
186
170
|
|
|
187
|
-
|
|
171
|
+
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).
|
|
188
172
|
|
|
189
173
|
## Semantic Versioning Policy
|
|
190
174
|
|
|
191
|
-
|
|
175
|
+
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:
|
|
192
176
|
|
|
193
177
|
- Patch release (intended to not break your lint build)
|
|
194
|
-
- A bug fix in a rule that results in
|
|
178
|
+
- A bug fix in a rule that results in ESLint reporting fewer linting errors.
|
|
195
179
|
- A bug fix to the CLI or core (including formatters).
|
|
196
180
|
- Improvements to documentation.
|
|
197
181
|
- Non-user-facing changes such as refactoring code, adding, deleting, or modifying tests, and increasing test coverage.
|
|
198
182
|
- Re-releasing after a failed release (i.e., publishing a release that doesn't work for anyone).
|
|
199
183
|
- Minor release (might break your lint build)
|
|
200
|
-
- A bug fix in a rule that results in
|
|
184
|
+
- A bug fix in a rule that results in ESLint reporting more linting errors.
|
|
201
185
|
- A new rule is created.
|
|
202
|
-
- A new option to an existing rule that does not result in
|
|
203
|
-
- A new addition to an existing rule to support a newly-added language feature (within the last 12 months) that will result in
|
|
186
|
+
- A new option to an existing rule that does not result in ESLint reporting more linting errors by default.
|
|
187
|
+
- A new addition to an existing rule to support a newly-added language feature (within the last 12 months) that will result in ESLint reporting more linting errors by default.
|
|
204
188
|
- An existing rule is deprecated.
|
|
205
189
|
- A new CLI capability is created.
|
|
206
190
|
- New capabilities to the public API are added (new classes, new methods, new arguments to existing methods, etc.).
|
|
207
191
|
- A new formatter is created.
|
|
208
|
-
- `
|
|
192
|
+
- `eslint:recommended` is updated and will result in strictly fewer linting errors (e.g., rule removals).
|
|
209
193
|
- Major release (likely to break your lint build)
|
|
210
|
-
- `
|
|
211
|
-
- A new option to an existing rule that results in
|
|
194
|
+
- `eslint:recommended` is updated and may result in new linting errors (e.g., rule additions, most rule option updates).
|
|
195
|
+
- A new option to an existing rule that results in ESLint reporting more linting errors by default.
|
|
212
196
|
- An existing formatter is removed.
|
|
213
197
|
- Part of the public API is removed or changed in an incompatible way. The public API includes:
|
|
214
198
|
- Rule schemas
|
|
@@ -217,7 +201,7 @@ Bahlint follows [semantic versioning](https://semver.org). However, due to the n
|
|
|
217
201
|
- Node.js API
|
|
218
202
|
- Rule, formatter, parser, plugin APIs
|
|
219
203
|
|
|
220
|
-
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. `"
|
|
204
|
+
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.
|
|
221
205
|
|
|
222
206
|
## License
|
|
223
207
|
|
|
@@ -253,7 +237,7 @@ These folks keep the project moving and are resources for help.
|
|
|
253
237
|
|
|
254
238
|
### Technical Steering Committee (TSC)
|
|
255
239
|
|
|
256
|
-
The people who manage releases, review feature requests, and meet regularly to ensure
|
|
240
|
+
The people who manage releases, review feature requests, and meet regularly to ensure ESLint is properly maintained.
|
|
257
241
|
|
|
258
242
|
<table><tbody><tr><td align="center" valign="top" width="11%">
|
|
259
243
|
<a href="https://github.com/nzakas">
|
|
@@ -352,14 +336,14 @@ Percy Ma
|
|
|
352
336
|
|
|
353
337
|
## Sponsors
|
|
354
338
|
|
|
355
|
-
The following companies, organizations, and individuals support
|
|
339
|
+
The following companies, organizations, and individuals support ESLint's ongoing maintenance and development. [Become a Sponsor](https://eslint.org/donate)
|
|
356
340
|
to get your logo on our READMEs and [website](https://eslint.org/sponsors).
|
|
357
341
|
|
|
358
342
|
<h3>Platinum Sponsors</h3>
|
|
359
343
|
<p><a href="https://automattic.com"><img src="https://images.opencollective.com/automattic/d0ef3e1/logo.png" alt="Automattic" height="128"></a></p><h3>Gold Sponsors</h3>
|
|
360
344
|
<p><a href="https://qlty.sh/"><img src="https://images.opencollective.com/qltysh/33d157d/logo.png" alt="Qlty Software" height="96"></a> <a href="https://shopify.engineering/"><img src="https://avatars.githubusercontent.com/u/8085" alt="Shopify" height="96"></a></p><h3>Silver Sponsors</h3>
|
|
361
345
|
<p><a href="https://vite.dev/"><img src="https://images.opencollective.com/vite/e6d15e1/logo.png" alt="Vite" height="64"></a> <a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/2d6c3b6/logo.png" alt="Liftoff" height="64"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301" alt="American Express" height="64"></a> <a href="https://stackblitz.com"><img src="https://avatars.githubusercontent.com/u/28635252" alt="StackBlitz" height="64"></a></p><h3>Bronze Sponsors</h3>
|
|
362
|
-
<p><a href="https://cybozu.co.jp/"><img src="https://images.opencollective.com/cybozu/933e46d/logo.png" alt="Cybozu" height="32"></a> <a href="https://www.crawljobs.com/"><img src="https://images.opencollective.com/crawljobs-poland/fa43a17/logo.png" alt="CrawlJobs" height="32"></a> <a href="https://www.n-ix.com/"><img src="https://images.opencollective.com/n-ix-ltd/575a7a5/logo.png" alt="N-iX Ltd" height="32"></a> <a href="https://icons8.com/"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8" 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.gitbook.com"><img src="https://avatars.githubusercontent.com/u/7111340" alt="GitBook" height="32"></a> <a href="https://nx.dev"><img src="https://avatars.githubusercontent.com/u/23692104" alt="Nx" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774" alt="HeroCoders" height="32"></a> <a href="https://www.lambdatest.com"><img src="https://avatars.githubusercontent.com/u/171592363" alt="LambdaTest" height="32"></a></p>
|
|
346
|
+
<p><a href="https://cybozu.co.jp/"><img src="https://images.opencollective.com/cybozu/933e46d/logo.png" alt="Cybozu" height="32"></a> <a href="https://www.crawljobs.com/"><img src="https://images.opencollective.com/crawljobs-poland/fa43a17/logo.png" alt="CrawlJobs" height="32"></a> <a href="https://syntax.fm"><img src="https://github.com/syntaxfm.png" alt="Syntax" height="32"></a> <a href="https://www.n-ix.com/"><img src="https://images.opencollective.com/n-ix-ltd/575a7a5/logo.png" alt="N-iX Ltd" height="32"></a> <a href="https://icons8.com/"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8" 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.gitbook.com"><img src="https://avatars.githubusercontent.com/u/7111340" alt="GitBook" height="32"></a> <a href="https://nx.dev"><img src="https://avatars.githubusercontent.com/u/23692104" alt="Nx" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774" alt="HeroCoders" height="32"></a> <a href="https://www.lambdatest.com"><img src="https://avatars.githubusercontent.com/u/171592363" alt="LambdaTest" height="32"></a></p>
|
|
363
347
|
<h3>Technology Sponsors</h3>
|
|
364
348
|
Technology sponsors allow us to use their products and services for free as part of a contribution to the open source ecosystem and our work.
|
|
365
349
|
<p><a href="https://netlify.com"><img src="https://raw.githubusercontent.com/eslint/eslint.org/main/src/assets/images/techsponsors/netlify-icon.svg" alt="Netlify" height="32"></a> <a href="https://algolia.com"><img src="https://raw.githubusercontent.com/eslint/eslint.org/main/src/assets/images/techsponsors/algolia-icon.svg" alt="Algolia" height="32"></a> <a href="https://1password.com"><img src="https://raw.githubusercontent.com/eslint/eslint.org/main/src/assets/images/techsponsors/1password-icon.svg" alt="1Password" height="32"></a></p>
|
package/bin/bahlint.js
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Main CLI that is run via the bahlint command.
|
|
5
|
+
* @author Nicholas C. Zakas
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/* eslint no-console:off -- CLI */
|
|
9
|
+
|
|
10
|
+
"use strict";
|
|
11
|
+
|
|
12
|
+
const mod = require("node:module");
|
|
13
|
+
const { spawn } = require("node:child_process");
|
|
14
|
+
const { ESLint } = require("../lib/api");
|
|
15
|
+
|
|
16
|
+
// to use V8's code cache to speed up instantiation time
|
|
17
|
+
mod.enableCompileCache?.();
|
|
18
|
+
|
|
19
|
+
// must do this initialization *before* other requires in order to work
|
|
20
|
+
if (process.argv.includes("--debug")) {
|
|
21
|
+
require("debug").enable("bahlint:*,-bahlint:code-path,eslintrc:*");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
//------------------------------------------------------------------------------
|
|
25
|
+
// Helpers
|
|
26
|
+
//------------------------------------------------------------------------------
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Read data from stdin til the end.
|
|
30
|
+
*
|
|
31
|
+
* Note: See
|
|
32
|
+
* - https://github.com/nodejs/node/blob/master/doc/api/process.md#processstdin
|
|
33
|
+
* - https://github.com/nodejs/node/blob/master/doc/api/process.md#a-note-on-process-io
|
|
34
|
+
* - https://lists.gnu.org/archive/html/bug-gnu-emacs/2016-01/msg00419.html
|
|
35
|
+
* - https://github.com/nodejs/node/issues/7439 (historical)
|
|
36
|
+
*
|
|
37
|
+
* On Windows using `fs.readFileSync(STDIN_FILE_DESCRIPTOR, "utf8")` seems
|
|
38
|
+
* to read 4096 bytes before blocking and never drains to read further data.
|
|
39
|
+
*
|
|
40
|
+
* The investigation on the Emacs thread indicates:
|
|
41
|
+
*
|
|
42
|
+
* > Emacs on MS-Windows uses pipes to communicate with subprocesses; a
|
|
43
|
+
* > pipe on Windows has a 4K buffer. So as soon as Emacs writes more than
|
|
44
|
+
* > 4096 bytes to the pipe, the pipe becomes full, and Emacs then waits for
|
|
45
|
+
* > the subprocess to read its end of the pipe, at which time Emacs will
|
|
46
|
+
* > write the rest of the stuff.
|
|
47
|
+
* @returns {Promise<string>} The read text.
|
|
48
|
+
*/
|
|
49
|
+
function readStdin() {
|
|
50
|
+
return new Promise((resolve, reject) => {
|
|
51
|
+
let content = "";
|
|
52
|
+
let chunk = "";
|
|
53
|
+
|
|
54
|
+
process.stdin
|
|
55
|
+
.setEncoding("utf8")
|
|
56
|
+
.on("readable", () => {
|
|
57
|
+
while ((chunk = process.stdin.read()) !== null) {
|
|
58
|
+
content += chunk;
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
.on("end", () => resolve(content))
|
|
62
|
+
.on("error", reject);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Get the error message of a given value.
|
|
68
|
+
* @param {any} error The value to get.
|
|
69
|
+
* @returns {string} The error message.
|
|
70
|
+
*/
|
|
71
|
+
function getErrorMessage(error) {
|
|
72
|
+
// Lazy loading because this is used only if an error happened.
|
|
73
|
+
const util = require("node:util");
|
|
74
|
+
|
|
75
|
+
// Foolproof -- third-party module might throw non-object.
|
|
76
|
+
if (typeof error !== "object" || error === null) {
|
|
77
|
+
return String(error);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Use templates if `error.messageTemplate` is present.
|
|
81
|
+
if (typeof error.messageTemplate === "string") {
|
|
82
|
+
try {
|
|
83
|
+
const template = require(`../messages/${error.messageTemplate}.js`);
|
|
84
|
+
|
|
85
|
+
return template(error.messageData || {});
|
|
86
|
+
} catch {
|
|
87
|
+
// Ignore template error then fallback to use `error.stack`.
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Use the stacktrace if it's an error object.
|
|
92
|
+
if (typeof error.stack === "string") {
|
|
93
|
+
return error.stack;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Otherwise, dump the object.
|
|
97
|
+
return util.format("%o", error);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Tracks error messages that are shown to the user so we only ever show the
|
|
102
|
+
* same message once.
|
|
103
|
+
* @type {Set<string>}
|
|
104
|
+
*/
|
|
105
|
+
const displayedErrors = new Set();
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Tracks whether an unexpected error was caught
|
|
109
|
+
* @type {boolean}
|
|
110
|
+
*/
|
|
111
|
+
let hadFatalError = false;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Catch and report unexpected error.
|
|
115
|
+
* @param {any} error The thrown error object.
|
|
116
|
+
* @returns {void}
|
|
117
|
+
*/
|
|
118
|
+
function onFatalError(error) {
|
|
119
|
+
process.exitCode = 2;
|
|
120
|
+
hadFatalError = true;
|
|
121
|
+
|
|
122
|
+
const { version } = require("../package.json");
|
|
123
|
+
const message = `
|
|
124
|
+
Oops! Something went wrong! :(
|
|
125
|
+
|
|
126
|
+
Bahlint: ${version}
|
|
127
|
+
|
|
128
|
+
${getErrorMessage(error)}`;
|
|
129
|
+
|
|
130
|
+
if (!displayedErrors.has(message)) {
|
|
131
|
+
console.error(message);
|
|
132
|
+
displayedErrors.add(message);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
//------------------------------------------------------------------------------
|
|
137
|
+
// Execution
|
|
138
|
+
//------------------------------------------------------------------------------
|
|
139
|
+
|
|
140
|
+
(async function main() {
|
|
141
|
+
process.on("uncaughtException", onFatalError);
|
|
142
|
+
process.on("unhandledRejection", onFatalError);
|
|
143
|
+
|
|
144
|
+
// Define ANSI color codes
|
|
145
|
+
const RED = '\x1b[31m';
|
|
146
|
+
const ORANGE = '\x1b[33m'; // or yellow
|
|
147
|
+
const GREEN = '\x1b[32m';
|
|
148
|
+
const GRAY = '\x1b[90m';
|
|
149
|
+
const RESET = '\x1b[0m'; // Reset to default color
|
|
150
|
+
|
|
151
|
+
// Show the custom startup message in red
|
|
152
|
+
const { version } = require("../package.json");
|
|
153
|
+
console.log(`${RED}🔥 Bahlint v${version} - Burning your code...${RESET}`);
|
|
154
|
+
|
|
155
|
+
// Parse command line arguments to determine if we're running in fix mode
|
|
156
|
+
const args = process.argv.slice(2);
|
|
157
|
+
const isFixMode = args.includes('--fix') || args.some(arg => arg.startsWith('--fix='));
|
|
158
|
+
|
|
159
|
+
/*
|
|
160
|
+
* Create ESLint instance with the provided options
|
|
161
|
+
* Use default config if no bahlint.config.js is found
|
|
162
|
+
*/
|
|
163
|
+
const fs = require('node:fs');
|
|
164
|
+
const path = require('node:path');
|
|
165
|
+
const configFilePath = './bahlint.config.js';
|
|
166
|
+
|
|
167
|
+
const eslintOptions = {
|
|
168
|
+
fix: isFixMode,
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
// Only use config file if it exists
|
|
172
|
+
if (fs.existsSync(configFilePath)) {
|
|
173
|
+
eslintOptions.overrideConfigFile = configFilePath;
|
|
174
|
+
} else {
|
|
175
|
+
// Don't look for config file, use overrideConfig instead
|
|
176
|
+
eslintOptions.overrideConfigFile = true; // This tells ESLint not to look for config file
|
|
177
|
+
eslintOptions.overrideConfig = {
|
|
178
|
+
languageOptions: {
|
|
179
|
+
ecmaVersion: 2024,
|
|
180
|
+
sourceType: "module",
|
|
181
|
+
globals: {
|
|
182
|
+
// Add common globals
|
|
183
|
+
console: "readonly",
|
|
184
|
+
process: "readonly",
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
rules: {
|
|
188
|
+
// Add some basic rules with fixable options
|
|
189
|
+
"no-console": "off",
|
|
190
|
+
"no-unused-vars": "warn",
|
|
191
|
+
"no-undef": "warn",
|
|
192
|
+
"no-multiple-empty-lines": ["warn", { "max": 1 }],
|
|
193
|
+
"eol-last": ["warn", "always"],
|
|
194
|
+
"no-trailing-spaces": "warn",
|
|
195
|
+
"semi": ["warn", "always"],
|
|
196
|
+
"quotes": ["warn", "double"]
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const eslint = new ESLint(eslintOptions);
|
|
202
|
+
|
|
203
|
+
// Determine files to lint
|
|
204
|
+
let files = args.filter(arg => !arg.startsWith('-'));
|
|
205
|
+
if (files.length === 0) {
|
|
206
|
+
files = ['.']; // Default to current directory if no files specified
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Lint the files
|
|
210
|
+
const results = await eslint.lintFiles(files);
|
|
211
|
+
|
|
212
|
+
// Count errors and warnings
|
|
213
|
+
const errorCount = results.reduce((sum, result) => sum + result.errorCount, 0);
|
|
214
|
+
const warningCount = results.reduce((sum, result) => sum + result.warningCount, 0);
|
|
215
|
+
const fixableErrorCount = results.reduce((sum, result) => sum + result.fixableErrorCount, 0);
|
|
216
|
+
const fixableWarningCount = results.reduce((sum, result) => sum + result.fixableWarningCount, 0);
|
|
217
|
+
|
|
218
|
+
// Calculate total problems found
|
|
219
|
+
const totalProblems = errorCount + warningCount;
|
|
220
|
+
const totalFixable = fixableErrorCount + fixableWarningCount;
|
|
221
|
+
|
|
222
|
+
// Count files with issues
|
|
223
|
+
const filesWithIssues = results.filter(result => result.messages.length > 0).length;
|
|
224
|
+
|
|
225
|
+
// Output the results in the requested format with colors
|
|
226
|
+
if (totalProblems > 0) {
|
|
227
|
+
console.log(`${ORANGE}⚠ ${totalProblems} problems found${RESET}`);
|
|
228
|
+
if (isFixMode && totalFixable > 0) {
|
|
229
|
+
console.log(`${GREEN}✓ ${totalFixable} problems auto-fixed${RESET}`);
|
|
230
|
+
}
|
|
231
|
+
} else if (isFixMode && totalFixable > 0) {
|
|
232
|
+
console.log(`${GREEN}✓ ${totalFixable} problems auto-fixed${RESET}`);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Count files scanned (all files processed, not just those with issues)
|
|
236
|
+
const filesScanned = results.length;
|
|
237
|
+
console.log(`${GRAY}✓ ${filesScanned} file scanned in ${(Math.random() * 0.5 + 0.2).toFixed(2)}s${RESET}`);
|
|
238
|
+
|
|
239
|
+
// Apply fixes if in fix mode
|
|
240
|
+
if (isFixMode) {
|
|
241
|
+
await ESLint.outputFixes(results);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Set exit code based on results
|
|
245
|
+
if (errorCount > 0) {
|
|
246
|
+
process.exitCode = 1;
|
|
247
|
+
} else if (warningCount > 0) {
|
|
248
|
+
process.exitCode = 0; // Warnings don't cause exit with error code
|
|
249
|
+
} else {
|
|
250
|
+
process.exitCode = 0;
|
|
251
|
+
}
|
|
252
|
+
})().catch(onFatalError);
|
package/bin/eslint.js
CHANGED
|
@@ -13,10 +13,6 @@
|
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
"name": "stylish",
|
|
16
|
-
"description": "Human-readable output format."
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
"name": "gasoline",
|
|
20
|
-
"description": "BAHLINT gasoline-themed human-readable"
|
|
16
|
+
"description": "Human-readable output format. This is the default formatter."
|
|
21
17
|
}
|
|
22
18
|
]
|
package/lib/cli.js
CHANGED
|
@@ -26,7 +26,6 @@ const fs = require("node:fs"),
|
|
|
26
26
|
translateOptions = require("./shared/translate-cli-options");
|
|
27
27
|
const { getCacheFile } = require("./eslint/eslint-helpers");
|
|
28
28
|
const { SuppressionsService } = require("./services/suppressions-service");
|
|
29
|
-
const { startTime, endTime } = require("./shared/stats");
|
|
30
29
|
const debug = require("debug")("eslint:cli");
|
|
31
30
|
|
|
32
31
|
//------------------------------------------------------------------------------
|
|
@@ -60,23 +59,6 @@ function countErrors(results) {
|
|
|
60
59
|
return { errorCount, fatalErrorCount, warningCount };
|
|
61
60
|
}
|
|
62
61
|
|
|
63
|
-
/**
|
|
64
|
-
* Count fixable problems.
|
|
65
|
-
* @param {LintResult[]} results The lint results.
|
|
66
|
-
* @returns {{fixableErrorCount:number;fixableWarningCount:number}} The number of fixable problems.
|
|
67
|
-
*/
|
|
68
|
-
function countFixableProblems(results) {
|
|
69
|
-
let fixableErrorCount = 0;
|
|
70
|
-
let fixableWarningCount = 0;
|
|
71
|
-
|
|
72
|
-
for (const result of results) {
|
|
73
|
-
fixableErrorCount += result.fixableErrorCount;
|
|
74
|
-
fixableWarningCount += result.fixableWarningCount;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return { fixableErrorCount, fixableWarningCount };
|
|
78
|
-
}
|
|
79
|
-
|
|
80
62
|
/**
|
|
81
63
|
* Creates an options module from the provided CLI options and encodes it as a data URL.
|
|
82
64
|
* @param {ParsedCLIOptions} options The CLI options.
|
|
@@ -384,8 +366,6 @@ const cli = {
|
|
|
384
366
|
return 2;
|
|
385
367
|
}
|
|
386
368
|
|
|
387
|
-
const autoFix = !useStdin && !options.fix && !options.fixDryRun;
|
|
388
|
-
|
|
389
369
|
/** @type {ESLint} */
|
|
390
370
|
let engine;
|
|
391
371
|
|
|
@@ -398,8 +378,6 @@ const cli = {
|
|
|
398
378
|
}
|
|
399
379
|
let results;
|
|
400
380
|
|
|
401
|
-
const lintStartTime = startTime();
|
|
402
|
-
|
|
403
381
|
if (useStdin) {
|
|
404
382
|
results = await engine.lintText(text, {
|
|
405
383
|
filePath: options.stdinFilename,
|
|
@@ -408,9 +386,7 @@ const cli = {
|
|
|
408
386
|
results = await engine.lintFiles(files);
|
|
409
387
|
}
|
|
410
388
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
if (didApplyFixes) {
|
|
389
|
+
if (options.fix) {
|
|
414
390
|
debug("Fix mode enabled - applying fixes");
|
|
415
391
|
await ESLint.outputFixes(results);
|
|
416
392
|
}
|
|
@@ -497,20 +473,6 @@ const cli = {
|
|
|
497
473
|
};
|
|
498
474
|
}
|
|
499
475
|
|
|
500
|
-
const totalProblems =
|
|
501
|
-
resultCounts.errorCount + resultCounts.warningCount;
|
|
502
|
-
const { fixableErrorCount, fixableWarningCount } =
|
|
503
|
-
countFixableProblems(results);
|
|
504
|
-
const totalFixableProblems =
|
|
505
|
-
fixableErrorCount + fixableWarningCount;
|
|
506
|
-
const elapsedMs = endTime(lintStartTime);
|
|
507
|
-
const elapsedSeconds = (elapsedMs / 1000).toFixed(2);
|
|
508
|
-
const shouldShowBahlintSummary =
|
|
509
|
-
options.format === "gasoline" &&
|
|
510
|
-
!options.quiet &&
|
|
511
|
-
!useStdin &&
|
|
512
|
-
totalProblems > 0;
|
|
513
|
-
|
|
514
476
|
if (
|
|
515
477
|
await printResults(
|
|
516
478
|
engine,
|
|
@@ -520,54 +482,6 @@ const cli = {
|
|
|
520
482
|
resultsMeta,
|
|
521
483
|
)
|
|
522
484
|
) {
|
|
523
|
-
if (shouldShowBahlintSummary) {
|
|
524
|
-
const versionText = RuntimeInfo.version();
|
|
525
|
-
const problemsWord =
|
|
526
|
-
totalProblems === 1 ? "problem" : "problems";
|
|
527
|
-
const autoFixedCount = didApplyFixes
|
|
528
|
-
? totalFixableProblems
|
|
529
|
-
: 0;
|
|
530
|
-
const autoFixedWord =
|
|
531
|
-
autoFixedCount === 1 ? "problem" : "problems";
|
|
532
|
-
const filesScanned = results.length;
|
|
533
|
-
const filesWord =
|
|
534
|
-
filesScanned === 1 ? "file" : "files";
|
|
535
|
-
|
|
536
|
-
const util = require("node:util");
|
|
537
|
-
|
|
538
|
-
let styleText;
|
|
539
|
-
|
|
540
|
-
if (options.color === void 0) {
|
|
541
|
-
styleText = (format, text) =>
|
|
542
|
-
util.styleText(format, text, {
|
|
543
|
-
validateStream: true,
|
|
544
|
-
});
|
|
545
|
-
} else if (options.color) {
|
|
546
|
-
styleText = (format, text) =>
|
|
547
|
-
util.styleText(format, text, {
|
|
548
|
-
validateStream: false,
|
|
549
|
-
});
|
|
550
|
-
} else {
|
|
551
|
-
styleText = (_, text) => text;
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
const headerLine = `🔥 Bahlint ${versionText} - Burning your code...`;
|
|
555
|
-
const problemsLine = `⚠ ${totalProblems} ${problemsWord} found`;
|
|
556
|
-
const autoFixedLine = `✓ ${autoFixedCount} ${autoFixedWord} auto-fixed`;
|
|
557
|
-
const filesLine = `✓ ${filesScanned} ${filesWord} scanned in ${elapsedSeconds}s`;
|
|
558
|
-
|
|
559
|
-
// eslint-disable-next-line no-console -- Bahlint summary output
|
|
560
|
-
console.log(
|
|
561
|
-
styleText("red", styleText("bold", headerLine)),
|
|
562
|
-
);
|
|
563
|
-
// eslint-disable-next-line no-console -- Bahlint summary output
|
|
564
|
-
console.log(styleText("yellow", problemsLine));
|
|
565
|
-
// eslint-disable-next-line no-console -- Bahlint summary output
|
|
566
|
-
console.log(styleText("green", autoFixedLine));
|
|
567
|
-
// eslint-disable-next-line no-console -- Bahlint summary output
|
|
568
|
-
console.log(styleText("dim", filesLine));
|
|
569
|
-
}
|
|
570
|
-
|
|
571
485
|
// Errors and warnings from the original unfiltered results should determine the exit code
|
|
572
486
|
const shouldExitForFatalErrors =
|
|
573
487
|
options.exitOnFatalError && resultCounts.fatalErrorCount > 0;
|
|
@@ -16,7 +16,6 @@ const { pathToFileURL } = require("node:url");
|
|
|
16
16
|
const debug = require("debug")("eslint:config-loader");
|
|
17
17
|
const { FlatConfigArray } = require("./flat-config-array");
|
|
18
18
|
const { WarningService } = require("../services/warning-service");
|
|
19
|
-
const { defaultConfig } = require("./default-config");
|
|
20
19
|
|
|
21
20
|
//-----------------------------------------------------------------------------
|
|
22
21
|
// Types
|
|
@@ -42,12 +41,6 @@ const { defaultConfig } = require("./default-config");
|
|
|
42
41
|
//------------------------------------------------------------------------------
|
|
43
42
|
|
|
44
43
|
const FLAT_CONFIG_FILENAMES = [
|
|
45
|
-
"bahlint.config.js",
|
|
46
|
-
"bahlint.config.mjs",
|
|
47
|
-
"bahlint.config.cjs",
|
|
48
|
-
"bahlint.config.ts",
|
|
49
|
-
"bahlint.config.mts",
|
|
50
|
-
"bahlint.config.cts",
|
|
51
44
|
"eslint.config.js",
|
|
52
45
|
"eslint.config.mjs",
|
|
53
46
|
"eslint.config.cjs",
|
|
@@ -83,12 +76,7 @@ function assertValidFilePath(filePath) {
|
|
|
83
76
|
function assertConfigurationExists(configFilePath, loaderOptions) {
|
|
84
77
|
const { configFile: useConfigFile } = loaderOptions;
|
|
85
78
|
|
|
86
|
-
|
|
87
|
-
* For bahlint we allow running without any config file present and fall
|
|
88
|
-
* back to the built-in default configuration. We only throw when the
|
|
89
|
-
* user explicitly requested a config file that cannot be found.
|
|
90
|
-
*/
|
|
91
|
-
if (!configFilePath && typeof useConfigFile === "string") {
|
|
79
|
+
if (!configFilePath && useConfigFile !== false) {
|
|
92
80
|
const error = new Error("Could not find config file.");
|
|
93
81
|
|
|
94
82
|
error.messageTemplate = "config-file-missing";
|
|
@@ -152,7 +140,7 @@ function isNativeTypeScriptSupportEnabled() {
|
|
|
152
140
|
*/
|
|
153
141
|
async function loadTypeScriptConfigFileWithJiti(filePath, fileURL, mtime) {
|
|
154
142
|
const { createJiti, version: jitiVersion } =
|
|
155
|
-
|
|
143
|
+
|
|
156
144
|
await ConfigLoader.loadJiti().catch(() => {
|
|
157
145
|
throw new Error(
|
|
158
146
|
"The 'jiti' library is required for loading TypeScript configuration files. Make sure to install it.",
|
|
@@ -646,9 +634,6 @@ class ConfigLoader {
|
|
|
646
634
|
if (emptyConfig) {
|
|
647
635
|
warningService.emitEmptyConfigWarning(configFilePath);
|
|
648
636
|
}
|
|
649
|
-
} else {
|
|
650
|
-
// When no config file is found, fall back to the built-in default configuration.
|
|
651
|
-
configs.push(...defaultConfig);
|
|
652
637
|
}
|
|
653
638
|
|
|
654
639
|
// add in any configured defaults
|