Skip to content

Contributing

albertoodev edited this page Aug 24, 2026 · 6 revisions

Contributing

This page explains where an SPM change belongs and what evidence should accompany it. See Development for the full test commands and Architecture for the layer boundaries.

Getting set up

git clone https://github.com/32bytess/spm.git
cd spm
dart pub get
dart analyze     # must be clean
dart test        # must be green

Requirements match the rest of the toolchain: Dart 3.9.2 or newer and Flutter 3.3 or newer.

Before you open a PR

Run the full local gate. A change is not ready until all three pass:

dart analyze                  # zero issues
dart test                     # all tests green
dart format .                 # formatted

A PR is expected to:

  • keep dart analyze clean and dart test green;
  • add or update tests for the behavior it changes (see the per-area guides below);
  • stay within one feature module where possible, since analysis/, isolation/, injection/, profiler/, and validation/ are independent;
  • follow the code conventions below.

Use a topic branch (not master) and keep the commit history readable.

Code conventions

These conventions are enforced in review and described further in Architecture and Development:

  • Type aliases. Use the aliases in src/core/types.dart (Result<T>, AsyncResult<T>, AsyncVoidResult, AsyncVoid, and JsonRecord); never spell the full types out inline.
  • Error handling. Return Either<Failure, T> (Left is the error case) throughout the data and domain layers. Only throw at the outermost CLI boundary. Data sources may throw; the repository layer maps those exceptions to a typed Failure.
  • New error types go in src/core/errors/failures.dart as a Failure subclass; aggregate several with CompoundFailure.
  • Logging goes through SpmLogger, never print.
  • DI. Each feature has a static service locator (AnalysisDI, IsolationDI, InjectionDI, ValidationDI) built on lazy ??= getters. When wiring a new dependency, add it there.

Testing conventions

The suite has firm rules, so read Development before writing tests. The essentials:

  • Hand-written fakes only, never mocks. Implement the repository/data-source interface directly. Repository fakes expose givenSuccess() / givenFailure(Failure); data-source fakes expose givenSuccess() / givenThrows(Exception).
  • Copy list references when capturing call arguments in a fake: List.of(targets).
  • Async exception tests are async and await the call inside a try/catch.
  • File-I/O tests create a Directory.systemTemp.createTempSync(...) in setUp and delete it in tearDown. Never write test artifacts into the repo.
  • When testing through the DI layer, call the feature DI's reset() in setUp/tearDown.

Adding to a feature

A new analysis metric / extractor

  1. Add a fixture Dart file under test/fixtures/analysis/ that exercises the case.
  2. Add the extractor/visitor in the relevant analysis/data/data_sources/ set.
  3. If it produces a new output field, add it to AnalysisResultModel.toJson and document it in Output Formats and Extracted Features. The wiki lists the exact field set, so a new key must land in both.
  4. Add a test under test/features/analysis/, preferring getResultsForFixture(...) from test/features/analysis/utils/test_helper.dart over re-wiring the pipeline.

A new rebuild-scope pattern

Scope detection is shared: the kind lists live in AppConstants (builderScopeWidgets, positionalBuilderScopeWidgets, rebuildScopeTypes) and the predicates in analysis/data/data_sources/extensions/state_class_detector.dart. Both isolate (RebuildScopeVisitor) and analyze (RebuildScopeAnalysisVisitor) read from them.

  1. Add a realistic fixture under test/fixtures/isolation/ and, if the new kind should be measured, one under test/fixtures/analysis/rebuild_scopes/.
  2. Add the pattern to the shared constants/predicates rather than to one visitor.
  3. Add tests under test/features/isolation/ and test/features/analysis/.
  4. A new scope type widens the --scope-types allowed values and the scopeType column, so document it in analyze and Output Formats.

A new validation check

  1. Add the code to the ViolationCode enum in validation/domain/entities/validation_report.dart (keep the JSON schema stable).
  2. Implement the check so it appends a Violation{code, severity, detail}.
  3. Add a fixture case under test/fixtures/validation/<case>/{base.dart, mutation.dart} proving the violation, and a test under test/features/validation/.
  4. Update validate and Validate: AST Internals to move the code from the "not yet implemented" list into the checks table.

Keeping docs in sync

This wiki documents exact field names and schemas taken from the code. If your change touches a toJson, a CLI flag, an event name, or a Failure/ViolationCode, update the corresponding wiki page in the same PR so the two never drift.

Clone this wiki locally