blob: 4699bed1173b43419241d5ccdcd2fc36b20caa76 [file] [log] [blame]
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:nnbd_migration/src/hint_action.dart';
/// Information about what should be populated into the "Edit Details" view of
/// the migration preview tool.
class EditDetails {
/// A list of edits that can be offered to the user related to this source
/// location (e.g. adding/removing hints). `null` if this feature is
/// disabled.
final List<EditLink>? edits;
/// A string explanation of the edit.
final String? explanation;
/// The line number of the edit.
final int? line;
/// The path of the file that was edited, to be shown to the user.
final String? displayPath;
/// The path of the file that was edited, as a URI.
final String? uriPath;
/// A list of traces representing stacktrace-like views of why the change was
/// made, or the empty list if there are no traces for this change.
final List<Trace>? traces;
EditDetails(
{this.edits,
required this.explanation,
required this.line,
required this.displayPath,
required this.uriPath,
this.traces = const []});
EditDetails.fromJson(dynamic json)
: edits = _decodeEdits(json['edits'] as List<Object?>?),
explanation = json['explanation'] as String?,
line = json['line'] as int?,
displayPath = json['displayPath'] as String?,
uriPath = json['uriPath'] as String?,
traces = _decodeTraces(json['traces'] as List<Object?>?);
Map<String, Object?> toJson() => {
if (edits != null) 'edits': [for (var edit in edits!) edit.toJson()],
'explanation': explanation,
'line': line,
'displayPath': displayPath,
'uriPath': uriPath,
if (traces != null)
'traces': [for (var trace in traces!) trace.toJson()],
};
static List<EditLink>? _decodeEdits(List<Object?>? json) =>
json == null ? null : [for (var edit in json) EditLink.fromJson(edit)];
static List<Trace>? _decodeTraces(List<Object?>? json) =>
json == null ? null : [for (var trace in json) Trace.fromJson(trace)];
}
/// Information about a single link that should be included in the
/// "Edit Details" view of the migration preview tool, where the purpose of the
/// link is to allow the user to make a change to the source file (e.g. to add
/// or remove a hint).
class EditLink {
/// Description of the change to be performed.
final String? description;
/// The href to link to.
final String? href;
EditLink({required this.description, required this.href});
EditLink.fromJson(dynamic json)
: description = json['description'] as String?,
href = json['href'] as String?;
Map<String, Object?> toJson() => {
'description': description,
'href': href,
};
}
/// Information about a single link that should be included in the
/// "Edit Details" view of the migration preview tool, where the purpose of the
/// link is to allow the user to navigate to a source file containing
/// information about the rationale for a change.
class TargetLink {
/// The href to link to.
final String? href;
/// The line number of the link.
final int? line;
/// Relative path to the source file (intended for display).
final String? path;
TargetLink({required this.href, required this.line, required this.path});
TargetLink.fromJson(dynamic json)
: href = json['href'] as String?,
line = json['line'] as int?,
path = json['path'] as String?;
Map<String, Object?> toJson() => {
'href': href,
'line': line,
'path': path,
};
}
/// A trace of why a nullability decision was made.
class Trace {
/// Text description of the trace.
final String? description;
/// List of trace entries.
final List<TraceEntry> entries;
Trace({required this.description, required this.entries});
Trace.fromJson(dynamic json)
: description = json['description'] as String?,
entries = [
for (var entry in json['entries'] as List<Object?>)
TraceEntry.fromJson(entry)
];
Map<String, Object?> toJson() => {
'description': description,
'entries': [for (var entry in entries) entry.toJson()]
};
}
/// Information about a single entry in a nullability trace.
class TraceEntry {
/// Text description of the entry.
final String? description;
/// The function associated with the entry. We display this before the link
/// so that the trace has the familiar appearance of a stacktrace.
///
/// Null if not known.
final String? function;
/// Source code location associated with the entry, or `null` if no source
/// code location is known.
final TargetLink? link;
/// The hint actions available to affect this entry of the trace, or `[]` if
/// none.
final List<HintAction> hintActions;
TraceEntry(
{required this.description,
this.function,
this.link,
this.hintActions = const []});
TraceEntry.fromJson(dynamic json)
: description = json['description'] as String?,
function = json['function'] as String?,
link = _decodeLink(json['link']),
hintActions = (json['hintActions'] as List?)
?.map((value) =>
HintAction.fromJson(value as Map<String, Object?>))
.toList() ??
const [];
Map<String, Object?> toJson() => {
'description': description,
if (function != null) 'function': function,
if (link != null) 'link': link!.toJson(),
if (hintActions.isNotEmpty)
'hintActions': hintActions.map((action) => action.toJson()).toList()
};
static TargetLink? _decodeLink(dynamic json) =>
json == null ? null : TargetLink.fromJson(json);
}