bahlint 28.58.6934001 → 28.58.69340002
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/lib/cli-engine/formatters/formatters-meta.json +1 -5
- package/lib/cli.js +1 -87
- package/lib/config/config-loader.js +1 -16
- package/lib/config/default-config.js +48 -66
- package/lib/options.js +1 -1
- package/lib/rule-tester/rule-tester.js +180 -8
- 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>
|
|
@@ -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";
|
|
@@ -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
|
|
@@ -10,87 +10,69 @@
|
|
|
10
10
|
//-----------------------------------------------------------------------------
|
|
11
11
|
|
|
12
12
|
const Rules = require("../rules");
|
|
13
|
-
const js = require("@eslint/js");
|
|
14
13
|
|
|
15
14
|
//-----------------------------------------------------------------------------
|
|
16
15
|
// Helpers
|
|
17
16
|
//-----------------------------------------------------------------------------
|
|
18
17
|
|
|
19
18
|
const sharedDefaultConfig = [
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
19
|
+
// intentionally empty config to ensure these files are globbed by default
|
|
20
|
+
{
|
|
21
|
+
files: ["**/*.js", "**/*.mjs"],
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
files: ["**/*.cjs"],
|
|
25
|
+
languageOptions: {
|
|
26
|
+
sourceType: "commonjs",
|
|
27
|
+
ecmaVersion: "latest",
|
|
28
|
+
},
|
|
29
|
+
},
|
|
31
30
|
];
|
|
32
31
|
|
|
33
32
|
exports.defaultConfig = Object.freeze([
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
{
|
|
34
|
+
plugins: {
|
|
35
|
+
"@": {
|
|
36
|
+
languages: {
|
|
37
|
+
js: require("../languages/js"),
|
|
38
|
+
},
|
|
40
39
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
40
|
+
/*
|
|
41
|
+
* Because we try to delay loading rules until absolutely
|
|
42
|
+
* necessary, a proxy allows us to hook into the lazy-loading
|
|
43
|
+
* aspect of the rules map while still keeping all of the
|
|
44
|
+
* relevant configuration inside of the config array.
|
|
45
|
+
*/
|
|
46
|
+
rules: new Proxy(
|
|
47
|
+
{},
|
|
48
|
+
{
|
|
49
|
+
get(target, property) {
|
|
50
|
+
return Rules.get(property);
|
|
51
|
+
},
|
|
53
52
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
53
|
+
has(target, property) {
|
|
54
|
+
return Rules.has(property);
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
),
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
language: "@/js",
|
|
61
|
+
linterOptions: {
|
|
62
|
+
reportUnusedDisableDirectives: 1,
|
|
63
|
+
},
|
|
64
|
+
},
|
|
66
65
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
// default ignores are listed here
|
|
67
|
+
{
|
|
68
|
+
ignores: ["**/node_modules/", ".git/"],
|
|
69
|
+
},
|
|
71
70
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
// 1) ESLint JS recommended rules
|
|
75
|
-
...js.configs.recommended,
|
|
76
|
-
|
|
77
|
-
// 2) Your overrides / extra rules
|
|
78
|
-
{
|
|
79
|
-
files: ["**/*.{js,mjs,cjs}"],
|
|
80
|
-
languageOptions: {
|
|
81
|
-
ecmaVersion: "latest",
|
|
82
|
-
sourceType: "module",
|
|
83
|
-
},
|
|
84
|
-
rules: {
|
|
85
|
-
"no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
|
|
86
|
-
"no-console": "off",
|
|
87
|
-
"no-debugger": "warn",
|
|
88
|
-
},
|
|
89
|
-
},
|
|
71
|
+
...sharedDefaultConfig,
|
|
90
72
|
]);
|
|
91
73
|
|
|
92
74
|
exports.defaultRuleTesterConfig = Object.freeze([
|
|
93
|
-
|
|
75
|
+
{ files: ["**"] }, // Make sure the default config matches for all files
|
|
94
76
|
|
|
95
|
-
|
|
77
|
+
...sharedDefaultConfig,
|
|
96
78
|
]);
|
package/lib/options.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
//------------------------------------------------------------------------------
|
|
12
12
|
|
|
13
13
|
const assert = require("node:assert"),
|
|
14
|
+
{ existsSync, readFileSync } = require("node:fs"),
|
|
14
15
|
util = require("node:util"),
|
|
15
16
|
path = require("node:path"),
|
|
16
17
|
equal = require("fast-deep-equal"),
|
|
@@ -666,6 +667,177 @@ function getInvocationLocation(relative = getInvocationLocation) {
|
|
|
666
667
|
return stack.split("\n")[1].replace(/.*?\(/u, "").replace(/\)$/u, "");
|
|
667
668
|
}
|
|
668
669
|
|
|
670
|
+
/**
|
|
671
|
+
* Estimates the location of the test case in the source file.
|
|
672
|
+
* @param {Function} invoker The method that runs the tests.
|
|
673
|
+
* @returns {(key: string) => string} The lazy resolver for the estimated location of the test case.
|
|
674
|
+
*/
|
|
675
|
+
function buildLazyTestLocationEstimator(invoker) {
|
|
676
|
+
const invocationLocation = getInvocationLocation(invoker);
|
|
677
|
+
let testLocations = null;
|
|
678
|
+
return key => {
|
|
679
|
+
if (testLocations === null) {
|
|
680
|
+
let [sourceFile, sourceLine = "1", sourceColumn = "1"] =
|
|
681
|
+
invocationLocation
|
|
682
|
+
.replace(/:\\/u, "\\\\") // Windows workaround for C:\\
|
|
683
|
+
.split(":");
|
|
684
|
+
sourceFile = sourceFile.replace(/\\\\/u, ":\\");
|
|
685
|
+
sourceLine = Number(sourceLine);
|
|
686
|
+
sourceColumn = Number(sourceColumn);
|
|
687
|
+
testLocations = { root: invocationLocation };
|
|
688
|
+
|
|
689
|
+
if (existsSync(sourceFile)) {
|
|
690
|
+
let content = readFileSync(sourceFile, "utf8")
|
|
691
|
+
.split("\n")
|
|
692
|
+
.slice(sourceLine - 1);
|
|
693
|
+
content[0] = content[0].slice(Math.max(0, sourceColumn - 1));
|
|
694
|
+
content = content.map(
|
|
695
|
+
l =>
|
|
696
|
+
l
|
|
697
|
+
.trim() // Remove whitespace
|
|
698
|
+
.replace(/\s*\/\/.*$(?<!,)/u, ""), // and trailing in-line comments that aren't part of the test `code`
|
|
699
|
+
);
|
|
700
|
+
|
|
701
|
+
// Roots
|
|
702
|
+
const validStartIndex = content.findIndex(line =>
|
|
703
|
+
/\bvalid:/u.test(line),
|
|
704
|
+
);
|
|
705
|
+
const invalidStartIndex = content.findIndex(line =>
|
|
706
|
+
/\binvalid:/u.test(line),
|
|
707
|
+
);
|
|
708
|
+
|
|
709
|
+
testLocations.valid = `${sourceFile}:${
|
|
710
|
+
sourceLine + validStartIndex
|
|
711
|
+
}`;
|
|
712
|
+
testLocations.invalid = `${sourceFile}:${
|
|
713
|
+
sourceLine + invalidStartIndex
|
|
714
|
+
}`;
|
|
715
|
+
|
|
716
|
+
// Scenario basics
|
|
717
|
+
const validEndIndex =
|
|
718
|
+
validStartIndex < invalidStartIndex
|
|
719
|
+
? invalidStartIndex
|
|
720
|
+
: content.length;
|
|
721
|
+
const invalidEndIndex =
|
|
722
|
+
validStartIndex < invalidStartIndex
|
|
723
|
+
? content.length
|
|
724
|
+
: validStartIndex;
|
|
725
|
+
|
|
726
|
+
const validLines = content.slice(
|
|
727
|
+
validStartIndex,
|
|
728
|
+
validEndIndex,
|
|
729
|
+
);
|
|
730
|
+
const invalidLines = content.slice(
|
|
731
|
+
invalidStartIndex,
|
|
732
|
+
invalidEndIndex,
|
|
733
|
+
);
|
|
734
|
+
|
|
735
|
+
let objectDepth = 0;
|
|
736
|
+
const validLineIndexes = validLines
|
|
737
|
+
.map((l, i) => {
|
|
738
|
+
// matches `key: {` and `{`
|
|
739
|
+
if (/^(?:\w+\s*:\s*)?\{/u.test(l)) {
|
|
740
|
+
objectDepth++;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
if (objectDepth > 0) {
|
|
744
|
+
if (l.endsWith("}") || l.endsWith("},")) {
|
|
745
|
+
objectDepth--;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
return objectDepth <= 1 && l.includes("code:")
|
|
749
|
+
? i
|
|
750
|
+
: null;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
return l.endsWith(",") ? i : null;
|
|
754
|
+
})
|
|
755
|
+
.filter(Boolean);
|
|
756
|
+
const invalidLineIndexes = invalidLines
|
|
757
|
+
.map((l, i) =>
|
|
758
|
+
l.trimStart().startsWith("errors:") ? i : null,
|
|
759
|
+
)
|
|
760
|
+
.filter(Boolean);
|
|
761
|
+
|
|
762
|
+
Object.assign(
|
|
763
|
+
testLocations,
|
|
764
|
+
{
|
|
765
|
+
[`valid[0]`]: `${sourceFile}:${
|
|
766
|
+
sourceLine + validStartIndex
|
|
767
|
+
}`,
|
|
768
|
+
},
|
|
769
|
+
Object.fromEntries(
|
|
770
|
+
validLineIndexes.map((location, validIndex) => [
|
|
771
|
+
`valid[${validIndex}]`,
|
|
772
|
+
`${sourceFile}:${
|
|
773
|
+
sourceLine + validStartIndex + location
|
|
774
|
+
}`,
|
|
775
|
+
]),
|
|
776
|
+
),
|
|
777
|
+
Object.fromEntries(
|
|
778
|
+
invalidLineIndexes.map((location, invalidIndex) => [
|
|
779
|
+
`invalid[${invalidIndex}]`,
|
|
780
|
+
`${sourceFile}:${
|
|
781
|
+
sourceLine + invalidStartIndex + location
|
|
782
|
+
}`,
|
|
783
|
+
]),
|
|
784
|
+
),
|
|
785
|
+
);
|
|
786
|
+
|
|
787
|
+
// Indexes for errors inside each invalid test case
|
|
788
|
+
invalidLineIndexes.push(invalidLines.length);
|
|
789
|
+
|
|
790
|
+
for (let i = 0; i < invalidLineIndexes.length - 1; i++) {
|
|
791
|
+
const start = invalidLineIndexes[i];
|
|
792
|
+
const end = invalidLineIndexes[i + 1];
|
|
793
|
+
const errorLines = invalidLines.slice(start, end);
|
|
794
|
+
let errorObjectDepth = 0;
|
|
795
|
+
const errorLineIndexes = errorLines
|
|
796
|
+
.map((l, j) => {
|
|
797
|
+
if (l.startsWith("{") || l.endsWith("{")) {
|
|
798
|
+
errorObjectDepth++;
|
|
799
|
+
|
|
800
|
+
if (l.endsWith("}") || l.endsWith("},")) {
|
|
801
|
+
errorObjectDepth--;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
return errorObjectDepth <= 1 ? j : null;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
if (errorObjectDepth > 0) {
|
|
808
|
+
if (l.endsWith("}") || l.endsWith("},")) {
|
|
809
|
+
errorObjectDepth--;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
return null;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
return l.endsWith(",") ? j : null;
|
|
816
|
+
})
|
|
817
|
+
.filter(Boolean);
|
|
818
|
+
|
|
819
|
+
Object.assign(
|
|
820
|
+
testLocations,
|
|
821
|
+
Object.fromEntries(
|
|
822
|
+
errorLineIndexes.map((line, errorIndex) => [
|
|
823
|
+
`invalid[${i}].errors[${errorIndex}]`,
|
|
824
|
+
`${sourceFile}:${
|
|
825
|
+
sourceLine +
|
|
826
|
+
invalidStartIndex +
|
|
827
|
+
start +
|
|
828
|
+
line
|
|
829
|
+
}`,
|
|
830
|
+
]),
|
|
831
|
+
),
|
|
832
|
+
);
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
return testLocations[key] || "unknown source";
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
|
|
669
841
|
//------------------------------------------------------------------------------
|
|
670
842
|
// Public Interface
|
|
671
843
|
//------------------------------------------------------------------------------
|
|
@@ -866,7 +1038,7 @@ class RuleTester {
|
|
|
866
1038
|
assertRule(rule, ruleName);
|
|
867
1039
|
assertTest(test, ruleName);
|
|
868
1040
|
|
|
869
|
-
const
|
|
1041
|
+
const estimateTestLocation = buildLazyTestLocationEstimator(this.run);
|
|
870
1042
|
|
|
871
1043
|
const baseConfig = [
|
|
872
1044
|
{
|
|
@@ -1744,9 +1916,9 @@ class RuleTester {
|
|
|
1744
1916
|
error.stack = error.stack.replace(
|
|
1745
1917
|
/^ +at /mu,
|
|
1746
1918
|
[
|
|
1747
|
-
` at RuleTester.run.valid[${index}]`,
|
|
1748
|
-
` at RuleTester.run.valid`,
|
|
1749
|
-
` at RuleTester.run (${
|
|
1919
|
+
` roughly at RuleTester.run.valid[${index}] (${estimateTestLocation(`valid[${index}]`)})`,
|
|
1920
|
+
` roughly at RuleTester.run.valid (${estimateTestLocation("valid")})`,
|
|
1921
|
+
` at RuleTester.run (${estimateTestLocation("root")})`,
|
|
1750
1922
|
" at ",
|
|
1751
1923
|
].join("\n"),
|
|
1752
1924
|
);
|
|
@@ -1789,12 +1961,12 @@ class RuleTester {
|
|
|
1789
1961
|
...(typeof errorIndex ===
|
|
1790
1962
|
"number"
|
|
1791
1963
|
? [
|
|
1792
|
-
` at RuleTester.run.invalid[${index}].error[${errorIndex}]`,
|
|
1964
|
+
` roughly at RuleTester.run.invalid[${index}].error[${errorIndex}] (${estimateTestLocation(`invalid[${index}].errors[${errorIndex}]`)})`,
|
|
1793
1965
|
]
|
|
1794
1966
|
: []),
|
|
1795
|
-
` at RuleTester.run.invalid[${index}]`,
|
|
1796
|
-
` at RuleTester.run.invalid`,
|
|
1797
|
-
` at RuleTester.run (${
|
|
1967
|
+
` roughly at RuleTester.run.invalid[${index}] (${estimateTestLocation(`invalid[${index}]`)})`,
|
|
1968
|
+
` roughly at RuleTester.run.invalid (${estimateTestLocation("invalid")})`,
|
|
1969
|
+
` at RuleTester.run (${estimateTestLocation("root")})`,
|
|
1798
1970
|
" at ",
|
|
1799
1971
|
].join("\n"),
|
|
1800
1972
|
);
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bahlint",
|
|
3
|
-
"version": "28.58.
|
|
3
|
+
"version": "28.58.69340002",
|
|
4
4
|
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
|
|
5
5
|
"description": "An AST-based pattern checker for JavaScript.",
|
|
6
6
|
"type": "commonjs",
|
|
7
7
|
"bin": {
|
|
8
|
-
"
|
|
8
|
+
"eslint": "./bin/eslint.js"
|
|
9
9
|
},
|
|
10
10
|
"main": "./lib/api.js",
|
|
11
11
|
"types": "./lib/types/index.d.ts",
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
],
|
|
104
104
|
"repository": "eslint/eslint",
|
|
105
105
|
"funding": "https://eslint.org/donate",
|
|
106
|
-
"homepage": "https://
|
|
106
|
+
"homepage": "https://eslint.org",
|
|
107
107
|
"bugs": "https://github.com/eslint/eslint/issues/",
|
|
108
108
|
"dependencies": {
|
|
109
109
|
"@eslint-community/eslint-utils": "^4.8.0",
|
|
@@ -142,8 +142,8 @@
|
|
|
142
142
|
"@babel/core": "^7.4.3",
|
|
143
143
|
"@babel/preset-env": "^7.4.3",
|
|
144
144
|
"@cypress/webpack-preprocessor": "^6.0.2",
|
|
145
|
-
"@eslint/eslintrc": "^3.3.3",
|
|
146
145
|
"@eslint/json": "^0.14.0",
|
|
146
|
+
"@eslint/eslintrc": "^3.3.3",
|
|
147
147
|
"@trunkio/launcher": "^1.3.4",
|
|
148
148
|
"@types/esquery": "^1.5.4",
|
|
149
149
|
"@types/node": "^22.13.14",
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Gasoline-themed reporter for Bahlint.
|
|
3
|
-
* Inspired by the default stylish formatter, but with a fuel-oriented twist.
|
|
4
|
-
* @author ESLint
|
|
5
|
-
*/
|
|
6
|
-
"use strict";
|
|
7
|
-
|
|
8
|
-
const util = require("node:util"),
|
|
9
|
-
table = require("../../shared/text-table");
|
|
10
|
-
|
|
11
|
-
//------------------------------------------------------------------------------
|
|
12
|
-
// Helpers
|
|
13
|
-
//------------------------------------------------------------------------------
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Returns a styling function based on the color option.
|
|
17
|
-
* @param {boolean|undefined} color Indicates whether to use colors.
|
|
18
|
-
* @returns {Function} A function that styles text.
|
|
19
|
-
*/
|
|
20
|
-
function getStyleText(color) {
|
|
21
|
-
if (typeof color === "undefined") {
|
|
22
|
-
return (format, text) =>
|
|
23
|
-
util.styleText(format, text, { validateStream: true });
|
|
24
|
-
}
|
|
25
|
-
if (color) {
|
|
26
|
-
return (format, text) =>
|
|
27
|
-
util.styleText(format, text, { validateStream: false });
|
|
28
|
-
}
|
|
29
|
-
return (_, text) => text;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Given a word and a count, append an s if count is not one.
|
|
34
|
-
* @param {string} word A word in its singular form.
|
|
35
|
-
* @param {number} count A number controlling whether word should be pluralized.
|
|
36
|
-
* @returns {string} The original word with an s on the end if count is not one.
|
|
37
|
-
*/
|
|
38
|
-
function pluralize(word, count) {
|
|
39
|
-
return count === 1 ? word : `${word}s`;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
//------------------------------------------------------------------------------
|
|
43
|
-
// Public Interface
|
|
44
|
-
//------------------------------------------------------------------------------
|
|
45
|
-
|
|
46
|
-
module.exports = function (results, data) {
|
|
47
|
-
const styleText = getStyleText(data?.color);
|
|
48
|
-
|
|
49
|
-
let output = "\n",
|
|
50
|
-
errorCount = 0,
|
|
51
|
-
warningCount = 0,
|
|
52
|
-
fixableErrorCount = 0,
|
|
53
|
-
fixableWarningCount = 0;
|
|
54
|
-
|
|
55
|
-
results.forEach(result => {
|
|
56
|
-
const messages = result.messages;
|
|
57
|
-
|
|
58
|
-
if (messages.length === 0) {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
errorCount += result.errorCount;
|
|
63
|
-
warningCount += result.warningCount;
|
|
64
|
-
fixableErrorCount += result.fixableErrorCount;
|
|
65
|
-
fixableWarningCount += result.fixableWarningCount;
|
|
66
|
-
|
|
67
|
-
// Highlight file path like a fuel line.
|
|
68
|
-
output += `${styleText(
|
|
69
|
-
"underline",
|
|
70
|
-
styleText("yellow", result.filePath),
|
|
71
|
-
)}\n`;
|
|
72
|
-
|
|
73
|
-
output += `${table(
|
|
74
|
-
messages.map(message => {
|
|
75
|
-
const line = String(message.line || 0);
|
|
76
|
-
const column = String(message.column || 0);
|
|
77
|
-
const isError = message.fatal || message.severity === 2;
|
|
78
|
-
|
|
79
|
-
const messageType = styleText(
|
|
80
|
-
isError ? "red" : "yellow",
|
|
81
|
-
isError ? "ERR" : "WARN",
|
|
82
|
-
);
|
|
83
|
-
|
|
84
|
-
return [
|
|
85
|
-
"",
|
|
86
|
-
line,
|
|
87
|
-
column,
|
|
88
|
-
messageType,
|
|
89
|
-
message.message.replace(/([^ ])\.$/u, "$1"),
|
|
90
|
-
message.ruleId ? styleText("dim", message.ruleId) : "",
|
|
91
|
-
];
|
|
92
|
-
}),
|
|
93
|
-
{
|
|
94
|
-
align: ["", "r", "l"],
|
|
95
|
-
stringLength(str) {
|
|
96
|
-
return util.stripVTControlCharacters(str).length;
|
|
97
|
-
},
|
|
98
|
-
},
|
|
99
|
-
)
|
|
100
|
-
.split("\n")
|
|
101
|
-
.map(el =>
|
|
102
|
-
el.replace(/(\d+)\s+(\d+)/u, (m, p1, p2) =>
|
|
103
|
-
styleText("dim", `${p1}:${p2}`),
|
|
104
|
-
),
|
|
105
|
-
)
|
|
106
|
-
.join("\n")}\n\n`;
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
const total = errorCount + warningCount;
|
|
110
|
-
|
|
111
|
-
/*
|
|
112
|
-
* We can't use a single `styleText` call like `styleText([summaryColor, "bold"], text)` here.
|
|
113
|
-
* This is a bug in `util.styleText` in Node.js versions earlier than v22.15.0 (https://github.com/nodejs/node/issues/56717).
|
|
114
|
-
* As a workaround, we use nested `styleText` calls.
|
|
115
|
-
*/
|
|
116
|
-
if (total > 0) {
|
|
117
|
-
let summaryColor;
|
|
118
|
-
let statusLabel;
|
|
119
|
-
|
|
120
|
-
if (errorCount > 0) {
|
|
121
|
-
summaryColor = "red";
|
|
122
|
-
statusLabel = "ENGINE KNOCK";
|
|
123
|
-
} else {
|
|
124
|
-
summaryColor = "yellow";
|
|
125
|
-
statusLabel = "LOW OCTANE";
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const summaryText = [
|
|
129
|
-
"[BAHLINT] FUEL STATUS: ",
|
|
130
|
-
statusLabel,
|
|
131
|
-
" - ",
|
|
132
|
-
total,
|
|
133
|
-
pluralize(" issue", total),
|
|
134
|
-
" (",
|
|
135
|
-
errorCount,
|
|
136
|
-
pluralize(" error", errorCount),
|
|
137
|
-
", ",
|
|
138
|
-
warningCount,
|
|
139
|
-
pluralize(" warning", warningCount),
|
|
140
|
-
")",
|
|
141
|
-
].join("");
|
|
142
|
-
|
|
143
|
-
output += `${styleText(
|
|
144
|
-
summaryColor,
|
|
145
|
-
styleText("bold", summaryText),
|
|
146
|
-
)}\n`;
|
|
147
|
-
|
|
148
|
-
if (fixableErrorCount > 0 || fixableWarningCount > 0) {
|
|
149
|
-
const fixSummaryText = [
|
|
150
|
-
"[BAHLINT] ",
|
|
151
|
-
fixableErrorCount,
|
|
152
|
-
pluralize(" error", fixableErrorCount),
|
|
153
|
-
" and ",
|
|
154
|
-
fixableWarningCount,
|
|
155
|
-
pluralize(" warning", fixableWarningCount),
|
|
156
|
-
" potentially fixable with the `--fix` pit stop.",
|
|
157
|
-
].join("");
|
|
158
|
-
|
|
159
|
-
output += `${styleText(
|
|
160
|
-
summaryColor,
|
|
161
|
-
styleText("bold", fixSummaryText),
|
|
162
|
-
)}\n`;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// Resets output color, to prevent changes on the top level
|
|
167
|
-
return total > 0 ? styleText("reset", output) : "";
|
|
168
|
-
};
|