Skip to content

Commit

Permalink
Add reportUnscopedDisables and --report-unscoped-disables (#8024)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mouvedia authored Oct 24, 2024
1 parent f7e82c7 commit d4aa865
Show file tree
Hide file tree
Showing 21 changed files with 438 additions and 66 deletions.
5 changes: 5 additions & 0 deletions .changeset/few-spies-double.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"stylelint": minor
---

Added: `--report-unscoped-disables` CLI flag and `reportUnscopedDisables` option to Node.js API and configuration object
4 changes: 4 additions & 0 deletions docs/user-guide/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ Produce a report of the `stylelint-disable` comments that used for rules that do

Produce a report to clean up your codebase, keeping only the `stylelint-disable` comments that serve a purpose. [More info](options.md#reportneedlessdisables).

### `--report-unscoped-disables, --rud`

Produce a report of the configuration comments that are not scoped to one or more rules. [More info](options.md#reportunscopeddisables).

### `--stdin-filename`

A filename to assign the input. [More info](options.md#codefilename).
Expand Down
15 changes: 15 additions & 0 deletions docs/user-guide/configure.md
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,7 @@ The available reports are:
- [`reportDescriptionlessDisables`](#reportdescriptionlessdisables)
- [`reportInvalidScopeDisables`](#reportinvalidscopedisables)
- [`reportNeedlessDisables`](#reportneedlessdisables)
- [`reportUnscopedDisables`](#reportunscopeddisables)
They are configured like rules. They can have one of three values:
Expand Down Expand Up @@ -559,6 +560,20 @@ For example:
[More info](options.md#reportneedlessdisables).
### `reportUnscopedDisables`
Report configuration comments that are not scoped to at least one rule. A [`report*`](#report) property.
For example:
```json
{
"reportUnscopedDisables": true
}
```
[More info](options.md#reportunscopeddisables).
## `configurationComment`
You can set what configuration comments like `/* stylelint-disable */` start with. This can be useful if you use multiple instances of Stylelint with different configurations.
Expand Down
14 changes: 11 additions & 3 deletions docs/user-guide/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ You can use this option to see what your linting results would be like without t

CLI flags: `--report-descriptionless-disables, --rdd`

Report `stylelint-disable` comments without a description.
Report [configuration comments][1] without a description.

The following patterns are reported:

Expand Down Expand Up @@ -204,13 +204,19 @@ a {}

CLI flags: `--report-invalid-scope-disables, --risd`

Report `stylelint-disable` comments that don't match rules that are specified in the configuration object.
Report [configuration comments][1] that don't match rules that are specified in the configuration object.

## `reportNeedlessDisables`

CLI flags: `--report-needless-disables, --rd`

Report `stylelint-disable` comments that don't actually match any lints that need to be disabled.
Report [configuration comments][1] that don't actually match any lints that need to be disabled.

## `reportUnscopedDisables`

CLI flags: `--report-unscoped-disables, --rud`

Report [configuration comments][1] that aren't scoped to one or more rules.

## `validate`

Expand Down Expand Up @@ -246,3 +252,5 @@ Only register problems for rules with an "error"-level severity (ignore "warning
CLI flag: `--quiet-deprecation-warnings`

Ignore deprecation warnings.

[1]: ../user-guide/ignore-code.md#parts-of-a-file
1 change: 1 addition & 0 deletions lib/__tests__/cli.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ describe('buildCLI', () => {
reportDescriptionlessDisables: false,
reportInvalidScopeDisables: false,
reportNeedlessDisables: false,
reportUnscopedDisables: false,
stdin: false,
validate: true,
version: false,
Expand Down
1 change: 0 additions & 1 deletion lib/__tests__/reportDisables.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ describe('reportDisables', () => {
expect(results[0].warnings).toHaveLength(0);
});

// This should be handled by the global `reportUnscopedDisables` option (#2292).
it("doesn't report unscoped disables", async () => {
const config = {
rules: { 'block-no-empty': [true, { reportDisables: true }] },
Expand Down
200 changes: 200 additions & 0 deletions lib/__tests__/unscopedDisables.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
import standalone from '../standalone.mjs';
import { stripIndent } from 'common-tags';

it('does report unscoped configuration comments even when they are needless', async () => {
const config = {
rules: { 'block-no-empty': true },
};

const css = stripIndent`/* stylelint-disable-next-line */
a { color: red; }`;

const { results } = await standalone({
config,
code: css,
reportUnscopedDisables: [true],
});

expect(results[0].warnings).toHaveLength(1);
expect(unscopedWarnings(results[0])).toEqual([
{
line: 1,
column: 1,
endLine: 1,
endColumn: 33,
rule: '--report-unscoped-disables',
severity: 'error',
text: 'Configuration comment must be scoped',
},
]);
});

it('unscopedDisables true', async () => {
const config = {
rules: {
'selector-type-case': 'lower',
},
};

const css = stripIndent`
/* stylelint-disable */
a {}
/* stylelint-enable */
a {} /* stylelint-disable-line */
/* stylelint-disable-next-line */
a {}
`;

const { results } = await standalone({
config,
code: css,
reportUnscopedDisables: [true],
});

const common = {
rule: '--report-unscoped-disables',
severity: 'error',
text: 'Configuration comment must be scoped',
};

expect(results[0].warnings).toHaveLength(3);
expect(unscopedWarnings(results[0])).toEqual([
{
line: 1,
column: 1,
endLine: 1,
endColumn: 23,
...common,
},
{
line: 5,
column: 6,
endLine: 5,
endColumn: 33,
...common,
},
{
line: 7,
column: 1,
endLine: 7,
endColumn: 33,
...common,
},
]);
});

it('unscopedDisables false', async () => {
const config = {
rules: {
'selector-type-case': 'lower',
},
};
const css = stripIndent`a {} /* stylelint-disable-line */`;

const { results } = await standalone({
config,
code: css,
reportUnscopedDisables: [false],
});

expect(results[0].warnings).toHaveLength(0);
});

it('unscopedDisables false except empty', async () => {
const config = {
rules: {
'selector-type-case': 'lower',
},
};
const css = stripIndent`a {} /* stylelint-disable-line */`;

const { results } = await standalone({
config,
code: css,
reportUnscopedDisables: [false, { except: [] }],
});

expect(results[0].warnings).toHaveLength(0);
});

it('unscopedDisables false except / same line', async () => {
const config = {
rules: {
'block-no-empty': true,
'selector-type-case': 'lower',
},
};
const css = stripIndent`
A {} /* stylelint-disable-line */
A {} /* stylelint-disable-line block-no-empty */
A {} /* stylelint-disable-line selector-type-case */
`;

const { results } = await standalone({
config,
code: css,
reportUnscopedDisables: [false, { except: ['selector-type-case', 'block-no-empty'] }],
});

expect(results[0].warnings).toHaveLength(3);
expect(unscopedWarnings(results[0])).toEqual([
{
line: 1,
column: 6,
endLine: 1,
endColumn: 33,
rule: '--report-unscoped-disables',
severity: 'error',
text: 'Configuration comment must be scoped',
},
]);
});

it('unscopedDisables false except / separate lines', async () => {
const config = {
rules: {
'block-no-empty': true,
'selector-type-case': 'lower',
},
};
const css = stripIndent`
a {} /* stylelint-disable-line */
A { color:red } /* stylelint-disable-line */
a { color:red } /* stylelint-disable-line */
`;

const { results } = await standalone({
config,
code: css,
reportUnscopedDisables: [false, { except: ['selector-type-case', 'block-no-empty'] }],
});

expect(results[0].warnings).toHaveLength(2);
expect(unscopedWarnings(results[0])).toEqual([
{
line: 1,
column: 6,
endLine: 1,
endColumn: 33,
rule: '--report-unscoped-disables',
severity: 'error',
text: 'Configuration comment must be scoped',
},
{
line: 2,
column: 17,
endLine: 2,
endColumn: 44,
rule: '--report-unscoped-disables',
severity: 'error',
text: 'Configuration comment must be scoped',
},
]);
});

function unscopedWarnings(result) {
return result.warnings.filter(({ rule }) => rule === '--report-unscoped-disables');
}
51 changes: 20 additions & 31 deletions lib/augmentConfig.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -496,38 +496,27 @@ function addOptions(stylelint, config) {
...config,
};

if (stylelint._options.ignoreDisables) {
augmentedConfig.ignoreDisables = stylelint._options.ignoreDisables;
}

if (stylelint._options.quiet) {
augmentedConfig.quiet = stylelint._options.quiet;
}

if (stylelint._options.reportNeedlessDisables) {
augmentedConfig.reportNeedlessDisables = stylelint._options.reportNeedlessDisables;
}

if (stylelint._options.reportInvalidScopeDisables) {
augmentedConfig.reportInvalidScopeDisables = stylelint._options.reportInvalidScopeDisables;
}

if (stylelint._options.reportDescriptionlessDisables) {
augmentedConfig.reportDescriptionlessDisables =
stylelint._options.reportDescriptionlessDisables;
}

if (stylelint._options.customSyntax) {
augmentedConfig.customSyntax = stylelint._options.customSyntax;
}

if (stylelint._options.fix) {
augmentedConfig.fix = stylelint._options.fix;
}
const subset = /** @type {const} */ ([
'customSyntax',
'fix',
'ignoreDisables',
'quiet',
'reportDescriptionlessDisables',
'reportInvalidScopeDisables',
'reportNeedlessDisables',
'reportUnscopedDisables',
'validate',
]);

/**
* @template T
* @param {T extends typeof subset[number] ? T : never} key
*/
const addOption = (key) => {
if (stylelint._options[key]) augmentedConfig[key] = stylelint._options[key];
};

if (stylelint._options.validate) {
augmentedConfig.validate = stylelint._options.validate;
}
subset.forEach((key) => addOption(key));

return augmentedConfig;
}
Expand Down
Loading

0 comments on commit d4aa865

Please sign in to comment.