Skip to content

Commands inject

albertoodev edited this page Jul 31, 2026 · 4 revisions

inject: code transformation

inject reads the JSONL manifest from analyze and changes each matching State class to extend SPM's SpmState base class. The remove mode restores the original classes.

Usage

spm inject --jsonl results.jsonl /path/to/project              # inject (default)
spm inject -j results.jsonl -m inject /path/to/project
spm inject -j results.jsonl -m remove /path/to/project         # revert

Options and flags

Flag / Option Short Description
--jsonl <path> -j Required. JSONL manifest from analyze.
--mode <mode> -m inject (default) or remove.
--verbose -v Print progress to stdout.
<repo_root> Path to the Flutter project root (exactly one).

--mode accepts only inject and remove. Passing any other value is a usage error.

What it rewrites

Only State subclasses can be given an SpmState base class, so inject reads the manifest and skips every row whose scopeType is not State (consumer widgets, builder callbacks). A full-scope analyze output can therefore be passed straight to inject; manifests produced before rebuild-scope support carry no scopeType and are treated as all-State.

For each target State class listed in the manifest, inject mode:

  1. Inserts an instanceId getter right after the class's opening brace:
    @override
    String get instanceId => '<instanceId-from-manifest>';
  2. Replaces extends State<T> with extends SpmState<T> in the extends clause.
  3. Adds the SpmState import (package:spm/spm.dart) to the file. This is the only supported public import from SPM.

remove mode reverts all three: it deletes the instanceId getter, changes SpmState back to State, and removes the import.

How runtime metrics get selected

inject does not choose between performance and dataflow measurement. That happens at runtime, inside SpmState.setState, based on the Flutter build mode:

Build mode Runtime call Emitted event
--profile (kProfileMode) SpmProfiler.monitor(...) performance_metric
--debug (kDebugMode) SpmProfiler.monitorDataFlow(..., context: ...) dataflow-metric
release plain super.setState(fn) none (no instrumentation)

So the same injected code produces performance metrics under --profile and dataflow metrics under --debug. See Output Formats for both event schemas.

Notes

  • Run --mode remove to restore the source once profiling is complete.
  • Injection is driven by the analyze manifest, so re-run analyze whenever the target source changes.

Related

  • run applies injection and launches the app in --profile mode in one step.
  • Output Formats documents the runtime JSONL the instrumented app emits.

Clone this wiki locally