WorldManifest.fromDocument constructor

WorldManifest.fromDocument(
  1. Map<String, dynamic> doc
)

Parse a manifest document. Throws WorldManifestError (with fix hints) on structural violations.

Implementation

factory WorldManifest.fromDocument(Map<String, dynamic> doc) {
  final schema = (doc['schema'] as num?)?.toInt() ?? 0;
  if (schema != schemaVersion) {
    throw WorldManifestError(
      'world manifest schema $schema is not $schemaVersion '
      '--> fix: regenerate the world with `zfa simulate init`.',
    );
  }
  final scenario = doc['scenario'] as String? ?? '';
  if (scenario.isEmpty) {
    throw const WorldManifestError(
      'world manifest without a scenario name --> fix: set "scenario" '
      '(the `zfa simulate --scenario` key).',
    );
  }
  final touchpoints = (doc['touchpoints'] as List? ?? const [])
      .map(
        (t) => WorldTouchpoint.fromJson(Map<String, dynamic>.from(t as Map)),
      )
      .toList(growable: false);
  if (touchpoints.isEmpty) {
    throw WorldManifestError(
      'world "$scenario" declares no touchpoints --> fix: declare the '
      'dependency rows (External Dependencies table) and re-run '
      '`zfa simulate init $scenario`.',
    );
  }
  final storms =
      (((doc['failureSchedule'] as Map<String, dynamic>? ??
                      const <String, dynamic>{})['storms']
                  as List? ??
              const [])
          .map(
            (s) => WorldStorm.fromJson(Map<String, dynamic>.from(s as Map)),
          )
          .toList(growable: false));
  final behaviors = (doc['behaviors'] as List? ?? const [])
      .map((b) => WorldBehavior.fromJson(Map<String, dynamic>.from(b as Map)))
      .toList(growable: false);
  final latency = <String, WorldLatencyBands>{};
  final latencyDoc = doc['latency'] as Map? ?? const {};
  for (final entry in latencyDoc.entries) {
    final value = entry.value;
    if (value is Map) {
      latency[entry.key.toString()] = WorldLatencyBands.fromJson(
        Map<String, dynamic>.from(value),
      );
    }
  }
  final corpus = <String, Map<String, dynamic>>{};
  final corpusDoc = doc['corpus'] as Map? ?? const {};
  for (final entry in corpusDoc.entries) {
    final value = entry.value;
    if (value is Map) {
      corpus[entry.key.toString()] = Map<String, dynamic>.from(value);
    }
  }
  return WorldManifest(
    schema: schema,
    spec: (doc['spec'] as num?)?.toInt() ?? specNumber,
    scenario: scenario,
    feature: doc['feature'] as String? ?? '',
    version: (doc['version'] as num?)?.toInt() ?? 1,
    seed: (doc['time'] is Map
        ? ((doc['time'] as Map)['seed'] as num?)?.toInt() ?? 0
        : 0),
    touchpoints: touchpoints,
    latency: latency,
    storms: storms,
    corpus: corpus,
    behaviors: behaviors,
    description: doc['description'] as String? ?? '',
  );
}