Diagnostic.fromJson constructor

Diagnostic.fromJson(
  1. Map<Object?, Object?> json
)

Implementation

factory Diagnostic.fromJson(Map<Object?, Object?> json) {
  String requiredString(String key) {
    final value = json[key];
    if (value is! String || value.isEmpty) {
      throw FormatException('Diagnostic requires non-empty $key');
    }
    return value;
  }

  DiagnosticSeverity parseSeverity(Object? value) => switch (value) {
    'info' => DiagnosticSeverity.info,
    'warning' => DiagnosticSeverity.warning,
    'error' => DiagnosticSeverity.error,
    _ => throw FormatException('Unknown diagnostic severity: $value'),
  };

  DiagnosticOwner parseOwner(Object? value) => switch (value) {
    null || 'unknown' => DiagnosticOwner.unknown,
    'project' => DiagnosticOwner.project,
    'environment' => DiagnosticOwner.environment,
    'zuke' => DiagnosticOwner.zuke,
    _ => throw FormatException('Unknown diagnostic owner: $value'),
  };

  String? optionalString(String key) {
    final value = json[key];
    if (value == null) return null;
    if (value is! String || value.isEmpty) {
      throw FormatException('Diagnostic $key must be non-empty');
    }
    return value;
  }

  final rawRemediation = json['remediation'];
  if (rawRemediation != null && rawRemediation is! String) {
    throw const FormatException('Diagnostic remediation must be a string');
  }

  final rawContext = json['context'];
  final context = <String, String>{};
  if (rawContext != null) {
    if (rawContext is! Map ||
        rawContext.keys.any((key) => key is! String) ||
        rawContext.values.any((value) => value is! String)) {
      throw const FormatException(
        'Diagnostic context must be string-to-string',
      );
    }
    for (final entry in rawContext.entries) {
      context[entry.key as String] = entry.value as String;
    }
  }
  return Diagnostic(
    code: requiredString('code'),
    stage: requiredString('stage'),
    severity: parseSeverity(json['severity']),
    owner: parseOwner(json['owner']),
    message: requiredString('message'),
    remediation: rawRemediation as String? ?? '',
    profile: optionalString('profile'),
    runnerId: optionalString('runnerId'),
    context: context,
  );
}