No schema for analysis_options.yaml exists anywhere today. The Dart team
declined to ship one in March 2025 and invited
the community to do it instead; SchemaStore has 1470 schemas and none of them match this file
(verified against the live catalog, 2026-09-18). VS Code's Dart extension contributes no
yamlValidation either — its completion comes from the analysis server, so there is nothing to
copy.
This repo generates one, and proves it against every analysis_options.yaml on the machine.
tool/build.sh # regenerate both variants, then validate
tool/verify_rules.sh # re-check the alias data against a real analyzer
| Input | Source | Why this one |
|---|---|---|
| Lint rule names, descriptions, state, SDK version | rules.json on SDK main |
Machine-readable and maintained by the linter team |
| Option key surface | analyzer package 9.0.0 sources, lib/src/analysis_options/analysis_options_file.dart and options_file_validator.dart |
The code that actually accepts or rejects keys, not prose |
| Documentation links, rule spellings | dart.dev/tools/linter-rules | Canonical per-rule doc URLs |
| Alternate rule spellings | dart analyze, run locally |
See below — the other sources disagree |
Prose docs (dart.dev/tools/analysis) were used only as a
cross-check. Every option key documented there is in the schema; the schema additionally covers
analyzer.cannot-ignore, analyzer.optional-checks, code-style.format, formatter.trailing_commas
and the modern top-level plugins, which the page does not document but the analyzer accepts.
1. rules.json is not the set of names the analyzer accepts. Three rules are listed there in
all-lowercase (prefer_iterable_wheretype), while dart.dev and the Flutter SDK's own
analysis_options.yaml files use camelCase (prefer_iterable_whereType). Both spellings work.
Putting both in one file yields duplicate_rule, not undefined_lint — proof the analyzer resolves
them to the same rule. An enum generated from rules.json alone rejects files that analyze
cleanly, including several inside the Flutter SDK. tool/alias_rules.json carries the three
extra spellings, with tool/verify_rules.sh to re-prove them.
2. rules.json's sets field is empty for all 264 rules. Core/recommended/flutter membership
cannot be read from it. The lints and flutter_lints packages are the real source if that is ever
wanted here.
3. dart.dev appears to list 265 rules; it lists 264. The 265th link is
/tools/linter-rules/index, which is not a rule. The two sources agree on count.
4. The analyzer has no top-level key validator at all. _AnalyzerTopLevelOptionsValidator
checks keys inside analyzer:; nothing checks the top level, so an unknown top-level key is
silently ignored. Third-party Dart tooling relies on this and stores its own configuration under a
top-level key in analysis_options.yaml — one such tool accounts for the single file in the
validation corpus below that the strict variant rejects.
That last one is the only genuine judgment call in this repo, so it is a switch, not a decision baked into the output:
| File | additionalProperties at top level |
For |
|---|---|---|
schemas/analysis-options.json |
allowed | The default, and what is prepared for SchemaStore. Matches the analyzer. Will not flag a co-located tool config. |
schemas/analysis-options.strict.json |
rejected | Catches analyser: and other typos the analyzer stays silent about. Costs a false positive on any file carrying another tool's config. |
Both are generated and both are tested. --strict-top-level picks the second.
include (string or list — current SDKs merge a list in order), analyzer (errors, exclude,
language, enable-experiment, cannot-ignore, optional-checks, plugins, the deprecated
strong-mode), linter.rules in both the list form and the map form, formatter
(page_width, trailing_commas), code-style.format, and the top-level plugins map.
Every rule carries its description, its sinceDartSdk version and a link to its dart.dev page, so
editor hovers are useful:
Deprecated and removed rules are included rather than rejected — the analyzer only warns about them,
and rejecting would flag files that still work. deprecationMessage is honoured by the VS Code
JSON/YAML language services, which strike the name through.
Empty sections (analyzer: with nothing under it, a bare rules:) parse as YAML null and are
accepted; 8 files in the corpus do this.
tool/validate.py does four things, and the build fails if any of them regress:
- the schema is a valid draft-07 schema;
- every real
analysis_options.yamlunder~/fvm/versionsand~/Projectsis accepted — 130 files, 130 accepted; - seven deliberately broken files are rejected, each for the reason recorded in its
.expectedfile, plus the unknown-top-level-key case against the strict variant and the assertion that the default variant accepts it; - five hand-written valid fixtures covering corners the corpus misses.
Failure messages come from jsonschema's best_match, so they point at the offending line rather
than at the enclosing anyOf:
at linter/rules/1: 'prefer_const_construtors' is not valid under any of the given schemas
at analyzer/errors/invalid_assignment: 'fatal' is not one of ['ignore', 'false', ...]
at formatter/page_width: 0 is less than the minimum of 1
rules.json is committed so the build is reproducible offline. When the SDK adds rules:
tool/build.sh --refresh # re-download rules.json, regenerate, revalidateIf a new alias appears, add it to tool/alias_rules.json and prove it with
tool/verify_rules.sh <path-to-dart>. That script fails if its own control name is not rejected, so
it cannot pass vacuously.
Prepared under schemastore/, in the layout that repo uses. Nothing here has been committed,
pushed, or opened as a PR.
| Prepared file | Goes to |
|---|---|
schemastore/src/schemas/json/analysis-options.json |
src/schemas/json/analysis-options.json |
schemastore/src/test/analysis-options/*.yaml (5) |
src/test/analysis-options/ |
schemastore/src/negative_test/analysis-options/*.yaml (7) |
src/negative_test/analysis-options/ |
schemastore/catalog-entry.json |
one entry in src/api/json/catalog.json |
The catalog is ordered by name but not strictly sorted, so insert by neighbour rather than by sort:
the entry goes at index 356, after Dagger module and before Dart Build Config (dart-build.json).
Before opening anything, run their prettier over the added files — SchemaStore enforces formatting
in CI, and this schema was written by json.dumps, not by their toolchain.
Note the negative tests are the seven that the shipped (permissive) schema rejects. The
unknown-top-level-key fixture lives in test/fixtures/invalid-strict/ and is deliberately not part
of the contribution, because the shipped schema accepts it on purpose.
{ "const": "avoid_as", "description": "REMOVED. Avoid using `as`. (since Dart 2.0)\n\nhttps://dart.dev/tools/linter-rules/avoid_as", "deprecationMessage": "The lint rule 'avoid_as' has been removed and no longer has any effect." }