No description
- Dart 91.4%
- Python 7.5%
- Shell 0.9%
- JavaScript 0.2%
Found by dogfooding on nuwayze: `pipe queries lib` from the repo root
failed with
no resolved package graph at .dart_tool/package_config.json
remedy: run `flutter pub get` or `dart pub get` in .../nuwayze-w3/lib
It failed even with the package resolved, because the path was taken
as the project root: pipe looked for lib/.dart_tool/package_config.json,
which never exists, and the remedy sent the user to run pub get in a
directory that has no pubspec.
enclosingPackage() (project.dart) splits a path into the package that
contains it (the path itself when it holds a pubspec.yaml, else the
nearest ancestor that does) and the directory it names under that
root. `pipe queries` loads the package root and scans only that
directory, so `pipe queries lib/services` is `--dir lib/services` on
the package; an explicit --dir with such a path is relative to it.
Without a resolved graph the error now names the package root.
loadProject's own remedy uses the same lookup, so `pipe check lib`
(and the other commands, which still take the path as the root) now
says the path is inside the package at <root> and suggests passing
that with `--dir lib`, instead of pub get in lib.
Tests: enclosingPackage on a root, a nested directory, a nested
package and a missing path; loadProject's remedy for a directory
inside a package; and `pipe queries` on the fixture's lib/data
(root reported as the package, one file discovered), with
`lib --dir data`, and on an unresolved package where the remedy names
the root, not lib.
On nuwayze-w3: `pipe queries lib` exits 0 with 313 queries over 847
files, identical to `pipe queries .`; `pipe queries lib/services` scans
161 files and every one of its 212 queries sits under lib/services.
233 tests pass.
|
||
|---|---|---|
| .githooks | ||
| .github | ||
| bin | ||
| docs | ||
| lib | ||
| recall | ||
| scripts | ||
| test | ||
| tool | ||
| .gitignore | ||
| .release-please-manifest.json | ||
| analysis_options.yaml | ||
| commitlint.config.js | ||
| pubspec.lock | ||
| pubspec.yaml | ||
| README.md | ||
| release-please-config.json | ||
pipe
Static state-flow analysis for Dart and Flutter apps. pipe maps how state
moves through an app's state management and reports the breakages that make it
behave worse than the code suggests: a spinner that never stops, an error the
user never sees, a tap that does nothing.
It is built to guide agents and reviewers on large codebases, not to score
style. Every finding carries file:line evidence, a confidence, a severity and
a remediation, and every report states how much of the project it covered.
Coverage
| State management | Support |
|---|---|
BLoC / Cubit (on<Event>, emit, sealed, abstract, enum or freezed unions) |
yes |
Single state class with a bool loading-style flag (copyWith) |
yes |
Riverpod (FutureProvider, StreamProvider, NotifierProvider, .family, ...) |
yes |
provider + ChangeNotifier |
yes, with limits |
C++ enum class state (experimental, via libclang) |
see design |
Firestore query inventory (pipe queries, no rules) |
see queries |
| Navigation, layout, theming | no |
Quick start
dart pub get
tool/build_release.sh # prints the binary's path under build/
# below, `pipe` is that binary on your PATH (or `dart run bin/pipe.dart`)
pipe index <path> # can the project be analysed?
pipe check <path> # ranked findings
pipe suggest <path> # what to fix first, per file
pipe guide <path> --format agent # a brief to paste into an agent prompt
pipe queries <path> # every Firestore query, as typed records
In CI, accept today's findings once and fail only on new ones:
pipe check . --write-baseline .pipe-baseline.json
pipe check . --baseline .pipe-baseline.json --fail-on warning
pipe verify . --expect-resolved # after a fix; reads .pipe-baseline.json
Rules
| Rule | Meaning |
|---|---|
emitted-not-rendered |
A state is emitted but no UI code matches it, so the user never sees it. |
rendered-not-emitted |
A UI branch no emitted state can reach: dead UI. |
loading-not-reset |
An in-progress state whose failure path never resolves, so the spinner sticks. |
loading-flag-not-reset |
The same, for a bool loading flag left set after an error. |
event-without-handler |
A dispatched event with no on<Event>, so the interaction does nothing. |
dead-handler |
An on<Event> that nothing dispatches or constructs. |
riverpod-async-gap |
An async provider read in the UI whose error or loading state is never handled. |
notifier-never-notifies |
A ChangeNotifier method changes observable state without notifying. |
notifier-inert-consumer |
A consumed notifier that never notifies, so its consumers never rebuild. |
provider-read-in-build |
A Listenable read without subscribing inside build, so it can render stale. |
notifier-field-unread |
A public member of a consumed notifier that nothing reads. |
provider-created-in-build |
A provider constructed in build, so its state is recreated on rebuild. |
Measured precision, recall and the limits of each rule are in docs/rules.md.
Documentation
- Usage: commands, flags, SDK discovery, CI ratcheting, verification, fix order, agent briefs.
- Rules: what each rule claims, the evidence behind it, and how precision and recall are measured.
- Firestore queries: the query inventory, its schema and adapter config.
- Design: why pipe exists, how it is built, the state-model seam, and the experimental C++ front end.
- Development: building, performance, tests and hooks.