# New YAML configuration for diagnostics analysis options Addresses https://github.com/dart-lang/sdk/issues/58693 ## Problem: confusing way to specify diagnostics options Let's look at an example: ```yaml analyzer: errors: unused_element: ignore unused_import: warning dead_code: error language: - strict-casts linter: rules: double_quotes: false single_quotes: true ``` Section by section: * `analyzer/errors`: In this section, we can set the _severity_ of individual _diagnostic codes_. In the example, the `unused_element` Warning's severity is set to "ignore", the `unused_import` Warning's severity is set to "warning" (the diagnostic type, "Warning," is distinct from the severity, "warning"), and the `dead_code` Warning's severity is set to "error." * `analyzer/language`: In this section, we can enable three different "strict analysis modes": `strict-casts`, `strict-inference`, and `strict-raw-types`. * `linter/rules`: In this section, we can specify a list of lint rules to enable (distinct from the names of the diagnostics they produce), or a map, where each key is a lint rule name, and each value is `true` or `false`, enabling or disabling the lint rule. There can be confusion around these three sections, as they seem to each serve approximately the _same function_: enabling and disabling diagnostics that are produced by the analyzer. ## Proposal: a single section I believe we can combine these three sections into a single one, placed at `analyzer/diagnostics` (or alternatively just a top-level `diagnostics` section). The above example would be written as: ```yaml analyzer: diagnostics: unused_element: false|disable unused_import: warning dead_code: error strict-casts: warning|enable double_quotes: false|disable single_quotes: warning|enable ``` Here's how it works: * The `analyzer/diagnostics` section must be a YAML map. * Each key is just a diagnostic name. In the case of Warning diagnostics, this can be a "shared name" (e.g. `unnecessary_null_comparison` or a "unique name" (e.g. `unnecessary_null_comparison_always_null_false`). In the case of Lint diagnostics, this can be a lint rule name, which acts as a shared name (e.g. `invalid_runtime_check_with_js_interop_types`), or can be a unique diagnostic name (e.g. `invalid_runtime_check_with_js_interop_types_dart_as_js`). The three "strict modes" will have to be changed to report diagnostics that have a shared name like `strict_casts` (or they could be refactored in a bigger way to just be like lint rules...). * There are four possible values: `false`, `info`, `warning`, and `error`. * `false` means "don't report this." * `info`, `warning`, and `error` mean, "do enable this, and report violations at this severity." * Alternative possible values: `disable`, `enable`, `info`, `warning`, and `error`. * `disable` means "don't report this." * `enable` means "do enable this, and report violations at the default severity." * `info`, `warning`, and `error` mean "do enable this, and report violations at this severity." ## Alternatives ### Using a YAML list The `analyzer/diagnostics` section could be a list. This would allow specifying lint rules without a true/false/warning/whatever value: ```yaml analyzer: diagnostics: - unused_element: false - unused_import: warning - dead_code: error - strict-casts - double_quotes: false - single_quotes ``` I think this probably makes the syntax more confusing, and not much more terse. One benefit is that developers don't have to "choose" what severity lint rules are reported at (e.g. "warning"). ### Save the strict modes for later It can be an incremental migration. Refactoring the strict modes may be a bigger effort. We could leave them in place, for a first phase of migrating to `analyzer/diagnostics`. The two sections which are most important to combine are `analyzer/errors` and `linter/rules`. ## Migration The migration would be incremental. 1. In one release, Dart _3.N_, we introduce the `analyzer/diagnostics` section. It cannot be specified side-by-side with `analyzer/errors` or `linter/rules`, but the values _can_ be merged with included files. * If a file with `analyzer/diagnostics` includes one-or-more files with `analyzer/errors` or `linter/rules`, the options are merged, not at the YAML level, but at the internal-representation level. * If a file with `analyzer/errors` or `linter/rules` includes one-or-more files with `analyzer/diagnostics`, the options are merged, not at the YAML level, but at the internal-representation level. * In this release, we also offer an assist to migrate the contents of an analysis options file from the old format to the new. (I guess we'd offer it for any file named `*.yaml` which has either an `analyzer/errors` section or a `linter/rules` section? 2. In the next release, Dart _3.N+1_, we deprecate the old options. There is no change in the behavior of what options are parsed; only new warnings are reported in analysis options files. We delay deprecating them for CI purposes. (Maybe this can be done between dev releases or flutter rolls... but tricky with the customer tests.) 3. In the next release, Dart _3.N+2_, we stop respecting the old sections (and report the old sections as "unknown"?). CC @dart-lang/analyzer-team @DanTup @parlough