Skip to content

Commit 37c78bf

Browse files
committed
change default to warn and keep boolean values around
1 parent 8e231bb commit 37c78bf

File tree

1 file changed

+59
-78
lines changed
  • designs/2022-unused-disable-directive-flexible-config

1 file changed

+59
-78
lines changed

designs/2022-unused-disable-directive-flexible-config/README.md

+59-78
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
<!-- One-paragraph explanation of the feature. -->
1111

12-
Provide users with more flexible, intuitive control over how unused disable directives are reported by switching the CLI and config file options from using a boolean value to a severity level. Change the default behavior to error on unused disable directives.
12+
Provide users with more flexible, intuitive control over how unused disable directives are reported by switching the CLI and config file options from using a boolean value to a severity level. Change the default behavior to warn on unused disable directives.
1313

1414
## Motivation
1515

@@ -35,12 +35,9 @@ These existing solutions have various downsides:
3535

3636
### New Design
3737

38-
We propose a new "explicit severity" design where the user can set the severity level of unused disable directive reporting using either the CLI option or the config file option. This design has the following benefits:
38+
We propose a new "explicit severity" design where the user can set the severity level of unused disable directive reporting using either the CLI option or the config file option. As a result, the user should always be able to achieve the desired effect (`off` / `warn` / `error`), regardless of where they set the option from (CLI option, config file option, or even from a shareable config).
3939

40-
- The user should always be able to achieve the desired effect (`off` / `warn` / `error`), regardless of where they set the option from (CLI option, config file option, or even from a shareable config)
41-
- No confusing inconsistency where one of the options triggers errors but the other triggers warnings
42-
43-
We will also change the default behavior to error on unused disable directives so that all users (unless they opt-out) will benefit from the detection (and automatic removal with `--fix`) of unused disable directives.
40+
We will also change the default behavior to warn on unused disable directives so that all users (unless they opt-out) will benefit from the detection (and automatic removal with `--fix`) of unused disable directives.
4441

4542
## Detailed Design
4643

@@ -55,42 +52,49 @@ We will also change the default behavior to error on unused disable directives s
5552

5653
How the new "explicit severity" design works:
5754

58-
- The config and CLI options are both changed from booleans to instead accept standard severity level string values: `off`, `warn`, `error` (or a the corresponding number for each level)
55+
- The config and CLI options are both changed to also accept standard severity level string values: `off`, `warn`, `error` (or a the corresponding number for each level)
5956
- If both options are present, the CLI option takes precedence over (overrides) the config option
6057
- If only one of the options is present, the value of the present option is used
61-
- If neither option is present, the default value (`error`) is used
58+
- If neither option is present, the default value (`warn`) is used
6259
- Note: There's only one underlying setting, and the config and CLI options are just two different ways of controlling it
6360

64-
To reduce complexity and avoid confusion, we will not allow boolean values to be provided anymore, except during a possible intermediary [phase](#phases).
61+
Boolean values will continue to be allowed with no change in behavior, as summarized below.
6562

66-
In addition to allowing an explicit severity level to be passed to the CLI option `--report-unused-disable-directives` (e.g. `--report-unused-disable-directives warn`), we will also allow the option to be provided without a value (e.g. `--report-unused-disable-directives`) (a common CLI shorthand) which will default to `error` severity, the same as today.
63+
Allowed values for the config file option:
6764

68-
### Phases
65+
- `reportUnusedDisableDirectives: true` - same behavior as today (`warn`)
66+
- `reportUnusedDisableDirectives: false` - same behavior as today (`off`)
67+
- `reportUnusedDisableDirectives: "error"` - new value
68+
- `reportUnusedDisableDirectives: "warn"` - new value
69+
- `reportUnusedDisableDirectives: "off"` - new value
6970

70-
The implementation of this RFC will likely involve two phases:
71+
Allowed values for the CLI option:
7172

72-
1. Phase 1: A non-breaking change to add support for the new severity levels, in addition to the existing boolean values. This intermediary, dual-support phase will give shareable configs using `reportUnusedDisableDirectives: true` a chance to switch over to `reportUnusedDisableDirectives: "warn"` while supporting both the ESLint minor version (e.g. `v8.x`) in which phase 1 gets implemented as well as the ESLint major version in which phase 2 gets implemented (e.g. `v9.0`).
73-
2. Phase 2: A breaking change intended for a major release in which support for the boolean values is removed, and the default behavior is changed to `error`.
73+
- `--report-unused-disable-directives` - same behavior as today (`error`) (common CLI shorthand to omit the value)
74+
- `--report-unused-disable-directives=true` - same behavior as today (`error`)
75+
- `--report-unused-disable-directives=false` - same behavior as today (`off`)
76+
- `--report-unused-disable-directives=error` - new value
77+
- `--report-unused-disable-directives=warn` - new value
78+
- `--report-unused-disable-directives=off` - new value
7479

75-
Pros of the phased approach:
80+
### Phases
7681

77-
1. Without this phased approach, the only chance the user would have to cut-over to the new severity levels would be during the ESLint major version bump in which they were implemented. A shareable config would only be able to support the pre-implementation major version or the post-implementation major version.
78-
2. Separating breaking changes from non-breaking changes keeps the changes focused.
79-
3. Users can use and benefit from the new severity levels sooner, without having to wait for them in the next major version.
82+
The implementation of this RFC will likely involve two phases:
8083

81-
Cons of the phased approach:
84+
1. Phase 1: A non-breaking change to add support for the new severity levels.
85+
2. Phase 2: A breaking change intended for a major release in which the default behavior is changed to `warn`.
8286

83-
1. Lengthier / more drawn-out implementation.
84-
2. Complexity/overhead of supporting both booleans and severity levels during the transition period.
85-
3. Based on searching the top 1,000 ESLint plugins with [eslint-ecosystem-analyzer](https://github.com/bmish/eslint-ecosystem-analyzer), I found only a handful of shared configs setting `reportUnusedDisableDirectives` who would be impacted by this.
87+
This allows us to get the new functionality out to users as soon as possible as a smaller change with reduced risk, while also keeping the breaking change small and focused.
8688

8789
### Code Changes
8890

89-
- `conf/config-schema.js` - switch to string / number
91+
- `conf/flat-config-schema.js` - also support string / number type
9092
- `conf/default-cli-options.js` - use new default
91-
- `lib/options.js` - switch to string / number and use new default
92-
- Anywhere `reportUnusedDisableDirectives` is passed around as a boolean needs to change to using a severity level (and no more need to convert between boolean and severity level)
93-
- A few test files that set `reportUnusedDisableDirectives` as a boolean will be updated to use a severity level
93+
- `lib/options.js` - also support string / number type and use new default for the option
94+
- Something like `type: "Boolean|String|Number"` and `enum: ["true", "false", "error", "warn", "off", "0", "1", "2"]`
95+
- When processing the config or CLI options, convert any boolean value provided to a severity level
96+
- Anywhere `reportUnusedDisableDirectives` is passed around as a boolean needs to change to using a severity level
97+
- In addition to testing `reportUnusedDisableDirectives` as a boolean, we'll also need to test it as a severity level
9498

9599
Luckily, `reportUnusedDisableDirectives` is already stored as a severity level in much of the underlying code.
96100

@@ -101,14 +105,18 @@ Luckily, `reportUnusedDisableDirectives` is already stored as a severity level i
101105
on the ESLint blog to explain the motivation?
102106
-->
103107

104-
These documentation pages will be updated to reflect the new behavior of these options:
108+
These documentation pages will be updated to reflect the new option values and defaults:
105109

106110
- Configuration Files
107111
- Configuring Rules
108112
- Command Line Interface
109113
- Node.js API
110114
- `eslint --help`
111115

116+
Documentation will focus on the new severity level values as opposed to the boolean values. We may choose to leave the boolean values undocumented in some places, or add a note that they are deprecated and remain in place only for backwards compatibility, similar to the note in the [globals configuration section](https://eslint.org/docs/latest/user-guide/configuring/language-options#specifying-globals) that says:
117+
118+
> For historical reasons, the boolean value false and the string value "readable" are equivalent to "readonly". Similarly, the boolean value true and the string value "writeable" are equivalent to "writable". However, the use of these older values is deprecated.
119+
112120
## Drawbacks
113121

114122
<!--
@@ -122,44 +130,10 @@ These documentation pages will be updated to reflect the new behavior of these o
122130
implementing this RFC as possible.
123131
-->
124132

125-
- [Breaking changes](#backwards-compatibility-analysis) cause churn and disruption.
126-
- Potential [semver policy implications](#semver-policy) as described below.
127-
128-
### Semver Policy
129-
130-
Erroring by default on unused disable directives will require slight tweaks to our [semantic versioning policy](https://github.com/eslint/eslint#semantic-versioning-policy). It currently reads:
131-
132-
> Patch release (intended to not break your lint build)
133-
> > A bug fix in a rule that results in ESLint reporting fewer linting errors.
134-
> > ...
135-
>
136-
> Minor release (might break your lint build)
137-
> > A bug fix in a rule that results in ESLint reporting more linting errors.
138-
> > ...
139-
140-
These lines will need to be adjusted because a bug fix that causes a rule to produce fewer errors will now break builds if disable directives become unused as a result. See this context:
141-
142-
- <https://github.com/eslint/eslint/issues/12703#issuecomment-568582014>
143-
> If we allowed for errors to be reported with reportUnusedDisableDirectives, we would limit what kind of changes we could publish in a semver-patch release (since fixing a bug that would result in fewer errors could create additional unused disable directives).
144-
- <https://github.com/eslint/eslint/pull/14699#discussion_r650863268>
145-
> ...because of our semver policy, which says that bug fixes that produce fewer errors should not break builds.
146-
147-
#### Semver Policy Alternative 1
148-
149-
One possibility for updating the semver policy is that we could consider any bug fix to a rule, regardless of whether it results in more or less violations, as simply a bug fix and therefore suitable for release as a patch release.
150-
151-
- This is my preference.
152-
- It's how I believe most of the ecosystem (i.e. ESLint plugins) treats bug fixes in real-world usage.
153-
- It's also similar to [Prettier's policy](https://github.com/prettier/prettier/issues/2201) that allows formatting tweaks/fixes in any type of release:
154-
> If prettier produces a different output on two different versions, that's not a breaking change. Ideally prettier will never have any breaking changes, but if there are, it would be to the the API/CLI itself, not the output.
155-
- Some bug fixes cause a rule to produce a combination of more violations and less violations. The distinction between the two is not always clear-cut and not necessarily deserving of different treatment in the semver policy.
156-
- From what I can tell, attempts to work around the existing semver policy are why we have ended up with such a convoluted and unsatisfying design for reporting unused disable directives in the first place, so it could be time to rethink this constraint.
157-
- In addition, the current restriction of lint-build-breaking changes to minor releases already seems arbitrary, as technically, any breaking changes should be limited to major releases according to semver. This obviously wouldn't be practical for us, as it would prevent us from making any bug fixes to rules except in annual major releases. So since ESLint already does not strictly follow semver in terms of breaking lint builds, why impose this arbitrary limitation on what types of bug fixes can be made in patch releases?
158-
- Even today, it's somewhat aspirational to proclaim that a patch release will never break your lint build.
159-
160-
#### Semver Policy Alternative 2
161-
162-
If, however, we want to maintain the categorization of changes based on whether they can break your lint build, then any change to the number of violations a rule produces would have to change from being patch release compatible to only minor release compatible.
133+
- While we attempted to limit the [breaking changes](#backwards-compatibility-analysis) involved, any amount of breaking changes can still be disruptive.
134+
- Some users may not like the new default behavior of warning on unused disable directives and will be burdened by having to opt-out.
135+
- The new warnings can be easily ignored and some may prefer to only use warnings [temporarily](https://github.com/eslint/eslint/discussions/16512#discussioncomment-4089769).
136+
- Keeping around the boolean values for backwards compatibility means increased complexity in supporting both boolean and severity level values. It also means we still have the inconsistency where `reportUnusedDisableDirectives: true` means `warn` but `--report-unused-disable-directives=true` means `error`.
163137

164138
## Backwards Compatibility Analysis
165139

@@ -169,16 +143,13 @@ If, however, we want to maintain the categorization of changes based on whether
169143
to existing users?
170144
-->
171145

172-
Users specifying the following config file options will experience a breaking change:
173-
174-
- `reportUnusedDisableDirectives: true`. No longer allowed, must be changed to `reportUnusedDisableDirectives: "warn"` for the same behavior.
175-
- `reportUnusedDisableDirectives: false`. No longer allowed, must be changed to `reportUnusedDisableDirectives: "off"` for the same behavior.
146+
Users that already specify `reportUnusedDisableDirectives` or `--report-unused-disable-directives` will not experience any breaking changes, as the current behavior will be maintained.
176147

177-
Shareable configs specifying `reportUnusedDisableDirectives: true` will need to be updated to avoid breaking consumers.
148+
Users that do not specify any of these options but do specify [`--max-warnings`](https://eslint.org/docs/latest/user-guide/command-line-interface#--max-warnings) will experience a breaking change, as the additional warnings could cause ESLint to exit with a non-zero exit code.
178149

179-
Based on searching the top 1,000 ESLint plugins, only a handful of usages of `reportUnusedDisableDirectives` were found, so this breaking change may have limited impact. Also see the earlier discussion of [phases](#phases) that should help ease migration.
150+
Users that do not specify any of these options are less likely to experience a breaking change, as additional warnings will simply show up as output text. Note that this could still be a breaking change if the user cares about ESLint's exact output text to stdout, or that running with `--fix` will now fix the new warnings.
180151

181-
Users specifying `--report-unused-disable-directives` on the CLI will not experience a breaking change, as this will continue to report unused disable directives as errors. However, since erroring on unused disable directives is the new default behavior, specifying this option is now redundant.
152+
We don't need tweak our [semantic versioning policy](https://github.com/eslint/eslint#semantic-versioning-policy) (discussed more in [Alternatives](#alternatives)), as the policy will only be violated (i.e. patch releases can break CI) if the user opts-in by setting one of the options to `error`.
182153

183154
## Alternatives
184155

@@ -189,11 +160,23 @@ Users specifying `--report-unused-disable-directives` on the CLI will not experi
189160
projects have already implemented a similar feature.
190161
-->
191162

192-
1. Leave as-is. Reduces churn, but has downsides as mentioned above.
193-
2. Allow both existing boolean values and also new severity levels indefinitely. This has the potential to cause confusion, increase complexity, and continue to be unintuitive as to how the boolean values map to severities. We might as well bite the bullet and fully cleanup and simplify the allowed values instead of allowing the legacy values indefinitely.
194-
3. Adopt new option design but use `warn` as the default behavior. But `warn` is easily ignored and best used only [temporarily](https://github.com/eslint/eslint/discussions/16512#discussioncomment-4089769).
163+
1. Leave as-is. But this means continued lack of configuration flexibility and discoverability of unused disable directives.
164+
2. Remove boolean values for configuration options. We decided against this because it's a breaking change that could be too disruptive for users, and the overhead of supporting both booleans and severity levels is limited.
165+
3. Adopt new option design but use `error` as the default behavior. We decided against this because causing CI to fail due to unused disable directives could be too disruptive to users and violates the current [semantic versioning policy](https://github.com/eslint/eslint#semantic-versioning-policy):
166+
> Patch release (intended to not break your lint build)
167+
> > A bug fix in a rule that results in ESLint reporting fewer linting errors.
168+
> > ...
169+
>
170+
> Minor release (might break your lint build)
171+
> > A bug fix in a rule that results in ESLint reporting more linting errors.
172+
> > ...
173+
174+
- <https://github.com/eslint/eslint/issues/12703#issuecomment-568582014>
175+
> If we allowed for errors to be reported with reportUnusedDisableDirectives, we would limit what kind of changes we could publish in a semver-patch release (since fixing a bug that would result in fewer errors could create additional unused disable directives).
176+
- <https://github.com/eslint/eslint/pull/14699#discussion_r650863268>
177+
> ...because of our semver policy, which says that bug fixes that produce fewer errors should not break builds.
195178
4. Adopt new option design but use `off` as the default behavior. This would maintain the existing behavior for the majority of users who aren't reporting unused violations. But most users would continue to miss out on the benefit of this feature then.
196-
5. Turn `reportUnusedDisableDirectives` into a regular ESLint rule as suggested in [#13104](https://github.com/eslint/eslint/issues/13104). While this could enable us to reduce complexity by eliminating a config option, a new rule implementing this feature may require special case handling, and it's not clear it's possible to implement within the current architecture.
179+
5. Turn `reportUnusedDisableDirectives` into a regular ESLint rule as suggested in [#13104](https://github.com/eslint/eslint/issues/13104). While this could enable us to reduce complexity by eliminating a config option, a new rule implementing this feature may require special case handling, and it's not clear it's possible to implement within the current architecture. It's also a larger breaking change.
197180

198181
## Open Questions
199182

@@ -209,8 +192,6 @@ Users specifying `--report-unused-disable-directives` on the CLI will not experi
209192
-->
210193

211194
1. Should we allow severity levels to be provided as numbers? If we allow these numbers everywhere else and have no plans to scrap them, then we likely want to allow them here as well for consistency.
212-
2. Is the [phased approach](#phases) worth the overhead?
213-
3. Which [semver policy](#semver-policy) alternative do we prefer?
214195

215196
## Help Needed
216197

0 commit comments

Comments
 (0)