encodeCanonicalGraph function
Kanonisches Graph-JSON nach DD §C: rekursiv sortierte Schlüssel,
2-Space-Indent, LF, abschließender Zeilenumbruch, kein generatedAt.
adapterName ist der meta.adapters-Eintrag: cliAdapterName für den
CLI-Scan, builderAdapterName für das build_runner-Artefakt (Weg D) —
ansonsten sind beide Ausgaben byte-identisch (Paritätsgarantie).
Implementation
String encodeCanonicalGraph({
required List<GraphFlow> flows,
required List<GraphNode> nodes,
required List<GraphEdge> edges,
String adapterName = cliAdapterName,
}) {
int byId(String a, String b) => a.compareTo(b);
final graph = <String, Object?>{
'schemaVersion': schemaVersion,
'flows': ([...flows]..sort((a, b) => byId(a.id, b.id)))
.map((f) => f.toJson())
.toList(),
'nodes': ([...nodes]..sort((a, b) => byId(a.id, b.id)))
.map((n) => n.toJson())
.toList(),
'edges': ([...edges]..sort((a, b) => byId(a.id!, b.id!)))
.map((e) => e.toJson())
.toList(),
'meta': {
'adapters': [
{'name': adapterName, 'version': adapterVersion},
],
},
};
final encoded =
const JsonEncoder.withIndent(' ').convert(_canonicalize(graph));
return '$encoded\n';
}