npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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

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.yaml enables 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.json

Updating 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 in isRemovedLint() in scripts/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

  1. Check what Codacy runs: .tool_version in codacy/codacy-dartanalyzer, or the version field from https://app.codacy.com/api/v3/tools. Track that, not the newest stable release.
  2. Update preferredVersion in src/metadata.ts. The download URL is derived from it, so nothing else changes.
  3. Run pnpm prefetch and pnpm fetch-rule-types to pick up new and removed rules.
  4. Run pnpm test.
  5. 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-dart

codacy-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:

  1. Recover — if the root config carries the codacy-cli-generated-analysis-options marker, a previous run was killed mid-swap: restore .codacy/generated/dartanalyzer/analysis_options.yaml.orig if present, otherwise delete the file.
  2. 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.
  3. Run every dart analyze chunk under that one config.
  4. 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 no include:, so a lint it does not name is already off. (Skipping include: also avoids the package:flutter_lints resolution failure the Docker wrapper works around with a container-root dart pub add.)
  • Selected diagnostics get no entry. They already fire at their default severity, and Issue.severity comes from patterns.json. Writing a level here would mean translating Codacy's High into a section that accepts only ignore|info|warning|error — the wrapper writes high, 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.yaml beats it, so Codacy's pattern selection is ignored for files under that package. Tracked in docs/tech-debt.md.
  • Concurrent runs. Two codacy-analysis analyze processes on one repository race on the swap.
  • One analysis server per chunk. Each dart analyze invocation starts its own analysis server, so a file list large enough to be split across argv chunks pays that startup more than once.