saropa_lints 16.2.1
saropa_lints: ^16.2.1 copied to clipboard
2332 custom lint rules with 254 quick fixes for Flutter and Dart. Static analysis for security, accessibility, and performance.
Changelog #
....
-+shdmNMMMMNmdhs+-
-odMMMNyo/-..``.++:+o+/-
/dMMMMMM/ `````
dMMMMMMMMNdhhhdddmmmNmmddhs+-
/MMMMMMMMMMMMMMMMMMMMMMMMMMMMMNh/
. :sdmNNNNMMMMMNNNMMMMMMMMMMMMMMMMm+
o ..~~~::~+==+~:/+sdNMMMMMMMMMMMo
m .+NMMMMMMMMMN
m+ :MMMMMMMMMm
/N: :MMMMMMMMM/
oNs. +NMMMMMMMMo
:dNy/. ./smMMMMMMMMm:
/dMNmhyso+++oosydNNMMMMMMMMMd/
.odMMMMMMMMMMMMMMMMMMMMdo-
-+shdNNMMMMNNdhs+-
``
Made by Saropa. All rights reserved.
Learn more at https://saropa.com, or mailto://dev.tools@saropa.com
2300+ custom lint rules with 250+ quick fixes for Flutter and Dart — static analysis for security, accessibility, performance, and library-specific patterns. Includes a VS Code extension with Package Vibrancy scoring.
Package — pub.dev/packages/saropa_lints
Releases — github.com/saropa/saropa_lints/releases
VS Code Marketplace — marketplace.visualstudio.com/items?itemName=saropa.saropa-lints
Open VSX Registry — open-vsx.org/extension/saropa/saropa-lints
16.2.1 #
Patch release fixing false positives in two lint rules, adding a project-level allowlist for avoid_ignoring_return_values, and resolving unwanted reload behavior in the Config and Findings Dashboards when editing text fields. log
Added #
avoid_ignoring_return_values now supports a project-level allowlist via analysis_options_custom.yaml — add method names under avoid_ignoring_return_values: safe_to_ignore: to exempt project-specific methods whose return values are safely ignored. No action required unless you have project-specific methods you want to allowlist.
Fixed #
google_sign_in_auth_token_from_authenticate no longer flags .accessToken reads on already-migrated GoogleSignInClientAuthorization results or unrelated model classes with a same-named field. No action required.
avoid_public_members_in_states no longer flags WidgetsBindingObserver/RouteAware/AutomaticKeepAliveClientMixin callback methods (e.g. didChangeAppLifecycleState, didPushNext, wantKeepAlive) on a State class that carries the interface via with or implements — their public spelling is mandated by the framework, so the rule's own suggested private-rename fix would have silently broken dispatch. No action required.
prefer_late_final no longer flags a late field whose assigning method is passed elsewhere as a bare tear-off (e.g. setState(_initFutures)) — the tear-off's runtime call count can't be bounded from the declaration site, so the field may genuinely be reassigned even though only one direct call site is visible in the AST. No action required.
avoid_ignoring_return_values no longer flags a project-local extension method whose name follows a mutate-verb convention (add*, append*, insert*, remove*, update*, set*) and returns bool — the same structural shape as allowlisted stdlib mutators like List.add, where the bool is a "did it happen" convenience the caller is not required to consult. No action required.
require_ios_accessibility_large_text no longer flags TextStyle(fontSize:) when the value comes from a non-const getter, method call, or property access — only bare numeric literals and const identifiers are flagged. Previously the rule pattern-matched source text for textScaleFactor/textScaler/MediaQuery substrings and missed any design-system token that applies Dynamic Type scaling through a helper. No action required.
Fixed (Extension) #
- The Config Dashboard and Findings Dashboard no longer constantly reload while you type into a search box or text field — a background refresh (triggered by the analyzer's live diagnostics, config-file saves, or workspace tree updates) was rebuilding the whole panel on every tick regardless of whether you were mid-edit, which also made the Config Dashboard's "Matching rules" → "in
<package>" links appear dead since the panel they lived in kept getting torn down. Both dashboards now wait until you leave the field before redrawing. - The Config Dashboard's collapsible sections (packs, disabled rules, shed rules, style & opinions) now remember whether you left them open or closed, the same way the Findings Dashboard's sections already did.
16.2.0 #
The audit command now gives you complete visibility into suppressed warnings across your codebase, revealing exactly what is being silenced in your project. A new diagnostic flags unbounded images that waste memory, while the extension introduces robust workspace hazard scans and a fully collapsible Findings Dashboard. log
Added #
The audit command now gives you complete visibility into suppressed warnings across your codebase. You can optionally expose findings previously hidden by ignore directives or baseline files to understand exactly what is being silenced in your project. log
New rule avoid_unbounded_image_in_full_bleed_container: flags an Image/Image.asset/Image.network/Image.memory/Image.file with no width/height/cacheWidth/cacheHeight sitting inside a full-bleed ancestor (Positioned.fill, SizedBox.expand, or a Stack with fit: StackFit.expand) — the image decodes at native resolution and is then stretched to fill an arbitrarily large parent, wasting decode memory. Skips false positives where a nearer SizedBox/Container/ConstrainedBox/AspectRatio already constrains the image's own size.
Added (Extension) #
- New file-watcher exclusion audit checks the workspace's
files.watcherExcludesetting on activation and recommends missing patterns for heap dumps, build output, and tooling caches that can crash VS Code when tracked. "Add All" writes them into workspace settings in one click; "Dismiss" suppresses the prompt permanently for that workspace. - Extension host process memory monitoring: the ProcessMonitor now samples the Node.js extension host RSS and heap on each poll, with trend tracking and a configurable warning threshold (
extensionHostWarningGB, default 1 GB) that surfaces in the status bar — the blind spot behind the 2026-09-05 crash. - Workspace hazard scan: on activation, scans for dangerously large files (heap dumps, oversized logs, any file >100 MB) not excluded from the file watcher. Warns with a one-click action to add
files.watcherExcludepatterns. Disable viasaropaLints.systemHealth.workspaceHazardScan. - Workspace readiness indicator: combines hazard scan, watcher exclude audit, and extension host memory into a single status bar signal with a
saropaLints.showWorkspaceReadinesscommand that opens an actionable quick-pick listing each issue. - Every top-level section of the Findings Dashboard (Overview KPIs, Charts, TODO/HACK, Drift Advisor, Suppressions, Top Rules, Findings) is now individually collapsible via a native disclosure triangle. Each section remembers its open/closed state per workspace, and a collapsed section still shows its counter so you know how many items are inside without expanding it.
- Unified every counter on the Findings Dashboard (chart totals, section headers, TODO/HACK counts, and the big KPI stat-card numbers) onto the same pill component already used by the status-line pills, for one consistent counter look across the page. Severity colors are unchanged.
- "Include suppressed" checkbox in the Findings Dashboard toolbar (visible only in audit mode) passes the new
--include-suppressedCLI flag through the UI — check it, run audit, and suppressed violations appear in the findings table with an orange "Suppressed" pill badge. No config files are touched. - New "Copy everything as JSON" and "Save everything report" items in the More-actions menu (audit mode only) export the raw, unfiltered audit result — bypassing all dashboard filters and including suppressed findings — so you can get a true everything-export without manually clearing filters first.
- New "Suppressed Findings" collapsible section appears in the dashboard when audit mode has
--include-suppressedactive and there are suppressed violations. Groups findings by suppression kind (ignore, ignore_for_file, baseline) with a mini table and per-row "Unsuppress" button (currently shows a hint — full comment-removal is planned). - New "Suppress all visible" bulk action in the Findings Dashboard's More-actions menu inserts
// ignore: <rule>above every finding currently shown in the table, in one confirmed, all-or-nothing edit across every affected file. Disabled when there are no findings to suppress. - New extension-native check flags a
bugs/*.mdreport marked Fixed, Closed, or Declined that is still sitting inbugs/instead of being archived toplans/history/, as a Problems-panel hint on the report'sStatus:line. No action required — this only surfaces reports that were left un-archived. - New extension-native check (mirror image of the above) flags a markdown file filed under the configured archive directory (default
plans/history/) that still reads as open work — an openStatus:/Severity:field or an unaddressed action-items heading — as a Problems-panel hint suggesting it be moved to the open-issues directory instead. Archive glob, open-issues directory, and the open/closed signal patterns are all configurable viasaropaLints.docPlacement.*settings; disable withsaropaLints.docPlacement.enabled.
Fixed (Extension) #
-
Drift Advisor integration now supports authenticated servers via a new
saropaLints.driftAdvisor.authTokensetting, with matching guidance states in both the tree view (linking to Settings) and the Findings Dashboard status pill when a token is missing or was rejected by the server. -
Fixed Code Health dashboard KPI tiles silently losing their semantic color coding (red/amber/info) after the pill-unification refactor —
kpiCard()was missing the.pillclass that the updated CSS selectors require. -
Fixed silent status bar disappearance when
updateAllStatusBarsthrows (e.g. corruptedworkspaceStateafter a VS Code hard crash). The bar now catches errors, shows a visible$(error) Saropa Lints: Errorstate with an error-themed background, and logs to the output channel so the failure is discoverable.
Internal #
- Converted the workspace hazard scan's recursive directory walk from synchronous
fs.readdirSync/fs.statSyncto asyncfs.promises.readdir/fs.promises.stat, preventing the extension host thread from blocking on large workspaces. Subdirectory walks and file stat calls now fan out concurrently viaPromise.all. - Extracted duplicate watcher-exclude merge logic (read config, spread, set keys, write at workspace level) from both
workspaceHazardScan.tsandwatcherExcludeAudit.tsinto a sharedmergeWatcherExcludeshelper inwatcherExcludeHelpers.ts. - Added a guard around the watcher-exclude audit's
workspaceState.getcall so a corrupted workspace state after a VS Code crash does not prevent the audit from running. - Fixed extension version scheme so stable releases supersede their betas on Marketplace and Open VSX. Stable versions now bump minor to the next even above the prerelease odd minor (e.g.
16.2.x>16.1.x). - Documented the split between Dart AST rules (
lib/src/rules/, scoped to resolved.dartfiles) and ad hoc extension-native checks (extension/src/, full workspace file access, ownDiagnosticCollectioneach, not yet surfaced in the web report) inbugs/ISSUE_REPORT_GUIDE.md, so non-Dart-file issues are routed correctly instead of being misfiled as out of scope. No action required.
16.0.1 #
Adds a "What's New" panel that surfaces on activation, flagging the v16 diagnostic engine change (LSP server replacing the Analyzer Plugin), the new machine health monitoring, and the sidebar redesign — with a one-click revert to the previous engine. log
Added (Extension) #
- New "What's New" panel opens on activation, summarizing the v16 diagnostic engine change (Analyzer Plugin → LSP server, on by default), the new machine health monitoring, and the sidebar redesign — with one-click actions including reverting to the Analyzer Plugin, plus a live rule-count stat strip and a discovery grid linking straight into the Findings, Package, and Rules & Tiers dashboards. The panel keeps reappearing on every activation until you scroll through it and uncheck "Show this next time"; reopen it anytime from the Command Palette or Help Hub ("Saropa Lints: What's New"). No action required unless your diagnostics look different after this upgrade, in which case the panel's revert button restores the previous engine.
Added (Lint Rules) #
- New
always_specify_parameter_namesrule (Professional tier) flags call sites passing 2+ consecutive positional arguments of the same or confusable type (e.g. two Strings, int+double), where named arguments could prevent silent swap bugs. Allowlists idiomatic Dart/Flutter constructors likeOffset(dx, dy)(matched by declaring library, so a project's own same-named class is never silently exempted); add project-specific allowlist entries underalways_specify_parameter_names: allowlist:inanalysis_options_custom.yaml.
Fixed (Lint Rules) #
- Fixed
avoid_unbounded_dependencyfalse positive in Melos/pub-workspace monorepos where a dependency withanyconstraint is paired with apath:entry independency_overrides:. Theanyis inert in that case because pub resolves via the local path, not the loose constraint. Onlypath:overrides suppress the lint;git:andhosted:overrides do not.
Improved (Extension) #
- "Run analysis" now reads live VS Code diagnostics instead of spawning a cold
dart analyzesubprocess, completing in milliseconds instead of tens of seconds on large projects. The three analysis paths (full workspace, per-file, and post-config-change) all use the live diagnostic stream. The data written toviolations.jsonis structurally identical to what the Problems panel shows, eliminating stale-data divergence between runs.
Internal #
- Fixed the publish workflow authenticating to pub.dev with a stale OIDC token.
setup-dartmints the credential once, right after SDK install; Analyze plus the full test suite then run for 9-10 minutes before the publish step, long enough for the short-lived token to expire and be rejected asInvalid JWT token: invalid timestamps. This had been misdiagnosed twice (beta.6, beta.9) as a transient pub.dev outage.setup-dartnow re-runs immediately beforedart pub publishso the token is minted at the point of use. - Bumped GitHub Actions across all workflows to Node.js 24-compatible major versions (
actions/checkoutv4→v5,actions/setup-pythonv5→v6,actions/setup-nodev4→v5 with runtime bumped to Node 22,actions/upload-artifactv4→v5,actions/github-scriptv7→v8), resolving the Node.js 20 deprecation warning on GitHub-hosted runners.
16.0.0-beta.9 #
Activation is now resilient — commands register and the sidebar warns on failure instead of going blank. The Findings Dashboard absorbs the full-project audit as a scope selector and gains severity coloring, clickable file paths and rule names, a filter-aware page limit, and JSON export. Sidebar rows show live counts, and per-file analysis no longer blocks the extension host. Publish-pipeline fixes stop the i18n audit from launching Ollama and the local pub.dev fallback from flooding the terminal. log
Fixed (Extension) #
- Fixed "command not found" errors for dashboard and config commands when unrelated activation setup threw an error. The 80-command registration block now always executes regardless of whether earlier setup (providers, watchers, LSP) succeeded or failed. No action required.
- When activation setup fails, the sidebar now shows a warning banner ("Activation Error — Check Extension Host log for details") instead of empty panels. No action required.
- Fixed "Prune ignores" crashing the Flutter daemon on Windows by spawning
dartdirectly instead of via acmd.exewrapper, eliminating process-tree complexity that competed for SDK resources. AlldartCLI invocations now use direct spawn;flutter(a.batwrapper) retains the shell path, and an ENOENT fallback retries with a shell for legacy SDK installs. No action required. - Fixed per-file analysis (
runAnalysisForFiles) blocking the extension host with a synchronousspawnSynccall for the entiredart analyzeduration. Converted to the asyncrunInWorkspaceAsyncvariant that the full-workspace analysis already uses, keeping the event loop responsive and adding a Cancel button to the progress notification. No action required. - "Run Analysis" now reads live VS Code diagnostics instantly instead of spawning a
dart analyzesubprocess. Completes in milliseconds instead of tens of seconds. The zero-violations case now shows a confirmation message instead of silent completion. Config-change rescans use an event-driven freshness gate instead of a fixed delay. No action required. - Sidebar dashboard rows now show live counts instead of static labels — Findings Dashboard shows violation count and health score, Package Dashboard shows how many packages have features to adopt, and the activity bar badge now reflects only lint violations. No action required.
- Findings Dashboard sidebar row now shows "updated Ns ago" once live diagnostics have changed at least once this session, so a stale-looking count can be told apart from a genuinely fresh one at a glance. The freshness timestamp now only updates for
.dartfile diagnostics, not unrelated file types, and the row's icon switches from a warning triangle to a clock once the timestamp is over an hour old, so an aging count no longer reads as an up-to-date warning. No action required.
Improved (Extension) #
- Full Audit is now a "Source" scope selector inside the Findings Dashboard toolbar (Live diagnostics / Full project / Changed vs main / Changed vs branch) instead of a separate sidebar entry that opened a VS Code quick-pick menu and a second report panel. Progress and results render in the same dashboard you already have open, the chosen scope is remembered across sessions, and a legacy
saropa_lintsversion's audit output normalizes to the current severity vocabulary the same way the batch report already did. - Audit report: severity is now color-coded — error rows get a red left border, warning rows amber, and severity pills/chips use tinted text for quick scanning.
- Audit report: all counts use thousands separators (e.g. 151,919 instead of 151919) for readability.
- Audit report: filter chip counts use a consistent badge style instead of bare parenthesized numbers.
- Audit report: removed the duplicate read-only KPI chip strip — the interactive filter chips already show the same counts.
- Audit report: the 500-row page limit now applies after filtering, not before. The pagination note clarifies this.
- Audit report: added "Export JSON" button that saves the full diagnostics to a user-chosen file.
- Audit report: file paths are visually clickable (link color + underline on hover) and now jump to the diagnostic line instead of just opening the file.
- Audit report: rule names are clickable — clicking one filters the table to show only findings for that rule, with a dismissible banner.
- Audit report: when errors or warnings exist, INFO findings are hidden by default so actionable findings are immediately visible. Click the INFO chip to show them.
- Audit report: a severity summary bar below the header shows the error/warning/info ratio as colored segments with tooltips. No action required.
- Audit report: clicking a file path now jumps to the exact column, not just the line. No action required.
Internal #
- Sidebar data is now computed once per refresh cycle (
prepareRefreshCycle) instead of being cleared and rebuilt by each provider independently. Eliminates redundantreadVisibleLiveViolations+computeLiveHealthScorecalls when multiple sidebar sections refresh together. - Fixed i18n audit (
--mode audit) probing Ollama engine availability vialow_quality_entries(), which self-provisioned the daemon and pulled the model — an expensive, risky side effect during a read-only coverage check. Audit now usesaudit_only=Trueto scan cache provenance tags without any subprocess calls. No action required. - Fixed
dart pub publish --force(local fallback) printing its full file-tree listing to stdout, flooding the terminal and pushing prior publish-step output out of the scrollback buffer. Output is now captured; only the pub.dev confirmation line is surfaced. No action required. - Added manual translations to
dictionaries.pyfor 5 gaps across 4 locales (ar, de, fil, pt) that MT engines did not translate: RSS warning description, "Dev Tool Budget", "Set Cap", "Translation Engine (Ollama)". No action required. - Added
COGNATESapproval list todictionaries.pyfor words that are spelled identically in specific target languages (e.g. "Source" in French). Previously each cognate needed a per-locale"X": "X"passthrough scattered across the file; the centralized list merges them at import time, with locale-code validation (typos raiseValueError), empty/duplicate-locale guards, drift detection (--fail-on-drift), and a--check-cognatesflag (now in the publish pipeline) that catches conflicts and DO_NOT_TRANSLATE redundancies. No action required.
16.0.0-beta.8 #
🌍 Milestone: 25 languages, 2,319 translated fields — extension ships in 25 locales (Arabic, Bengali, Chinese, Dutch, English, Farsi, Filipino, French, German, Hebrew, Hindi, Indonesian, Italian, Japanese, Korean, Polish, Portuguese, Russian, Spanish, Swahili, Thai, Turkish, Ukrainian, Urdu, Vietnamese).
Fixed a sidebar action that could crash on a project's first scan or run twice on rapid clicks, and shortened several sidebar labels. System Health now monitors the whole machine — not just saropa_lints' own processes — with proactive warnings and one-click fixes. log
Added (Extension) #
- Machine-wide health monitoring: system RAM, every Dart analysis server, Flutter daemon, and Ollama/llama-server process grouped by category with contextual recommendations and one-click actions (restart server, set heap cap, reclaim orphans, unload model). Accessible from the sidebar and command palette. No action required.
- Dev Tool Budget indicator: a single percentage showing how much of the machine's RAM dev tools consume versus a configurable target (
saropaLints.systemHealth.devToolBudgetPercent, default 60%). Warns when dev tools exceed the budget. No action required. - Proactive warnings when free RAM drops below a configurable threshold (
saropaLints.systemHealth.systemMemoryWarningPercent, default 15%) or any single analysis server exceeds a configurable size (saropaLints.systemHealth.analysisServerWarningGB, default 4 GB), plus a one-time session-start check. System-wide free RAM now appears in the status bar tooltip. No action required.
Fixed (Extension) #
- Fixed "Fix stale ignores" sidebar action crashing with ENOENT when the
reports/.saropa_lints/directory does not yet exist (e.g. first run on a project). The directory is now created before the scan CLI writes its JSON output. No action required. - Fixed all stale-ignore commands allowing concurrent execution when double-clicked or triggered in rapid succession, which could launch duplicate CLI processes. A busy guard now shows a brief status-bar message and drops the duplicate click. No action required.
Changed (Extension) #
- Shortened sidebar action labels: "Fix stale ignores" → "Prune ignores", "Initialize / Update config" → "Update config". Descriptions now carry the detail the labels shed. No action required.
Internal #
- Extracted
createBusyGuardtocommandGuards.tsas a reusable concurrency guard with visible status-bar feedback, replacing four identical inline busy-flag patterns in the stale-ignore commands. No action required. - Routed the three sidebar Actions labels ("Run analysis", "Prune ignores", "Update config") through
l10n()with newsidebar.actions.*keys inen.json, closing an i18n gap where two of the three labels were hardcoded English. No action required. - Hardened Machine Health dashboard: Windows-only platform guard with localized message, narrow viewport wrapping/scrolling, two-tier query/notification throttle (2 min / 10 min) to reduce unnecessary PowerShell shell-outs, undefined-arg guard on Unload Ollama Model command. No action required.
- System memory warning now honors the user's configured threshold directly instead of silently clamping to a 20% minimum at session start. No action required.
16.0.0-beta.7 #
Process Health now tracks only saropa-owned memory, so other VS Code windows no longer trigger false alerts. The tooltip adds a trend arrow, sparkline chart, and early leak detection. Also fixes the dashboard's "Enable all recommended packs" button showing stale results. log
Added #
- New rule
add_resolution_workspace(recommended tier, WARNING): flags a package listed in a Dart pub workspace that is missingresolution: workspacein its pubspec.yaml, catching version drift beforepub getfails. Quick fix inserts the key after theenvironment:block. No action required. - New rule
flag_missing_workspace_member(recommended tier, INFO): flags a workspace root whose subdirectories contain pubspec.yaml files not listed in theworkspace:list, catching packages that silently resolve independently instead of joining the shared lockfile. Scans up to 3 levels deep, skips listed members' children (no example/ false positives). No action required. - New rule
workspace_dependency_version_sync(recommended tier, INFO): flags a workspace whose member packages declare different version constraints for the same dependency, catching version drift that produces misleading pubspecs since all members share one lockfile. No action required. - New rule
workspace_member_order(recommended tier, INFO): flags a workspace root whoseworkspace:list entries are not in alphabetical order, making large workspaces easier to scan and reducing merge conflicts from unordered insertions. No action required. - New rule
prefer_publish_to_none(recommended tier, INFO): flags a pubspec.yaml that has nopublish_tofield and appears to be an application (missing homepage/repository metadata), guarding against accidentaldart pub publishto pub.dev. Quick fix insertspublish_to: noneafterdescription:(or aftername:if there is no description). No action required. - New rule
avoid_dependency_overrides(recommended tier, WARNING): flags any non-emptydependency_overrides:section in pubspec.yaml, which silently diverges the resolved dependency graph from declared constraints and masks real conflicts. No action required. - New rule
prefer_pinned_version_syntax(stylistic tier, INFO): flags caret-range version constraints (^X.Y.Z) in app pubspecs (publish_to: none), suggesting exact pins for reproducible builds. Conflicting pair withprefer_caret_constraint_in_app— opt-in only. No action required. - Process Health tooltip now shows an RSS trend arrow (↑ rising / → stable / ↓ falling) next to the saropa section header. A rising trend is an early memory-leak warning before the red threshold trips. Based on a 5-sample split-mean with a 10% change threshold. No action required.
- Process Health tooltip includes a Unicode sparkline chart (▁▂▃▄▅▆▇█) showing saropa RSS over the last ~30 minutes. Gives a visual memory profile at a glance without opening a panel. No action required.
- Process Health now detects monotonically rising RSS and shows a one-time "possible memory leak" notification before the red threshold trips. Based on 8/10 consecutive non-decreasing comparisons, tolerating brief GC dips. No action required.
Fixed #
- Fixed Process Health status bar falsely attributing system-wide Dart memory to saropa_lints. The red/yellow thresholds now evaluate saropa-owned process RSS only (scan daemon, CLI scans), not the aggregate of all Dart processes. A 12GB analysis server from another VS Code window no longer makes the saropa_lints indicator go red.
- Process Health tooltip now shows a per-process breakdown: saropa-owned processes first (with health check), Flutter daemons, then other Dart processes as informational. Top 3 processes per category listed by RSS. Hints when multiple analysis servers are detected.
- Fixed "Enable all recommended packs" button showing "no applicable rule packs detected" while the dashboard table correctly showed 87 detected packs. The button now uses
getDetectedPackIds, a shared helper that both the table and the button call, so the two surfaces can never diverge. No action required.
Internal #
- Hardened
add_resolution_workspacequick fix: re-verifiesresolution: workspaceabsence before inserting (guards against stale diagnostics and batch "fix all" duplicates), added trailing-newline guard when inserting after the environment block, and tolerates blank lines inside the environment block. The detection regex now also accepts quoted forms ("workspace"/'workspace'). - Hardened
flag_missing_workspace_memberscan: deduplicated path-normalization logic into a shared public helper, extended case-insensitive path comparison to macOS (default APFS), and made thebuild/directory skip case-insensitive. - Extracted
findDivergentDependencyConstraintsfromworkspace_dependency_version_syncinto the pubspec constraint parser, creating a pure-function seam for unit testing and removing an unreachable block-dep guard that the parser already handles. - Hardened Process Health tooltip: process labels truncated at 30 chars for width safety, analysis server detection broadened with
--protocol=lspfor future binary rename resilience, ✓/↑ conflict resolved (rising trend suppresses the healthy checkmark to avoid mixed signals), and partition assertion added to catch filter coupling drift. - Expanded RSS history ring buffer from 5 to 30 samples for sparkline rendering while preserving trend computation on the most recent 5.
- Added monotonic growth detector as a pure function with 8/10 threshold — fires a one-time informational toast directing the user to the health panel.
- Hardened sparkline renderer to use reduce loops instead of spread for stack safety, and ProcessMonitor returns a defensive copy of the RSS history buffer.
- Added
classifyProcess()as a discriminated union (ProcessCategory+ label) replacing the duplicated predicate chains across tooltip, snapshot, and label functions. Boolean predicates (isSaropaProcess,isDaemonProcess,isAnalysisServerProcess) now delegate to it, and the tooltip builder uses a single-pass partition instead of three independent filter passes with a runtime assertion. - Fixed leak detection "Open Health Panel" button silently no-oping because it called unregistered command
showHealthPanelinstead of the registeredshowProcessHealth. - Added 45 tests total in the systemHealth suite (90 passing):
classifyProcessdiscriminated union (8), process partition mutual exclusivity (3), marker substring containment invariant (1), plus the existingprocessLabel(9),isAnalysisServerProcess(4),truncateLabel(5), RSS trend boundary (2),renderSparkline(6),detectMonotonicGrowth(7). - Extracted
getDetectedPackIdsinrulePackDefinitions.tsas the single source of truth for pack applicability. The dashboard table and "Enable all" button both call it instead of inliningisPackDetectedfilters independently. - Replaced the collapsed HTML Maintenance expander changelog convention with a
### Internalheading, enforced by a pre-commit hook and a publish-time gate. No action required.
16.0.0-beta.6 #
Fixes a false positive in the l10n diagnostic provider and catches more CI-only test failures locally before publishing. log
Fixed #
- Fixed the l10n diagnostic provider (
saropa-l10n) reporting false-positive "expects params but none passed" warnings whenl10n()receives its params via a variable or expression instead of an inline object literal. The parser now recognizes non-literal second arguments and skips static key extraction for them. No action required. - Fixed the l10n diagnostic silently accepting
l10n('key', undefined)andl10n('key', null)without warning when the template expects params. These keyword arguments are now correctly treated as "no params passed." No action required.
Internal #
- Introduced a branded
OpaqueParamstype for the l10n parser sentinel, preventing accidental use of the sentinel string in key-extraction functions at compile time. - Extracted
extractBalancedBraceas a shared export froml10nParsers.ts, deduplicating the brace-matching loop previously inlined inextractParamsBlock. - Added missing
usesTypeResolutionoverride toAvoidCaseSensitivePathComparisonRule(usesstaticType). - Added 4 missing codes to the
flutter_skill_lintsmigration pack that moved from TODO/PARTIAL to HAVE. - Publish script:
create_git_tagnow prompts before moving a stale remote tag to HEAD on retry instead of hard-failing. - Publish script:
_find_workflow_runskips already-failed runs so retry doesn't re-attach to old workflows. - Publish script: delta test pass now includes integrity and config test suites when rule/config files change, catching cross-cutting failures locally instead of deferring to CI.
16.0.0-beta.5 #
Hardens memory safety and scan reliability across the extension and CLI. Memory pressure detection now attributes usage correctly, preventing false pauses on large projects, and a stalled scan on save can no longer disable the feature for the session. Also fixes false positives in timer-lifecycle and manifest rules, and adds orphaned-process detection at startup. log
Added #
- Memory debug mode: set
SAROPA_LINTS_DEBUG_MEMORY=1to log per-cache size breakdowns on every periodic memory trend line. Helps diagnose which plugin caches are growing when investigating memory pressure. No action required. - Orphaned process check: finds model host and Dart processes left behind by earlier sessions, reports how much memory they hold, and offers to reclaim them after you confirm. Runs once shortly after startup and is also available from the Process Health panel and the command palette. No action required.
- New
saropaLints.scanOnSave.timeoutSecondssetting (default 180, range 30 to 1800) caps how long a single scan on save may run before it is abandoned. Raise it on very large projects if scans are cut short. No action required. - Diagnostic triage script:
python scripts/triage_scan.pypost-processes--format jsonscan output into five priority buckets (errors → bulk fixes → individual triage → dev code → forked code), replacing manual categorization of bulk lint sweeps. Supports--suppress-dirs,--dev-dirs,--bulk-threshold, and--format jsonfor machine-readable output. No action required.
Fixed #
- Fixed stale diagnostics persisting in the Problems panel after adding
// ignore:directives or fixing code. The scan CLI now honors// ignore:and// ignore_for_file:directives, and "Restart Analysis Server" now also clears scan-on-save diagnostics and rescans open editors. No action required. - Fixed hard RSS valve pausing all rules based on the analysis server's total process memory instead of the plugin's own contribution. On large projects the server's AST caches and resolved element model consume 70–90% of RSS, tripping the valve even when the plugin's estimated footprint is under 100 MB. The valve now checks plugin attribution: it only pauses rules when the plugin's estimated memory exceeds 100 MB or 5% of process RSS. A separate unconditional panic threshold at 90% of system RAM provides last-resort OOM protection. No action required.
- Fixed the Drift Advisor integration opening every Dart file in the workspace on each 30-second poll, which could cascade into repeated whole-project scans and exhaust system memory until VS Code crashed. Table lookups now read files directly without creating editor documents, and results are cached until Dart sources change. No action required; the integration is off by default, so only users who enabled it were affected.
- Fixed scan on save treating a file opened by other extension code as a file the user opened, which let any extension's background file access trigger lint scans. Scans now run only for files you actually have open or have saved. No action required.
- Fixed a stalled scan permanently disabling scan on save for the rest of the session. Scans now time out, are canceled when a newer save supersedes them, and release their slot on every failure path. No action required.
- Fixed the memory status bar showing a red critical badge next to a healthy memory figure when the real trigger was orphaned background processes. The badge now names whichever condition actually tripped, and a memory reading shows the same total the warning threshold is compared against. No action required.
- Fixed every level of memory pressure painting the status bar error red, including informational ones such as a light rule shed. Only genuinely severe states are red now, with moderate states amber and informational states left uncolored. No action required.
- Fixed a Dart file open only as one side of a diff or merge view never receiving scan on save diagnostics, because only ordinary tabs were recognized. No action required.
- Fixed a canceled scan leaving an orphaned Dart process on macOS and Linux, and a failure to launch the process cleanup command being able to crash the extension host. No action required.
- Fixed the memory status bar showing plugin state that was no longer live, so a project with the analyzer plugin switched off could still display paused rules and a large memory figure from an earlier session. Nothing is shown now unless the plugin is enrolled and the reading is from the current session. No action required.
- Fixed the memory safety valve never resuming rules after it paused them. Clearing the plugin's own caches made it a minor memory contributor, but release was tested against total process memory, which the analysis server keeps high, so rules stayed paused indefinitely. No action required.
- Fixed the memory valve repeatedly re-measuring every cache while the analysis server sat above the memory cap, which made the common case the most expensive one. No action required.
- Fixed the translation tooling abandoning multi-gigabyte model host processes on every run, by terminating whole process trees rather than a parent alone, sweeping for survivors, and refusing to start when abandoned processes are already present. No action required.
- Fixed
require_copy_with_null_handlingfiring oncopyWithmethods where all fields using??are non-nullable types. The sentinel/wrapper pattern adds no value when a field cannot be null, so??is the correct pattern. The rule now checks class field nullability before emitting. No action required. - Fixed
require_permission_manifest_androidasserting a missing manifest entry when it cannot read AndroidManifest.xml. Downgraded to INFO severity since the rule is advisory only. No action required. - Fixed
require_url_launcher_queries_androidasserting missing<queries>blocks when it cannot read AndroidManifest.xml. Downgraded to INFO severity since the rule is advisory only. No action required. - Fixed
require_workmanager_for_backgroundfiring onTimer.periodicinsideStatesubclasses with propercancel()indispose(). UI-lifecycle timers are not background tasks. No action required. - Extended
require_workmanager_for_backgroundto also detectStream.periodic— the same background-polling anti-pattern using the stream API. No action required. - Fixed
avoid_ios_battery_drain_patternsfiring onTimer.periodicinsideStatesubclasses with propercancel()indispose(). Widget-bound timers cannot drain battery in the background. No action required.
Internal #
- Triage script (
scripts/triage_scan.py): added diagnostic-key validation (warns whenfilePath/severity/ruleNameare missing), and a 29-test unit-test suite covering path classification, bucket assignment, and output formatting. No action required. - Changelog guard hook (
scripts/hooks/changelog_guard.py): removed thepackage.jsonversion-drift check that false-alarmed every beta cycle because VS Code uses a different version scheme. Guard 1 (multiple unreleased sections) still triggers onpackage.jsonedits. No action required. - Extracted shared
isTimerLifecycleBoundToDisposableState()helper to eliminate duplicate private implementations across timer lifecycle rules. No action required.
16.0.0-beta.4 #
Adds five new lint rules covering unsafe late-final fields, constructor and widget ordering, and Equatable prop sorting. Extends the dashboards with inline rule guidance, embedded Package Dashboard tabs, live sidebar data, and scan progress in Health Panel and Project Map. Also fixes several false-positive and over-suppression bugs in existing rules. log
Added #
- New rule
avoid_public_late_final_without_initializer: flags publiclate finalfields with no initializer — a runtime crash waiting to happen if any caller reads the field before it is assigned. No action required. - New rule
avoid_unnecessary_factory_constructor: flagsfactoryconstructors whose body just returnsClassName(...)— a factory keyword adds indirection with no benefit when the constructor could be a regular named or unnamed constructor. No action required. - New rule
no_internal_method_docs: flags DartDoc comments on private methods in non-library code — internal-only methods rarely benefit from doc comments and the noise makes public API docs harder to find. No action required. - New rule
prefer_state_class_below_widget: flags aState<X>class declared above itsStatefulWidget X— the conventional Flutter ordering places the widget's public API first. Closes the DCMkeep-state-below-its-widgetgap. No action required. - New rule
prefer_sorted_equatable_props: flags an Equatablepropsgetter whose field order doesn't match the class's field declaration order — props that drift out of declaration order are harder to audit for missing fields. Closes the DCMsort-equatable-propsgap. No action required. - Findings dashboard: the top-rules expander now shows each rule's how-to-fix guidance, OWASP mapping, related rules, and supersedes/migration notes inline, instead of requiring a jump to the separate Rule Explain screen. This detail is now also available during live analysis, not only after a batch export. No action required.
- Package Dashboard: the Upgrades, Full report, and Known issues tabs now render their content inline instead of opening a separate editor tab. Compare still opens as its own panel. No action required.
- Analysis Optimizer (embedded in the Lints Config dashboard): sortable columns and a working select-all, matching the standalone panel. Sort choice is remembered per dashboard. No action required.
- Project Map: a live percentage progress bar with a file count during scanning, plus pause and cancel, and a Files / Lines / Size summary in the header. Older engines without progress support fall back to the previous elapsed-time view. No action required.
- Project Map reports: the severity and doctor reports now render as sortable typed tables rather than preformatted text, via a new
--format jsonmode on both command-line tools. No action required. - Health Panel: engine cards now show live scan progress ("Scan: N/M files") while the language server is scanning a workspace. No action required.
- Lints Config, Config file tab: a "Migrate config keys" action now appears there when legacy plugin-block keys remain, replacing the sidebar row that previously carried it. No action required.
- Findings dashboard status line and the sidebar's Code Health row now show quality-gate state. A failing gate previously appeared only inside the Code Health screen, so it was invisible unless you went looking for it. No action required.
- Sidebar Code Health and Project Map rows now show live data — health grade and score, and how long ago the project was last scanned — instead of fixed descriptive text. Both read already-computed results and never start a scan. No action required.
- Scan CLI:
--no-excludeflag disables all hardcoded path exclusions (example/,build/,.dart_tool/, etc.) so the scan covers every.dartfile it finds. User-supplied--exclude-globsstill apply. No action required. - LSP Server: new
saropaLints.lspServer.workspaceScanDelaysetting (default 5 seconds) defers the workspace scan after the analyzer is ready, letting VS Code's startup burst settle first. Set to 0 for immediate scan. No action required.
Changed #
-
require_test_description_conventionnow recognizes 23 additional action verbs as good description indicators and uses word-boundary matching to prevent false negatives on substring matches (e.g. "maps" no longer matches inside "hashmaps"). No action required. -
require_test_description_conventionquick fix now handles interpolated test descriptions — previously it silently skipped them because the full string value was null. No action required. -
prefer_state_class_below_widgetnow detects third-party widget/state pairs — Riverpod'sConsumerStatefulWidget/ConsumerStateand flutter_hooks'HookStatefulWidget/HookState— in addition to core Flutter'sStatefulWidget/State. No action required. -
Renamed engine names throughout the extension: "Analyzer Plugin" → "Live Analysis", "Scan Daemon" → "Scan on Save" in the Health Panel; "Turn Off Lint Integration" → "Disable Saropa Lints" and "Re-enable In-Process Plugin" → "Re-enable Live Analysis" in the command catalog. Updated notification strings that referenced "Lint integration" to say "Scan on save". No action required.
-
Sidebar restructured into three sections totalling 14 rows: Dashboards, Status, and Actions. Rows that open a screen, rows that report state, and rows that run something are now separated, so a row's section tells you what clicking it will do. No setting is flipped from the sidebar any more. No action required.
-
Package Dashboard now uses the shared dashboard chrome for page spacing and typography. Body padding, base font size, and line height change slightly as a result; layout is otherwise unchanged.
-
The bundled rule catalog now carries correction text and OWASP mappings for every rule, so live analysis can show them without a batch export. This grows the packaged catalog by roughly 0.5 MB. No action required.
Fixed #
-
Fixed LSP Server flooding the output channel with
didClosemessages on startup — VS Code sends a burst of didClose notifications for files from the previous session; these are now trace-level and only visible with verbose logging. No action required. -
Fixed
avoid_string_substringfalse positives where the index was already guaranteed in bounds by a regexhasMatch()guard, anindexOf()/lastIndexOf()result, or aRegExpMatch's.start/.end/.group(). No action required. -
Fixed
avoid_case_sensitive_path_comparisonfalse positives on non-path string comparisons: CLI flag literals, Dart import URI comparisons, filesystem root-detection idioms (dir.path != dir.parent.path), and identifiers where "path" was embedded in an unrelated word (e.g. "pathology"). Also fixed import-URI suppression failing to detect camelCaseUrisegments (e.g.namedUri) because the boundary check ran on the lowercased name. No action required. -
Fixed
avoid_unsafe_castfalse positives onProcessResult.stdout/.stderrcast toString— the SDK default encoding always decodes toString, so the cast is only unsafe when the call explicitly passes anullencoding to request raw bytes. Also fixed a false positive when a cast is preceded by an exact-typeischeck on the same expression in an enclosingifcondition (e.g.if (v is List) { v as List }); only&&compounds are recognized as guards — anischeck inside||does not guarantee the type. No action required. -
Fixed
avoid_nullable_interpolationfalse positive when a!= nullguard for the interpolated expression is buried inside a compound&&condition (e.g.if (isChurning(f) && f.churn != null)), not just a bareif (expr != null). No action required. -
Fixed
avoid_stack_trace_in_productionfalse positives in developer-tool code:dart:developer'slog()is now recognized as a diagnostics API (never user-visible output) regardless of package type, and files under abin//tool/directory are skipped even in mixed packages that aren't wholly CLI tools. No action required. -
Fixed
require_url_validationfalse positive on localfile://path validation — the scheme-guard heuristic now also recognizes.isScheme('file')checks and thefilescheme, not just.schemereads againsthttps/http. No action required. -
Fixed
runtime_tierbeing silently ignored when set inanalysis_options_custom.yaml. The Config file tab writes this key, but the parser only ever recognizedsaropa_tier, so the chosen value was written to disk and then dropped with no warning. It is now recognized as a deprecated alias and reports a migration warning. Set the tier in theplugins: saropa_lints:block to have it take effect. -
Fixed the Health Panel reporting scan-on-save as "idle" while it was actually disabled — the status only tracked memory-pressure suspension and never read the master switch, so a disabled scanner looked healthy. No action required.
-
Fixed
--formatbeing swallowed as the target path by the severity report and doctor command-line tools, so the flag had no effect and the positional path was lost. No action required. -
Fixed selecting a package from the embedded Upgrades tab opening the detail pane behind a hidden tab; the dashboard now switches back to Overview first. No action required.
-
Fixed Package Dashboard's Full report and Upgrades embedded tabs showing "Generating…" forever on first open, and rendering stale data from the previous scan on subsequent opens. The async builders now read the current scan results instead of the not-yet-assigned options object. No action required.
-
Fixed Full report tab's "Expand/Collapse all" button toggling every
<details>element in the Package Dashboard (charts, package filters, grade breakdown in Overview), not just the Feature Inventory's own disclosures. The script is now IIFE-wrapped and scoped to its own tab container. No action required. -
Fixed the Health Panel engine card showing "scanning N/M files" indefinitely after a canceled workspace scan. The LSP server's scan progress notification now carries an explicit
doneflag on terminal ticks (cancel or completion), so the client no longer relies solely on the filesScanned/totalFiles ratio. No action required. -
Fixed severity report and doctor typed tables falling back to raw text on the first run after install or
pub get, because Dart's "Building package executable…" stderr banner was mixed into the JSON parse buffer. Only stdout is now accumulated for JSON parsing. No action required. -
Fixed Project Map progress bar never reaching 100% when the CLI's final progress event arrived without a trailing newline. The partial-line flush on process exit now routes through the progress parser instead of bypassing it. No action required.
-
Fixed
avoid_nullable_interpolationfalse positive onMatch[n]andMatch.group(n)in string interpolations — when the regex pattern literal is visible, a group-count parser now verifies the accessed index refers to a required capture group; the parser now also traces through variable assignments (final re = RegExp(r'...'); re.firstMatch(...)) and correctly handles groups containing alternation (e.g.(a|b)is always required). No action required. -
Fixed
avoid_dynamic_calls_extendedover-suppression: dynamic calls inside catch clauses and finally blocks are no longer wrongly exempted by the try/catch guard (only the try body is exempted). Barecatch(e)andon Objectno longer suppress dynamic-call warnings — onlyon NoSuchMethodErrorandon TypeErrorindicate intentional duck-typing. No action required. -
Fixed
require_catch_loggingover-suppression:catch (e) { return null; }with an unused exception variable was falsely exempt — the return/continue/break exemption now fires only when the exception variable is actually referenced. No action required. -
Fixed
require_url_validationover-suppression: substring'file'no longer matches inside identifiers likeprofileId;startsWithguards are now checked against the actual URL variable; CLI exemption is scoped to the file's directory rather than disabling the rule project-wide. No action required. -
Fixed
avoid_global_stateover-suppression:_hasClearOrResetFunctionnow matches exact identifier tokens instead of substrings;??=lazy-init detection uses a word-boundary regex instead of raw source text; multi-variable declarations no longer fire duplicate diagnostics. No action required. -
Fixed
require_cache_expirationover-suppression:.clear()detection is now scoped to the flagged cache class's own Map fields rather than matching any.clear()in the file;HashMap/hashCodeare no longer treated as crypto-hash indicators. No action required. -
Fixed
avoid_string_substringover-suppression:indexOfresults are recognized as safe index sources alongsideRegExpMatch.start/.end/.group(); a regexhasMatch()guard on the receiver is now accepted inif-condition and ternary branches. No action required. -
Fixed
avoid_case_sensitive_path_comparisonover-suppression: the root-detection idiom check now verifies both sides of a||share the same base expression. No action required. -
Fixed
require_test_description_conventionfalse positives on data-driven test descriptions built with string interpolation (e.g.test('${'$'}{c.rule} should ...', ...)) — the rule readstringValue, which is always null for a non-constant string, so every interpolated description was flagged regardless of its actual wording. It now reads the literal text segments instead. No action required.
Internal #
-
Archived 36 tier-1 quick-win proposals already covered by existing rules — 19 implemented under the same name, 8 under a different name or alias, and 9 identified as functional duplicates of rules shipped in prior versions. Updated 15 migration guides to reflect the closures (TODO → HAVE with correct saropa rule name). No action required.
-
Added fixture coverage for
require_ios_deployment_target_consistency's collection-literal guard — GOOD cases with a rule-name string inside aSetand as aMapvalue, confirmingisDataLiteralElement()(shipped in beta.3) already prevents the false positive reported in a duplicate bug report. No action required. -
Added GOOD fixture cases for
require_catch_loggingandavoid_swallowing_exceptionscovering fallback-return, loop-continue, and loop-break catch bodies, confirming the return/continue/break handling guard closes the intentional-fallback false positive reported against both rules. No action required. -
Fixed 12 false-positive rule implementations:
avoid_unsafe_reducenow skips non-empty list/set literals;avoid_accessing_collections_by_constant_indexnow skips write targets (DP row init);require_catch_loggingandavoid_swallowing_exceptionsnow accept return/continue/break as valid handling;avoid_dynamic_calls_extendednow exempts Object methods and try/catch-guarded duck-typing;avoid_unsafe_castnow recognizes precedingischecks;avoid_global_statenow exempts lazy-init (??=) and managed-lifecycle globals;avoid_case_sensitive_path_comparisonnow skips root-detection idioms and CLI flag literals;avoid_platform_specific_imports,avoid_stack_trace_in_production,require_cache_expiration,avoid_unbounded_cache_growth, andrequire_url_validationnow skip CLI tool and analyzer plugin packages via newProjectContext.isCliOrToolPackage(). No action required. -
Extended
avoid_global_state's managed-lifecycle exemption to also recognize a same-filedispose*function (previously onlyclear*/reset*), and confirmedlate finalglobals were already exempt via the existing const/final skip. No action required. -
Fixed
avoid_unnecessary_factory_constructorcompile error against analyzer 12.x — used removedClassDeclaration.namegetter instead ofnameToken, causing the LSP server to crash on startup (exit 255). -
Fixed unsafe
as Map<String, dynamic>cast inaudit_baseline.dart—jsonDecodeon a valid-but-non-object baseline file (e.g.[]) threwTypeErrorinstead of returningnullper the documented contract. Replaced withis!type check. -
Fixed 6 broken
// ignore:comments missing thesaropa_lints/prefix — suppressions inproject_context.dart,pubspec_constraint_parser.dart(3),project_context_parallel_batch.dart, andproject_vibrancy_resolved_usage.dartwere silently ineffective. -
Fixed case-sensitive path comparison in
project_vibrancy.dart—--fileCLI argument now compared withp.equals()for Windows/macOS compatibility. -
Fixed nullable interpolation in
health_export_markdown.dart—churnfield interpolated without null guard, producing "null commits" in markdown export. -
Fixed forward-slash path construction in
log_writer.dart(2 sites) andinit_runner.dart— replaced string interpolation withp.join()/p.basename()for cross-platform correctness. -
Filed 13 false-positive bug reports across 13 rules against own-dogfood scan findings (305 total, 295 confirmed FP). See
bugs/for details. -
Fixed
commandCatalogRegistry.test.tsfailures: added 17 missing catalog entries for commands that existed inpackage.jsonbut had no catalog registration, and marked 15 palette-hidden commands asinternal. All 17 catalog sync tests now pass. -
Fixed remaining
require_cache_expiration/avoid_unbounded_cache_growthfalse positives on content-addressed caches: both rules now skip classes keyed by hash/sha/fingerprint/digest (a stale entry under an unchanged key is structurally impossible), skip files under abin//tool/directory in addition to the existing whole-package check, and skip caches with an explicit.clear()call anywhere in the same file. No action required. -
Partially migrated the Package Dashboard's parallel stylesheet onto the shared dashboard chrome: the accessibility helper, hero header, status line, and page layout families now come from the shared layer. The remaining duplicated families cannot be adopted piecemeal because the shared chrome's exported functions bundle unrelated rules — adopting the motion helper would also restyle inline code, and adopting the layout helper drags a full body reset with it. Splitting the chrome into single-concern exports is a prerequisite for finishing this.
-
Reworked the embedded Known issues tab to prefix element ids and scope its script, preventing collisions with the host dashboard's own search and table when both render in one document.
-
Added regression coverage for the areas above: the scan progress event schema and cancel path, the language server's progress notification shape, the rule-catalog correction/OWASP backfill, the report totals parser, the optimizer sort and bulk-select, the rule-detail expander, and the embedded tab contracts.
-
Added CI compile-check gate (
dart compile kernel) for allbin/entry points — catches build-breaking analyzer API changes thatdart analyzemisses because rule files are loaded at runtime. -
Added CI
check_analyzer_api_compat.pyscript that greps rule files for known-removed analyzer package APIs (e.g.ClassDeclaration.name.lexeme) before they reach users as a crash. -
Extracted shared
catchHandlesViaControlFlow()andcatchBodyUsesException()utilities intocatch_body_logging_utils.dart— eliminates duplicated return/continue/break and exception-usage checks betweenrequire_catch_loggingandavoid_swallowing_exceptions. No action required. -
Split the shared dashboard chrome stylesheet into single-concern exports, with the existing public functions preserved as compositions so every consumer renders identically. The previous bundling made the layer un-adoptable piecemeal: taking the hero animation also took an unrelated monospace rule, and taking the full-width toggle dragged a whole body reset with it. A unit test now pins each composition.
-
Removed a duplicate
.sr-onlyaccessibility rule from the token layer after confirming every consumer already pairs it with the accessibility helper; the test suite now pins that rule as defined exactly once. -
Fixed 9 self-dogfood lint warnings in test files: 3
avoid_misused_test_matchers(rawtrue/false→isTrue/isFalse), 5require_test_description_convention(added "should" keyword to interpolated test descriptions), and 1prefer_setup_teardown(hoisted repeated_violationsForExample()call intosetUpAll). -
Adopted the shared hero animation and reduced-motion rules in the Package Dashboard stylesheet. The summary cards, table toolbar, and footprint toggle stay local by decision, not omission — each differs from its chrome counterpart in layout semantics, domain color vocabulary, or ARIA interaction model, and the reasons are documented in the code. See
plans/PLAN_ext_ui_report_styles.mdfor the full disposition. -
Fixed 2 stale curated dictionary keys in
dictionaries.py: removed thedeentry whose English source text was rewritten (daemon label, LSP/plugin separation), and capitalized thefil"Analyzer Plugin" key to match the current source strings. Patched 48 missing translations across 21 locales — 4 format/loanword strings added toDO_NOT_TRANSLATE, 15 locale-specific entries hand-translated. Added--strict-dntflag togenerate_locales.py— treatsDO_NOT_TRANSLATEcollision warnings as errors for CI gating. -
Added "Make member public (remove underscore)" quick fix for
no_internal_method_docs— strips the leading_from the declaration name as an alternative to the existing "Convert to a regular comment" fix. -
Added fixture files for
no_internal_method_docs,prefer_state_class_below_widget, andprefer_sorted_equatable_props. Extendedavoid_public_late_final_without_initializerfixture with static and multi-variable edge cases. -
Added
DeprecatedNewInCommentReferenceRuleinstantiation test to the documentation rules test suite. -
Fixed scan CLI silently excluding
example_packages/fixtures: the hardcoded/examplesubstring inscan_runner.dartmatchedexample_packages/, the--filesflag applied exclusions to explicitly named files, andshouldSkipFile's fixture-skip exemption missed relative paths andexample_packages/. Three-part fix: tightened the substring to/example/, bypassed exclusions when--filesis explicitly provided, and addedstartsWithchecks for relative paths. -
Fixed three CodeQL
js/bad-tag-filteralerts (two reported, one preemptive) in test infrastructure — closing-tag regexes now tolerate attributes and case variants. No action required. -
Added
check_html_tag_regex.pyCI script that detects HTML tag regexes missing case-insensitive flags or attribute-tolerant closing tags before CodeQL reports them on push. No action required. -
Moved
require_test_description_conventionfixture fromexample/lib/testing_best_practices/(whereisTestPathnever matched, so theFileType.test-gated rule silently never ran) toexample/lib/test/with real BAD/GOOD examples covering simple strings and interpolated descriptions. Added toexpectedFromFixturesin the integration test. -
Added
check_fixture_filetype_match.pyCI script that audits all rules withapplicableFileTypes => {FileType.test}and verifies their fixture files live at paths matchingisTestPath()— wired into the publish pipeline as a blocking check viarun_pre_publish_audits(), and supports--fixto bulk-relocate misplaced fixtures viagit mv. No action required.
16.0.0-beta.3 #
Streamlines the extension sidebar by moving rows that duplicated dashboard controls onto the Findings and Rules & Tiers dashboards instead. Fixes path traversal vulnerabilities in the HTML reporter and package detection, plus false positives in the path-comparison rule and several iOS rules. Also fixes a startup crash on large workspaces and makes the in-editor scan progressive and cancelable. log
Changed #
- Sidebar collapsed from 25–39 rows to 13 steady-state (15 worst case). Severity toggles, setting-value rows (run-after-config/dependency, UI language, detected packages), and triage rows removed from the Settings panel — each was a duplicate of a richer control on the Rules & Tiers Automation/Extension tabs, Package Dashboard, or Findings Dashboard's top-rules table. No action required.
- Sidebar Tier and Lane rows folded into the Dashboards "Lints Config" row description (
Tier: recommended · Lane: light), replacing two click-only rows with always-visible state. No action required. - Sidebar "Migrate config keys" row now appears only while legacy plugin-block keys remain to clean up, instead of rendering unconditionally. No action required.
- Findings dashboard status line gains trend, regression, and security-hotspot pills — the same data the sidebar Status rows showed, now persistent and clickable instead of buried in a collapsible panel. No action required.
- Sidebar Status section: Hotspots, Trends, Score regression, Suppression count, and Last-run rows removed — all now live on the Findings dashboard's status line or are straight duplicates of Findings data. Health row gains a "Last analysis: {ago}" tooltip. No action required.
- Sidebar Status panel now visible on all Dart projects, not just those with violations — Lint integration status was hidden exactly when it mattered most (integration off = no violations = panel gone). No action required.
Added #
- Quick fix for
avoid_misused_test_matchers— auto-rewritesexpect(x, true)→expect(x, isTrue),expect(x, false)→expect(x, isFalse),expect(x, null)→expect(x, isNull), andexpect(x.length, N)→expect(x, hasLength(N)). No action required. - Rules & Tiers Config file tab: Lane card. Switch between Light (~200 rules in-editor) and Full (all enabled rules) from the same dashboard that already shows every other
analysis_options_custom.yamlkey. No action required. - Config file tab: the Baseline card now shows a "Diff vs current" subsection listing violations resolved since the baseline and new since the baseline, each with a file/line/rule table. Reads live diagnostics — never triggers a scan and stays current as you edit. No action required.
- Live sidebar badges: the Status view's Activity Bar icon now carries a numeric badge (critical count when any exist, else total violations), and the Dashboards view carries a badge for packages with unadopted features. No action required.
- Rules & Tiers and Project Map dashboards now show a "?" button that opens a list of the tab-jump shortcuts already available (
1-7on Rules & Tiers,1/2on Project Map) — previously these shortcuts worked but had no in-app way to discover them.
Fixed #
- Fixed path traversal vulnerability in
cross_file reportHTML output —outputDirfrom--output-diris now normalized and rejected if it contains..segments. No action required. - Fixed
avoid_path_traversalindetectProjectPackages—targetDirparameter is now canonicalized before reachingFile(). No action required. - Fixed
avoid_case_sensitive_path_comparisonfalse positive on non-string comparisons — null checks, boolean/integer/double/enum guards on path-named variables no longer fire. No action required. - Fixed
require_ios_deployment_target_consistencyfalse positive on any string literal containing "async" — the rule's_ios15PlusApismap included a bare'async'entry intended to detect Swift concurrency, but it substring-matched every Dart string containing "async" (rule names, identifiers, comments). Removed the entry. No action required. - Hardened 6 iOS rules against false positives on collection-literal data tables — string literals inside list, set, or map literals (rule-name registries, route catalogs, path inventories) are now skipped by
AvoidIos13DeprecationsRule,AvoidIosSimulatorOnlyCodeRule,RequireIosMinimumVersionCheckRule,AvoidIosDeprecatedUikitRule,RequireIosDeploymentTargetConsistencyRule, andRequireIosCertificatePinningRule. No action required. - Sidebar Status panel no longer silently drops the Health row before any analysis has ever run — it now shows a "Health: —" row explaining why, with a one-click link to run analysis. No action required.
- Fixed LSP server crash on startup in large projects — the Dart VM exhausted its OS thread pool when the workspace scan called
lastModifiedSync/listSyncon hundreds of files. Replaced sync I/O with batched async equivalents (capped at 20 concurrent file operations) and added error handlers so failures exit cleanly instead of triggering an infinite restart loop. No action required. - LSP workspace scan is now progressive and cancelable — diagnostics publish incrementally as each file is analyzed, and the scan aborts cleanly on shutdown or config reload instead of racing to completion. Progress is logged every 50 files. No action required.
Internal #
- Fixed 15 pre-existing extension test failures: added missing
onDidChangeConfigurationmock (13 issuesTree tests), updated stale locale coverage assertions (languagePick), and updated sidebar panel count from 5 to 4 after Help view removal (uxLabels). No action required. - Updated stale path reference in the UI redesign plan after archiving completed sub-plans. No action required.
- Package Dashboard (Overview and Upgrades tabs): now pulls its color/spacing/radius design tokens from the same canonical token layer already used by the Settings and tab-bar surfaces, instead of only the legacy report stylesheet. No visible change — additive groundwork for retiring the older parallel styling system.
- l10n diagnostics now recognize
// l10n:passthroughon the same line as a suppress directive for calls whose{placeholders}are substituted by caller code (e.g.pluralize()) rather than byl10n()itself. Annotated all existingpluralize()+l10n()call sites. No action required. - Removed
transformProjectMapHtml()andwebviewThemeOverride()fromprojectMapView.ts— dead since the standalone Project Map panel switched to the composedprojectMapShell.tsdocument in Phase 6; their only remaining reference was a historical code comment. - Added unit test coverage for
projectMapShell.ts(shell tab structure, scanning-state pane, done-state pane) andprojectMapReports.ts(report-card catalog, Reports tab HTML, quality-gate config read/write, panel-message routing) — both had zero tests before this pass. - Fixed null-unsafe map access and direct
ascasts inasset_scanner.dart,health_cache.dart, andsaropa_lint_rule.dart— own-dogfood violations fromrequire_null_safe_json_accessandavoid_unsafe_cast. No action required. - Fixed 5 own-dogfood
avoid_misused_test_matchersviolations across 4 test files — replacedexpect(x.length, N)withexpect(x, hasLength(N)). No action required. - Extracted shared
sanitizePath()utility topath_guard.dart— centralizes the normalize-and-reject-traversal pattern so future CLI entry points get path safety automatically. No action required. - README rewritten for readability — cut from 1,598 lines to ~430. Extension detail moved to
doc/guides/extension.md, configuration reference todoc/guides/configuration.md, troubleshooting merged intodoc/troubleshooting.md, FAQ todoc/faq.md. Added alternative package coverage table (46 packages audited, ~75% rule coverage). Deleted redundantplans/GAP_ANALYSIS.md— per-package data lives in migration guides. - Suppressed own-dogfood false positives in
analyzer_compat.dart(dynamic dispatch, bare catches, swallowed exceptions are intentional version-probing shims) andscan_runner.dart(safe-by-construction cast). Fixed nullable interpolation inDiagnosticCodeLowerCaseCompat.lowerCaseName.
16.0.0-beta.2 #
Fixes the VS Code pre-release install button and removes a publish-time blocker that stalled builds. log
Changed #
- Sidebar: "Lint integration" is now one row in the Status section that toggles on a single click, instead of two separate copies of the same state in different panels. No action required.
- Sidebar: "Find stale ignores" and "Fix stale ignores" merged into one row that detects, shows the count, then asks to confirm before removing anything. No action required.
- Sidebar: Analysis Optimizer, Upgrade Opportunities, and the Feature Inventory export are no longer separate Dashboards rows — each is reachable as a tab inside Rules & Tiers or the Package Dashboard. Command Catalog moved next to Run analysis and Fix stale ignores. No action required.
- Sidebar: "Engines (LSP / Analyzer)" and "Process health" rows — announced in beta.1 — removed from the Settings panel. Engine toggles remain accessible from the Status section's Engines row (visible when debug mode is on), Health Panel, and Command Catalog. No action required.
Fixed #
- Fixed VS Code "Switch to Pre-Release Version" button failing with
net::ERR_FAILED— pre-release extension versions now use an odd minor number as VS Code requires. - Fixed status-bar click behavior: beta.1 stated clicking while lint integration is off opens the Dashboards view — it actually opens Findings in every state (
extension.ts:1310). The click target is intentionally Findings regardless of integration state. No action required. - Fixed CI watch blocking publish by defaulting to skip (press
yto opt in). - Fixed the status bar cramming memory/system-health warnings into the same text as the lint score, with no way to click through to the details — split into a second status bar item that only appears when there's something to report and opens the Process Health panel on click. No action required.
- Fixed the status bar's hover tooltip being read-only text with no way to act on it — it's now a clickable menu (toggle analysis on/off, jump to the Violations Report, Package Dashboard, Process Health, Command Catalog, or About). No action required.
Internal #
- Fixed publish script writing raw pub.dev version to
package.jsoninstead of the converted extension version — caused preflight version check to fail on every pre-release publish. - Hardened publish version verification:
_is_head_pushed()now handles detached HEAD and unreachable remote,_verify_versions_in_commitdocstring documents that it runs after HEAD is pushed (step 13 after step 12), andextension_version_for()idempotency contract is explicit. - Added
--dry-runmode toset_extension_version()— returns the converted extension version without touching the file, useful for preflight checks that need the expected version without side effects. - Extracted the status bar tooltip's action-menu rows (
buildStatusBarMenuItems) and its command allow-list (STATUS_BAR_TRUSTED_COMMANDS) intostatusBarLabel.ts, with a unit test asserting every row's command id is covered by the allow-list — a renamed or added command that falls out of sync would previously break the tooltip link with no test failure.
16.0.0-beta.1 #
--- IMPORTANT NOTE ---
Major release — LSP server (BETA). A new standalone LSP server replaces the in-process analyzer plugin as the default diagnostic engine, using far less memory while still providing diagnostics, quick fixes, and per-rule overrides. It's ON by default — check its status in the Health Panel. If you hit issues, toggle it off there to fall back to the Analyzer Plugin. log
Fixed #
- Auto-migrate legacy plugin-block config keys. Projects with
log_level,lane,memory_mode, orrule_packsunderplugins > saropa_lints:inanalysis_options.yamltriggeredunsupported_optionwarnings that were fatal under--fatal-warnings, breaking CI. The plugin now auto-migrates these keys toanalysis_options_custom.yamlat load time — no manual action required. - LSP server: fix 0 diagnostics on opened files. The CLI scanner's built-in path exclusions (which drop
example/,bin/, generated files) were silently filtering out files the user opened in the editor, producing 0 diagnostics. The LSP server now bypasses scan exclusions since the user explicitly requested analysis by opening the file, and falls back to therecommendedtier when the project has nosaropa_lints: tier:shorthand. - LSP server: fix didOpen flood. VS Code sends
textDocument/didOpenfor every Dart file in the workspace on activation (~200+ for real projects), each triggering a full rule scan. The server now debounces didOpen — only the last file opened within a 1.5-second window gets analyzed. The extension also filters didOpen to only forward files in visible editors. Save still triggers immediate analysis. - LSP server: message queue resilience. A malformed or unexpected JSON-RPC message could crash the async queue processor, silently dropping all subsequent messages. Each message is now handled in its own try-catch so one bad message doesn't stall the server.
- LSP server: Windows CRLF config parsing. The tier config reader failed to match
tier:whenanalysis_options.yamlhad Windows\r\nline endings with lines betweensaropa_lints:andtier:. Line endings are now normalized before parsing. - Debug panel: analyzer toggle restores extension setting. Toggling the Analyzer Plugin OFF correctly set
saropaLints.enabled = false, but toggling it back ON never restored the setting — the extension stayed disabled until manually re-enabled in VS Code settings. No action required. avoid_platform_channel_on_web: false positive with early-return guards. The rule fired onMethodChannel(...)even when preceded byif (kIsWeb) return;orif (kIsWeb) throw ...;, because it only recognized platform checks that wrapped the node as an ancestor, not preceding sibling guard statements. No action required.no_direct_iterable_access: fixed off-by-one false negative and hardened guard detection.index <= list.lengthwas wrongly accepted as a sufficient bounds guard even thoughindex == list.lengthstill throws; only<is now accepted. The rule also now recognizes the early-return guard-clause idiom (if (index >= list.length) return;),else-branch guards, reversed comparisons (list.length > index),RangeError.checkValidIndex(index, list), collection-forelements, and typed-data lists (Uint8Listand friends), closing several false-positive/false-negative gaps in the initial implementation. No action required.- Dashboard contrast and a11y fixes. A new visual-regression pass (rendering Home, Rules & Tiers, and Project Map through the extension's Playwright a11y harness for the first time) found and fixed real WCAG AA contrast failures: the red "Cancel" button, table column headers, the Rules & Tiers tier picker, and the Home hub's "needs attention" KPI tiles all read below the 4.5:1 contrast floor in at least one theme. Also fixed a missing accessible name on the Config file tab's severity-level dropdown, a missing document language attribute on the Rules & Tiers dashboard, and a narrow-window layout bug where the tier picker's pill buttons could push the whole dashboard into horizontal scroll. No action required.
- Full Audit report contrast fixes. Migrating the Full Audit report onto the shared dashboard chrome (below) gave it its first-ever visual-regression pass, which caught severity badges and KPI chips rendering colored text/fills as low as 2.93:1 contrast — now fixed to clear the 4.5:1 AA floor in every theme. No action required.
- Sidebar Status and Home hub KPIs could show "All clear" while the Problems panel had real findings. The sidebar's Status section and Home hub's issue count/health tiles read
reports/.saropa_lints/violations.json, a file only written by an explicit scan — so a project with the LSP server running (default since this release) and real diagnostics visible in the Problems panel could still show "No violations" if no scan had ever been run. Both now read the same live diagnostics the status bar and Issues tree already use, so they can no longer disagree with the Problems panel. The health score keeps using the last scan's file-count denominator (there's no equivalent from live diagnostics alone) so its coverage caveat is unchanged — only the violation counts and the score's numerator are now always current. - Sidebar Settings rows had no icons. Every row in the Settings panel (Lint integration, Analyzer plugin, Tier, Lane, Run-analysis toggles, UI language, Detected, config actions, dashboard shortcuts) rendered with no icon at all, unlike every other panel — a wall of unlabeled text. Every row now has a distinct icon. Also adds an "Engines (LSP / Analyzer)" row so the Analyzer Plugin/LSP Server/Scan Daemon toggles (Health Panel) are reachable from the sidebar instead of Command Palette only.
Changed #
- LSP server is now ON by default (BETA). New installations start with
saropaLints.lspServer.enabled: true. The analyzer plugin is automatically disabled when the LSP server is on — it's no longer needed and its ~10GB RAM footprint is eliminated. Turning the LSP server off re-enables the analyzer plugin. To revert: toggle "LSP Server" OFF in the Health Panel, or set the setting tofalsein VS Code workspace settings. - Sidebar: severity toggles are single-click; Diagnostics and Help panels folded away. The Show errors/warnings/infos/hints rows previously required an undiscoverable double-click; they now toggle on a single click. The standalone Diagnostics panel (severity toggles, Lint integration, Analyzer plugin, Tier) merged into the Settings panel, and the standalone Help panel (Getting Started, About, pub.dev, AI agent instructions) moved into the Dashboards panel's "..." menu. Clicking the status bar while lint integration is off now opens the Dashboards view instead of doing nothing.
- Debug Panel merged into the Health Panel. The sidebar's standalone Debug Panel (engine toggles, PID/RSS, Kill All / Restart All, log) is gone — that content now lives inside "Saropa Lints: Show Process Health" alongside the Dart process table, so engine controls and process diagnostics are in one place instead of two. The engine log is now a collapsed-by-default expander. The sidebar container is down to 4 panels total (from 7).
- "Saropa Dashboards" home hub removed. It duplicated the sidebar and each dashboard's own settings without adding anything a dashboard couldn't already show — the status bar and every former "Saropa Dashboards" link now open Findings instead.
- Package dashboard command palette decluttered. 38 of the 63
Saropa Lints: Package...commands (row-argument actions like "go to package", "suppress package", bulk major/minor/patch updaters, and niche registry-auth setup) no longer show in the Command Palette — they still work exactly as before from the dashboard's buttons, CodeLens, and context menus, which is how they were actually used. The palette now shows 25 general-purpose package commands instead of 56.
Added #
- Sidebar Status section: Engines row. Shows "Engines: N running" with a one-line summary of the Analyzer Plugin, Scan Daemon, and LSP Server's live status, right below Health — click to open the Health Panel. Turns amber when zero engines are running, so a fully-off diagnostics setup is visible without opening the panel. Previously this state was only visible by opening the panel itself. No action required.
- Package dashboard: tabs and an in-dashboard Settings form. The Package Dashboard now has a tab bar (Overview · Upgrades · Full report · Known issues · Compare · Settings). Upgrades, Full report, Known issues, and Compare open their existing panel with one click from inside the dashboard instead of only being reachable as separate sidebar rows. The new Settings tab renders every
packageVibrancy.*setting as a grouped form (Access, Scan, Display, Score Weights, Upgrade, Watch, Budget, Vulnerabilities) that writes straight to your workspace settings — the 7 dependency-budget limits are one "Budget" card instead of 7 separate settings. - LSP server: quick fixes (lightbulb menu).
textDocument/codeActionnow returns real quick fixes for rules that have fix generators. The server resolves the file, instantiates the rule'sSaropaFixProducer, and returns workspace edits — same fixes the native plugin offers, without the in-process memory cost. No action required. - LSP server: per-rule config overrides. The server now reads per-rule enable/disable from both
analysis_options.yaml(diagnostics:section) andanalysis_options_custom.yaml(severities:section), layered on top of the tier. Rules the user disabled stay off; rules they enabled run even if the tier wouldn't include them. - Health Panel: every engine and action now has a description. The Analyzer Plugin, Scan Daemon, and LSP Server cards each show a one-line "what this does" subtitle. Kill All and Restart All show what they actually affect — both currently control the LSP Server only; the Analyzer Plugin and Scan Daemon each have their own ON/OFF toggle.
- Debug panel: all three engine toggles now work. The "Analyzer Plugin" card's ON/OFF buttons previously did nothing — only the LSP Server card was wired up. Toggling the analyzer card now runs the same enable/disable mechanism as the "Lint integration" sidebar toggle, and the card reflects the real on-disk state instead of always showing "active". The Scan Daemon toggle now suspends/resumes the daemon process. The LSP Server toggle persists to
saropaLints.lspServer.enabledin settings. All toggles log their action to the debug panel's LOG section for immediate user feedback. - LSP server: live config reload.
workspace/didChangeConfigurationnow re-reads the tier fromanalysis_options.yamland re-analyzes every file with published diagnostics, so editing per-rule overrides or the tier takes effect immediately instead of requiring a server restart. - LSP server: full workspace scan on startup with incremental re-scan. After the analyzer warms up, the server scans all Dart files project-wide so diagnostics appear in the Problems panel without opening every file. Subsequent re-scans (e.g. after a config change) are incremental — only files modified since the last scan are re-analyzed. Which directories are scanned and whether the scan runs at all are configurable via
saropaLints.lspServer.scanDirectoriesandsaropaLints.lspServer.workspaceScanin VS Code settings. - Project Map dashboard: live scan + a Reports tab for 7 CLI tools. The Project Map panel now opens immediately with a live activity log and a working Cancel/Restart, instead of freezing until the whole scan finishes. A new Reports tab adds a Run button for every
saropa_lintsreport CLI that previously had no UI at all — Severity Report, Impact Report, Quality Gate (with an inline editor forsaropa_quality_gate.yaml), Stub Test Report, Accuracy Report, Memory Report, and Doctor — each streaming its output live and saving a copy underreports/.saropa_lints/reports-tab/. - Rules & Tiers dashboard is now the full config surface, with 7 tabs. The dashboard (formerly "Lints Config") is now organized as Tier · Rule packs · Overrides · SDK rollout · Config file · Automation · Extension. The new Config file tab adds a control for every
analysis_options_custom.yamlkey that previously had no UI —max_issues,output,platforms,severities,banned_usage,saropa_tier,runtime_tier, anddiagnostic_statisticsthresholds — plus a Baseline card (create/refresh, with the current baseline rendered as a table) and the Analysis Optimizer embedded as a live tab (its standalone command still opens it in its own editor tab). The new Automation and Extension tabs render every remainingsaropaLints.*setting (outside the Package/Code Health/TODO/Drift groups, which keep their own settings surfaces) as a live control, read directly from the extension's manifest so a setting added later appears automatically. The Disabled rules section moved from the old dashboard into this one's Overrides tab. Editinganalysis_options_custom.yamlin another editor now refreshes this dashboard automatically if it is open. - Packages and Project Map dashboards: number-key tab shortcuts. Pressing
1-6on the Package Dashboard, or1/2on Project Map, jumps straight to that tab — matching the shortcut Rules & Tiers already had. Ignored while typing in a search box or form field. - 19 new tier-1 quick-win lint rules. No action required.
avoid_disposing_late_fieldsflags.dispose()on conditionally-initializedlatefields (Recommended).avoid_dynamic_calls_extendedcatches method/property/index access through resolveddynamic(Recommended). Named_extended—avoid_dynamic_callsis a core Dart analyzer lint name.avoid_equals_and_hash_code_on_mutable_classes_extendedprevents==/hashCodeoverrides on classes with non-final fields (Essential). Named_extended— the base name is a core Dart analyzer lint name.avoid_futureor_return_typeflagsFutureOr<T>as a declared return type (Recommended).avoid_implementing_value_types_extendedcatches classes thatimplementsa known value-equality type (Comprehensive). Named_extended— the base name is a core Dart analyzer lint name.avoid_mounted_check_in_finallyflagsmountedguards insidefinallyblocks (Recommended).document_enumrequires doc comments on public enums and enum values (Pedantic).duplicate_valuedetects repeated sub-expressions in boolean chains (Recommended).getters_in_member_listflags getters declared after behavior members (Pedantic).initializers_orderingenforces field-declaration order in constructor initializer lists (Pedantic).is_futurecatches runtimex is Futuretype checks (Recommended).mutable_tearoffflags method tear-offs from non-final fields (Professional).named_parameters_orderingenforces declaration-order named arguments at call sites (Pedantic).never_discard_build_contextcatches unusedBuildContextparams in builder callbacks (Recommended).new_instance_cascadesuggests cascades for consecutive statements on a freshly-created instance (Pedantic).no_direct_iterable_accessflagslist[i]index access without a bounds guard (Professional).prefer_typed_exceptionscatchesthrowof raw String/non-Exception values (Comprehensive).specify_unknown_enum_valuerequiresunknownEnumValueon@JsonSerializableenum fields (Comprehensive).use_compare_without_caseflagstoLowerCase() ==patterns that should usecompareTo(Pedantic).
Internal #
- Extended the extension's Playwright visual-regression harness (
test/ux/generate-pages.ts) to render the Home hub, two Rules & Tiers tabs, and both Project Map states, which previously had no rendered-HTML coverage at all. Added avscode.extensions.getExtensionstub to the shared test mock so the Rules & Tiers dashboard's manifest-driven settings tab can render outside a real VS Code host. - Style-system migration: Full Audit report.
audit/audit-report-styles.tsnow builds ongetDashboardChromeStyles()(.dash-hero,.chip-strip/.chip,.toolbar-band/.field,.btn,.dash-table,.empty-cta) instead of a fully bespoke stylesheet — one of the three remaining parallel CSS systems the redesign plan re-deferred at Phases 5 and 7 (plans/PLAN_extension_ui_redesign.md§1.5). Only severity-tinted pills, baseline badges, and the deferred-load banner remain bespoke. Added the first-everaudit-reportfixture to the Playwright UX harness. No markup IDs or client-script selectors changed, soaudit-report-script.tsneeded no edits. - Style-system migration: Findings dashboard.
violationsDashboardStylesParts.tsnow builds ongetDashboardChromeStyles()instead of a fully bespoke stylesheet — the second of the three parallel CSS systems the redesign plan re-deferred (plans/PLAN_extension_ui_redesign.md§1.5). The file shrank from 1337 to a much smaller "extras" sheet carrying only what the shared chrome doesn't cover (severity-tinted pills, the hero gauge'sanimation: none !importantoverride so the chrome's shared entrance keyframe doesn't play on this dashboard's rebuilds). One remaining parallel system (vibrancy/views/report-styles-parts.ts, the Package Dashboard) is still deferred. - Added a
vscode.languages.getDiagnosticsstub to the shared test mock (test/vibrancy/vscode-mock.ts) — the sidebar's live-diagnostics fix (above) calls it by default, and the mock's absence was silently breaking sidebar unit tests that don't care about diagnostic content. - New
scripts/check_rule_name.py. Checks a proposed rule name against the core Dart/Flutter analyzer lint namespace in one second, before any implementation work begins. The same collision gate (_tier_integrity.pyCheck 8) caught 3 rules that needed renaming at publish time three days running (2026-09-02, 2026-09-03, 2026-09-04) — each time meaning a rename acrosslib/,test/, andexample/after the fact. Wired into the rule-authoring checklist (.claude/skills/lint-rules/SKILL.md,CLAUDE.md) as step 0. - Extended
scripts/fix_ignores.py's rename map with the 3 rules renamed 2026-09-04 (avoid_dynamic_calls,avoid_equals_and_hash_code_on_mutable_classes,avoid_implementing_value_types, all now_extended), and fixed the corresponding stale "N/A (stock analyzer rule)" rows indoc/guides/migration_guides/migration_from_vga.mdtoENHANCED. scripts/publish.pynow routes a prerelease version (e.g.16.0.0-beta.1, the version this release ships as) to each store's prerelease channel automatically —vsce package/publish,ovsx publish, andgh release createall get their prerelease flag derived from the version string, no separate flag or prompt needed.extension/package.json'sversionfield, which the Marketplace requires to be a plainMAJOR.MINOR.PATCH(no hyphen, even with--pre-release), is instead derived viaextension_version_for(): the stripped core PATCH offset by a channel- and iteration-specific band, so successive beta/rc builds of the same base version get distinct extension versions instead of colliding at the Marketplace/Open VSX level. The.vsixfilename and store-verification poll stay consistent with whichever version was actually published.
Historical Changelog Archive #
Looking for older changes? See CHANGELOG_ARCHIVE.md for older versions.