saropa_lints 13.3.2
saropa_lints: ^13.3.2 copied to clipboard
2134 custom lint rules with 254 quick fixes for Flutter and Dart. Static analysis for security, accessibility, and performance.
Changelog #
2100+ 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
13.3.2 #
saropa_lints is installable again on Flutter stable. Versions 12.6.0 through 13.3.1 silently broke flutter pub add saropa_lints on every Flutter stable channel because the package required a newer meta than Flutter ships — Flutter consumers were stuck on 12.5.x. This release relaxes the analyzer constraint so resolution succeeds. Clicking Upgrade on the Saropa Lints update notification no longer locks up VS Code while pub get runs, and the progress popup now has a working Cancel button. The same fix applies to the Initialize / Update Analysis Options command. The ? keyboard-shortcuts overlay on the editor-area dashboards now closes properly via Esc, the × button, or backdrop-click. log
Fixed #
flutter pub add saropa_lintsnow resolves successfully on Flutter stable. Versions 12.6.0 through 13.3.1 requiredanalyzer ^12.1.0(which transitively requiresmeta ^1.18.0), but Flutter stable's SDK pinsmetaat 1.17.0 — so every Flutter consumer hit a resolution failure and was forced to pin to<= 12.5.3. The constraint is now>=9.0.0 <12.0.0, matching the package's documented compatibility contract. No action required — re-runflutter pub upgrade saropa_lintsto pick up the fix.
Fixed (Extension) #
- The Upgrade button on the saropa_lints update notification, and the Initialize / Update Analysis Options command, no longer freeze VS Code while
dart pub get/flutter pub getresolves. Both progress notifications are now cancellable; pressing Cancel terminates the underlying child process tree (Windows: viataskkill /T). No action required. - The keyboard-shortcuts overlay (
?key on editor-area dashboards) now actually closes when you press Esc, click the × button, or click the backdrop. The overlay'sdisplay: flexstyle was outranking thehiddenattribute, so close attempts had no visual effect. No action required.
Maintenance
BaselineManagerno longer trips its ownavoid_catch_allandavoid_blocking_main_threadrules on Flutter consumers — bare catches are nowon Object, the per-file date-baseline preload uses async I/O, and the sync startup path usesFileSystemEntity.isFileSync(semantically tighter; we want files specifically). No user-visible behavior change.BaselineDatecleared the sameavoid_catch_all/avoid_blocking_main_threadself-flags — three git-blame catch sites now useon Object catch (e, st), and_findGitRootwalks ancestor.gitdirs via asyncDirectory.exists()instead ofexistsSync()so it never blocks the analyzer isolate. No user-visible behavior change.- Plugin entrypoint
lib/saropa_lints.dartnow useson Object catch (e, st)for the version-resolver and analysis-config startup catches, matching theavoid_catch_allrule's recommended form. No user-visible behavior change.
13.3.0 #
This release rolls the keyboard-shortcut overlay out to the remaining editor-area dashboards (Command Catalog, Rule Explain, Telemetry, Comparison, Single-package detail, Package Dashboard), introduces inline match highlighting and recent-search dropdowns on the most-used search fields, and surfaces a partial-fetch banner with a Retry button on the Single-package detail panel when README or version-gap data fails to load. Logical CSS positioning brings the dashboards a step closer to right-to-left readiness. Saropa lint rules now skip files under your package's bin/ directory so CLI executables you write stop producing Flutter-only print and sync-I/O warnings.
Fixed #
- Saropa rules now skip files directly under your package's
bin/directory. CLI executables are pure command-line code whereprint()and synchronous I/O are legitimate, so Flutter-only rules likeavoid_print_in_releaseandavoid_blocking_main_threadno longer flag them. No action required.
Added (Extension) #
- The keyboard-shortcut overlay now ships on every editor-area dashboard. Press
?on Command Catalog, Rule Explain, Telemetry, Comparison, Single-package detail, or Package Dashboard to see the page-level bindings. The Package Dashboard overlay documents the existing arrow-key /j/krow navigation,Enter/Spacerow expansion, andAlt + ←back navigation; Command Catalog adds/to refocus the search andEscto clear it. No action required — every dashboard has the same?affordance. - Findings, Known Issues, Package Dashboard, and Command Catalog searches now highlight matched substrings inline. Each match is wrapped in a host-themed highlight that survives Dark+, Light+, and both High Contrast themes; multi-word queries on the Command Catalog highlight every matched token. No action required.
- Findings, Known Issues, and Command Catalog now show a Recent searches dropdown when the search field is focused empty. The dropdown lists the last ten searches from the current panel session; click an entry to re-apply it, click the per-row × to remove a single entry, or click Clear to drop the whole list. Persistence is in-session for now; cross-session persistence is tracked as follow-up work in
plan/UX_GUIDELINES_REMAINING.md. No action required. - The Single-package detail panel now renders a partial-fetch banner at the top of the page when README, version-gap PRs and issues, or the reverse dependency count fails to load. The banner names which sections are missing data and offers a single Retry button that re-runs the failed fetches; rapid clicks are throttled to one retry every two seconds so the panel can't spam pubdev or GitHub. No action required — the banner self-hides when every fetch is clean.
Changed (Extension) #
- The Findings Dashboard's text filter and the Command Catalog's search field bind their
?overlay trigger to the same hero slot that already houses the full-width toggle, so the trailing actions of every dashboard line up consistently. No action required.
Maintenance
- Position-based CSS offsets on dropdowns, popovers, the skip link, and search-clear buttons migrated to the logical
inset-inline-start/inset-inline-endpair so More-actions menus open from the trailing edge in either reading direction. The slider knob in the Lints Config dashboard kept its physicalleftbecause its on-state animation usestransform: translateX; full RTL support for the slider is tracked inplan/UX_GUIDELINES_REMAINING.md. - Tier A polish from
plan/UX_GUIDELINES_REMAINING.mdis complete and recorded against the matching items there. Tiers B / C / D remain earned-scope work and stay in the backlog plan.
13.2.0 #
This release is an accessibility, theming, and reading-quality pass on the editor-area dashboards. Keyboard users can now skip past the hero and toolbar to land directly on the data, screen readers announce filter and sort state changes through a polite live region, and every dashboard exposes proper landmark navigation. The Findings, Code Health, and Known Issues dashboards pick up a ? keyboard-shortcut overlay so the affordances they already supported (/ to focus search, Esc to clear) become discoverable instead of secret. Light and High Contrast theme rendering is fixed in places where dark-only color fallbacks were leaking through, the Package Vibrancy donut chart respects the OS Reduce motion setting, and several dashboards pick up plural-aware counts so "1 finding" reads naturally. Dashboards also print cleanly via your browser or OS print dialog. log
Added (Extension) #
- Every editor-area dashboard now exposes a Skip to content keyboard link as the first focusable element so keyboard users can bypass the hero and toolbar to land directly on the primary data. The link stays hidden until focused, then appears at the top-left for one tab cycle. No action required — press Tab on any dashboard to see it.
- Every editor-area dashboard now reports filter and sort state changes to screen readers through a polite live region. Findings, Code Health, and Known Issues announce visible-row counts on every filter change; Package Comparison announces the package being added when you click an Add button. No action required.
- Every editor-area dashboard now wraps its content in proper landmark regions (header / main / aside) so assistive tech can navigate by section instead of tabbing through every element. No action required.
- Editor-area dashboards now print cleanly via the OS print dialog. The print stylesheet hides toolbars and sticky headers, preserves severity and KPI colors so on-paper severity reads correctly, and prevents table rows from splitting across pages. No action required — print from the dashboard tab as you normally would.
- Findings, Code Health, and Known Issues now expose a keyboard-shortcut overlay: press
?(or click the?button next to the full-width toggle) for a popup listing the page-level shortcuts. The overlay also documents/to focus the search field andEscto clear a focused, non-empty search — bindings that now work consistently across these three dashboards. No action required. - Every webview search input now carries a properly-associated label for screen readers. Inputs that previously relied on placeholder text alone (Known Issues, Single-package detail's PR-and-issues filter, Package Dashboard) now announce their purpose to assistive technology even when the placeholder is hidden during typing. No action required — visual appearance is unchanged.
Fixed (Extension) #
- The Single-package detail panel renders correctly in Light and High Contrast themes. Previously, several borders and backgrounds carried dark-only color fallbacks that bled through whenever the host's theme tokens were briefly undefined, leaving dark patches visible on light themes. The fallbacks are gone and the host theme is now the only source of color. No action required — switch to Light or High Contrast and reopen the panel.
- The Package Vibrancy report's donut chart now respects the OS Reduce motion preference. When Reduce motion is on, the chart segments render in their final position immediately instead of animating in. The chart shape is identical either way; only the in-flight animation differs. No action required.
- Several dashboards now show grammatically correct counts: 1 finding / 2 findings in the Findings Dashboard, 1 function / 2 functions in Code Health, 1 dimension ranked / 2 dimensions ranked in Package Comparison, 1 total event / 2 total events in Related Rule Telemetry. Previously these read awkwardly when the count was 1 because "s" was appended unconditionally. No action required.
Maintenance
- Foundation work for an internal UX-guideline compliance sweep: shared empty-state, error-banner, print, and reduced-motion CSS primitives lifted into the chrome stylesheet so new dashboards inherit them automatically. Helper modules introduced for centralized number / pluralization / timestamp formatting (so a future internationalization pass becomes a config switch instead of a refactor across N surfaces). Structural-snapshot test harness and token-coverage matrix tool added for tracking visual drift. Layout primitives in the chrome use logical CSS properties so the dashboards are ready for right-to-left locales when that work is scheduled. The Command Catalog panel's main content region id changes from
catalogtocatalog-mainfor skip-link targeting (no impact unless external automation pinned the previous id). The compliance plan and per-surface status table live inplan/UX_GUIDELINES_COMPLIANCE.md. - Per-surface stylesheets now use logical CSS properties (
margin-inline-start/margin-inline-end/padding-inline-start/padding-inline-end/border-inline-start/border-inline-end) instead of physical*-left/*-rightdirections. Visual layout is identical in left-to-right locales; the dashboards are now closer to right-to-left ready when that work is scheduled. Position-basedleft:/right:(absolute / fixed positioning) is intentionally untouched and tracked inplan/UX_GUIDELINES_REMAINING.md. - Backlog plan added at
plan/UX_GUIDELINES_REMAINING.mdcovering the deferred guideline work (multi-column sort, multi-select, virtualization, column resize, offline / stale states, theme verification automation, and others), each with a sketch and an explicit Earn it when trigger so the items don't drift into "implement everything" scope creep. - Historical release notes rewritten for readability — older releases were revised in this version to drop code-internal vocabulary (HTML element names, CSS class names, em values, hex codes, internal tier-N button vocabulary) and reframe each bullet around what the user sees. Substance preserved across every entry; only the phrasing changes. Affected releases: 13.1.0 and earlier where applicable.
- Publish script (
scripts/modules/_publish_steps.py) now treats the mid-publish stale-plugin error as analyze-passed, removing two interactive prompts that previously fired on every release. Whenanalysis_options.yaml's plugin pin matches the localpubspec.yamlbut is newer than pub.dev's latest (the normal state of a release commit beforedart pub publishlands), the audit recognizes this as a transient resolution error rather than a real lint failure and proceeds without surfacing the Fix / Skip downgrade prompt or the Ignore / Retry / Abort failure prompt. The downgrade prompt still appears for genuine drift (pin disagrees with both pubspec and pub.dev). No action for package or extension users. - Root
analysis_options.yamlno longer pins thesaropa_lintsplugin to a hard-coded version. The pin used to chase the localpubspec.yamlversion on every release, which madedart analyzefail in this repo whenever the bumped version had not yet propagated to pub.dev. Without the pin the analyzer resolves the plugin from the workspace source itself (the package has no self-dependency inpubspec.yaml), so the chicken-and-egg between version bump and publish is gone. Consumer projects regenerating their config viadart run saropa_lints:initcontinue to receive aversion:pin matching their installed package — only the in-repo dogfood file is affected. No action for package or extension users.
13.1.0 #
This release polishes the VS Code extension's editor-tab dashboards and side panels so they read as one consistent product instead of a stack of one-off pages. KPI strips collapse cleanly when there is nothing to report, empty states offer a real next-action button instead of staring back blank, secondary buttons step out of overflow menus so the primary action stays obvious, and the Rule Explain, Command Catalog, Related Rule Telemetry, Single-package detail, Package Comparison, and Known Issues panels pick up the same card-style sections and toolbar layout already used on the main dashboards. Two long-standing rendering bugs are also fixed: the Package Vibrancy size-distribution bars now scale to their actual share, and the Command Catalog jump-to-section highlight reliably appears in webview environments where it previously did nothing. log
Changed (Extension) #
- The Findings Dashboard title now reads Saropa Findings Dashboard in the page heading (previously only the editor tab carried the Saropa prefix), and the toolbar's Copy JSON / Save report buttons have moved into the More actions ▾ overflow menu so the visible action row stays scannable. No action required — both exports remain reachable from the same overflow menu that already housed the rest of the palette.
- The Findings Dashboard suppressions list now styles rule names the same way as rule names in the findings table; previously the two surfaces rendered the same data differently, so suppression rows looked pre-highlighted compared to findings rows. No action required.
- The Code Health Dashboard KPI strip now suppresses zero-count categories and collapses to a single muted all clear line when every category is zero, instead of greeting healthy projects with a row of identical zeros. No action required — categories reappear as their counts grow.
- The Code Health Dashboard filtered table now shows an empty-state banner with a Reset filters button when search or a flag-card filter narrows it to zero rows, instead of leaving the user staring at an empty table with no cue. No action required — the banner appears and disappears with the filter state.
- The Code Health Dashboard gate-failure banner now carries an Open Code Health settings button so the user can act on a failing quality gate from inside the banner; previously it offered only explanatory text. No action required.
- The Rule Explain panel now uses the same card-style sections as the Findings and Code Health dashboards: each block (Problem / How to fix / OWASP / Related rules / Migration / Documentation) renders as a card with consistent subsection headings, OWASP entries display as a label/value list, and the documentation link appears as a button instead of a plain anchor. The panel also picks up the shared content width cap and full-width toggle, so it reads as part of the same product. No action required.
- The Rule Explain panel now omits the Problem section entirely when a rule carries no message, instead of advertising a No message placeholder card. No action required.
- The Command Catalog panel cleans up its toolbar: the search-tokenization hint moves below the toolbar so the toolbar reads as a pure control surface, the Frequent tiles render more quietly so toolbar buttons keep visual emphasis, and category-count badges grow a hover/focus outline so the click target is obvious before you commit. No action required.
- The Related Rule Telemetry panel right-aligns the Count column so wide numbers stay readable, drops Refresh out of the primary-action color (this read-only counter table doesn't have a dominant action), disables Reset counters when there's nothing to reset, and replaces the blank counter table with an Open Findings Dashboard button when no events have been recorded yet. No action required.
- The Single-package detail panel cleans up several rendering gaps. The page heading no longer doubles up the word Package (it reads Saropa http instead of Saropa Package: http), the external-link strip appears only once at the foot of the page (was duplicated under the hero), the gap-summary numbers read as KPIs at proper hero size, the version-gap filter row reads as a quiet segmented control instead of a row of identically-colored buttons, sections have visible card depth, and external links open without underline by default while in-panel links keep underline always so the two are distinguishable. The panel also renders correctly in Light and High Contrast themes — dark-only color fallbacks that bled through on lighter themes have been removed. No action required.
- The Package Comparison panel grows a summary row (Leading package, Packages compared, Dimensions ranked) and a toolbar with a Package Dashboard button, so the page no longer jumps from hero straight to a bare table. The empty state offers an Open Package Dashboard button instead of just explanatory text. Per-row Add to Project buttons render as secondary actions so the multiple inline buttons no longer compete with the toolbar for emphasis. No action required.
- The Known Issues Library panel now lights up the matching summary card when you click Has replacement or No replacement, so you can see at a glance which filter is on (the cards were clickable before but didn't visually reflect the active state). It also shows an active-filter strip below the toolbar with [×] buttons to remove individual constraints, and offers a Reset filters button when your search or filter narrows the table to zero packages. No action required.
Fixed (Extension) #
- The Size Distribution chart in the Package Vibrancy report now draws each bar at a length proportional to its percentage — previously every bar rendered at the full track width regardless of the package's share, making the visualization unreadable. No action required — reopen the report after updating.
- The Command Catalog category-jump flash (the brief tint that highlights a section after you click its count badge) now reliably appears in webview environments where CSS
var()references inside@keyframesfail to resolve — the highlight previously did nothing on those builds. No action required.
13.0.2 #
The Top Rules table in the Findings Dashboard now lets you choose between hiding a noisy rule just for yourself or disabling it across the whole project — two buttons per row, side by side, so the commitment is obvious before you click. Hide stays personal and reversible; Disable writes the rule into your project config and re-runs analysis on the spot. log
Added (Extension) #
- Each row in the Findings Dashboard Top Rules table now has a Disable button next to the existing Hide button — Hide is workspace-only (per-user, reversible via Clear Suppressions) while Disable writes the rule to
analysis_options_custom.yamlso the whole project stops running it (team-shared, persistent, re-runs analysis automatically). No action required — open the Findings Dashboard to use it.
13.0.1 #
The Findings Dashboard gets a Top Rules table that ranks the noisiest rules by count and gives you a one-click Hide button per row, so a screen full of repeated INFO lints stops drowning out the warnings you actually need to see. Behind the scenes the Code Health Dashboard scan no longer stacks parallel processes when you click rescan in quick succession, and every visible label, toast, and Command Catalog entry now uses the on-screen "Code Health" name instead of the older "Project Vibrancy" wording. log
Added (Extension) #
- The Findings Dashboard now shows a Top Rules triage table above the findings list, ranking the noisiest rules by count with severity and a per-row Hide button so a single click suppresses a rule across the workspace findings (same hide as the Issues tree's "Hide rule", reversible via Clear Suppressions). No action required — open the Findings Dashboard to use it.
Fixed (Extension) #
- The Code Health Dashboard scan no longer stacks parallel
dart runprocesses when the command fires repeatedly (sidebar item, rescan button, command palette) — concurrent invocations now share one in-flight scan, and the progress notification is cancellable so a runaway scan can be stopped from the toast. No action required. - Renamed every user-facing Project Vibrancy label to Code Health so toasts, banners, tooltips, the toolbar settings button, the Settings group title, the README section, and the Command Catalog all match the dashboard panel name. The setting keys (
saropaLints.projectVibrancy.*) and the underlying CLI executable (saropa_lints:project_vibrancy) are unchanged so existingsettings.jsonfiles keep working. The old name still appears once in the LCOV-path setting description as a migration breadcrumb so users searching for "Project Vibrancy" still find it. No action required. - Moved the Open Code Health Dashboard and Open Code Health Settings entries in the Command Catalog from the Package Vibrancy category to a new Code Health category — Code Health scores your own source, Package Vibrancy scores your dependencies, and they should not appear under the same heading.
- Removed two factually wrong claims from the README's Code Health section: the dashboard is an editor tab (not a sidebar webview, which was removed in v13.0.0), and the Refresh Project Vibrancy Sidebar command no longer exists. The section now describes the editor-tab dashboard, the KPI-card filters, and the actual ways to launch a scan.
13.0.0 #
This release rebuilds the VS Code extension around a single dashboard look so the Findings, Lints Config, Code Health Dashboard, Package Dashboard, Known Issues, and Package Comparison editor tabs all share the same hero band, status line, KPI cards that double as filters, sticky toolbars, and sortable tables. The Saropa activity bar collapses into one flat Saropa Lints sidebar — many duplicate tree views are gone in favor of the editor tabs they were always pointing at, so there is one obvious place to land for each task. A common nullable build-context guard pattern no longer trips the after-await context lints, and a handful of webview, path-resolution, and cache fixes round things out. log
Added (Extension) #
- The Lints Config header now carries a coverage gauge (red→amber→green) showing what fraction of the packs detected in your pubspec are actually enabled, so you can tell at a glance whether your config is taking advantage of the available tooling. No action required.
- The Pack coverage chart now renders a donut companion next to the existing horizontal-bar list — segments are clickable filters on the same pack contract as the bars, and they cross-highlight when a bar or segment is selected. No action required.
- A Copy config toolbar action copies a paste-ready
analysis_options.yamlsnippet (tier + enabled rule packs, sorted) to the clipboard so you can replicate the configuration in another project. No action required. - The Code Health Dashboard now opens with a status line (generated, function count, average score, gate state), an average-score gauge in the header, and KPI cards (Unused, Uncovered, Stub-tested, Suspicious coverage, Test drift) that double as click-to-filter presets on the table. No action required — open Saropa Lints: Open Code Health Dashboard to see the new layout.
Changed (Extension) #
- The Lints Config editor tab is rebuilt around the gold-standard dashboard pattern: a status line under the title now shows tier, pack coverage, applicable SDK migrations, and analysis freshness instead of marketing copy; KPI cards are clickable preset filters with hero-sized numbers; the tier selector is a real radio segmented control (replacing the read-only chips and the separate Set tier toolbar button); the toolbar is a banded sticky strip with one primary Run analysis action and a Enable applicable packs ▾ split-button for the breaking / deprecation variants. No action required — open the Lints Config tab to see the new layout.
- The two pack tables (SDK migration packs and Package rule packs) are merged into one searchable, sortable table with Type and Risk columns; the table now supports text search, type filter, Detected only / Enabled only checkboxes, and an active-filter chip strip with per-chip removal and Clear all. The Pack coverage chart is hidden when no pack is enabled or detected, and its bars now click through to filter the table. The suppressions snapshot, target platforms, and docs links move to a diagnostics band below the table. No action required.
- Findings, Lints Config, and Code Health dashboards now share one visual chrome (header band with status line and gauge, KPI cards as preset filters, banded sticky toolbar with density tiers, segmented filter controls, active-filter chip strip, sortable sticky-header table, bar+donut chart pair). Class names and tokens are unified so a user moving between the three sees the same buttons, fields, and layout grid. No action required.
- Every editor-area dashboard now adopts the gold-standard hero band — Saropa Package Dashboard, Saropa Package Comparison, Saropa Known Issues, Saropa Package Detail, Saropa Rule Explain, Saropa Related Rule Telemetry, and Saropa Lints — About all carry a Saropa-prefixed title, version stamp, and a status-line strip of facts (last run, counts, freshness) so each tab telegraphs what it knows right now without scrolling. Sidebar webviews and tree views keep their unprefixed labels because the activity bar already supplies the product context. No action required.
- Every editor-area dashboard now constrains content to a readable max-width (~1280px) with a ↔ full-width toggle in the status line, so panels stay legible on ultrawide monitors but can stretch on demand for wide tables and side-by-side comparisons. The toggle persists per webview session. No action required.
- Severity, impact, and replacement filter toggles render with an inverted visual model: included values stay quiet (the resting state) while excluded values are struck through and faded, so the dashboard greets you with calm chrome at defaults instead of a wall of blue pills, and only shouts when you have actively narrowed the view. The pressed-state vocabulary no longer collides with the Run analysis primary button. No action required.
- Tier and footprint-mode toggles (where exactly one option is active at a time) now read more quietly: the active option is marked with a subtle backdrop tint instead of a bright button-colored fill, so it no longer competes with the toolbar's Run analysis button for visual priority. The Lints Config Show detected / Show enabled filter uses a related quiet style. No action required.
- The Saropa Known Issues library now treats its summary cards as click-to-filter presets (Showing / Total / Has replacement / No replacement) and replaces the binary checkbox with a multi-toggle segmented control, so each card maps to a distinct filter state instead of acting as decoration. No action required.
- The Saropa Package Comparison panel moves the recommendation summary below the comparison table — the user's reason for opening the panel is the data, not the synthesis — and the empty-state still leads with the Saropa-prefixed hero so the page identity is visible before content arrives. No action required.
- The Saropa Related Rule Telemetry panel adopts the shared toolbar layout, the same empty-state pattern as other dashboards, and a clear button hierarchy (Refresh, Copy JSON, Reset counters with the destructive action visually distinct), so it reads as part of the same product instead of a one-off debug page. No action required.
- The Saropa Package Dashboard and Saropa Command Catalog hero bands now match the contained, rounded look of the Findings dashboard — replacing the bare top section and the full-width gradient stripe respectively, so all four editor dashboards open with the same visual signature. No action required.
- The Command Catalog editor tab is redesigned around the editor-dashboard guidelines so the 156-command list no longer reads as one uniform wall: the marketing subtitle is replaced with a real status line (commands, categories, recent count, internal-hidden), search and the context-menu toggle live in one sticky toolbar band with an inline (×) clear and an active-filter chip strip, the Recent strip caps at six chips behind +N more above a new usage-ranked Frequent band, rows are slimmed to icon + title + one-line description with the command id revealed via a hover-only copy affordance and tooltip, category cards lose their borders for sticky uppercase microlabel headers, count badges become click-to-jump anchors that flash the target section, and Up/Down/Home/End navigate visible rows for keyboard-first browsing. No action required.
- The Saropa activity bar now hosts a single flat sidebar named Saropa Lints instead of the previous Dashboards + Overview & options split, with no in-panel group headers; editor-tab dashboards, run/discover actions, project status rows, settings toggles, triage groups, and help links all sit at the top level so duplicate copies of Run analysis, Getting Started, About, and pub.dev are gone. No action required; if you set
saropaLints.sidebar.showOverviewtofalseit now hides the unified view. - The Dashboards activity-bar hub drops the Violations tools row group; the same filter, grouping, suppression, and navigation commands remain on the Findings Dashboard tab (toolbar + More commands) and in the Command Palette. No config change.
- The Findings Dashboard adds Refresh extension (full
saropaLints.refresh: trees, annotations, report-backed views) next to Refresh from disk. No config change. - The Saropa activity bar keeps Dashboards and Overview & options only; per-section
saropaLints.sidebar.show*toggles under Overview were removed with the migrated views.saropaLints.exportOwaspReportis available from the Command Palette when the workspace has violations. - The five dashboard hub labels drop the Saropa prefix (now Lints Config, Package Dashboard, Code Health Dashboard, Findings Dashboard, Command Catalog) so the activity-bar tree stops reading as "Saropa Saropa Lints …"; editor-tab titles and primary headings keep the Saropa prefix so the tabs stay findable in Quick Open, Recent Files, and the editor tab dropdown. No action required.
- Package Vibrancy timestamped JSON, Markdown, and SBOM exports now save under
<workspace>/reports/instead ofreport/, matching cross_file CLI defaults and other Saropa on-disk report paths. No action required if you only use extension commands and webviews. - Automation that consumed
report/*_saropa_vibrancy.*must usereports/; first-time vibrancy history backfill still scans legacyreport/when importing old timestamped JSON into.saropa/vibrancy-history.json. - The Dashboards hub lists editor dashboards only (the extra “Violations sidebar” jump row is removed because that tree no longer exists). No action required.
- The Findings Dashboard adds a compact More commands row (palette actions for filters, help, vibrancy, config, and Copy tree JSON) so shortcuts that lived on the old Violations title bar stay one click away in the editor tab. No action required.
- Help & resources includes Create AI agent instructions so that command stays visible after the hub trim. No action required.
- The Findings Dashboard editor tab now includes Suppressions (export) (same breakdown as the violations export summary) and Issues view hides (workspace list filters) with actions to clear filters, drill by rule or file, and clear view hides, so you can review suppressions without a separate Violations tree. No action required.
- The Findings Dashboard is redesigned around a hero strip (title, version stamp, last-run pill, severity-weighted health gauge), interactive KPI cards that double as preset filters (Errors, Warnings, Critical+High, Files affected, Top rule), an active-filters chip strip with one-click removal, a sortable sticky-header findings table with per-row Copy and group expand/collapse, a Save-report button that writes timestamped JSON under
reports/YYYYMMDD/, and an overflow More ▾ menu replacing the flat 14-button palette row; severity/impact mix renders as bars + donut and the card hides entirely when every slot is zero. No action required—filters and existing actions remain in place. - The Findings Dashboard suppressions block drops the inert By kind sub-list (clicks did nothing) and inlines the kind breakdown next to the section title, so every visible row is now actionable—rule and file rows still drill into Findings; analyzer / view-hide sections collapse to a one-line muted footer when there is nothing to show. No action required.
- The Findings Dashboard TODOs, HACKS, and Drift Advisor sections render in density-first order above empty placeholders so actionable markers stay above the fold; sections with no data collapse to a single muted footer rather than reserving full bordered bands. No action required.
- The Config Dashboard shows a read-only Suppressions (export) strip (totals and by-kind snapshot from the current report, after the disabled-rule filter) plus Open Findings Dashboard for the full breakdown; browse, clear view hides, and drill-down stay on Findings. No action required.
- Package Vibrancy user-facing text now refers to the activity-bar list, Package Dashboard (editor tab), and CodeLens instead of generic “tree view” wording; Saropa Lints: Open Package Dashboard is the palette label for
saropaLints.packageVibrancy.showReport(same command id). No config change. - Open Package Vibrancy, Open Code Health Dashboard, and Open Project Vibrancy Settings now have toolbar icons, and the Dashboards hub title bar includes Open Package Vibrancy and Open Code Health Dashboard in Dart workspaces so the main vibrancy webviews stay one click away from the activity bar. No config change.
- Config Dashboard (rule packs, tiers, charts) opens as an editor tab instead of a Saropa sidebar webview so the layout matches a real dashboard width. No action required.
- Open Config Dashboard has a toolbar icon on the Dashboards hub in Dart workspaces (Overview title unchanged); the
saropaLints.sidebar.showRulePackssetting is removed because that sidebar section no longer exists—delete the key from settings JSON if you set it explicitly. No other migration. - Composite analyzer plugin scaffold shows an explanatory notification with Continue and Open guide before the folder prompt so the flow is obvious; Open guide opens the composite-plugin documentation in the browser without writing files. No action required.
- Editor-area dashboards (Package Vibrancy, Package Details, Telemetry, Command Catalog) now share a consistent pill-shaped button style that contrasts correctly in Light, Dark, and High Contrast themes, so the toolbar buttons read the same across all four dashboards. No action required.
- Improved readability of detail and summary panels in the Package Vibrancy report and Package Details view: increased the small text size and replaced an over-faded muted-label color with the theme's standard description color, so panels like Health Score, summary cards, and gap-table cards meet WCAG contrast in Light, Dark, and High Contrast themes. No action required.
- The Findings Dashboard Severity mix and Impact mix charts hide rows whose count is zero (and show a single muted No findings. line when every bucket is empty) so empty tracks no longer pad the chart cards. No action required.
- The Lints Config Rule packs table and Disabled rules block are now collapsible expanders — packs open by default, the (previously wall-of-text) disabled-rules block starts collapsed — so the dashboard reads as two intentional sections instead of one long scroll. No action required.
- The Lints Config Disabled rules block now ships with a search input and groups rules by their owning rule pack (with a Tier-only (no pack) bucket last), so triaging large override lists is one search box instead of an alphabetical scroll. No action required.
Removed (Extension) #
- The Composite analyzer plugin (scaffold) row is removed from the Saropa Lints sidebar (both the Config tree and the sectioned sidebar) because the action only applies to teams that ship their own custom analyzer rules alongside Saropa, and the term was jargon for the typical user. The action stays available via the command palette (
Saropa Lints: Create Composite Analyzer Plugin (scaffold)),Saropa Lints: Show All Commands, the CLI flagdart run saropa_lints:init --emit-composite-plugin-scaffold, anddoc/guides/composite_analyzer_plugin.md. No action required. - The palette entry Saropa Lints: Focus Violations View (
saropaLints.focusView) is removed because it did not focus a violations tree and duplicated Open Overview behavior; the main Saropa status bar still opens the Overview view via the same underlying focus command. No action unless you referencedsaropaLints.focusViewin keybindings or tasks—usesaropaLints.overview.focusinstead. - The Violations activity-bar tree (
saropaLints.issues) is removed from the extension manifest so lint findings are not hosted in a duplicate sidebar; use the Findings Dashboard editor tab and the$(warning)status item. ThesaropaLints.sidebar.showIssuessetting is removed—delete it from JSON if present. - The Commands sidebar webview (
saropaLints.commandCatalogSidebar) andsaropaLints.sidebar.showCommandCatalogare removed; Browse All Commands / Command Catalog open the editor tab only. - The Project Vibrancy sidebar view and its refresh command are removed so function-level vibrancy lives only in the editor-area report, which removes duplicate UI and avoids cramped sidebar layouts. Use Saropa Lints: Open Code Health Dashboard (Command Palette or Saropa navigation where offered). No config change.
- Summary, Suppressions, Suggestions, Security Posture, File Risk, TODOs & Hacks, Drift Advisor, Package Vibrancy (dependency tree), and Package Details (sidebar webview) are removed from the Saropa activity bar; use the Findings Dashboard, Lints Config, Package Dashboard, and Command Palette instead. Delete
saropaLints.sidebar.showSummarythroughsaropaLints.sidebar.showDriftAdvisorfrom settings JSON if you set them explicitly—onlysaropaLints.sidebar.showOverviewremains under Activity bar.
Fixed #
avoid_context_across_asyncandavoid_context_after_await_in_staticno longer report the idiomatic compound nullable guardcontext != null && context.mounted ? context : null(used by extension methods and static helpers that take aBuildContext?parameter); both the null-checkcontextand the then-branchcontextare now recognized as part of the guard. Remove any temporary// ignoreworkarounds you added for that pattern.
Fixed (Extension) #
- The Package Dashboard's Active filters: strip no longer flashes an empty "Active filters: Clear all" band when no filters are active — previously a layout race could leave the strip visible at zero height with just the label and the Clear all link showing. The strip now stays reliably hidden until you set at least one filter. No action required.
- Reclicking the Lints Config entry in the Saropa sidebar when the dashboard tab is already open now moves keyboard focus into the dashboard, instead of leaving focus on the sidebar tree row (which made the reclick feel like a no-op). No action required.
- Header gauges on the Findings, Lints Config, Code Health, and Package dashboards now render their arc at the correct level and animate in on first paint, instead of appearing as a tiny dot next to the grade letter. Previously the gauge fill was being suppressed by the dashboard's security settings and only redrew on later score changes, so the very first render of any dashboard looked broken. No action required.
- The Rescan button in the Package Vibrancy report now clears the per-package pub.dev cache before scanning, so the report reflects current pub.dev versions instead of silently re-using cached entries within the 24-hour TTL. A new Saropa: Rescan Packages (Fresh) command exposes the same behavior from the Command Palette; the existing Scan Packages command stays cache-friendly for the file watcher and startup paths. No action required.
- Dashboards hub rows no longer show stale Saropa-prefixed labels after the quick-actions split (Full-width tabs, Lints Config, Package Dashboard, Project Dashboard, and quick-action descriptions without redundant Saropa wording); reload the window after upgrading the VSIX or dev build to pick up the tree provider. No config change.
- Opening a file from the Project Vibrancy report now resolves report paths against the workspace root on Windows and mixed path styles, so jump-to-file from a hit works reliably instead of failing on path shape. No action required.
- The Code Health Dashboard now invokes
dart run saropa_lints:project_vibrancy(registered package executable) instead of the source pathbin/project_vibrancy.dart, so the dashboard works in every consumer workspace instead of failing with "Could not find filebin/project_vibrancy.dart" outside the saropa_lints repo. No action required. - Hardened three editor-area panels against script injection from untrusted content: the Package Details panel tightens its content-security policy so a malicious package or registry response cannot inject script tags via the panel's HTML, the About panel renders unsafe markdown link schemes (
javascript:,data:,vbscript:,file:) as plain text instead of a clickable link, and the Rule Explain panel safely escapes rule names that contain script-terminating sequences. No action required. - The About Saropa Lints panel now indents sub-bullets under their parent in sections like VS Code Extensions and Smart Features, restoring the parent/child hierarchy that previously collapsed into a flat sibling list and made product descriptions blur into the product names. No action required.
Maintenance
- VS Code Project Vibrancy scan startup now resolves the Dart executable per platform (
dart.baton Windows,dartelsewhere) and surfaces the underlying spawn error in the notification when startup fails, which prevents false “Dart SDK missing” messages on Windows PATH setups. - Added
scripts/run_extension_local.pyto compileextension/and launch an Extension Development Host (sharedscripts/modules/_utilsbranding, step progress, Node/npm/distchecks); seescripts/README.md. No action for pub.dev or Marketplace users. - Recorded the native-plugin quick-fix migration as structurally complete in
plan/TESTING_AND_RELEASE.md§3 —lib/has 0extends DartFixand 221extends SaropaFixProducerfiles; remaining work is end-to-end verification, not migration. - Added
doc/troubleshooting.mdcovering the three IDE-specific failure modes (custom_lint not running, rules absent from Problems panel, missing lightbulb fix), separate from the broader README §Troubleshooting. - Added a "Supported Versions" note to
README.mddescribing the active 12.x line and security-only backport policy for earlier majors. scripts/run_extension_local.pyauto-detect now preferscode(VS Code) overcode-insidersandcursor, so devs with both editors installed get the VS Code Extension Development Host by default; override with--editor cursororSAROPA_VSCODE_CLI.scripts/run_extension_local.pynow starts a detachednpm run watchafter compile so.tssaves rebuilddist/extension.jsautomatically for the running EDH session — previously the bundle stayed frozen at launch and every code change required re-running the script. Disable with--no-watch; logs land inextension/.watcher.log.- Expanded
plan/guides/UX_UI_GUIDELINES.mdwith toolbar density tiers, mandatory active-filter chip strip, status-line under H1, button hierarchy beyond primary/secondary, "same row visual = same row contract" rule, and a new §14 anti-pattern catalog (bait-and-switch rows, doubled empty states, placeholder-as-content, flat-toolbar overflow, buried high-value sections, decorative weight without depth, density-first content ordering, inert KPI cards, status-line absence, identical-twin KPI cards) so future surfaces avoid the failure modes that prompted the Findings Dashboard redesign. scripts/modules/_git_ops.py_push_with_retrynow prompts the developer to retry or abort on hard push failures (missing remote, auth error, network outage) instead of aborting the whole publish. Empty input defaults to retry so the dev can fix the underlying issue (e.g. re-addorigin) and press Enter to continue from the same release commit.
12.8.3 #
This patch release focuses on reducing noisy false positives so everyday Flutter and Dart code reads cleaner in the editor. Common animation flows, validated parsing paths, numeric loop accumulation, parent-data lifecycle field patterns, and guarded render-object parentData casts should now lint the way you expect. No config updates are needed; re-run analysis and you should see fewer distracting reports. log
Fixed #
avoid_redundant_awaitno longer flagsawaitonAnimationController.forward()and.reverse()sequencing calls that returnTickerFuture, so valid animation orchestration is not misreported as redundant. No action required.avoid_inert_animation_value_in_buildno longer reportsAnimation.valuereads inside child widgetbuild()methods when that child is instantiated from a listening builder callback (for exampleAnimatedBuilder), so tick-driven subtrees are not misclassified as inert snapshots. No action required.prefer_try_parse_for_dynamic_datanow skipsparse(...)calls when the input is provably safe (valid numeric literals and digit-only regex-validated captures/substrings), so common validated parsing paths are no longer false positives. Remove any temporary local suppressions you added for those patterns.avoid_memory_intensive_operationsnow reports loop+=only when the operation is on strings, so numeric accumulation patterns no longer produce false positives. No action required.avoid_unassigned_late_fieldsno longer reportslatefields declared on RenderObject parent-data classes (types in theParentDatainheritance chain), so lifecycle-initialized layout fields are not misclassified as unassigned. No action required.avoid_unsafe_castno longer flags guardedRenderObject.parentDatacasts to*ParentDatatypes when the enclosing class safely initializes that parent data shape insetupParentData(...), so valid render-object parent-data workflows are not misclassified as unsafe casts. No action required.
12.8.2 #
The VS Code extension now registers the Suppressions sidebar at startup, so you should see fewer “view not registered” glitches after an update or a full window reload. avoid_redundant_await also stops mis-flagging await on some third-party async builder-style APIs. No config change. log
Fixed #
avoid_redundant_awaitno longer flagsawaitwhen the expression’s static type is a class that implementsFutureorStream(e.g. Postgrest/Supabase builder APIs) instead of the plainFuture<…>type, so legitimate awaits are not misreported as redundant. Remove any temporary// ignoreworkarounds you added for that pattern.avoid_inert_animation_value_in_buildno longer reportsAnimation.valuereads inside child widgetbuild()methods when that child is instantiated from a listening builder callback (for exampleAnimatedBuilder), so tick-driven subtrees are not misclassified as inert snapshots. No action required.
Fixed (Extension) #
- The Suppressions tree binds at activation like other first-class sidebar trees, which avoids intermittent registration failures for that view. No action required; if a one-off error persists from an older session, use Developer: Reload Window.
Maintenance
- Tag-publish and CI analyze jobs run nested
dart pub get(discovered underpackages/, with the same retries as the root install) beforedart analyzeso nested packages resolve on fresh checkouts. No action for pub.dev or extension users.
12.8.0 #
Cross-file and snapshot loading forgive bad JSON or YAML on disk, so one broken l10n file should not take down a whole run. Many rules now offer IDE quick fixes where a mechanical edit is safe, and you can cap which cumulative tier runs with an environment variable or plugin config if you do not want to hand-edit huge rule lists. A handful of rules were renamed for clarity, and exports plus the extension Issues view prioritize and label findings a bit more helpfully—re-run analysis if you rely on violations.json. log
Fixed #
- Cross-file unused-l10n and snapshot loading from disk tolerate corrupt JSON and YAML so a broken ARB or snapshot file no longer aborts the whole run; if results look incomplete, fix or regenerate that file. No config change.
Added #
-
Many widget flex/scroll, GetX, iOS lifecycle, iOS capabilities, and security auth/storage rules now register IDE quick fixes where a safe mechanical edit applies (layout unwraps, physics helpers, HTTPS in string URLs, GetX
superlifecycle inserts, and similar). No config change; use the lightbulb when the offered fix matches your intent. -
Optional runtime tier cap lets you set
SAROPA_TIERtoessential,recommended,professional,comprehensive, orpedanticso analysis skips rules above that cumulative band without editing generated rule lists, or set the same value assaropa_tierinanalysis_options_custom.yamlor asruntime_tier/saropa_tierunderplugins.saropa_lintswhen you prefer file-based config; the environment variable wins if both are set. No action required until you want CI or local runs to enforce a lower band than your YAML enables.
Changed #
- Lint identifiers:
annotate_redeclares,document_ignores,duplicate_constructor, andpackage_nameswere renamed toannotate_inherited_member_redeclaration,document_analyzer_ignore_rationale,duplicate_constructor_declarations, andpubspec_package_name_conventionfor clearer multi-word names; updateanalysis_options.yaml/ Saropa config if you toggled those rules by id. prefer_schedule_microtask_over_window_postmessageis included in the Professional cumulative tier (alongside other web guidance). No change unless you rely on tier lists for automation.- VS Code: the Triage tree no longer shows volume or critical groups when
violations.jsonis missing, is older than four hours, or lackssummary.issuesByRule, because those states would mislead group-level rule actions; a single row with a Run analysis action explains the issue instead. Re-run analysis to refresh; no config change. - Plugin: report import graph lookup now uses a path key index and caches the analyzed file set after
compute, which cuts report-side overhead on large projects. No action required. - Plugin + VS Code: each entry in
violations.jsonnow includes a numericpriority(same combined score as the report’s FIX PRIORITY section), and the Saropa Issues tree sorts findings by that score (then line) so the extension matches “fix what matters first” without opening the log. Re-run analysis to refresh the export; Problems tab behavior is unchanged. - Cross-file
dart run saropa_lints:cross_file reportwritesfeature-deps.htmland a sharedreport.css(light and dark via the browser) into the output folder, and the README explains that the CLI analyzes one package root at a time so monorepo users know to run it per package. Re-runreportto refresh an existing output directory; no config changes.
Maintenance
- Release tooling: full publish builds
extension/saropa-lints-*.vsixbefore the optional “re-run failed CI and watch” step so a long or interrupted watch does not leave the tree without a packaged extension whennpm/vscesucceeded. No action for pub.dev or extension users. - Stopping a CI run watch with Ctrl+C during publish is treated as “done watching” and the pipeline continues to tag, pub upload, and extension install or store publish; use n at the watch prompt to skip waiting. Maintainers only.
scripts/README.mddocumentspython -m unittest discoverfor the Pythonscripts/tests/suite (no pytest). Maintainers and CI already use the same command.
12.7.0 #
Package Vibrancy and cross-file analysis get proper extension UI and several new CLI modes, metadata-rich exports make related rules and triage easier, and security hotspots plus suppressions are more workable end-to-end. This is a big extension-focused drop—update the VS Code side if you use those panels or vibrancy. Most Dart-only users still just upgrade the package and re-run analysis. log
Added #
- Project Vibrancy now has primary extension UI surfaces: a dedicated sidebar webview (filters, quick unused/uncovered slices, persisted filter state, and
--sincegit-ref scoped scans) plus a full report webview command with clickable file links per function row (opens the editor at the reported line range), so teams can use project-level code-health scoring directly in the IDE instead of CLI-only output. No action required beyond updating the extension and opening Project Vibrancy from the Saropa sidebar. - Project Vibrancy now emits
stub_tested,suspicious_coverage, andtest_driftper function with summary counts in JSON, the sidebar, and the full report, plus optional--max-stub-tested,--max-suspicious-coverage, and--max-test-driftCI gates. No action required unless you adopt those gates in automation. - Related-rule guidance is now available end-to-end via exported data (
config.relatedRulesByRule/config.ruleMetadataByRuleinviolations.json, plusconsumer_contract.json), extension surfaces (Violations/Issues tree hovers with See also: related rules, Rule Explain links, Suggestions), and init post-write hints so users can discover complementary rules faster without manual lookup. No action required. - The VS Code extension now exposes cross-file analysis commands (unused files, circular dependencies, import stats, DOT graph export, and HTML report) with command-catalog and walkthrough discoverability, so CLI-only cross-file features are usable from the UI. No action required beyond updating the extension and running the new
Saropa Lints: Cross-File — ...commands. - Cross-file CLI now includes
feature-depsoutput that reports feature-to-feature adjacency and concrete cross-feature import edges forlib/features/<name>/...projects, so architecture boundary drift is visible without custom scripts. No action required unless you want to consume the newfeatureDependencies/crossFeatureImportsfields from JSON output. - Cross-file CLI now includes a first-pass
unused-symbolsmode that reports likely unused top-level declarations across project files, so teams can identify dead public code quickly before deeper cleanup passes; use--exclude-public-apito skip exported lib files and--include-privateto widen detection. No action required unless you want to run the new command and review candidates. - The VS Code extension cross-file command set now includes feature dependency and unused symbol actions in addition to file/cycle/stats/graph/report, so new cross-file CLI capabilities stay discoverable in the command palette, walkthrough, and command catalog. No action required beyond updating the extension and running the added
Saropa Lints: Cross-File — ...commands. - Cross-file CLI now includes a first-pass
dead-importsmode for likely dead relative imports, with extension command support, so teams can spot stale local imports during architecture cleanup without custom scripts; later bullets in this section add combinator imports, local re-export awareness, and deferredloadLibrary()handling on top of the first pass, while full analyzer-accurate symbol resolution remains future work. No action required unless you want to run the new command and review candidates. - Cross-file
dead-importsdetection now understands aliased and combinator imports (as/show/hide) in its first-pass heuristic, so cleanup results are more accurate on common Dart import patterns without needing analyzer-level symbol resolution. No action required. - Cross-file CLI now includes a first-pass
watchmode that re-runs analysis on Dart file changes with configurable debounce and command targeting, so teams can iterate on architecture checks without manually re-running commands after each edit. No action required unless you want to usewatchwith--commandand optional--watch-debounce-ms. - Cross-file
watchmode now prints per-rerun delta summaries (new vs resolved finding sets forunused-files,circular-deps,feature-deps,dead-imports, andunused-symbols, or per-rerunimport-statsfile/total-import count deltas), so ongoing edits are easier to track than re-reading full output each time. No action required. - Cross-file text reporting now includes a feature dependency matrix view alongside adjacency listings, so boundary relationships are easier to scan visually in terminal and CI logs without post-processing. No action required.
- Added
tool/cross_file_benchmark.dartto run repeatable cross-file performance benchmarks on synthetic 1000+-file projects, so maintainers can measure analysis throughput and compare optimization changes with a consistent harness. No action required unless you want to run benchmark checks locally or in CI. - Cross-file
dead-importsnow understands local file re-exports when determining whether imported symbols are referenced, so barrel-file import patterns are less likely to be misreported as dead imports in the first-pass heuristic. No action required. - Cross-file
dead-importsnow treats deferred imports as used when their prefix is used to callloadLibrary(), reducing false positives in lazy-loading patterns while semantic resolution work continues. No action required. - Package Vibrancy now persists per-package score snapshots in workspace-local history and renders inline sparklines in the report so users can see score direction at a glance without external tracking. No action required.
- Package Vibrancy now auto-exports Markdown and JSON reports after each successful scan, so report files are always available without manual export clicks; set
saropaLints.packageVibrancy.autoExportReportsOnScantofalseif you prefer manual-only exports. No action required unless you want to disable auto-export. - Package Vibrancy now runs a one-time historical backfill from existing vibrancy JSON report files with visible progress and completion messaging, so long-time users get trend sparklines without manually rebuilding history. No action required.
- Rule metadata now ships in analysis export output (
ruleMetadataByRulein config and per-violation metadata) with summary breakdowns byruleTypeandruleStatus, so downstream tooling can build metadata-aware reports and gates without re-parsing rule classes. No action required unless you consumeviolations.json, in which case the new fields are available immediately. - Violations view now supports metadata-driven workflows with Summary drill-down and direct toolbar filtering by rule metadata (
ruleType/ruleStatus), so users can isolate vulnerability/hotspot/beta clusters in one click instead of hand-curating rule lists. No action required. - Security hotspots now have a persisted review workflow (
open,reviewed-safe,reviewed-fixed) with Issues actions and Summary/Overview progress counts, so teams can track triage completion across scans without external spreadsheets. No action required unless you want to start recording hotspot review state from the Violations context menu. - Rule Packs now include SDK-gated packs (
dart_sdk_3_2,dart_sdk_3_4,flutter_sdk_3_0,flutter_sdk_3_7,flutter_sdk_3_10,flutter_sdk_3_16,flutter_sdk_3_18,flutter_sdk_3_19,flutter_sdk_3_22,flutter_sdk_3_24,flutter_sdk_3_28,flutter_sdk_3_29,flutter_sdk_3_32,flutter_sdk_3_35,flutter_sdk_3_38) driven by pubspecenvironmentconstraints, so migration packs can be suggested/enabled by target SDK level instead of only dependency names. No action required unless you want these packs, in which case add them underplugins.saropa_lints.rule_packs.enabled. dart run saropa_lints:init --emit-composite-plugin-scaffold [dir]writes a minimal composite analyzer-plugin package (Saropa registrars + hook for your rules) so orgs can wire a singleplugins:key without hand-authoring boilerplate from scratch; the VS Code extension exposes the same flow as a command (see Added (Extension)). No action required unless you are building a meta-plugin, in which case use the command or flag and followdoc/guides/composite_analyzer_plugin.md.- The repo now includes
saropa_lints_api(packages/saropa_lints_api/), a thin re-export ofregisterSaropaLintRulesand the Saropa YAML loaders for composite plugins that prefer a small dependency surface. No action required unless you maintain a meta-plugin, in which case you may depend onsaropa_lints_apiinstead of importingsaropa_lintsdirectly.
Added (Extension) #
- Saropa Lints: Create Composite Analyzer Plugin (scaffold) is available from the command palette and from Saropa Lints → Config (sidebar), prompting for a workspace-relative output folder and running the same scaffold as
dart run saropa_lints:init --emit-composite-plugin-scaffold, so composite meta-plugins do not require CLI-only setup. No action required unless you are building a meta-plugin, in which case use the command and followdoc/guides/composite_analyzer_plugin.md.
Changed #
- Cross-file
unused-symbolsnow uses the Dart analyzer to resolve references (with automatic fallback to the prior regex heuristic if resolution fails), so type annotations and constructor type names count as real uses instead of being misreported as unused. No action required unless you need the old behavior, in which case pass the heuristic-only flag shown indart run saropa_lints:cross_file --help. - Extension UX now promotes a dedicated Config Dashboard plus Triage naming, default-on Dashboard/Package Vibrancy sidebar sections, and direct open commands, so users can reach configuration and dependency-health surfaces without hunting through tree views. No action required.
- Config Dashboard rule-pack UX now includes staged SDK rollout controls (all, breaking-only, deprecation-only), risk-first SDK grouping/badges, and a confirmation prompt before bulk enablement, so teams can adopt migration packs incrementally with less accidental churn in
analysis_options.yaml. No action required beyond using the new SDK rollout actions. - Violations grouping now includes
Rule TypeandRule Statusin addition to Severity/File/Impact/Rule/OWASP, so teams can pivot directly by semantic class and lifecycle state during triage. No action required. - Rule-pack config parsing now tolerates quoted ids, inline comments, and spacing variations while preserving legacy
migration_packsread compatibility and normalizing writes to canonicalrule_packs, so mixed/older configs keep working and converge automatically; if your config still usesmigration_packs, run init or toggle any Rule Pack once to rewrite it. No action required for already-canonicalrule_packssetups. - Rule-pack ownership is now authoritative over tiers: every rule code assigned to any registered rule pack (library packs such as Bloc/Dio/Firebase, SDK-gated migration packs, and similar) is subtracted from tier-derived enables first, then only re-enabled when its pack is listed under
plugins.saropa_lints.rule_packs.enabled, so pack toggles control those diagnostics instead of tier defaults alone. Action required if you relied on tier-only activation for any pack-listed rule—enable the corresponding packs to restore those lints. - Package Vibrancy now surfaces a dedicated Activity grade (A-F) based on both recent commits and release cadence across table, hover, and detail surfaces, so users can distinguish "quiet but active" packages from genuinely dormant ones at a glance; review Activity badges and dormancy hints in the report when triaging dependencies. No action required.
- Suppression tracking now surfaces as a dedicated extension sidebar section with by-kind/by-rule/by-file drilldown, includes suppression-rate context in Overview, and is reflected in export/governance outputs so teams can audit ignored diagnostics without custom tooling. No action required unless you consume report exports, in which case
summary.suppressionsis now documented for CI use.
Fixed #
avoid_money_arithmetic_on_doubleno longer treats standalonerateas a money word (so bare*Ratesuffixes such asframeRate/sampleRate/heartRateare not financial intent by themselves), while expressions that pair a money-named operand with a*Ratefactor—e.g.amount * taxRate—still trigger because identifiers likeamount/taxmatch the financial heuristics. No action required.prefer_skeleton_over_spinnerno longer reports determinateCircularProgressIndicator/LinearProgressIndicatorusage (valuenamed argument present and notnull) inside conditional UI branches, so real progress meters are not mislabeled as loading placeholders; indeterminate indicators inif/ ternary / collection-ifbranches continue to be reported (spinners not under those constructs are out of scope for this rule). No action required.prefer_layout_builder_for_constraintsnow skipsMediaQuerysize reads in non-build scopes (for example lifecycle/setup methods and callbacks without aBuildContextparameter), which removes false positives whereLayoutBuildercannot be applied while still reporting build-phase and builder-callback sizing misuse. No action required.prefer_single_ticker_provider_state_mixinnow skips State classes that hand offvsync: thisto external helpers, which prevents unsafe suggestions to downgrade toSingleTickerProviderStateMixinwhen multiple ticker consumers exist. No action required.- Rule execution profiling now records actual callback timing and exposes a stable JSON contract (
ruleName,totalMs,callCount,avgMsper rule), so CI can detect performance regressions without parsing human-formatted logs. No action required unless you are consuming timing data, in which case switch to the JSON payload. - Diagnostic statistics now support per-rule threshold gates and baseline-diff reporting in both the analysis report and
violations.json, so CI can fail on targeted rule regressions and track newly introduced violations without custom parsers. To adopt this workflow, generate a baseline withdart run saropa_lints:diagnostic_baselineand reference it underdiagnostic_statistics.baseline.fileinanalysis_options_custom.yaml. - Project Vibrancy scoring no longer crashes when LCOV coverage is missing or unreadable, when the on-disk vibrancy cache file is corrupt, or when individual
git log/git blame/git hash-objectcalls fail for a single file. The scan reports a short diagnostic and degrades gracefully (zero coverage, empty cache, missing timestamps) instead of aborting the whole run. No action required.
Maintenance
- Discussion #59 (custom suppression prefixes) is now explicitly deferred as policy-blocked in its discussion document, so contributors do not accidentally implement plugin-side custom ignore parsing under current project policy. No action required for package users.
- Added a dedicated
diagnostic-baseline-strictGitHub Actions workflow for maintainers to fail fast whenviolations.jsonis missing before baseline refresh, so strict baseline regeneration can be run independently without changing default CI behavior. No action required for package users. - Added a dedicated Project Vibrancy GitHub Actions workflow that emits a JSON artifact on pull requests that touch Project Vibrancy sources (see workflow
paths:filters) and onworkflow_dispatchmanual runs, so maintainers can inspect code-health snapshots from CI without running the CLI locally. No action required for package users. - Added sidebar UI-state regression checks for Project Vibrancy scope badge/count and persisted filter wiring, so future extension refactors are less likely to silently break the primary filtering flow. No action required for package users.
- Removed many tautological
isNotNullexpectations on guaranteed-non-null rule metadata strings in package tests (CI already enforces stub integrity), preserving rule instantiation, fixture checks, and substantive assertions such as fix metadata and AST-backed tests. No action required for pub.dev or Marketplace users.
12.6.1 #
More rules now ship IDE quick fixes for repetitive, low-risk edits (secure URL schemes, image and HTTP/Firestore/Drift call shapes), so you can apply the suggested remediation from the lightbulb menu instead of typing boilerplate by hand. Update the package and re-analyze to see new fix actions where diagnostics already appear. log
Added #
require_image_error_builder,require_image_dimensions,require_placeholder_for_network,require_https_over_http, andrequire_wss_over_wsgain quick fixes that insert a minimalerrorBuilder, placeholderwidth/height, a loading/placeholder callback, or rewritehttp:///ws://prefixes where the rule already fires, so common widget and URL hygiene fixes are one action in the IDE. No action required beyond updating and using the fix when offered; adjust inserted dimensions to your layout.require_websocket_error_handlinggains a quick fix that appends a stubonErrorargument to flaggedlistencalls so you can fill in logging or reconnection logic without retyping the signature. No action required beyond updating and using the fix when offered.incorrect_firebase_parameter_nameoffers a quick fix that rewrites hyphenated Analytics parameter keys to underscores when that alone satisfies Firebase’s naming rules, so commonitem-idstyle keys becomeitem_idin one step. No action required beyond updating and using the fix when offered; reserved-prefix violations still need a manual rename.avoid_firestore_unbounded_queryoffers a quick fix that insertslimit(100).before.get/.snapshotson flagged collection chains so you can cap reads without manually editing the method chain. Review the chosen limit for your product before shipping. No action required to adopt beyond the package update.prefer_timeout_on_requestsandrequire_request_timeoutoffer quick fixes that append.timeout(const Duration(seconds: 30))after the flagged HTTP client call when the rule applies, matching the documented remediation pattern. Tune the duration in code if 30 seconds is not right for your endpoints. No action required beyond updating and using the fix when offered.avoid_drift_enum_index_reorderoffers a quick fix that renamesintEnumtotextEnumon flagged Drift column builders so you can switch to name-backed enum storage in one step; you must still migrate existing stored ordinals and adjust relatedTypeConvertercode the rule flags separately. No action required beyond updating and using the fix when offered.
12.6.0 #
New recommended-tier migrations cover Flutter scrollbar theme lookup and several Dart 3.2 dart:js_interop signature changes. The interop rules only fire when the real SDK library is resolved, so local types or extensions that reuse the same names should stay quiet, and outdated .toDart chains are still caught when the bool result is cast through dynamic first. log
Added #
prefer_scrollbar_theme_ofguidesScrollbarTheme.of(context)instead ofTheme.of(context).scrollbarThemeso inherited scrollbar themes are not skipped. No action required until you enable or adopt the recommended tier.avoid_legacy_jsboolean_return_assumptions,prefer_string_for_typeof_equals, andprefer_int_for_jsarray_with_lengthtarget Dart 3.2dart:js_interopchanges aroundtypeofEquals,instanceof, andJSArray.withLength. No action required until you enable or adopt the recommended tier.
Fixed #
avoid_legacy_jsboolean_return_assumptions,prefer_string_for_typeof_equals, andprefer_int_for_jsarray_with_lengthno longer treat unresolved elements or same-named user declarations asdart:js_interop, which removes false positives in mock-heavy code while keeping real interop call sites covered. No action required.
12.5.4 #
This release tightens a noisy repeated-map-lookup lint that could still report in code where extraction was not actually appropriate. The rule now stays out of assignment/update patterns and avoids conflating similarly named variables across different scopes when type resolution is ambiguous. If you were seeing stubborn false positives in loop-heavy or shadowed-variable code, those should now be gone. log
Fixed #
prefer_extracting_repeated_map_lookupnow hard-skips write contexts ([]=, compound assignment, and increment/decrement), only buckets map-like targets with resolved elements, and refuses unresolved target bucketing, which prevents lingering false positives in shadowed/sibling scopes and mixed read+write loops that users could not safely "extract" anyway. No action required.- Diagnostics from the same rule at the same file offset are now deduplicated in reporter emission paths, which reduces duplicate warnings when multiple AST callbacks converge on one location while preserving distinct reports at different offsets or from different rules. No action required.
12.5.3 #
This release focuses on reducing high-noise false positives in common Flutter patterns so teams can keep strict lint settings enabled without fighting the tool. Several rules now better distinguish real risks from valid callback, const-context, lifecycle, and helper-ownership code. You should see cleaner results in existing codebases with fewer diagnostics that require no meaningful code change. log
Fixed #
avoid_setstate_in_buildno longer fires onsetStatecalls inside event-handler closures (onTap:,onPressed:,onChanged:,Future.then, etc.) passed duringbuild(), since those closures are stored as callbacks and invoked later — not synchronously during the build pass. Genuine inlinesetStatecalls inbuild()are still reported. No action required.avoid_opacity_animationno longer fires on anOpacitywidget whoseopacity:argument is a constant numeric literal, even when it sits inside anAnimatedBuilderthat drives a sibling property (icon swap, color, layout). A constant value cannot animate, so the rebuild cost the rule targets does not exist; replacing it withFadeTransitionwould introduce flicker. Genuine animation-driven opacity expressions still warn. No action required.prefer_const_literals_to_create_immutablesno longer fires on collection literals whose enclosing constructor is alreadyconst(explicitly or via const context). The Dart language auto-promotes inner literals in that case, so adding an explicitconstwould be redundant and trigger the standard analyzer'sunnecessary_const— leaving the user with no valid resolution. Genuine cases (non-const parent with all-const elements) still warn. No action required.require_database_closeno longer fires on opener helpers whose lifetime is owned by their caller — methods namedinit*/_init*/open*/_open*/setup*/_setup*that returnFuture<bool>/Future<void>/bool/void. A success-flag return signals the helper hands control back to a caller that closes intry { … } finally { close(); }, the standard pattern for background-isolate / WorkManager / migration setup. Methods returning a connection (Future<Database>etc.) still warn because the return type transfers ownership. No action required.prefer_extracting_repeated_map_lookupno longer fires on assignment targets (map[key] = value,map[k] += 1) — those cannot be hoisted into a local since the assignment must remain on the map. The rule also stops conflating same-spelled variables in different scopes:cache[uuid]written inside three sequentialforloops, each declaring its ownuuid, is three independent lookups and is no longer flagged. No action required.require_clipboard_paste_validationno longer fires on reusable paste helpers that hand the pasted string to a callback parameter (callback.call(text),onPaste?.call(text),(callback)(text)) — those helpers have no semantic context to validate against, so the security boundary lives at the caller, not the paste site. Genuine cases (clipboard text written directly into a field with no validation regex nearby and no callback dispatch) still warn. No action required.use_setstate_synchronouslyno longer fires on asetStatethat lexically precedes the firstawait, even when both calls live inside a single compound statement (try,if,for,switch). Previously the rule treated any nestedawaitas if it preceded everysetStatein the enclosing block — which broke every codebase that wraps method bodies in mandatorytry { … } on Object catch (e, st) { … }blocks. The rule now tracks the await position andif (!mounted) return;guard scope in source order across nested blocks. No action required.
Maintenance
- Archived the resolved
avoid_opacity_animationconstant-opacity false-positive report underplan/history/2026.04/2026.04.26/and removed it frombugs/. No action required for package users.
12.5.2 #
This release is a quality pass aimed at precision: fewer accidental matches, fewer environment-related false alarms, and better handling of real-world project layouts. Notification, animation, platform-import, and permission checks now behave more predictably in production-style code. Most users only need to update and re-run analysis to get quieter, more actionable output. log
Fixed #
require_intl_plural_rulesnow treats comparisons to the integer literal 1 only when that digit is not part of a longer numeral, so helpers that branch on values like 12 or 100 (12-hour labels, build bands, and similar) are not misclassified as manual plural logic. No action required.- Long-task name matching for the
dbProcessAll…skip inrequire_notification_for_long_tasksno longer trips the package's ownavoid_string_substringrule, sodart analyze --fatal-infosstays clean for contributors building the package from source. No action required for end users. avoid_excessive_rebuilds_animationnow only considersAnimatedBuilderandListenableBuilderwhen the listenable resolves to anAnimationsubtype, soFutureBuilder,StreamBuilder,ValueListenableBuilder, and non-animation listenables no longer get a misleading “every frame” warning. No action required.require_notification_for_long_tasksnow matches long-operation tokens on camelCase boundaries (so names likeImportAllowedno longer hitimportAll), skipsdbProcessAll…DB helpers, skips the whole file when common in-app progress or notification-plugin strings appear, and splits example fixtures so BAD cases are not suppressed by GOOD escape hatches in the same file. No action required.- Rules that read
Info.plistthrough the shared helper now re-read when the file’s size or modification time changes, match keys with whitespace-tolerant XML checks, and normalize analyzerfile:URIs to OS paths, sorequire_image_picker_permission_iosno longer false-positives onceNSCameraUsageDescriptionis present. No action required. require_image_picker_permission_androidnow readsAndroidManifest.xmllike the iOS camera rule readsInfo.plist, so it stays silent whenandroid.permission.CAMERAis already declared; it also coverspickVideoas well aspickImageforImageSource.camera. No action required.avoid_platform_specific_importsand sibling rules that consultProjectContext.hasWebSupportnow run that check while visiting each library, so Flutter projects without a rootweb/directory are correctly treated as non-web anddart:ioimports stop false-alarming there; pure Dart packages still get web-portability warnings by default. No action required.prefer_layout_builder_for_constraintsno longer double-reports onMediaQuery.of(context).size.width/.height, skips intentional screen fractions and numeric breakpoint comparisons, documents whenMediaQuerysizing is appropriate, and treatsMediaQuery.sizeOf(context).width/.heightlike the.of().size.*pattern. No action required.
Maintenance
- Archived the closed
require_notification_for_long_tasksforeground false-positive report underplan/history/2026.04/2026.04.26/and removed it frombugs/. No action required for package users. - Archived the resolved
avoid_excessive_rebuilds_animationfalse-positive report underplan/history/2026.04/2026.04.26/and removed it frombugs/. No action required for package users. - Archived the resolved
prefer_layout_builder_for_constraintsfalse-positive report underplan/history/2026.04/2026.04.26/and removed it frombugs/. No action required for package users.
12.5.1 and Earlier #
Looking for older changes? See CHANGELOG_ARCHIVE.md for versions 0.1.0 through 12.5.1.