runPipeline function
String
runPipeline({
- required List<
ScannedFile> files, - AdapterConfig config = const AdapterConfig(),
- required void warn(),
- AnnotationResolution? resolution,
- String adapterName = cliAdapterName,
Pipeline auf bereits gescannten Dateien — gemeinsame Basis von Adapter-CLI
und build_runner-Builder (Weg D). Gleiche Merge-/Sortier-/
Serialisierungslogik für beide Zubringer (Paritätsgarantie): Unterschiede
entstehen nur durch resolution (zusätzlich aufgelöste Werte) und
adapterName (meta.adapters-Eintrag).
Implementation
String runPipeline({
required List<ScannedFile> files,
AdapterConfig config = const AdapterConfig(),
required void Function(String) warn,
AnnotationResolution? resolution,
String adapterName = cliAdapterName,
}) {
final errors = <String>[];
final nodes = <GraphNode>[];
final flows = <GraphFlow>[];
final actions = <ActionCandidate>[];
final manualScreenClasses = <String, String>{};
// Weg A + B — manuelle Quellen, Dateien in sortierter Reihenfolge.
for (final file in files) {
for (final extraction in [
parseComments(file, warn, errors),
extractAnnotations(file, warn, errors, resolution: resolution),
]) {
nodes.addAll(extraction.nodes);
flows.addAll(extraction.flows);
actions.addAll(extraction.actions);
extraction.screenClassNames.forEach(
(cls, id) => manualScreenClasses.putIfAbsent(cls, () => id));
}
}
// Weg C — Ableitungen.
var autoRoute = AutoRouteDerivation();
if (config.deriveAutoRoute) {
autoRoute = deriveAutoRoute(files, warn);
nodes.addAll(autoRoute.nodes);
}
final edges = <GraphEdge>[];
var builderClassToScreen = const <String, String>{};
if (config.deriveGoRouter) {
final goRouter = deriveGoRouter(
files,
warn,
manualScreenClasses: manualScreenClasses,
extraClassToScreen: autoRoute.classToScreen,
extraPathToScreen: autoRoute.pathToScreen,
);
nodes.addAll(goRouter.nodes);
flows.addAll(goRouter.flows);
edges.addAll(goRouter.edges);
builderClassToScreen = goRouter.builderClassToScreen;
}
// from-Inferenz für Actions ohne explizites `from` (DD §B.3): umschließende
// Klasse muss als Screen bekannt sein (Annotation, Kommentar oder
// builder-/auto_route-Zuordnung).
for (final action in actions) {
var from = action.from;
if (from == null) {
final cls = action.enclosingClassName;
from = cls == null
? null
: manualScreenClasses[cls] ??
autoRoute.classToScreen[cls] ??
builderClassToScreen[cls];
if (from == null) {
errors.add('${action.sourceRef}: Action "${action.label}" ohne "from" '
'— umschließende Klasse ${cls ?? '(keine)'} ist kein bekannter '
'Screen.');
continue;
}
}
edges.add(GraphEdge(
id: action.id,
from: from,
to: action.to,
trigger: action.trigger,
label: action.label,
condition: action.condition,
source: SourceKind.annotation,
sourceRef: action.sourceRef,
));
}
if (errors.isNotEmpty) {
throw AdapterException(errors);
}
final merged = mergeGraph(nodes: nodes, edges: edges, flows: flows);
return encodeCanonicalGraph(
flows: merged.flows,
nodes: merged.nodes,
edges: merged.edges,
adapterName: adapterName,
);
}