vibe_check 1.0.1
vibe_check: ^1.0.1 copied to clipboard
Lints that catch AI-generated Dart slop — inline async in builders, redundant null checks, swallowed exceptions, and more.
1.0.1 - 2026-09-12 #
Documentation only — no rule, quick-fix or preset behaviour changed.
Changed #
- The rule-configuration recipe now sits with the rules it configures. The
README's "Changing the rules" — the
diagnostics:map to copy out ofnylo.yaml, the values each entry accepts (true/false,info,warning,error), the reminder thatplugins:is top-level andanalyzer: errors:never reaches plugin diagnostics, and the// ignore:comments — moved from the bottom of the file to directly beneath the rules table, where the On by default column raises the question. It is now a subsection of "The rules" rather than a top-level section, so the per-rule sections still nest under that heading; the#changing-the-rulesanchor is unchanged, so links to it still resolve. nylo.yaml's note on switchingunlocalized_stringon pointed at a "Configuration section" the README does not have — it now names "Changing the rules".
1.0.0 - 2026-09-06 #
Initial release: a small, trustworthy set of opt-in lint rules for the
first-party Dart analyzer plugin system (analysis_server_plugin), packaged
as a drop-in baseline for AI-assisted Flutter/Dart and Nylo projects. All
rules are off by default — adopt them with a one-line include: of a shipped
preset (package:vibe_check/nylo.yaml for Nylo apps,
package:vibe_check/recommended.yaml or strict.yaml for plain Flutter/Dart).
Quick-fixes are IDE-only: the plugin protocol (analyzer_plugin) has no
bulk-fix request, and the dart fix CLI resolves --code= against the
analyzer's built-in diagnostics only. Plugin diagnostics themselves surface
only when dart analyze runs from the package root with no path argument
(or .) — dart analyze lib and flutter analyze both drop them.
Added #
-
inline_async_in_builder(warning) — flags aFuture/Streamconstructed inline in aFutureBuilder/StreamBuilder, Nylo'sFutureWidget, or its Nylo 6 nameNyFutureBuilder, which is recreated on every rebuild, restarting the builder and flashing loading states. Matched on the resolved element — class name and declaring library URI — so a same-named class from another package is never flagged, and each builder is matched only on the named argument it actually declares (future:orstream:). -
redundant_null_check(info, quick-fix) — flags null comparisons and null-aware operators applied to a statically non-nullable value. The fix rewrites each form to its known result (x != null→true,x == null→false,x ?? y→x,x!→x). -
swallowed_exception(warning, quick-fix) — flags empty or silently-swallowingcatchclauses; the fix insertsrethrow;. -
nonstandard_nylo_page, the page rule (warning/info, nine quick-fixes across its fourteen diagnostics, all sharing this rule's name so onediagnostics:entry or// ignore:covers them) — holds a page underlib/resources/pages/to the shapemetro make:pagegenerates: astatic RouteView path, asuper(child: () => _XState())constructor, anNyPage<X>state,initinstead ofinitState, andviewinstead ofbuild. The most common drift — the class named after the file extending a plainStatelessWidget/StatefulWidget, soinitnever runs and there is no controller — is its own warning. Stays quiet on correct code: a plainStategets only the base-class diagnostic,viewis resolved through the real inheritance chain so app-local bases andNavigationHubpass, abstractNyStatefulWidgetsubclasses are treated as bases rather than pages, and the structural checks engage only on classes extending Nylo'sNyStatefulWidget— so the rule is inert on Nylo 8's single-class shape. Only the class named after the file is held to being a page, so helper widgets in the same file stay silent. -
unlocalized_string, the localization rule (info/warning, off by default) — one rule, two diagnostics sharing its name, covering both ways a string ends up on screen in one language while the code looks fine: a user-visible string written as a bare literal inlib/resources/pages/orlib/resources/widgets/(Text,Tooltip(message:), andInputDecoration's text fields), and a translation key built by interpolation ('Hello $name'.tr()), which can never match a lang-file entry and so silently renders the key. Detection is structural rather than API-specific — any way of localizing a string produces something that isn't a bare literal, so it works with any localization package without knowing any of them by name — and deliberate dynamic keys ('status_$code'.tr()) stay silent. Listed off innylo.yamlsince it only means something once an app has adopted localization. -
Preset configs for one-line adoption —
include:a shipped preset instead of listing rules by hand. Each preset declares the plugin source itself (path: ../, resolved relative to the preset file, so it always points at the vibe_check package that supplied it, from the pub cache or a local checkout alike), so a project's entire configuration is theinclude:line:package:vibe_check/nylo.yaml— the Nylo baseline. Bundlespackage:flutter_lints/flutter.yaml(vibe_check declaresflutter_lintsas a regular dependency, so this resolves transitively with nothing to add to the consumer'spubspec.yaml), turns on the three framework-agnostic rules plusnonstandard_nylo_page, and listsunlocalized_stringoff.package:vibe_check/recommended.yaml— the framework-agnostic baseline for plain Flutter/Dart projects: the three general rules plus the companion core lintsspecify_nonobvious_local_variable_typesandspecify_nonobvious_property_types, which flag AI type-omission likefinal user = fetchUser()while leaving obvious cases likefinal x = truealone.package:vibe_check/strict.yaml— the same three rules withalways_specify_types, requiring an explicit type on every declaration.
Declaring a
plugins: vibe_check:entry alongside a preset'sinclude:replaces it wholesale rather than merging — the analyzer keeps one configuration per plugin name — so a project customizes by redeclaring the whole entry (copied from the preset) instead of adding one next to the include.