saropa_lints 13.7.1
saropa_lints: ^13.7.1 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.7.1 Unreleased #
Fixed #
avoid_string_substringno longer fires on indexOf-guarded, loop-bounded, or early-exit-guarded substring calls — the rule now recognizeswhile/forloop conditions, precedingif (idx == -1) returnguards, and if-conditions that reference substring arguments as evidence of bounds safety. No action required.- Analyzer v9
useDeclaringConstructorsAstcrashes resolved — all.namePart.typeNameaccesses (132 sites) and.namePart.typeParametersaccesses (4 sites) now use safenameToken/nameTypeParametersextensions that fall back to the pre-gate.name/.typeParametersAPI; additionally,_wrapCallbacknow catchesUnsupportedErrorglobally so any remaining gated property on any analyzer version skips the rule gracefully instead of crashing the plugin. Closes the remaining failures reported in #224. No action required.
Fixed (Extension) #
- Regression-nudge toasts no longer stack during slow linting — when the analyzer writes partial results over several seconds the score can cross multiple thresholds downward, previously firing a separate notification for each; now the nudge debounces for 3 seconds and shows only the worst threshold crossed. No action required.
Maintenance
- Ran
dart pub getinpackages/saropa_lints_api/to resolve missingtestdependency; added source comment noting sub-package requires its own dependency resolution. - Tracked
reports/organize_reports.pyin git by switching.gitignorefrom directory-level to content-level ignore with a negation rule; also addedexample*/reports/to.gitignoreso generated report output under example directories stays untracked.
13.7.0 #
The VS Code extension dashboard is now fully internationalized, and two analyzer-facing bugs are fixed — a false positive on Face ID rules when the plist key was already present, and a crash on projects running analyzer v9.
Changed (Extension) #
- Dashboard i18n: remaining webview strings routed through runtime keys — Code Health, Config Dashboard suppressions strip, Lints Config mirrors, Related Rule Telemetry, sidebar layout panel, and Security Posture tree now resolve all user-facing text through
l10n()instead of hardcoded English literals; locale files regenerated for all 24 shipped locales. No action required. - Language picker: reload prompt and multilingual discoverability — changing the UI language now prompts to reload the window (manifest NLS labels like sidebar and command titles require a VS Code reload to take effect); the command palette entry shows the word "Language" in five languages so non-English speakers can find it; the "Auto" option shows which locale it resolves to. No action required.
Fixed #
- Analyzer v9
useDeclaringConstructorsAstcrash — all 335+.body.memberscall sites now use safebodyMembers/bodyConstantsextensions that fall back to the pre-declaring-constructors API when the gate throws; projects onanalysis_server_plugin ^0.3.4withanalyzer 9.xcan rundart analyzewithout the plugin crashing. No action required. require_ios_face_id_usage_descriptionfalse positive when Info.plist key is present — the rule's early-return guard failed to locate the project root when the analyzed file was resolved via a non-filesystem URI scheme (package:,dart:, etc.), causing the guard to fall through and fire on everyLocalAuthenticationcall site even whenNSFaceIDUsageDescriptionwas already configured; URI handling and Windows path normalization inInfoPlistCheckerare now robust. No action required.
Maintenance
- **Runtime i18n function renamed `t()` → `l10n()`** — the translation lookup function in `runtime.ts` is now `l10n()` for clarity; all 492 call sites updated. No action required unless you import `t` from `src/i18n/runtime` in a fork.13.6.0 #
This release improves how you steer large findings lists and repeat searches across sessions (multi-key sort, bulk JSON copy, and workspace-persisted recents). It tightens RTL behavior for stack toggles, adds cross-file CLI defaults you can commit in analysis_options.yaml, gives IDE troubleshooting clearer native-plugin-first guidance, and ships a verify-nls-keys check for Marketplace manifest parity. Score and dashboard consistency improvements from earlier work remain in place. log
Changed (Extension) #
- Findings Dashboard consistency and run UX — score/toast regression nudges now use the same visible-findings basis as the dashboard (ending stale-history vs dashboard-empty mismatches), and the dashboard now shows an in-panel progress bar with duplicate-click guard plus an automatic full refresh after analysis completes; no action required.
- Findings triage ergonomics — you can Shift+click a second column header as a tie-breaker (labeled ① / ②), checkbox-select multiple findings, and copy the selection as JSON; large tables defer off-screen row work via
content-visibilityso scrolling stays smoother; recent text-filter queries now persist per workspace across reloads alongside the Known Issues catalog and Command Catalog search popovers; no action unless you routinely clear Workspace State intentionally. - Lints Config pack toggles RTL — the enable switch knob now tracks right-to-left layouts using logical positioning so the knob lands on the expected side; reload the dashboard if you switched UI direction mid-session; no YAML change needed.
- Manifest localization guard —
npm run verify-nls-keys(underextension/) asserts every%…%placeholder fromextension/package.jsonresolves inextension/package.nls.json, catching missing English strings before Marketplace packaging; contributors should run it after editing contributed labels or command titles. - More shipped UI locales filled —
package.nls.*andsrc/i18n/locales/*now include machine-translated copy forbn,fa,fil,he,id,pl,sw,th,tr,uk, andvi(plus corrections forde,nl, andrudependency-count wording); regenerate withSAROPA_I18N_MACHINE_TRANSLATE=1if you fork strings. Hebrew uses Google target codeiwin the generator. - Package Vibrancy freshness vs tree — new-version toasts patch the last scan so the tree and dashboard match the toast, rewrite the workspace startup fingerprint with that snapshot so VS Code reloads before the next full scan still show those versions, and reuse the last dependency graph for lightweight republish; no action required beyond normal Package Vibrancy use.
Changed #
- Cross-file CLI project defaults —
dart run saropa_lints:cross_file …merges optionalsaropa_lints_cross_filesettings fromanalysis_options.yaml(shared excludes and heuristic/analysis toggles), with explicit CLI flags still applied on top; add that map once per repo if you reuse the same exclusions between engineers and CI; no Dart source change beyond refreshing config when adopting it. - Additional quick fixes —
avoid_redundant_semantics,require_baseline_text_baseline, andavoid_unconstrained_dialog_columnnow offer IDE fixes (remove redundantSemanticsaround anImagethat already hassemanticLabel, inserttextBaselinewhen using baseline cross-axis alignment, and addmainAxisSize: MainAxisSize.minforColumninside dialogs); apply only where the suggestion matches intent; no config change.
Maintenance
- Contributor planning docs — assorted
plans/*.mdchecklists (quick-fix, testing/release, stub tests, localization guide, severity follow-ups, cross-file CLI, UX backlog, rule-pack migration, comment coverage) were refreshed for clearer sequencing and sign-off trails; docs only, no shipped rule or extension behavior beyond what is listed under### Changed (Extension)above. - Maintainer tooling — the quick-fix audit script prints a stdout summary before writing the dated report file, and the bundled quality-gate example YAML documents recommended
new_*metrics with legacy-alias notes; no action unless you vendor that sample into your own CI gate. - Comment coverage CLI — the worst-files table uses an L/C column (physical lines per comment line, higher means sparser) instead of a percentage so maintainers spot thin files faster when running the comment-coverage script locally.
13.5.0 #
This release restores real compatibility for analyzer 9 consumers, including Flutter-stable setups that cannot move to analyzer 12+ yet. The plugin and CLI now build cleanly instead of failing during startup due to missing analyzer APIs, so projects pinned to analyzer 9 can run dart analyze again with current saropa_lints. log
Fixed #
- Analyzer 9 compatibility — analyzer-version shims now backfill API gaps (
lowerCaseName, constructor/extension-type accessors, and registry deltas) so saropa_lints compiles and runs on analyzer 9 instead of crashing during plugin bootstrap; no action required beyond upgrading. - Rule AST compatibility — extension/constructor rule paths now handle analyzer-9 node shapes (nullable extension bodies, primary-constructor availability, and member traversal) so previously failing rule files compile and execute consistently; no action required beyond upgrading.
- CLI bootstrap on older analyzers — CLI entrypoint shebang handling was corrected so command wrappers no longer fail parsing before imports on analyzer-9 toolchains; no action required beyond upgrading.
13.4.9 #
This release smooths language and notification behavior in the extension. UI language selection now saves reliably, and score-milestone feedback is quieter during cleanup work. Translation strings for the picker are now complete across shipped locales, so language switching feels consistent. log
Fixed (Extension) #
- Pick UI language — choosing a language no longer fails with "Unable to write to Workspace Settings … not a registered configuration"; the picker now saves
saropaLints.uiLanguageto User settings so the choice applies reliably across workspaces. No action required — pick your language again if a previous attempt failed.
Changed (Extension) #
- Health score milestones — crossing an upward band (50–90) now shows a short status-bar message instead of an information notification, so steady improvement does not spam the notification center. No action required.
- Pick UI language — the quick pick and sidebar UI language row list each language in native script with the English name in parentheses (except English), so the list is readable in the language itself and still easy to cross-reference for maintainers. No action required.
- Runtime locale catalogs —
uiLanguage.pick.*strings (quick pick title, placeholder, and Auto row) are translated in every shippedextension/src/i18n/locales/<locale>.json, with matching phrase keys inextension/scripts/i18n/dictionaries.pysogenerate_locales.pykeeps them after regeneration. No action required. - UI language scope (docs) —
extension/scripts/i18n/README.mdnow states explicitly that User settings are the intended scope so one language applies across all workspaces; per-workspace overrides remain out of scope unless product requirements change. No action required.
Maintenance
- Publish workflow —
scripts/publish.py/ extension packaging: US English spelling check skipsextension/scripts/i18n/(translation data, not US-maintained prose); optional regeneration ofpackage.nls.<locale>.jsonand runtime locale JSON from English sources before compiling the VSIX. No action required for package consumers.
13.4.8 #
This release adds first-class localization support to the extension UI and introduces a direct language picker workflow. It also fixes a lingering package-size chart issue so visual weighting matches real values. If you use translated UI strings or the vibrancy chart, this is the reliability pass for both. log
Added (Extension) #
- Localization framework — contribution strings in
package.jsonnow resolve throughpackage.nls.json, with generatedpackage.nls.<locale>.jsonfiles for additional languages. Shared webview strings live underextension/src/i18n/with a runtime locale picked from VS Code's display language orsaropaLints.uiLanguage. - Pick UI language — new command and prominent Actions row to switch language; open dashboards refresh automatically so you can verify translations without reloading the window.
Fixed (Extension) #
- Size Distribution chart now actually renders each bar at a length proportional to its share of total size. The fix shipped in v13.4.6 didn't take effect in the live webview and v13.4.7 didn't carry a re-fix, so bars kept rendering at the full track width across both releases; this release switches to the same CSS pattern the Findings Dashboard's bar charts have used reliably for months. No action required — reopen the report after updating.
13.4.7 #
Package Vibrancy no longer launches a fresh scan after every individual pub upgrade. The watcher now waits for a whole upgrade session to settle, runs at most one scan at a time, and skips when pubspec.lock has not actually changed — the overlapping toasts and slowdown when upgrading several packages in a row are gone. The Package Dashboard webview also stops looking like a "dead page" during the very first scan: instead of the empty-state grade-E gauge with zero rows it now shows a clear "Scan in progress" placeholder, and the open panel auto-refreshes when the scan finishes.
Changed (Extension) #
- Package Vibrancy — the file-system watcher now debounces
pubspec.lockchanges by 30s (was 5s) so a session of back-to-backpub upgradecalls collapses into a single trailing scan instead of starting a fresh ~60s scan after each individual upgrade. Previously the abort-on-supersede pattern still left earlier scans running to completion (their HTTP fetches don't honor the abort signal), so three sequential upgrades produced three overlapping toasts and heavy CPU/network contention. No action required. - Package Vibrancy —
runScannow coalesces concurrent invocations: if a scan is already in flight, a second call stashes its options and the in-flight scan launches exactly one trailing scan when it finishes. Callers no longer stack parallel scans, andforceRefresh: trueis sticky across coalesced calls so a "Rescan (clear cache)" click is honored even when it lands during a watcher-triggered scan. No action required. - Package Vibrancy — the watcher now hashes
pubspec.lockagainst the persisted last-scan fingerprint and skips when bytes are unchanged.pub getagainst an unchanged tree, git operations that restore the same lock, and IDE auto-resolve no longer trigger a wasteful full rescan. No action required.
Fixed (Extension) #
- Package Dashboard — the webview now shows an explicit "Scan in progress" placeholder when opened during the first scan instead of the empty dashboard with
Grade E · 0/100, an empty radial gauge, and an empty table. Users were reading the empty-state render as a broken or failed scan. No action required — open the dashboard while a fresh scan is running to see the new placeholder. - Package Dashboard — the open dashboard panel now auto-refreshes when a scan completes. It used to be built once from
latestResultsand never re-render itself, so users who opened it during a scan stayed on stale or empty data until they manually reran the "Show Report" command. No action required.
13.4.6 #
This release fixes two high-friction issues users hit during normal analysis work: the Package Vibrancy size chart now renders proportionally, and tier YAML version pinning no longer breaks analyzer-plugin resolution on newer analyzer stacks. In practice, charts are readable again and analysis setup is less likely to fail after upgrades. log
Fixed (Extension) #
- The Size Distribution chart in the Package Vibrancy report now renders each bar at a length proportional to its share of total size. The earlier attempt to fix this didn't take effect in the VS Code webview, so bars kept rendering at the full track width; bars now use the same width-and-grow pattern the Findings Dashboard charts already use reliably. No action required — reopen the report after updating.
Fixed #
lib/tiers/{essential,recommended,professional,comprehensive,pedantic}.yamlno longer pin the embedded plugin to the old^5.0.0-beta.8constraint that's been frozen since Feb 2026. The Dart analyzer's plugin manager fetches that constraint into a synthetic project under.dartServer/.plugin_manager/<hash>/and runspub upgradeagainst it — with the stale pin, anyone whose project also depends on a package requiring a newer analyzer (e.g.riverpod_lint ^3.1.3requiringanalyzer ^9.0.0) haddart analyzeabort with "An error occurred while setting up the analyzer plugin package". The yamls now ship^13.0.0, which resolves cleanly against the current analyzer range, and the publish script keeps them in sync withpubspec.yamlon every major bump so they can't drift again. Reported as #216. No action required after upgrading; consumers usinginclude: package:saropa_lints/tiers/<tier>.yamlwill start resolving cleanly on the nextpub get.
Maintenance
- New module
scripts/modules/_tier_yaml_version.pyrewrites the saropa_lintsversion:line in eachlib/tiers/*.yamlat publish time, anchored to the current major frompubspec.yaml. Runs inside the existing "Version sync" step so the change ships in the same publish commit as the version bump. 13 unit tests pin the contract — major-only widening, idempotent re-runs, CRLF preservation, and no false-matches against unrelatedversion:keys.
13.4.5 #
This release reduces false positives in command-line and tooling code paths. Rules that make sense for Flutter UI threads no longer fire on scripts under tool/, so local utility scripts and generators stop producing noisy warnings. It keeps lint signal focused on code where the risk model actually applies. log
Fixed #
avoid_blocking_main_thread(and other UI-thread rules) no longer fire on scripts undertool/— repo-local CLI utilities run viadart runand never execute on a Flutter UI isolate, so sync I/O is legitimate there. Mirrors the existing skip forbin/. No action required.
Maintenance
tool/rule_pack_audit.dartandtool/generate_rule_pack_registry.dart—applyCompositeRulePacksnow returns a new map instead of mutating its argument, clearing theavoid_parameter_mutationlint. Both call sites updated to consume the returned map. No change to extracted pack contents or generator output.- Plugin self-source
analysis_options.yamlexcludestool/**belt-and-braces, matching the existingbin/**exclusion. The cached plugin snapshot lags local edits toSaropaContext.isCliToolScript, so the host-level exclude preventsdart analyzenoise during the cache rebuild window.
13.4.4 #
This release expands quick-fix coverage and hardens extension update-check behavior. More rules now have one-step IDE fixes, and upgrade notifications break through stale dismiss windows when a new version is actually available. For day-to-day users, that means faster cleanup and fewer “why didn’t I get prompted?” moments. log
Added #
- Quick fix coverage extended to ten more rules (Batch 13). Each rule now offers a one-step IDE correction so the lint can be cleared without manual edits — no action required if you already had these rules enabled. The newly-fixable rules are
prefer_raw_strings,prefer_period_after_doc,format_comment_style,prefer_const_border_radius,prefer_const_widgets_in_lists,avoid_redundant_async_on_load,avoid_single_cascade_in_expression_statements,avoid_escaping_inner_quotes,avoid_types_on_closure_parameters, andprefer_expression_body_getters.
Fixed (Extension) #
- Upgrade-check throttle now lets a newly-published
saropa_lintsversion break through the dismiss memory immediately instead of being suppressed for up to 24 hours. The previous gate was a single 24h timer, so a release published the morning after a dismiss stayed invisible until that timer elapsed; the gate is now a 1-hour anti-thrash window combined with a per-version dismiss memory, so a new pub.dev version always re-prompts even within the same day. Legacy state self-heals on the next write — no user action required.
Maintenance
- Removed two orphan extension commands —
saropaLints.config.copyAsJson("Copy Triage as JSON") andsaropaLints.overview.copyAsJson("Copy Overview as JSON") — that were declared inpackage.jsonand listed in the command catalog but had no runtime handler after the Triage and Overview trees were merged into Settings/dashboards. Invoking them from the palette previously failed withcommand not found; the entries are now gone. - Version 13.4.2 was bumped in
pubspec.yamlbut never tagged or published — the v13.4.3 publish run jumped past it. No 13.4.2 artifact exists on pub.dev or the Marketplace; consumers go directly from 13.4.1 to 13.4.3. scripts/modules/_version_changelog.pynow refuses to publish when any## [X.Y.Z]section inCHANGELOG.mdhas an empty body — that was the exact shape that caused the rename-collision recovery inapply_version_and_rename_unreleasedto silently skip 13.4.2 and bump straight to 13.4.3. Authors must now either delete the orphan stub or fill in its release notes before re-running publish.scripts/modules/_rule_metrics.pynow finds nested rule tests undertest/rules/{group}/, fixing the gap report that falsely listedwidget_patterns_avoid_prefer,structure,async,bloc, andperformanceas missing. The previous flattest/*_test.dartglob saw zero rule-category tests; coverage is now reported correctly (116/116 categories tested, 1095 test calls).scripts/modules/_extract_rule_messages.pynow extracts all 2165 rules instead of producing an empty JSON dump. Two bugs landed when the script was moved intoscripts/modules/: the flatglob("*_rules.dart")only matched the barrel export (zero LintCodes), and theparent.parentwalk pointed atscripts/lib/src/rules/— a non-existent path — so even fixing the glob alone would have returned zero. The CLI body is now guarded byif __name__ == "__main__":so importing the module no longer mkdirsreports/or writes a JSON file as a side effect.- Moved release notes for
12.5.2through12.6.1fromCHANGELOG.mdtoCHANGELOG_ARCHIVE.mdso the active changelog stays focused on the current13.xseries. No action required for package users. - Added file-level doc headers and per-test WHY comments to four low-coverage test files surfaced by the publish-time comment-coverage scan:
test/integrity/plan_additional_rules_21_30_test.dart,test/rules/architecture/compile_time_syntax_rules_test.dart,test/rules/core/performance_rules_test.dart, andextension/src/test/vibrancy/services/dep-graph.test.ts. Headers explain the contract under test (registration + tier + fixture invariants for the rule packs; two-output shape for the dep-graph parser) so a future reader can change a rule without first decoding what eachit()was guarding. No action required — no source, severity, tier, message, or fix changed.
13.4.3 #
Brings the Findings Dashboard back for projects whose report file was last produced by an older saropa_lints plugin — counts and the findings table agree again, no re-analysis needed. The "no analysis report" notice is also clearer: it spells out which piece of project setup is actually missing (pubspec, dev-dependency, analyzer config, or a top-level saropa_lints: key that doesn't enrol the plugin) and offers a one-click Set Up Project action for the common cases. log
Fixed (Extension) #
- Findings Dashboard no longer reads "401 findings" with an empty findings table when
reports/.saropa_lints/violations.jsonwas written by an older saropa_lints plugin (any version <13.4.x with the legacycritical/high/medium/low/opinionatedimpact vocabulary). The reader now normalizes those values to the currenterror/warning/infobuckets so the impact filter matches them. No action required after upgrading. Reported as a follow-up to #208. - The "no analysis report" notification now classifies the cause precisely — missing pubspec.yaml, missing
saropa_lintsdev-dependency, missinganalysis_options.yaml, malformed YAML inanalysis_options.yaml, or a bare top-levelsaropa_lints:key that doesn't enrol the plugin — and surfaces a one-click Set Up Project button as a modal that explicitly states configuration is required and the dashboard cannot show findings without it. The bare-key case (the issue #208 reporter's exact state) shows the validinclude: package:saropa_lints/tiers/recommended.yamlline inline so users can hand-fix without losing custom analyzer settings. The "no pubspec.yaml" and "exclude list too aggressive" cases stay non-modal — those need user judgment and Set Up Project would either be premature or clobber their customizations.
13.4.2 #
Skipped
13.4.1 #
Fixes a line-number drift in the Issues tree and the violations export where reported lines could land tens of lines away from the actual offending code on larger projects. The number now matches the squiggle in the editor again. Re-run analysis once after upgrading and the tree will refresh. log
Fixed #
- Lint violations now resolve their line number from the AST node's own compilation unit instead of a shared analyzer reference that could go stale between files or between library and part files, so the Issues tree and
reports/.saropa_lints/violations.jsonno longer drift away from the editor's squiggle on large projects. Reported as #208. Re-run analysis once after upgrading to refresh the export.
13.4.0 #
This release brings Saropa's severity counts in line with the Dart analyzer — the dashboards, sidebar, and update toasts now headline the same error / warning / info numbers as the IDE Problems tab, dropping the parallel critical / high / medium / low / opinionated vocabulary. Several rules also quiet down on common false-positive patterns, so a handful of // ignore: comments and local workarounds may no longer be needed. Squiggle tooltips read tighter — redundant "this is a critical X risk" sentences are gone. Existing CI thresholds and quality-gate configs keep working through back-compat aliases. log
Fixed #
avoid_gradient_in_buildno longer flagsLinearGradient/RadialGradient/SweepGradientconstructed inside aShaderMask.shaderCallbackclosure — that closure runs at paint time withRect boundsonly available there, so there is no "outside build()" location to hoist the gradient to (and the rule's correction message was impossible to satisfy for any animatedShaderMask). Bare gradients inbuild()and gradients nested in build-timeBoxDecorationstill fire as before. No action required — remove anydart:ui.Gradient.linearworkarounds or local suppressions you added forShaderMaskshader callbacks.require_https_onlyno longer flags'http://'literals used in search or comparison positions — needle argument toString.startsWith/endsWith/contains/indexOf/lastIndexOf/split, or operand of==/!=. Those literals are patterns being searched for or compared against, not URLs being requested, so flagging them forced rule-author and security-detection code to either reach for// ignore:or refactor literal patterns. URL construction (Uri.parse('http://...'), hardcoded HTTP endpoints, network-call arguments) still fires correctly. No action required.avoid_ios_hardcoded_status_barno longer flagsSizedBoxinstances that are clearly icon hitboxes or fixed-size containers — the rule now skips a SizedBox wheneverwidthis also set or thechildis an Icon-like widget (Icon,ImageIcon,FaIcon,CircularProgressIndicator,CupertinoActivityIndicator,Image, or any class whose name ends inIcon). Pure vertical spacers (SizedBox(height: 20|44|47|59)with nowidthand no Icon child) still lint as before. No action required — remove any local suppressions you added forSizedBox(width: X, height: X, child: Icon(...))patterns.require_data_encryptionno longer flags denormalized search-index columns whose Drift-generated field name contains "tokens" (searchTokens,lexerTokens,parserTokens,wordTokens,nGramTokens,routeTokens,cspTokens) — these are NLP / parser / routing material derived from public data, not credentials. The same fix retiresauthsubstring false positives onauthor/authority/authorship/authored/authoring(publishing & governance terms). Real credential identifiers —authToken,apiToken,accessToken,refreshToken,bearerToken,jwtToken,csrfToken,sessionToken,oauthToken,idToken,authorize,authorization,unauthorized,authentication— still match. No action required — remove any localtokens→searchIndexrenames you added to silence the rule.require_rtl_layout_supportno longer flagsAlignment.topLeft/Alignment.topRight/Alignment.bottomLeft/Alignment.bottomRight(andTextAlign.left/TextAlign.right) when they appear as the right-hand side of a switch arm whose pattern is a same-named enum constant (e.g.AlignmentOption.topLeft => Alignment.topLeft) — that shape is a physical-corner adapter whose enum API has already committed to physical-direction semantics, and converting toAlignmentDirectional.*Start/*Endwould silently flip the result under RTL. PlainAlignment.topLeftreferences and non-identity arms (e.g.MyEnum.start => Alignment.topLeft) still fire. No action required — remove any// ignore_for_file: require_rtl_layout_supportyou added to physical-corner enum mappers.require_unique_iv_per_encryptionno longer flags static fields whose initializers contain the substringIV.only inside a string literal (e.g.static const _fixKind = FixKind('...', 50, 'Use IV.fromSecureRandom(16)')). The check now walks the AST excludingStringLiteraldescendants so real IV usage (typed asIVor initialized viaIV.x(...)/IV(...)) still flags, but message strings that happen to mention theIV.token no longer trigger. No action required.avoid_string_substringno longer flagss.substring(N)calls when an enclosing if-statement or?:then-branch already proves the receiver is long enough — by callings.startsWith(...)/s.endsWith(...)on the same receiver, or by an explicits.lengthcomparison. Idioms likes.startsWith('v') ? s.substring(1) : sandif (s.startsWith('"') && s.endsWith('"')) s = s.substring(1, s.length - 1)are safe and now pass cleanly. Unguardedsubstring()calls on strings still fire as before. No action required.require_android_permission_requestno longer flags ambiguous method names (record,startRecording) when the receiver class name ends in a clearly non-audio suffix (Tracker,Logger,Tracer,Reporter,Metrics,Telemetry,Stats). Telemetry/logging idioms likeRuleTimingTracker.record(...)andMetricsLogger.record(...)no longer require permission-request scaffolding. Real audio recorders (Record,AudioRecorder,FlutterSoundRecorder) still flag because their class names don't end in those suffixes. No action required.
Changed #
- BREAKING: the
LintImpacttaxonomy collapsed from five buckets (critical / high / medium / low / opinionated) to three (error / warning / info), matching the Dart analyzer's native severity model. The mapping iscritical → error,high + medium → warning,low + opinionated → info. This affects theviolations.jsonschema (v.impactandsummary.byImpactnow emiterror|warning|info),LintImpact.values, every rule'simpactgetter, the health-score weights (error: 8, warning: 3, info: 0.25— wascritical: 8, high: 3, medium: 1, low: 0.25, opinionated: 0.05), and thebin/impact_report.dartCLI labels. Migration: external CI scripts andsaropa_quality_gate.yamlfiles keep working —quality_gateexposes back-compat aliases (new_critical_issuesreadserror,overall_high_issuesreadswarning, etc.) so existing thresholds don't need to be rewritten in lockstep with the upgrade. New code should usenew_errors / new_warnings / new_info(andoverall_*equivalents). Seeplans/COLLAPSE_LINT_IMPACT_TO_SEVERITY.mdfor the full rationale. - Lint problem messages no longer pad themselves with stand-alone "This is a critical X risk/issue/flaw." sentences. The surrounding text already names the specific harm (path traversal exposes sensitive files, missing migrations cause data loss, server-side IAP validation is mandatory, etc.), so squiggle tooltips read tighter and stop double-asserting severity. Eight rules updated:
avoid_path_traversal,require_sqflite_error_handling,require_dio_ssl_pinning,require_database_migration,avoid_instantiating_in_bloc_value_provider,avoid_webview_file_access,avoid_instantiating_in_value_provider,avoid_animation_in_build. No action required.
Changed (Extension) #
- The regression-nudge toast and the all-clear celebration now headline must-fix errors instead of a broader "critical" impact tally —
X errors — view.andNo errors!replaceX critical issues — view.andNo critical issues!. The number now lines up with the Dart analyzer's native severity (error = must fix, warning = could fail or look bad, info = FYI) so the headline count and the IDE Problems tab agree. No action required. - The Findings Dashboard now shows three severity-keyed KPI cards — Errors / Warnings / Info — replacing the prior five-card layout that mixed severity (Errors / Warnings) and impact (Critical / High). Card filters and tooltips updated to match. Drops the parallel 5-bucket taxonomy that disagreed with the IDE Problems tab and the analyzer's native severity. No action required.
- The Suggestions sidebar card, File Risk tree counts, Triage view group label, the Health Score walkthrough description, and the Triage walkthrough description now read in the three-severity vocabulary (
error / warning / info) instead of the old five-tier vocabulary (critical / high / medium / low / opinionated). The Essential tier picker description now reads "Security and must-fix errors only" instead of "Security and critical issues only". No action required.
Maintenance
- Plugin internals under
lib/src/native/andlib/src/report/now share the same self-skip path aslib/src/rules/andlib/src/fixes/, so detection rules no longer self-fire on telemetry hooks (RuleTimingTracker.record), CLI report writers (sync I/O, barePlatform.is*), or fix-class string literals ('Use IV.fromSecureRandom(16)'). Removes ~30 self-firing diagnostics observed in VS Code, which analyzes opened files directly and bypassesanalyzer.exclude. No user-visible behavior change. ReportConsolidatorbarecatchclauses (5 sites: session init, cleanup, stale-session sweep, batch read, directory list) are nowon Object catch (e, st)to match theavoid_catch_allrule's recommended form — fatal VM errors (OutOfMemoryError,StackOverflowError) propagate instead of being silently logged. No user-visible behavior change.- Internal dogfooding cleanups:
SaropaContext._timingEnablednow passes explicitdefaultValue:arguments tobool.fromEnvironment/String.fromEnvironment(resolves fouravoid_string_env_parsingself-hits and makes the off-by-default intent explicit), and the_LintImpactNumeric.numericValueswitch inImportGraphTrackerno longer carries duplicateLintImpact.warning/LintImpact.infoarms (dead copy-paste arms — the enum has only three values, so the second arm of each pair was unreachable). No user-visible behavior change.
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
plans/UX_GUIDELINES.md(Part B). 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 inplans/UX_GUIDELINES.md(Part B). - Tier A polish from
plans/UX_GUIDELINES.md(Part B) is 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 inplans/UX_GUIDELINES.md(Part A). - 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 inplans/UX_GUIDELINES.md(Part B). - Backlog plan added at
plans/UX_GUIDELINES.md(Part B) covering 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 retains the full set of menu items after the hub trim so previously-promoted commands stay one click away. 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
plans/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-insidersand other VS Code-compatible CLIs, so devs with multiple editors installed get the VS Code Extension Development Host by default; override with--editor <name>orSAROPA_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
plans/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 and Earlier #
Looking for older changes? See CHANGELOG_ARCHIVE.md for versions 0.1.0 through 12.6.1.