Skip to content
Back to archipelago.banuacoder.com

Shared Packages

How to enforce architecture rules in a Flutter monorepo with lints ​

Free Reference for app_lints: every variable, option and package it generates. Command: archipelago generate app_lints

Generate the app_lints analyzer plugin, learn its seven rules, fix the lint messages, and adopt the DI rules in an older project.

What you'll learn ​

  • Generating the app_lints analyzer plugin
  • Understanding the seven rules it enables
  • Reading and fixing the lint messages
  • Adopting the DI rules in an older project

Prerequisites ​

New projects already include this brick. Run it on an older project.

Step 1: Generate the Lint Package ​

bash
archipelago generate app_lints

The prompts are:

  • appName: the name of your app
  • isForMonorepo: leave this as true

Or use a config file:

json
{
  "appName": "MyApp",
  "isForMonorepo": true
}
bash
archipelago generate app_lints --config lints_config.json

Step 2: Understand the Generated Structure ​

The brick creates an analyzer plugin. It is not a lint rule package that you edit often.

text
utilities/
└── app_lints/
    ├── lib/
    │   ├── main.dart             # AppLintsPlugin registers the 7 rules
    │   └── src/
    │       ├── pii/              # Personal-data key matcher and call scanner
    │       └── rules/            # One file per rule
    ├── test/                     # Rule tests over an in-memory workspace
    ├── analysis_options.yaml
    └── pubspec.yaml

Step 3: Know the Seven Rules ​

The rules run during dart analyze and in your IDE.

Layer rules

  • api_no_external_deps: an *_api package imports only dart:*, shared packages, other _api packages and a short list of pub packages.
  • no_impl_cross_import: an *_impl package never imports another *_impl package. Go through the _api package.
  • no_upward_dependency: the layer order is apps, features, infrastructure, packages, shared. A lower layer never imports a higher one.

The layer comes from the folder of the resolved file, not from the package name.

DI rules (feature code only)

  • no_service_locator_outside_di: a GetIt value appears only in lib/src/di/ or in a MicroPackageModule. Take dependencies as constructor parameters.
  • feature_global_module_allowlist: a feature global module registers only its FeatureManifest, its own SDK, or a line marked // di-global: <reason>.
  • no_service_locator_in_manifest: a manifest never reads GetIt in its constructor, isEnabled or registerRoutes. Pass a provider closure instead.

Privacy rule

  • no_pii_in_telemetry: flags personal-data keys in maps passed to track, log, breadcrumb, recordError or captureCustomEvent.

Step 4: Check the Root analysis_options.yaml ​

The generated root file enables all three DI rules:

yaml
plugins:
  app_lints:
    path: utilities/app_lints
    diagnostics:
      feature_global_module_allowlist: true
      no_service_locator_outside_di: true
      no_service_locator_in_manifest: true

Run the analyzer to see findings:

bash
dart analyze

Step 5: Fix or Suppress Findings ​

Fix a service-locator finding by moving the lookup:

  • Pages get their dependencies from the shell page lease or a route builder.
  • State holders take dependencies by constructor.

Use // di-global: <reason> only for a port that code outside the feature resolves from the root.

An older project can adopt the rules step by step. Set no_service_locator_outside_di: false until you migrate. Or suppress single sites:

dart
// ignore: app_lints/no_service_locator_outside_di

The app_lints/ prefix is required for plugin diagnostics.

Key Customization Points ​

CustomizationWhere to Change
Turn a rule offThe diagnostics map in the root analysis_options.yaml
Suppress one siteAn // ignore: app_lints/<rule> comment
Change the personal-data key listlib/src/pii/pii_key_matcher.dart
Add a ruleA new file in lib/src/rules/, registered in lib/main.dart

Known Limitations ​

  • The DI rules report in the IDE and dart analyze only. No CI command gates them.
  • Generated *.module.dart files are not checked.
  • There is no baseline file yet.

Next Steps ​