@codacy/tools-dartanalyzer-3
v0.2.0
Published
dartanalyzer adapter — CLI-mode Dart analyzer (dart analyze)
Downloads
259
Readme
@codacy/tools-dartanalyzer-3
Table of Contents
- Overview
- Updating patterns
- Updating the pattern-type table
- Updating the Dart SDK version
- Development
- Notes for maintainers
Overview
dart analyze is the Dart SDK's built-in static analyzer — the same engine behind the Dart IDE
plugins. It reports two kinds of finding, and this adapter handles both:
- Lint rules (215 Codacy patterns) — style and best-practice checks. Opt-in: they only run when
an
analysis_options.yamlenables them. - Analyzer diagnostics (962 Codacy patterns) — compile-time errors, type errors, dead code. Always on, no configuration needed.
| Property | Value |
| -------------- | ----------------------------------------------- |
| Tool ID | dartanalyzer |
| Codacy UUID | d203d615-6cf1-41f9-be5f-e2f660f7850f |
| Strategy | CLI (spawnTool) |
| Languages | Dart |
| File patterns | **/*.dart |
| Runtime | Dart SDK 3.x (~210 MB, auto-installed) |
| Upstream docs | https://dart.dev/tools/dart-analyze |
| Codacy wrapper | https://github.com/codacy/codacy-dartanalyzer |
Updating patterns
# Re-fetch pattern metadata from the Codacy API
pnpm prefetch
# The pattern-type table is derived from patterns.json — always refresh it too
pnpm fetch-rule-types
# Commit both
git add src/patterns.json src/pattern-types.jsonUpdating the pattern-type table
src/pattern-types.json maps each bare rule name to lint, diagnostic or unknown. The adapter
needs it because analysis_options.yaml has two separate sections and a rule written to the wrong
one silently does nothing.
pnpm fetch-rule-types derives it from the Dart SDK's own machine-readable lint catalog
(pkg/linter/tool/machine/rules.json, overridable with DART_LINT_RULES_URL): a name the catalog
lists is a lint, anything else in Codacy's catalog is a diagnostic. It prints the resulting counts
plus two gaps worth watching:
- Removed lints (
unknown) — still in Codacy's catalog, gone from the SDK. Written to neither config section, since the analyzer recognises them in neither. The explicit list lives inisRemovedLint()inscripts/fetch-rule-types.mjs; prune entries Codacy drops. - SDK lints with no Codacy pattern — currently 47. They can never be enabled from a Codacy config, and there is nothing this package can do about it until Codacy's catalog catches up.
The Codacy wrapper ships an equivalent table as a hand-written docs/patterns_type.json. This one is
derived instead because that snapshot is already 44 lint rules behind the SDK; the two agree exactly
on the 1180 patterns they share (215 + 3 removed lints = the wrapper's 218; 962 diagnostics).
Updating the Dart SDK version
- Check what Codacy runs:
.tool_versionincodacy/codacy-dartanalyzer, or theversionfield fromhttps://app.codacy.com/api/v3/tools. Track that, not the newest stable release. - Update
preferredVersioninsrc/metadata.ts. The download URL is derived from it, so nothing else changes. - Run
pnpm prefetchandpnpm fetch-rule-typesto pick up new and removed rules. - Run
pnpm test. - A new Dart major version means a new adapter package (
dartanalyzer-4/).
Development
pnpm build # Build with tsup
pnpm test # Run tests (SDK-dependent tests skip when no dart is installed)Installing a Dart SDK locally, so the integration tests run instead of skipping:
brew install dart # macOS
# or install Flutter, which bundles Dart
# or https://dart.dev/get-dartcodacy-analysis analyze . --install-dependencies also works: it downloads the pinned portable SDK
into ~/.codacy/tools/dartanalyzer/dart-sdk/.
Notes for maintainers
The repository-root config swap
This is the one adapter that writes outside .codacy/, and it is not a shortcut — dart analyze
gives no alternative.
Every other tool here takes a --config <path>. dart analyze has no equivalent: dartdev exposes
only --format, --packages, --cache, --sdk-path and the --fatal-* flags. The analyzer finds
analysis_options.yaml by walking up the directory tree from the analyzed file
(ContextLocator in pkg/analyzer), so a config in .codacy/generated/ is never seen. The Codacy
Docker wrapper solves this by writing /analysis_options.yaml and mounting the repository at
/src — a parent directory it owns. Locally there is no such directory.
So analyze() does this, in order:
- Recover — if the root config carries the
codacy-cli-generated-analysis-optionsmarker, a previous run was killed mid-swap: restore.codacy/generated/dartanalyzer/analysis_options.yaml.origif present, otherwise delete the file. - Write the generated config to
.codacy/generated/dartanalyzer/analysis_options.yaml(kept there for inspection), back up any existing root config to…/analysis_options.yaml.orig, and copy the generated file to the repository root. - Run every
dart analyzechunk under that one config. - Restore in a
finally: put the backup back, or delete the generated file — and only ever delete a file carrying the marker, so a config the user created mid-run survives.
The marker is what makes every step safe to repeat. Two paths skip the swap entirely: when the
project's own config is in use (useLocalConfigurationFile), and when the swap fails (read-only
checkout, permissions) — that is a warning, not a failure, because analyzer diagnostics still work
without it and only the opt-in lint rules are lost.
Results are filtered post-hoc by enabled pattern ID regardless of which path ran, which is what makes the local-config path correct too.
Why the generated config looks half-empty
It writes enabled lints and ignored diagnostics, and nothing else:
analyzer:
errors:
unused_import: ignore # every diagnostic NOT selected
linter:
rules:
prefer_single_quotes: true # every lint selected- Unselected lints get no
false. The file has noinclude:, so a lint it does not name is already off. (Skippinginclude:also avoids thepackage:flutter_lintsresolution failure the Docker wrapper works around with a container-rootdart pub add.) - Selected diagnostics get no entry. They already fire at their default severity, and
Issue.severitycomes frompatterns.json. Writing a level here would mean translating Codacy'sHighinto a section that accepts onlyignore|info|warning|error— the wrapper writeshigh, which is invalid.
--format json, not --format machine
The wrapper uses --format machine with a comment that JSON "returns multiple objects after a given
limit". That is no longer true in SDK 3.x: emitJsonFormat is a single json.encode call. JSON is
strictly better here — it carries range.end (→ endLine/endColumn), correctionMessage
(→ Issue.suggestion), and code in its original lowercase, where machine format uppercases the
code and gives only a length offset delta that can span lines.
parseDartOutput still falls back to parsing concatenated documents line by line, in case that
behaviour ever returns.
Exit codes are 0 clean, 1 infos, 2 warnings, 3 errors, 4 crash — only 4 and above is a
failure.
Unresolved dependencies
dart analyze needs dart pub get to have run; without .dart_tool/package_config.json, every
package: import is unresolvable and reports uri_does_not_exist — hundreds of findings on a real
Flutter repository.
The adapter never runs pub get (it would write .dart_tool/ and pubspec.lock into the
repository, and needs the network — the same stance the ESLint adapters take on npm install).
Instead it warns, and suppresses uri_does_not_exist, uri_has_not_been_generated and
depend_on_referenced_packages for that run only. Suppression is post-hoc rather than a config
ignore so it also applies on the local-config path, where nothing is generated.
Part files
A Dart part file cannot be analyzed on its own; targeting one makes dart analyze report that it
"is a part and cannot be analyzed". That is a complaint about the invocation, not the code, so those
messages are dropped (the wrapper filters the same two strings). The library file carrying the part
directive is what should be analyzed. Diagnostics against non-.dart files (pubspec.yaml,
analysis_options.yaml) are dropped for the same reason.
Known limitations
- Dart monorepos. The swap only touches the repository root. A nested package with its own
analysis_options.yamlbeats it, so Codacy's pattern selection is ignored for files under that package. Tracked indocs/tech-debt.md. - Concurrent runs. Two
codacy-analysis analyzeprocesses on one repository race on the swap. - One analysis server per chunk. Each
dart analyzeinvocation starts its own analysis server, so a file list large enough to be split across argv chunks pays that startup more than once.
