Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fold-quiet-into-report-as.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"diagnostics-webpack-plugin": major
---

`quiet` is gone: `reportAs` says what a check reports its results as, one value covering its errors and its warnings alike and an object setting them apart, so `quiet: true` is `reportAs: { warnings: false }`.
58 changes: 24 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,49 +235,38 @@ See the [ESLint formatters](https://eslint.org/docs/user-guide/formatters/) and

### Errors and warnings

Every check reports its errors as webpack errors and its warnings as webpack warnings, which is what fails the build. `reportAs` overrides that, and `quiet` drops the warnings.
Every check reports its errors as webpack errors and its warnings as webpack warnings, which is what fails the build. `reportAs` overrides that.

#### `reportAs`

- Type:

```ts
type reportAs = "error" | "warning" | false;
type reportAs = Severity | { errors?: Severity; warnings?: Severity };
type Severity = "error" | "warning" | false;
```

- Default: unset — each result stays at the severity the check gave it

What a check reports its results as. Left unset, an error is a webpack error and a warning a webpack warning; naming one severity reports every result as that one, and `false` reports nothing.
What a check reports its results as. One value covers its errors and its warnings alike; an object sets them apart, and a severity the object leaves out keeps its own:

| Value | Effect |
| :---------- | :-------------------------------------------------------- |
| unset | Errors fail the build, warnings do not. |
| `"error"` | Everything fails the build, warnings included. |
| `"warning"` | Nothing fails the build; errors are reported as warnings. |
| `false` | Nothing is reported. An `outputReport` is still written. |

Together with [`quiet`](#quiet), which drops the warnings before any of this, that covers reporting and failing in one option:
| Value | Effect |
| :---------------------- | :--------------------------------------------------------- |
| unset | Errors fail the build, warnings do not. |
| `"error"` | Everything fails the build, warnings included. |
| `"warning"` | Nothing fails the build; errors are reported as warnings. |
| `false` | Nothing is reported. An `outputReport` is still written. |
| `{ warnings: false }` | The errors alone, still failing the build. |
| `{ warnings: "error" }` | Warnings fail the build too, and errors keep failing it. |
| `{ errors: "warning" }` | Errors stop failing the build, and warnings stay warnings. |

```js
new DiagnosticsPlugin({
reportAs: "warning", // report everything without failing the build
quiet: true, // and leave the warnings out of it
reportAs: { warnings: false }, // the errors alone
checks: [{ use: "eslint" }],
});
```

#### `quiet`

- Type:

```ts
type quiet = boolean;
```

- Default: `false`

Will process and report errors only and ignore warnings, if set to `true`. It drops the warnings before [`reportAs`](#reportas) decides what the rest is reported as.

#### `outputReport`

- Type:
Expand Down Expand Up @@ -421,7 +410,7 @@ new DiagnosticsPlugin({
});
```

Such an adapter is an object with a `name`, and a `create` returning the five functions the plugin drives it through — what to lint, what came back, which results are errors and which warnings, how to format them, and what to release afterwards. It splits its results by their own severity and nothing else; [`reportAs`](#reportas) and [`quiet`](#quiet) are applied to what it returns:
Such an adapter is an object with a `name`, and a `create` returning the five functions the plugin drives it through — what to lint, what came back, which results are errors and which warnings, how to format them, and what to release afterwards. It splits its results by their own severity and nothing else; [`reportAs`](#reportas) is applied to what it returns:

```js
module.exports = {
Expand Down Expand Up @@ -466,15 +455,16 @@ Move the options you were passing into a `checks` entry:

`emitError`, `emitWarning`, `failOnError` and `failOnWarning` are one [`reportAs`](#reportas) option now, because reporting a result as a webpack error is what fails the build — there is nothing left for a second option to say:

| Was | Is |
| :------------------------------------------ | :-------------------- |
| `emitWarning: false` | `quiet: true` |
| `emitError: false` and `emitWarning: false` | `reportAs: false` |
| `failOnError: true` | the default |
| `failOnError: false` | `reportAs: "warning"` |
| `failOnWarning: true` | `reportAs: "error"` |
| Was | Is |
| :------------------------------------------ | :-------------------------------- |
| `quiet: true`, `emitWarning: false` | `reportAs: { warnings: false }` |
| `emitError: false` | `reportAs: { errors: false }` |
| `emitError: false` and `emitWarning: false` | `reportAs: false` |
| `failOnError: true` | the default |
| `failOnError: false` | `reportAs: "warning"` |
| `failOnWarning: true` | `reportAs: { warnings: "error" }` |

The build is no longer aborted from inside the plugin: a result reported as a webpack error fails the build the way every other webpack error does, and the assets are still written. `emitError: false` on its own has no counterpart — reporting the warnings of a check while hiding its errors was never useful.
The build is no longer aborted from inside the plugin: a result reported as a webpack error fails the build the way every other webpack error does, and the assets are still written.

The shared options — `context`, `files`, `exclude`, `reportAs` and the rest of [Errors and warnings](#errors-and-warnings) — may stay at the top level instead. Everything else behaves as it did, and the default `cacheLocation` moved to `node_modules/.cache/diagnostics-webpack-plugin/.eslintcache`.

Expand Down
17 changes: 8 additions & 9 deletions src/check.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { isAbsolute, join } from "node:path";

import DiagnosticError from "./DiagnosticError.js";
import { reportedAs } from "./options.js";

/** @typedef {import("webpack").Compilation} Compilation */
/** @typedef {import("./checks/index.js").CheckResult} CheckResult */
Expand Down Expand Up @@ -82,16 +83,14 @@ function createCheckRunner(key, { name, adapter, options }, compilation) {
/** @type {Report} */
const report = {};

// `quiet` drops the warnings and `reportAs: false` everything, but an
// `outputReport` is still written from all of the results below.
if (options.reportAs !== false) {
if (warnings.length > 0 && !options.quiet) {
report.warnings = new DiagnosticError(name, await format(warnings));
}
// What `reportAs` drops is not formatted at all, but an `outputReport` is
// still written from all of the results below.
if (warnings.length > 0 && reportedAs(options.reportAs, "warnings")) {
report.warnings = new DiagnosticError(name, await format(warnings));
}

if (errors.length > 0) {
report.errors = new DiagnosticError(name, await format(errors));
}
if (errors.length > 0 && reportedAs(options.reportAs, "errors")) {
report.errors = new DiagnosticError(name, await format(errors));
}

const { outputReport } = options;
Expand Down
2 changes: 1 addition & 1 deletion src/checks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import stylelint from "./stylelint.js";
* @typedef {object} CheckInstance
* @property {(files: string[]) => Promise<CheckResult[]>} lintFiles lints the given files
* @property {(results: CheckResult[]) => Promise<CheckResult[]>} getResults turns the raw results of every `lintFiles` call into the results to report
* @property {(results: CheckResult[]) => { errors: CheckResult[], warnings: CheckResult[] }} splitResults splits the results by their own severity, leaving `reportAs` and `quiet` to the plugin
* @property {(results: CheckResult[]) => { errors: CheckResult[], warnings: CheckResult[] }} splitResults splits the results by their own severity, leaving `reportAs` to the plugin
* @property {(formatter?: FormatterOption) => Promise<Format>} getFormatter loads a formatter, falling back to the tool's default one
* @property {() => Promise<void>} cleanup releases whatever the tool holds after a run
*/
Expand Down
30 changes: 13 additions & 17 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import picomatch from "picomatch";
import { globSync } from "tinyglobby";

import createCheckRunner from "./check.js";
import { getOptions, validateOptions } from "./options.js";
import { getOptions, reportedAs, validateOptions } from "./options.js";
import {
arrify,
parseFiles,
Expand Down Expand Up @@ -257,24 +257,20 @@ class DiagnosticsWebpackPlugin {
for (const { options, runner } of runners) {
const { errors, warnings, outputReport } = await runner.report();

// `reportAs` names the one place every result goes; left unset, each
// stays at the severity the check gave it.
if (warnings) {
const reported =
options.reportAs === "error"
? compilation.errors
: compilation.warnings;
// `reportAs` has already dropped whatever it reports as `false`,
// so what is left only needs putting where it belongs.
for (const [results, reported] of /** @type {const} */ ([
["errors", errors],
["warnings", warnings],
])) {
if (!reported) continue;

reported.push(warnings);
}

if (errors) {
const reported =
options.reportAs === "warning"
? compilation.warnings
: compilation.errors;
const severity = reportedAs(options.reportAs, results);

reported.push(errors);
(severity === "error"
? compilation.errors
: compilation.warnings
).push(reported);
}

if (outputReport) {
Expand Down
25 changes: 22 additions & 3 deletions src/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ const nodeRequire = createRequire(import.meta.url);
const PLUGIN_NAME = "Diagnostics Webpack Plugin";

/** @typedef {import("webpack").Compiler} Compiler */
/** @typedef {"error" | "warning" | false} ReportAs */
/** @typedef {"error" | "warning" | false} Severity */
/** @typedef {"errors" | "warnings"} Results */
/** @typedef {Severity | { errors?: Severity, warnings?: Severity }} ReportAs */
/** @typedef {import("./checks/index.js").FormatterOption} FormatterOption */
/** @typedef {import("./checks/index.js").CheckAdapter} CheckAdapter */
/** @typedef {import("./checks/index.js").CheckAdapterInput} CheckAdapterInput */
Expand All @@ -35,7 +37,6 @@ const PLUGIN_NAME = "Diagnostics Webpack Plugin";
* @property {boolean=} fix apply fixes
* @property {FormatterOption=} formatter specify the formatter you would like to use to format your results
* @property {OutputReport=} outputReport writes the output of the errors to a file - for example, a `json` file for use for reporting
* @property {boolean=} quiet will process and report errors only and ignore warnings
* @property {RegExp | RegExp[] | string | string[]=} resourceQueryExclude specify the resource query to exclude
*/

Expand Down Expand Up @@ -113,6 +114,24 @@ function getSchemas() {
return schemas;
}

/** @type {Record<Results, Severity>} */
const REPORT_AS_DEFAULTS = { errors: "error", warnings: "warning" };

/**
* A severity covers a check's errors and its warnings alike unless an object
* sets them apart, and one it leaves out keeps its own.
* @param {ReportAs | undefined} reportAs the option as it was given
* @param {Results} results which of a check's results to answer for
* @returns {Severity} what they are reported as
*/
function reportedAs(reportAs, results) {
if (reportAs === undefined) return REPORT_AS_DEFAULTS[results];

if (reportAs === false || typeof reportAs === "string") return reportAs;

return reportAs[results] ?? REPORT_AS_DEFAULTS[results];
}

/**
* A `use` is either the name of a built-in check or an adapter of its own, so
* a check can ship outside this package.
Expand Down Expand Up @@ -231,4 +250,4 @@ function validateOptions(compiler, pluginOptions, checks) {
}
}

export { getOptions, validateOptions };
export { getOptions, reportedAs, validateOptions };
26 changes: 20 additions & 6 deletions src/shared-options.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,27 @@
}
]
},
"quiet": {
"description": "Will process and report errors only and ignore warnings, if set to `true`.",
"type": "boolean"
},
"reportAs": {
"description": "What a check reports its results as: `\"error\"` reports them as webpack errors and fails the build, `\"warning\"` reports them as webpack warnings, `false` reports nothing.",
"enum": ["error", "warning", false]
"description": "What a check reports its results as: `\"error\"` reports them as webpack errors and fails the build, `\"warning\"` reports them as webpack warnings, `false` reports nothing. One value covers a check's errors and its warnings alike, an object sets them apart, and a severity an object leaves out keeps its own.",
"anyOf": [
{
"enum": ["error", "warning", false]
},
{
"type": "object",
"additionalProperties": false,
"properties": {
"errors": {
"description": "What a check's errors are reported as, or `false` to drop them.",
"enum": ["error", "warning", false]
},
"warnings": {
"description": "What a check's warnings are reported as, or `false` to drop them.",
"enum": ["error", "warning", false]
}
}
}
]
},
"resourceQueryExclude": {
"description": "Specify the resource query to exclude.",
Expand Down
1 change: 0 additions & 1 deletion test/eslint-options.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ describe("eslint options", () => {
formatter: "table",
fix: true,
reportAs: false,
quiet: false,
outputReport: true,
};
assert.deepStrictEqual(getESLintOptions(options), {
Expand Down
22 changes: 0 additions & 22 deletions test/quiet.test.js

This file was deleted.

Loading
Loading